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");
6587 if(Roo.isBorderBox){
6588 cls.push('roo-border-box');
6590 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6591 var p = bd.dom.parentNode;
6593 p.className += ' roo-strict';
6596 bd.addClass(cls.join(' '));
6600 * @class Roo.EventObject
6601 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6602 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6605 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6607 var target = e.getTarget();
6610 var myDiv = Roo.get("myDiv");
6611 myDiv.on("click", handleClick);
6613 Roo.EventManager.on("myDiv", 'click', handleClick);
6614 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6618 Roo.EventObject = function(){
6620 var E = Roo.lib.Event;
6622 // safari keypress events for special keys return bad keycodes
6625 63235 : 39, // right
6628 63276 : 33, // page up
6629 63277 : 34, // page down
6630 63272 : 46, // delete
6635 // normalize button clicks
6636 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6637 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6639 Roo.EventObjectImpl = function(e){
6641 this.setEvent(e.browserEvent || e);
6644 Roo.EventObjectImpl.prototype = {
6646 * Used to fix doc tools.
6647 * @scope Roo.EventObject.prototype
6653 /** The normal browser event */
6654 browserEvent : null,
6655 /** The button pressed in a mouse event */
6657 /** True if the shift key was down during the event */
6659 /** True if the control key was down during the event */
6661 /** True if the alt key was down during the event */
6720 setEvent : function(e){
6721 if(e == this || (e && e.browserEvent)){ // already wrapped
6724 this.browserEvent = e;
6726 // normalize buttons
6727 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6728 if(e.type == 'click' && this.button == -1){
6732 this.shiftKey = e.shiftKey;
6733 // mac metaKey behaves like ctrlKey
6734 this.ctrlKey = e.ctrlKey || e.metaKey;
6735 this.altKey = e.altKey;
6736 // in getKey these will be normalized for the mac
6737 this.keyCode = e.keyCode;
6738 // keyup warnings on firefox.
6739 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6740 // cache the target for the delayed and or buffered events
6741 this.target = E.getTarget(e);
6743 this.xy = E.getXY(e);
6746 this.shiftKey = false;
6747 this.ctrlKey = false;
6748 this.altKey = false;
6758 * Stop the event (preventDefault and stopPropagation)
6760 stopEvent : function(){
6761 if(this.browserEvent){
6762 if(this.browserEvent.type == 'mousedown'){
6763 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6765 E.stopEvent(this.browserEvent);
6770 * Prevents the browsers default handling of the event.
6772 preventDefault : function(){
6773 if(this.browserEvent){
6774 E.preventDefault(this.browserEvent);
6779 isNavKeyPress : function(){
6780 var k = this.keyCode;
6781 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6782 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6785 isSpecialKey : function(){
6786 var k = this.keyCode;
6787 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6788 (k == 16) || (k == 17) ||
6789 (k >= 18 && k <= 20) ||
6790 (k >= 33 && k <= 35) ||
6791 (k >= 36 && k <= 39) ||
6792 (k >= 44 && k <= 45);
6795 * Cancels bubbling of the event.
6797 stopPropagation : function(){
6798 if(this.browserEvent){
6799 if(this.type == 'mousedown'){
6800 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6802 E.stopPropagation(this.browserEvent);
6807 * Gets the key code for the event.
6810 getCharCode : function(){
6811 return this.charCode || this.keyCode;
6815 * Returns a normalized keyCode for the event.
6816 * @return {Number} The key code
6818 getKey : function(){
6819 var k = this.keyCode || this.charCode;
6820 return Roo.isSafari ? (safariKeys[k] || k) : k;
6824 * Gets the x coordinate of the event.
6827 getPageX : function(){
6832 * Gets the y coordinate of the event.
6835 getPageY : function(){
6840 * Gets the time of the event.
6843 getTime : function(){
6844 if(this.browserEvent){
6845 return E.getTime(this.browserEvent);
6851 * Gets the page coordinates of the event.
6852 * @return {Array} The xy values like [x, y]
6859 * Gets the target for the event.
6860 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6861 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6862 search as a number or element (defaults to 10 || document.body)
6863 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6864 * @return {HTMLelement}
6866 getTarget : function(selector, maxDepth, returnEl){
6867 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6870 * Gets the related target.
6871 * @return {HTMLElement}
6873 getRelatedTarget : function(){
6874 if(this.browserEvent){
6875 return E.getRelatedTarget(this.browserEvent);
6881 * Normalizes mouse wheel delta across browsers
6882 * @return {Number} The delta
6884 getWheelDelta : function(){
6885 var e = this.browserEvent;
6887 if(e.wheelDelta){ /* IE/Opera. */
6888 delta = e.wheelDelta/120;
6889 }else if(e.detail){ /* Mozilla case. */
6890 delta = -e.detail/3;
6896 * Returns true if the control, meta, shift or alt key was pressed during this event.
6899 hasModifier : function(){
6900 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6904 * Returns true if the target of this event equals el or is a child of el
6905 * @param {String/HTMLElement/Element} el
6906 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6909 within : function(el, related){
6910 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6911 return t && Roo.fly(el).contains(t);
6914 getPoint : function(){
6915 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6919 return new Roo.EventObjectImpl();
6924 * Ext JS Library 1.1.1
6925 * Copyright(c) 2006-2007, Ext JS, LLC.
6927 * Originally Released Under LGPL - original licence link has changed is not relivant.
6930 * <script type="text/javascript">
6934 // was in Composite Element!??!?!
6937 var D = Roo.lib.Dom;
6938 var E = Roo.lib.Event;
6939 var A = Roo.lib.Anim;
6941 // local style camelizing for speed
6943 var camelRe = /(-[a-z])/gi;
6944 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6945 var view = document.defaultView;
6948 * @class Roo.Element
6949 * Represents an Element in the DOM.<br><br>
6952 var el = Roo.get("my-div");
6955 var el = getEl("my-div");
6957 // or with a DOM element
6958 var el = Roo.get(myDivElement);
6960 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6961 * each call instead of constructing a new one.<br><br>
6962 * <b>Animations</b><br />
6963 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6964 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6966 Option Default Description
6967 --------- -------- ---------------------------------------------
6968 duration .35 The duration of the animation in seconds
6969 easing easeOut The YUI easing method
6970 callback none A function to execute when the anim completes
6971 scope this The scope (this) of the callback function
6973 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6974 * manipulate the animation. Here's an example:
6976 var el = Roo.get("my-div");
6981 // default animation
6982 el.setWidth(100, true);
6984 // animation with some options set
6991 // using the "anim" property to get the Anim object
6997 el.setWidth(100, opt);
6999 if(opt.anim.isAnimated()){
7003 * <b> Composite (Collections of) Elements</b><br />
7004 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7005 * @constructor Create a new Element directly.
7006 * @param {String/HTMLElement} element
7007 * @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).
7009 Roo.Element = function(element, forceNew){
7010 var dom = typeof element == "string" ?
7011 document.getElementById(element) : element;
7012 if(!dom){ // invalid id/element
7016 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7017 return Roo.Element.cache[id];
7027 * The DOM element ID
7030 this.id = id || Roo.id(dom);
7033 var El = Roo.Element;
7037 * The element's default display mode (defaults to "")
7040 originalDisplay : "",
7044 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7049 * Sets the element's visibility mode. When setVisible() is called it
7050 * will use this to determine whether to set the visibility or the display property.
7051 * @param visMode Element.VISIBILITY or Element.DISPLAY
7052 * @return {Roo.Element} this
7054 setVisibilityMode : function(visMode){
7055 this.visibilityMode = visMode;
7059 * Convenience method for setVisibilityMode(Element.DISPLAY)
7060 * @param {String} display (optional) What to set display to when visible
7061 * @return {Roo.Element} this
7063 enableDisplayMode : function(display){
7064 this.setVisibilityMode(El.DISPLAY);
7065 if(typeof display != "undefined") this.originalDisplay = display;
7070 * 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)
7071 * @param {String} selector The simple selector to test
7072 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7073 search as a number or element (defaults to 10 || document.body)
7074 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7075 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7077 findParent : function(simpleSelector, maxDepth, returnEl){
7078 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7079 maxDepth = maxDepth || 50;
7080 if(typeof maxDepth != "number"){
7081 stopEl = Roo.getDom(maxDepth);
7084 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7085 if(dq.is(p, simpleSelector)){
7086 return returnEl ? Roo.get(p) : p;
7096 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7097 * @param {String} selector The simple selector to test
7098 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7099 search as a number or element (defaults to 10 || document.body)
7100 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7101 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7103 findParentNode : function(simpleSelector, maxDepth, returnEl){
7104 var p = Roo.fly(this.dom.parentNode, '_internal');
7105 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7109 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7110 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7111 * @param {String} selector The simple selector to test
7112 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7113 search as a number or element (defaults to 10 || document.body)
7114 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7116 up : function(simpleSelector, maxDepth){
7117 return this.findParentNode(simpleSelector, maxDepth, true);
7123 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7124 * @param {String} selector The simple selector to test
7125 * @return {Boolean} True if this element matches the selector, else false
7127 is : function(simpleSelector){
7128 return Roo.DomQuery.is(this.dom, simpleSelector);
7132 * Perform animation on this element.
7133 * @param {Object} args The YUI animation control args
7134 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7135 * @param {Function} onComplete (optional) Function to call when animation completes
7136 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7137 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7138 * @return {Roo.Element} this
7140 animate : function(args, duration, onComplete, easing, animType){
7141 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7146 * @private Internal animation call
7148 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7149 animType = animType || 'run';
7151 var anim = Roo.lib.Anim[animType](
7153 (opt.duration || defaultDur) || .35,
7154 (opt.easing || defaultEase) || 'easeOut',
7156 Roo.callback(cb, this);
7157 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7165 // private legacy anim prep
7166 preanim : function(a, i){
7167 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7171 * Removes worthless text nodes
7172 * @param {Boolean} forceReclean (optional) By default the element
7173 * keeps track if it has been cleaned already so
7174 * you can call this over and over. However, if you update the element and
7175 * need to force a reclean, you can pass true.
7177 clean : function(forceReclean){
7178 if(this.isCleaned && forceReclean !== true){
7182 var d = this.dom, n = d.firstChild, ni = -1;
7184 var nx = n.nextSibling;
7185 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7192 this.isCleaned = true;
7197 calcOffsetsTo : function(el){
7200 var restorePos = false;
7201 if(el.getStyle('position') == 'static'){
7202 el.position('relative');
7207 while(op && op != d && op.tagName != 'HTML'){
7210 op = op.offsetParent;
7213 el.position('static');
7219 * Scrolls this element into view within the passed container.
7220 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7221 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7222 * @return {Roo.Element} this
7224 scrollIntoView : function(container, hscroll){
7225 var c = Roo.getDom(container) || document.body;
7228 var o = this.calcOffsetsTo(c),
7231 b = t+el.offsetHeight,
7232 r = l+el.offsetWidth;
7234 var ch = c.clientHeight;
7235 var ct = parseInt(c.scrollTop, 10);
7236 var cl = parseInt(c.scrollLeft, 10);
7238 var cr = cl + c.clientWidth;
7246 if(hscroll !== false){
7250 c.scrollLeft = r-c.clientWidth;
7257 scrollChildIntoView : function(child, hscroll){
7258 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7262 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7263 * the new height may not be available immediately.
7264 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7265 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7266 * @param {Function} onComplete (optional) Function to call when animation completes
7267 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7268 * @return {Roo.Element} this
7270 autoHeight : function(animate, duration, onComplete, easing){
7271 var oldHeight = this.getHeight();
7273 this.setHeight(1); // force clipping
7274 setTimeout(function(){
7275 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7277 this.setHeight(height);
7279 if(typeof onComplete == "function"){
7283 this.setHeight(oldHeight); // restore original height
7284 this.setHeight(height, animate, duration, function(){
7286 if(typeof onComplete == "function") onComplete();
7287 }.createDelegate(this), easing);
7289 }.createDelegate(this), 0);
7294 * Returns true if this element is an ancestor of the passed element
7295 * @param {HTMLElement/String} el The element to check
7296 * @return {Boolean} True if this element is an ancestor of el, else false
7298 contains : function(el){
7299 if(!el){return false;}
7300 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7304 * Checks whether the element is currently visible using both visibility and display properties.
7305 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7306 * @return {Boolean} True if the element is currently visible, else false
7308 isVisible : function(deep) {
7309 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7310 if(deep !== true || !vis){
7313 var p = this.dom.parentNode;
7314 while(p && p.tagName.toLowerCase() != "body"){
7315 if(!Roo.fly(p, '_isVisible').isVisible()){
7324 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7325 * @param {String} selector The CSS selector
7326 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7327 * @return {CompositeElement/CompositeElementLite} The composite element
7329 select : function(selector, unique){
7330 return El.select(selector, unique, this.dom);
7334 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7335 * @param {String} selector The CSS selector
7336 * @return {Array} An array of the matched nodes
7338 query : function(selector, unique){
7339 return Roo.DomQuery.select(selector, this.dom);
7343 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7344 * @param {String} selector The CSS selector
7345 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7346 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7348 child : function(selector, returnDom){
7349 var n = Roo.DomQuery.selectNode(selector, this.dom);
7350 return returnDom ? n : Roo.get(n);
7354 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7355 * @param {String} selector The CSS selector
7356 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7357 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7359 down : function(selector, returnDom){
7360 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7361 return returnDom ? n : Roo.get(n);
7365 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7366 * @param {String} group The group the DD object is member of
7367 * @param {Object} config The DD config object
7368 * @param {Object} overrides An object containing methods to override/implement on the DD object
7369 * @return {Roo.dd.DD} The DD object
7371 initDD : function(group, config, overrides){
7372 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7373 return Roo.apply(dd, overrides);
7377 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7378 * @param {String} group The group the DDProxy object is member of
7379 * @param {Object} config The DDProxy config object
7380 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7381 * @return {Roo.dd.DDProxy} The DDProxy object
7383 initDDProxy : function(group, config, overrides){
7384 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7385 return Roo.apply(dd, overrides);
7389 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7390 * @param {String} group The group the DDTarget object is member of
7391 * @param {Object} config The DDTarget config object
7392 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7393 * @return {Roo.dd.DDTarget} The DDTarget object
7395 initDDTarget : function(group, config, overrides){
7396 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7397 return Roo.apply(dd, overrides);
7401 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7402 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7403 * @param {Boolean} visible Whether the element is visible
7404 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7405 * @return {Roo.Element} this
7407 setVisible : function(visible, animate){
7409 if(this.visibilityMode == El.DISPLAY){
7410 this.setDisplayed(visible);
7413 this.dom.style.visibility = visible ? "visible" : "hidden";
7416 // closure for composites
7418 var visMode = this.visibilityMode;
7420 this.setOpacity(.01);
7421 this.setVisible(true);
7423 this.anim({opacity: { to: (visible?1:0) }},
7424 this.preanim(arguments, 1),
7425 null, .35, 'easeIn', function(){
7427 if(visMode == El.DISPLAY){
7428 dom.style.display = "none";
7430 dom.style.visibility = "hidden";
7432 Roo.get(dom).setOpacity(1);
7440 * Returns true if display is not "none"
7443 isDisplayed : function() {
7444 return this.getStyle("display") != "none";
7448 * Toggles the element's visibility or display, depending on visibility mode.
7449 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7450 * @return {Roo.Element} this
7452 toggle : function(animate){
7453 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7458 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7459 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7460 * @return {Roo.Element} this
7462 setDisplayed : function(value) {
7463 if(typeof value == "boolean"){
7464 value = value ? this.originalDisplay : "none";
7466 this.setStyle("display", value);
7471 * Tries to focus the element. Any exceptions are caught and ignored.
7472 * @return {Roo.Element} this
7474 focus : function() {
7482 * Tries to blur the element. Any exceptions are caught and ignored.
7483 * @return {Roo.Element} this
7493 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7494 * @param {String/Array} className The CSS class to add, or an array of classes
7495 * @return {Roo.Element} this
7497 addClass : function(className){
7498 if(className instanceof Array){
7499 for(var i = 0, len = className.length; i < len; i++) {
7500 this.addClass(className[i]);
7503 if(className && !this.hasClass(className)){
7504 this.dom.className = this.dom.className + " " + className;
7511 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7512 * @param {String/Array} className The CSS class to add, or an array of classes
7513 * @return {Roo.Element} this
7515 radioClass : function(className){
7516 var siblings = this.dom.parentNode.childNodes;
7517 for(var i = 0; i < siblings.length; i++) {
7518 var s = siblings[i];
7519 if(s.nodeType == 1){
7520 Roo.get(s).removeClass(className);
7523 this.addClass(className);
7528 * Removes one or more CSS classes from the element.
7529 * @param {String/Array} className The CSS class to remove, or an array of classes
7530 * @return {Roo.Element} this
7532 removeClass : function(className){
7533 if(!className || !this.dom.className){
7536 if(className instanceof Array){
7537 for(var i = 0, len = className.length; i < len; i++) {
7538 this.removeClass(className[i]);
7541 if(this.hasClass(className)){
7542 var re = this.classReCache[className];
7544 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7545 this.classReCache[className] = re;
7547 this.dom.className =
7548 this.dom.className.replace(re, " ");
7558 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7559 * @param {String} className The CSS class to toggle
7560 * @return {Roo.Element} this
7562 toggleClass : function(className){
7563 if(this.hasClass(className)){
7564 this.removeClass(className);
7566 this.addClass(className);
7572 * Checks if the specified CSS class exists on this element's DOM node.
7573 * @param {String} className The CSS class to check for
7574 * @return {Boolean} True if the class exists, else false
7576 hasClass : function(className){
7577 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7581 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7582 * @param {String} oldClassName The CSS class to replace
7583 * @param {String} newClassName The replacement CSS class
7584 * @return {Roo.Element} this
7586 replaceClass : function(oldClassName, newClassName){
7587 this.removeClass(oldClassName);
7588 this.addClass(newClassName);
7593 * Returns an object with properties matching the styles requested.
7594 * For example, el.getStyles('color', 'font-size', 'width') might return
7595 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7596 * @param {String} style1 A style name
7597 * @param {String} style2 A style name
7598 * @param {String} etc.
7599 * @return {Object} The style object
7601 getStyles : function(){
7602 var a = arguments, len = a.length, r = {};
7603 for(var i = 0; i < len; i++){
7604 r[a[i]] = this.getStyle(a[i]);
7610 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7611 * @param {String} property The style property whose value is returned.
7612 * @return {String} The current value of the style property for this element.
7614 getStyle : function(){
7615 return view && view.getComputedStyle ?
7617 var el = this.dom, v, cs, camel;
7618 if(prop == 'float'){
7621 if(el.style && (v = el.style[prop])){
7624 if(cs = view.getComputedStyle(el, "")){
7625 if(!(camel = propCache[prop])){
7626 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7633 var el = this.dom, v, cs, camel;
7634 if(prop == 'opacity'){
7635 if(typeof el.style.filter == 'string'){
7636 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7638 var fv = parseFloat(m[1]);
7640 return fv ? fv / 100 : 0;
7645 }else if(prop == 'float'){
7646 prop = "styleFloat";
7648 if(!(camel = propCache[prop])){
7649 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7651 if(v = el.style[camel]){
7654 if(cs = el.currentStyle){
7662 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7663 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7664 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7665 * @return {Roo.Element} this
7667 setStyle : function(prop, value){
7668 if(typeof prop == "string"){
7670 if (prop == 'float') {
7671 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7676 if(!(camel = propCache[prop])){
7677 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7680 if(camel == 'opacity') {
7681 this.setOpacity(value);
7683 this.dom.style[camel] = value;
7686 for(var style in prop){
7687 if(typeof prop[style] != "function"){
7688 this.setStyle(style, prop[style]);
7696 * More flexible version of {@link #setStyle} for setting style properties.
7697 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7698 * a function which returns such a specification.
7699 * @return {Roo.Element} this
7701 applyStyles : function(style){
7702 Roo.DomHelper.applyStyles(this.dom, style);
7707 * 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).
7708 * @return {Number} The X position of the element
7711 return D.getX(this.dom);
7715 * 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).
7716 * @return {Number} The Y position of the element
7719 return D.getY(this.dom);
7723 * 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).
7724 * @return {Array} The XY position of the element
7727 return D.getXY(this.dom);
7731 * 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).
7732 * @param {Number} The X position of the element
7733 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7734 * @return {Roo.Element} this
7736 setX : function(x, animate){
7738 D.setX(this.dom, x);
7740 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7746 * 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).
7747 * @param {Number} The Y position of the element
7748 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7749 * @return {Roo.Element} this
7751 setY : function(y, animate){
7753 D.setY(this.dom, y);
7755 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7761 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7762 * @param {String} left The left CSS property value
7763 * @return {Roo.Element} this
7765 setLeft : function(left){
7766 this.setStyle("left", this.addUnits(left));
7771 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7772 * @param {String} top The top CSS property value
7773 * @return {Roo.Element} this
7775 setTop : function(top){
7776 this.setStyle("top", this.addUnits(top));
7781 * Sets the element's CSS right style.
7782 * @param {String} right The right CSS property value
7783 * @return {Roo.Element} this
7785 setRight : function(right){
7786 this.setStyle("right", this.addUnits(right));
7791 * Sets the element's CSS bottom style.
7792 * @param {String} bottom The bottom CSS property value
7793 * @return {Roo.Element} this
7795 setBottom : function(bottom){
7796 this.setStyle("bottom", this.addUnits(bottom));
7801 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7802 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7803 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7804 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7805 * @return {Roo.Element} this
7807 setXY : function(pos, animate){
7809 D.setXY(this.dom, pos);
7811 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7817 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7818 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7819 * @param {Number} x X value for new position (coordinates are page-based)
7820 * @param {Number} y Y value for new position (coordinates are page-based)
7821 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7822 * @return {Roo.Element} this
7824 setLocation : function(x, y, animate){
7825 this.setXY([x, y], this.preanim(arguments, 2));
7830 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7831 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7832 * @param {Number} x X value for new position (coordinates are page-based)
7833 * @param {Number} y Y value for new position (coordinates are page-based)
7834 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7835 * @return {Roo.Element} this
7837 moveTo : function(x, y, animate){
7838 this.setXY([x, y], this.preanim(arguments, 2));
7843 * Returns the region of the given element.
7844 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7845 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7847 getRegion : function(){
7848 return D.getRegion(this.dom);
7852 * Returns the offset height of the element
7853 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7854 * @return {Number} The element's height
7856 getHeight : function(contentHeight){
7857 var h = this.dom.offsetHeight || 0;
7858 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7862 * Returns the offset width of the element
7863 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7864 * @return {Number} The element's width
7866 getWidth : function(contentWidth){
7867 var w = this.dom.offsetWidth || 0;
7868 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7872 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7873 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7874 * if a height has not been set using CSS.
7877 getComputedHeight : function(){
7878 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7880 h = parseInt(this.getStyle('height'), 10) || 0;
7881 if(!this.isBorderBox()){
7882 h += this.getFrameWidth('tb');
7889 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7890 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7891 * if a width has not been set using CSS.
7894 getComputedWidth : function(){
7895 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7897 w = parseInt(this.getStyle('width'), 10) || 0;
7898 if(!this.isBorderBox()){
7899 w += this.getFrameWidth('lr');
7906 * Returns the size of the element.
7907 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7908 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7910 getSize : function(contentSize){
7911 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7915 * Returns the width and height of the viewport.
7916 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7918 getViewSize : function(){
7919 var d = this.dom, doc = document, aw = 0, ah = 0;
7920 if(d == doc || d == doc.body){
7921 return {width : D.getViewWidth(), height: D.getViewHeight()};
7924 width : d.clientWidth,
7925 height: d.clientHeight
7931 * Returns the value of the "value" attribute
7932 * @param {Boolean} asNumber true to parse the value as a number
7933 * @return {String/Number}
7935 getValue : function(asNumber){
7936 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7940 adjustWidth : function(width){
7941 if(typeof width == "number"){
7942 if(this.autoBoxAdjust && !this.isBorderBox()){
7943 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7953 adjustHeight : function(height){
7954 if(typeof height == "number"){
7955 if(this.autoBoxAdjust && !this.isBorderBox()){
7956 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7966 * Set the width of the element
7967 * @param {Number} width The new width
7968 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7969 * @return {Roo.Element} this
7971 setWidth : function(width, animate){
7972 width = this.adjustWidth(width);
7974 this.dom.style.width = this.addUnits(width);
7976 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7982 * Set the height of the element
7983 * @param {Number} height The new height
7984 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7985 * @return {Roo.Element} this
7987 setHeight : function(height, animate){
7988 height = this.adjustHeight(height);
7990 this.dom.style.height = this.addUnits(height);
7992 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7998 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7999 * @param {Number} width The new width
8000 * @param {Number} height The new height
8001 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8002 * @return {Roo.Element} this
8004 setSize : function(width, height, animate){
8005 if(typeof width == "object"){ // in case of object from getSize()
8006 height = width.height; width = width.width;
8008 width = this.adjustWidth(width); height = this.adjustHeight(height);
8010 this.dom.style.width = this.addUnits(width);
8011 this.dom.style.height = this.addUnits(height);
8013 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8019 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8020 * @param {Number} x X value for new position (coordinates are page-based)
8021 * @param {Number} y Y value for new position (coordinates are page-based)
8022 * @param {Number} width The new width
8023 * @param {Number} height The new height
8024 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8025 * @return {Roo.Element} this
8027 setBounds : function(x, y, width, height, animate){
8029 this.setSize(width, height);
8030 this.setLocation(x, y);
8032 width = this.adjustWidth(width); height = this.adjustHeight(height);
8033 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8034 this.preanim(arguments, 4), 'motion');
8040 * 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.
8041 * @param {Roo.lib.Region} region The region to fill
8042 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8043 * @return {Roo.Element} this
8045 setRegion : function(region, animate){
8046 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8051 * Appends an event handler
8053 * @param {String} eventName The type of event to append
8054 * @param {Function} fn The method the event invokes
8055 * @param {Object} scope (optional) The scope (this object) of the fn
8056 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8058 addListener : function(eventName, fn, scope, options){
8060 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8065 * Removes an event handler from this element
8066 * @param {String} eventName the type of event to remove
8067 * @param {Function} fn the method the event invokes
8068 * @return {Roo.Element} this
8070 removeListener : function(eventName, fn){
8071 Roo.EventManager.removeListener(this.dom, eventName, fn);
8076 * Removes all previous added listeners from this element
8077 * @return {Roo.Element} this
8079 removeAllListeners : function(){
8080 E.purgeElement(this.dom);
8084 relayEvent : function(eventName, observable){
8085 this.on(eventName, function(e){
8086 observable.fireEvent(eventName, e);
8091 * Set the opacity of the element
8092 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8093 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8094 * @return {Roo.Element} this
8096 setOpacity : function(opacity, animate){
8098 var s = this.dom.style;
8101 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8102 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8104 s.opacity = opacity;
8107 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8113 * Gets the left X coordinate
8114 * @param {Boolean} local True to get the local css position instead of page coordinate
8117 getLeft : function(local){
8121 return parseInt(this.getStyle("left"), 10) || 0;
8126 * Gets the right X coordinate of the element (element X position + element width)
8127 * @param {Boolean} local True to get the local css position instead of page coordinate
8130 getRight : function(local){
8132 return this.getX() + this.getWidth();
8134 return (this.getLeft(true) + this.getWidth()) || 0;
8139 * Gets the top Y coordinate
8140 * @param {Boolean} local True to get the local css position instead of page coordinate
8143 getTop : function(local) {
8147 return parseInt(this.getStyle("top"), 10) || 0;
8152 * Gets the bottom Y coordinate of the element (element Y position + element height)
8153 * @param {Boolean} local True to get the local css position instead of page coordinate
8156 getBottom : function(local){
8158 return this.getY() + this.getHeight();
8160 return (this.getTop(true) + this.getHeight()) || 0;
8165 * Initializes positioning on this element. If a desired position is not passed, it will make the
8166 * the element positioned relative IF it is not already positioned.
8167 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8168 * @param {Number} zIndex (optional) The zIndex to apply
8169 * @param {Number} x (optional) Set the page X position
8170 * @param {Number} y (optional) Set the page Y position
8172 position : function(pos, zIndex, x, y){
8174 if(this.getStyle('position') == 'static'){
8175 this.setStyle('position', 'relative');
8178 this.setStyle("position", pos);
8181 this.setStyle("z-index", zIndex);
8183 if(x !== undefined && y !== undefined){
8185 }else if(x !== undefined){
8187 }else if(y !== undefined){
8193 * Clear positioning back to the default when the document was loaded
8194 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8195 * @return {Roo.Element} this
8197 clearPositioning : function(value){
8205 "position" : "static"
8211 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8212 * snapshot before performing an update and then restoring the element.
8215 getPositioning : function(){
8216 var l = this.getStyle("left");
8217 var t = this.getStyle("top");
8219 "position" : this.getStyle("position"),
8221 "right" : l ? "" : this.getStyle("right"),
8223 "bottom" : t ? "" : this.getStyle("bottom"),
8224 "z-index" : this.getStyle("z-index")
8229 * Gets the width of the border(s) for the specified side(s)
8230 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8231 * passing lr would get the border (l)eft width + the border (r)ight width.
8232 * @return {Number} The width of the sides passed added together
8234 getBorderWidth : function(side){
8235 return this.addStyles(side, El.borders);
8239 * Gets the width of the padding(s) for the specified side(s)
8240 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8241 * passing lr would get the padding (l)eft + the padding (r)ight.
8242 * @return {Number} The padding of the sides passed added together
8244 getPadding : function(side){
8245 return this.addStyles(side, El.paddings);
8249 * Set positioning with an object returned by getPositioning().
8250 * @param {Object} posCfg
8251 * @return {Roo.Element} this
8253 setPositioning : function(pc){
8254 this.applyStyles(pc);
8255 if(pc.right == "auto"){
8256 this.dom.style.right = "";
8258 if(pc.bottom == "auto"){
8259 this.dom.style.bottom = "";
8265 fixDisplay : function(){
8266 if(this.getStyle("display") == "none"){
8267 this.setStyle("visibility", "hidden");
8268 this.setStyle("display", this.originalDisplay); // first try reverting to default
8269 if(this.getStyle("display") == "none"){ // if that fails, default to block
8270 this.setStyle("display", "block");
8276 * Quick set left and top adding default units
8277 * @param {String} left The left CSS property value
8278 * @param {String} top The top CSS property value
8279 * @return {Roo.Element} this
8281 setLeftTop : function(left, top){
8282 this.dom.style.left = this.addUnits(left);
8283 this.dom.style.top = this.addUnits(top);
8288 * Move this element relative to its current position.
8289 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8290 * @param {Number} distance How far to move the element in pixels
8291 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8292 * @return {Roo.Element} this
8294 move : function(direction, distance, animate){
8295 var xy = this.getXY();
8296 direction = direction.toLowerCase();
8300 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8304 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8309 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8314 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8321 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8322 * @return {Roo.Element} this
8325 if(!this.isClipped){
8326 this.isClipped = true;
8327 this.originalClip = {
8328 "o": this.getStyle("overflow"),
8329 "x": this.getStyle("overflow-x"),
8330 "y": this.getStyle("overflow-y")
8332 this.setStyle("overflow", "hidden");
8333 this.setStyle("overflow-x", "hidden");
8334 this.setStyle("overflow-y", "hidden");
8340 * Return clipping (overflow) to original clipping before clip() was called
8341 * @return {Roo.Element} this
8343 unclip : function(){
8345 this.isClipped = false;
8346 var o = this.originalClip;
8347 if(o.o){this.setStyle("overflow", o.o);}
8348 if(o.x){this.setStyle("overflow-x", o.x);}
8349 if(o.y){this.setStyle("overflow-y", o.y);}
8356 * Gets the x,y coordinates specified by the anchor position on the element.
8357 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8358 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8359 * {width: (target width), height: (target height)} (defaults to the element's current size)
8360 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8361 * @return {Array} [x, y] An array containing the element's x and y coordinates
8363 getAnchorXY : function(anchor, local, s){
8364 //Passing a different size is useful for pre-calculating anchors,
8365 //especially for anchored animations that change the el size.
8367 var w, h, vp = false;
8370 if(d == document.body || d == document){
8372 w = D.getViewWidth(); h = D.getViewHeight();
8374 w = this.getWidth(); h = this.getHeight();
8377 w = s.width; h = s.height;
8379 var x = 0, y = 0, r = Math.round;
8380 switch((anchor || "tl").toLowerCase()){
8422 var sc = this.getScroll();
8423 return [x + sc.left, y + sc.top];
8425 //Add the element's offset xy
8426 var o = this.getXY();
8427 return [x+o[0], y+o[1]];
8431 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8432 * supported position values.
8433 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8434 * @param {String} position The position to align to.
8435 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8436 * @return {Array} [x, y]
8438 getAlignToXY : function(el, p, o){
8442 throw "Element.alignTo with an element that doesn't exist";
8444 var c = false; //constrain to viewport
8445 var p1 = "", p2 = "";
8452 }else if(p.indexOf("-") == -1){
8455 p = p.toLowerCase();
8456 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8458 throw "Element.alignTo with an invalid alignment " + p;
8460 p1 = m[1]; p2 = m[2]; c = !!m[3];
8462 //Subtract the aligned el's internal xy from the target's offset xy
8463 //plus custom offset to get the aligned el's new offset xy
8464 var a1 = this.getAnchorXY(p1, true);
8465 var a2 = el.getAnchorXY(p2, false);
8466 var x = a2[0] - a1[0] + o[0];
8467 var y = a2[1] - a1[1] + o[1];
8469 //constrain the aligned el to viewport if necessary
8470 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8471 // 5px of margin for ie
8472 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8474 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8475 //perpendicular to the vp border, allow the aligned el to slide on that border,
8476 //otherwise swap the aligned el to the opposite border of the target.
8477 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8478 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8479 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8480 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8483 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8484 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8486 if((x+w) > dw + scrollX){
8487 x = swapX ? r.left-w : dw+scrollX-w;
8490 x = swapX ? r.right : scrollX;
8492 if((y+h) > dh + scrollY){
8493 y = swapY ? r.top-h : dh+scrollY-h;
8496 y = swapY ? r.bottom : scrollY;
8503 getConstrainToXY : function(){
8504 var os = {top:0, left:0, bottom:0, right: 0};
8506 return function(el, local, offsets, proposedXY){
8508 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8510 var vw, vh, vx = 0, vy = 0;
8511 if(el.dom == document.body || el.dom == document){
8512 vw = Roo.lib.Dom.getViewWidth();
8513 vh = Roo.lib.Dom.getViewHeight();
8515 vw = el.dom.clientWidth;
8516 vh = el.dom.clientHeight;
8518 var vxy = el.getXY();
8524 var s = el.getScroll();
8526 vx += offsets.left + s.left;
8527 vy += offsets.top + s.top;
8529 vw -= offsets.right;
8530 vh -= offsets.bottom;
8535 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8536 var x = xy[0], y = xy[1];
8537 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8539 // only move it if it needs it
8542 // first validate right/bottom
8551 // then make sure top/left isn't negative
8560 return moved ? [x, y] : false;
8565 adjustForConstraints : function(xy, parent, offsets){
8566 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8570 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8571 * document it aligns it to the viewport.
8572 * The position parameter is optional, and can be specified in any one of the following formats:
8574 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8575 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8576 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8577 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8578 * <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
8579 * element's anchor point, and the second value is used as the target's anchor point.</li>
8581 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8582 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8583 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8584 * that specified in order to enforce the viewport constraints.
8585 * Following are all of the supported anchor positions:
8588 ----- -----------------------------
8589 tl The top left corner (default)
8590 t The center of the top edge
8591 tr The top right corner
8592 l The center of the left edge
8593 c In the center of the element
8594 r The center of the right edge
8595 bl The bottom left corner
8596 b The center of the bottom edge
8597 br The bottom right corner
8601 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8602 el.alignTo("other-el");
8604 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8605 el.alignTo("other-el", "tr?");
8607 // align the bottom right corner of el with the center left edge of other-el
8608 el.alignTo("other-el", "br-l?");
8610 // align the center of el with the bottom left corner of other-el and
8611 // adjust the x position by -6 pixels (and the y position by 0)
8612 el.alignTo("other-el", "c-bl", [-6, 0]);
8614 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8615 * @param {String} position The position to align to.
8616 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8617 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8618 * @return {Roo.Element} this
8620 alignTo : function(element, position, offsets, animate){
8621 var xy = this.getAlignToXY(element, position, offsets);
8622 this.setXY(xy, this.preanim(arguments, 3));
8627 * Anchors an element to another element and realigns it when the window is resized.
8628 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8629 * @param {String} position The position to align to.
8630 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8631 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8632 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8633 * is a number, it is used as the buffer delay (defaults to 50ms).
8634 * @param {Function} callback The function to call after the animation finishes
8635 * @return {Roo.Element} this
8637 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8638 var action = function(){
8639 this.alignTo(el, alignment, offsets, animate);
8640 Roo.callback(callback, this);
8642 Roo.EventManager.onWindowResize(action, this);
8643 var tm = typeof monitorScroll;
8644 if(tm != 'undefined'){
8645 Roo.EventManager.on(window, 'scroll', action, this,
8646 {buffer: tm == 'number' ? monitorScroll : 50});
8648 action.call(this); // align immediately
8652 * Clears any opacity settings from this element. Required in some cases for IE.
8653 * @return {Roo.Element} this
8655 clearOpacity : function(){
8656 if (window.ActiveXObject) {
8657 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8658 this.dom.style.filter = "";
8661 this.dom.style.opacity = "";
8662 this.dom.style["-moz-opacity"] = "";
8663 this.dom.style["-khtml-opacity"] = "";
8669 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8670 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8671 * @return {Roo.Element} this
8673 hide : function(animate){
8674 this.setVisible(false, this.preanim(arguments, 0));
8679 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8680 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8681 * @return {Roo.Element} this
8683 show : function(animate){
8684 this.setVisible(true, this.preanim(arguments, 0));
8689 * @private Test if size has a unit, otherwise appends the default
8691 addUnits : function(size){
8692 return Roo.Element.addUnits(size, this.defaultUnit);
8696 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8697 * @return {Roo.Element} this
8699 beginMeasure : function(){
8701 if(el.offsetWidth || el.offsetHeight){
8702 return this; // offsets work already
8705 var p = this.dom, b = document.body; // start with this element
8706 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8707 var pe = Roo.get(p);
8708 if(pe.getStyle('display') == 'none'){
8709 changed.push({el: p, visibility: pe.getStyle("visibility")});
8710 p.style.visibility = "hidden";
8711 p.style.display = "block";
8715 this._measureChanged = changed;
8721 * Restores displays to before beginMeasure was called
8722 * @return {Roo.Element} this
8724 endMeasure : function(){
8725 var changed = this._measureChanged;
8727 for(var i = 0, len = changed.length; i < len; i++) {
8729 r.el.style.visibility = r.visibility;
8730 r.el.style.display = "none";
8732 this._measureChanged = null;
8738 * Update the innerHTML of this element, optionally searching for and processing scripts
8739 * @param {String} html The new HTML
8740 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8741 * @param {Function} callback For async script loading you can be noticed when the update completes
8742 * @return {Roo.Element} this
8744 update : function(html, loadScripts, callback){
8745 if(typeof html == "undefined"){
8748 if(loadScripts !== true){
8749 this.dom.innerHTML = html;
8750 if(typeof callback == "function"){
8758 html += '<span id="' + id + '"></span>';
8760 E.onAvailable(id, function(){
8761 var hd = document.getElementsByTagName("head")[0];
8762 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8763 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8764 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8767 while(match = re.exec(html)){
8768 var attrs = match[1];
8769 var srcMatch = attrs ? attrs.match(srcRe) : false;
8770 if(srcMatch && srcMatch[2]){
8771 var s = document.createElement("script");
8772 s.src = srcMatch[2];
8773 var typeMatch = attrs.match(typeRe);
8774 if(typeMatch && typeMatch[2]){
8775 s.type = typeMatch[2];
8778 }else if(match[2] && match[2].length > 0){
8779 if(window.execScript) {
8780 window.execScript(match[2]);
8788 window.eval(match[2]);
8792 var el = document.getElementById(id);
8793 if(el){el.parentNode.removeChild(el);}
8794 if(typeof callback == "function"){
8798 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8803 * Direct access to the UpdateManager update() method (takes the same parameters).
8804 * @param {String/Function} url The url for this request or a function to call to get the url
8805 * @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}
8806 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8807 * @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.
8808 * @return {Roo.Element} this
8811 var um = this.getUpdateManager();
8812 um.update.apply(um, arguments);
8817 * Gets this element's UpdateManager
8818 * @return {Roo.UpdateManager} The UpdateManager
8820 getUpdateManager : function(){
8821 if(!this.updateManager){
8822 this.updateManager = new Roo.UpdateManager(this);
8824 return this.updateManager;
8828 * Disables text selection for this element (normalized across browsers)
8829 * @return {Roo.Element} this
8831 unselectable : function(){
8832 this.dom.unselectable = "on";
8833 this.swallowEvent("selectstart", true);
8834 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8835 this.addClass("x-unselectable");
8840 * Calculates the x, y to center this element on the screen
8841 * @return {Array} The x, y values [x, y]
8843 getCenterXY : function(){
8844 return this.getAlignToXY(document, 'c-c');
8848 * Centers the Element in either the viewport, or another Element.
8849 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8851 center : function(centerIn){
8852 this.alignTo(centerIn || document, 'c-c');
8857 * Tests various css rules/browsers to determine if this element uses a border box
8860 isBorderBox : function(){
8861 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8865 * Return a box {x, y, width, height} that can be used to set another elements
8866 * size/location to match this element.
8867 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8868 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8869 * @return {Object} box An object in the format {x, y, width, height}
8871 getBox : function(contentBox, local){
8876 var left = parseInt(this.getStyle("left"), 10) || 0;
8877 var top = parseInt(this.getStyle("top"), 10) || 0;
8880 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8882 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8884 var l = this.getBorderWidth("l")+this.getPadding("l");
8885 var r = this.getBorderWidth("r")+this.getPadding("r");
8886 var t = this.getBorderWidth("t")+this.getPadding("t");
8887 var b = this.getBorderWidth("b")+this.getPadding("b");
8888 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)};
8890 bx.right = bx.x + bx.width;
8891 bx.bottom = bx.y + bx.height;
8896 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8897 for more information about the sides.
8898 * @param {String} sides
8901 getFrameWidth : function(sides, onlyContentBox){
8902 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8906 * 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.
8907 * @param {Object} box The box to fill {x, y, width, height}
8908 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8909 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8910 * @return {Roo.Element} this
8912 setBox : function(box, adjust, animate){
8913 var w = box.width, h = box.height;
8914 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8915 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8916 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8918 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8923 * Forces the browser to repaint this element
8924 * @return {Roo.Element} this
8926 repaint : function(){
8928 this.addClass("x-repaint");
8929 setTimeout(function(){
8930 Roo.get(dom).removeClass("x-repaint");
8936 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8937 * then it returns the calculated width of the sides (see getPadding)
8938 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8939 * @return {Object/Number}
8941 getMargins : function(side){
8944 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8945 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8946 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8947 right: parseInt(this.getStyle("margin-right"), 10) || 0
8950 return this.addStyles(side, El.margins);
8955 addStyles : function(sides, styles){
8957 for(var i = 0, len = sides.length; i < len; i++){
8958 v = this.getStyle(styles[sides.charAt(i)]);
8960 w = parseInt(v, 10);
8968 * Creates a proxy element of this element
8969 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8970 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8971 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8972 * @return {Roo.Element} The new proxy element
8974 createProxy : function(config, renderTo, matchBox){
8976 renderTo = Roo.getDom(renderTo);
8978 renderTo = document.body;
8980 config = typeof config == "object" ?
8981 config : {tag : "div", cls: config};
8982 var proxy = Roo.DomHelper.append(renderTo, config, true);
8984 proxy.setBox(this.getBox());
8990 * Puts a mask over this element to disable user interaction. Requires core.css.
8991 * This method can only be applied to elements which accept child nodes.
8992 * @param {String} msg (optional) A message to display in the mask
8993 * @param {String} msgCls (optional) A css class to apply to the msg element
8994 * @return {Element} The mask element
8996 mask : function(msg, msgCls)
8998 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
8999 this.setStyle("position", "relative");
9002 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9004 this.addClass("x-masked");
9005 this._mask.setDisplayed(true);
9010 while (dom && dom.style) {
9011 if (!isNaN(parseInt(dom.style.zIndex))) {
9012 z = Math.max(z, parseInt(dom.style.zIndex));
9014 dom = dom.parentNode;
9016 // if we are masking the body - then it hides everything..
9017 if (this.dom == document.body) {
9019 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9020 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9023 if(typeof msg == 'string'){
9025 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9027 var mm = this._maskMsg;
9028 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9029 if (mm.dom.firstChild) { // weird IE issue?
9030 mm.dom.firstChild.innerHTML = msg;
9032 mm.setDisplayed(true);
9034 mm.setStyle('z-index', z + 102);
9036 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9037 this._mask.setHeight(this.getHeight());
9039 this._mask.setStyle('z-index', z + 100);
9045 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9046 * it is cached for reuse.
9048 unmask : function(removeEl){
9050 if(removeEl === true){
9051 this._mask.remove();
9054 this._maskMsg.remove();
9055 delete this._maskMsg;
9058 this._mask.setDisplayed(false);
9060 this._maskMsg.setDisplayed(false);
9064 this.removeClass("x-masked");
9068 * Returns true if this element is masked
9071 isMasked : function(){
9072 return this._mask && this._mask.isVisible();
9076 * Creates an iframe shim for this element to keep selects and other windowed objects from
9078 * @return {Roo.Element} The new shim element
9080 createShim : function(){
9081 var el = document.createElement('iframe');
9082 el.frameBorder = 'no';
9083 el.className = 'roo-shim';
9084 if(Roo.isIE && Roo.isSecure){
9085 el.src = Roo.SSL_SECURE_URL;
9087 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9088 shim.autoBoxAdjust = false;
9093 * Removes this element from the DOM and deletes it from the cache
9095 remove : function(){
9096 if(this.dom.parentNode){
9097 this.dom.parentNode.removeChild(this.dom);
9099 delete El.cache[this.dom.id];
9103 * Sets up event handlers to add and remove a css class when the mouse is over this element
9104 * @param {String} className
9105 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9106 * mouseout events for children elements
9107 * @return {Roo.Element} this
9109 addClassOnOver : function(className, preventFlicker){
9110 this.on("mouseover", function(){
9111 Roo.fly(this, '_internal').addClass(className);
9113 var removeFn = function(e){
9114 if(preventFlicker !== true || !e.within(this, true)){
9115 Roo.fly(this, '_internal').removeClass(className);
9118 this.on("mouseout", removeFn, this.dom);
9123 * Sets up event handlers to add and remove a css class when this element has the focus
9124 * @param {String} className
9125 * @return {Roo.Element} this
9127 addClassOnFocus : function(className){
9128 this.on("focus", function(){
9129 Roo.fly(this, '_internal').addClass(className);
9131 this.on("blur", function(){
9132 Roo.fly(this, '_internal').removeClass(className);
9137 * 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)
9138 * @param {String} className
9139 * @return {Roo.Element} this
9141 addClassOnClick : function(className){
9143 this.on("mousedown", function(){
9144 Roo.fly(dom, '_internal').addClass(className);
9145 var d = Roo.get(document);
9146 var fn = function(){
9147 Roo.fly(dom, '_internal').removeClass(className);
9148 d.removeListener("mouseup", fn);
9150 d.on("mouseup", fn);
9156 * Stops the specified event from bubbling and optionally prevents the default action
9157 * @param {String} eventName
9158 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9159 * @return {Roo.Element} this
9161 swallowEvent : function(eventName, preventDefault){
9162 var fn = function(e){
9163 e.stopPropagation();
9168 if(eventName instanceof Array){
9169 for(var i = 0, len = eventName.length; i < len; i++){
9170 this.on(eventName[i], fn);
9174 this.on(eventName, fn);
9181 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9184 * Sizes this element to its parent element's dimensions performing
9185 * neccessary box adjustments.
9186 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9187 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9188 * @return {Roo.Element} this
9190 fitToParent : function(monitorResize, targetParent) {
9191 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9192 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9193 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9196 var p = Roo.get(targetParent || this.dom.parentNode);
9197 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9198 if (monitorResize === true) {
9199 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9200 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9206 * Gets the next sibling, skipping text nodes
9207 * @return {HTMLElement} The next sibling or null
9209 getNextSibling : function(){
9210 var n = this.dom.nextSibling;
9211 while(n && n.nodeType != 1){
9218 * Gets the previous sibling, skipping text nodes
9219 * @return {HTMLElement} The previous sibling or null
9221 getPrevSibling : function(){
9222 var n = this.dom.previousSibling;
9223 while(n && n.nodeType != 1){
9224 n = n.previousSibling;
9231 * Appends the passed element(s) to this element
9232 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9233 * @return {Roo.Element} this
9235 appendChild: function(el){
9242 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9243 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9244 * automatically generated with the specified attributes.
9245 * @param {HTMLElement} insertBefore (optional) a child element of this element
9246 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9247 * @return {Roo.Element} The new child element
9249 createChild: function(config, insertBefore, returnDom){
9250 config = config || {tag:'div'};
9252 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9254 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9258 * Appends this element to the passed element
9259 * @param {String/HTMLElement/Element} el The new parent element
9260 * @return {Roo.Element} this
9262 appendTo: function(el){
9263 el = Roo.getDom(el);
9264 el.appendChild(this.dom);
9269 * Inserts this element before the passed element in the DOM
9270 * @param {String/HTMLElement/Element} el The element to insert before
9271 * @return {Roo.Element} this
9273 insertBefore: function(el){
9274 el = Roo.getDom(el);
9275 el.parentNode.insertBefore(this.dom, el);
9280 * Inserts this element after the passed element in the DOM
9281 * @param {String/HTMLElement/Element} el The element to insert after
9282 * @return {Roo.Element} this
9284 insertAfter: function(el){
9285 el = Roo.getDom(el);
9286 el.parentNode.insertBefore(this.dom, el.nextSibling);
9291 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9292 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9293 * @return {Roo.Element} The new child
9295 insertFirst: function(el, returnDom){
9297 if(typeof el == 'object' && !el.nodeType){ // dh config
9298 return this.createChild(el, this.dom.firstChild, returnDom);
9300 el = Roo.getDom(el);
9301 this.dom.insertBefore(el, this.dom.firstChild);
9302 return !returnDom ? Roo.get(el) : el;
9307 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9308 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9309 * @param {String} where (optional) 'before' or 'after' defaults to before
9310 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9311 * @return {Roo.Element} the inserted Element
9313 insertSibling: function(el, where, returnDom){
9314 where = where ? where.toLowerCase() : 'before';
9316 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9318 if(typeof el == 'object' && !el.nodeType){ // dh config
9319 if(where == 'after' && !this.dom.nextSibling){
9320 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9322 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9326 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9327 where == 'before' ? this.dom : this.dom.nextSibling);
9336 * Creates and wraps this element with another element
9337 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9338 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9339 * @return {HTMLElement/Element} The newly created wrapper element
9341 wrap: function(config, returnDom){
9343 config = {tag: "div"};
9345 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9346 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9351 * Replaces the passed element with this element
9352 * @param {String/HTMLElement/Element} el The element to replace
9353 * @return {Roo.Element} this
9355 replace: function(el){
9357 this.insertBefore(el);
9363 * Inserts an html fragment into this element
9364 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9365 * @param {String} html The HTML fragment
9366 * @param {Boolean} returnEl True to return an Roo.Element
9367 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9369 insertHtml : function(where, html, returnEl){
9370 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9371 return returnEl ? Roo.get(el) : el;
9375 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9376 * @param {Object} o The object with the attributes
9377 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9378 * @return {Roo.Element} this
9380 set : function(o, useSet){
9382 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9384 if(attr == "style" || typeof o[attr] == "function") continue;
9386 el.className = o["cls"];
9388 if(useSet) el.setAttribute(attr, o[attr]);
9389 else el[attr] = o[attr];
9393 Roo.DomHelper.applyStyles(el, o.style);
9399 * Convenience method for constructing a KeyMap
9400 * @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:
9401 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9402 * @param {Function} fn The function to call
9403 * @param {Object} scope (optional) The scope of the function
9404 * @return {Roo.KeyMap} The KeyMap created
9406 addKeyListener : function(key, fn, scope){
9408 if(typeof key != "object" || key instanceof Array){
9424 return new Roo.KeyMap(this, config);
9428 * Creates a KeyMap for this element
9429 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9430 * @return {Roo.KeyMap} The KeyMap created
9432 addKeyMap : function(config){
9433 return new Roo.KeyMap(this, config);
9437 * Returns true if this element is scrollable.
9440 isScrollable : function(){
9442 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9446 * 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().
9447 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9448 * @param {Number} value The new scroll value
9449 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9450 * @return {Element} this
9453 scrollTo : function(side, value, animate){
9454 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9456 this.dom[prop] = value;
9458 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9459 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9465 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9466 * within this element's scrollable range.
9467 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9468 * @param {Number} distance How far to scroll the element in pixels
9469 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9470 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9471 * was scrolled as far as it could go.
9473 scroll : function(direction, distance, animate){
9474 if(!this.isScrollable()){
9478 var l = el.scrollLeft, t = el.scrollTop;
9479 var w = el.scrollWidth, h = el.scrollHeight;
9480 var cw = el.clientWidth, ch = el.clientHeight;
9481 direction = direction.toLowerCase();
9482 var scrolled = false;
9483 var a = this.preanim(arguments, 2);
9488 var v = Math.min(l + distance, w-cw);
9489 this.scrollTo("left", v, a);
9496 var v = Math.max(l - distance, 0);
9497 this.scrollTo("left", v, a);
9505 var v = Math.max(t - distance, 0);
9506 this.scrollTo("top", v, a);
9514 var v = Math.min(t + distance, h-ch);
9515 this.scrollTo("top", v, a);
9524 * Translates the passed page coordinates into left/top css values for this element
9525 * @param {Number/Array} x The page x or an array containing [x, y]
9526 * @param {Number} y The page y
9527 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9529 translatePoints : function(x, y){
9530 if(typeof x == 'object' || x instanceof Array){
9533 var p = this.getStyle('position');
9534 var o = this.getXY();
9536 var l = parseInt(this.getStyle('left'), 10);
9537 var t = parseInt(this.getStyle('top'), 10);
9540 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9543 t = (p == "relative") ? 0 : this.dom.offsetTop;
9546 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9550 * Returns the current scroll position of the element.
9551 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9553 getScroll : function(){
9554 var d = this.dom, doc = document;
9555 if(d == doc || d == doc.body){
9556 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9557 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9558 return {left: l, top: t};
9560 return {left: d.scrollLeft, top: d.scrollTop};
9565 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9566 * are convert to standard 6 digit hex color.
9567 * @param {String} attr The css attribute
9568 * @param {String} defaultValue The default value to use when a valid color isn't found
9569 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9572 getColor : function(attr, defaultValue, prefix){
9573 var v = this.getStyle(attr);
9574 if(!v || v == "transparent" || v == "inherit") {
9575 return defaultValue;
9577 var color = typeof prefix == "undefined" ? "#" : prefix;
9578 if(v.substr(0, 4) == "rgb("){
9579 var rvs = v.slice(4, v.length -1).split(",");
9580 for(var i = 0; i < 3; i++){
9581 var h = parseInt(rvs[i]).toString(16);
9588 if(v.substr(0, 1) == "#"){
9590 for(var i = 1; i < 4; i++){
9591 var c = v.charAt(i);
9594 }else if(v.length == 7){
9595 color += v.substr(1);
9599 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9603 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9604 * gradient background, rounded corners and a 4-way shadow.
9605 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9606 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9607 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9608 * @return {Roo.Element} this
9610 boxWrap : function(cls){
9611 cls = cls || 'x-box';
9612 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9613 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9618 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9619 * @param {String} namespace The namespace in which to look for the attribute
9620 * @param {String} name The attribute name
9621 * @return {String} The attribute value
9623 getAttributeNS : Roo.isIE ? function(ns, name){
9625 var type = typeof d[ns+":"+name];
9626 if(type != 'undefined' && type != 'unknown'){
9627 return d[ns+":"+name];
9630 } : function(ns, name){
9632 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9637 * Sets or Returns the value the dom attribute value
9638 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9639 * @param {String} value (optional) The value to set the attribute to
9640 * @return {String} The attribute value
9642 attr : function(name){
9643 if (arguments.length > 1) {
9644 this.dom.setAttribute(name, arguments[1]);
9645 return arguments[1];
9647 if (typeof(name) == 'object') {
9648 for(var i in name) {
9649 this.attr(i, name[i]);
9655 if (!this.dom.hasAttribute(name)) {
9658 return this.dom.getAttribute(name);
9665 var ep = El.prototype;
9668 * Appends an event handler (Shorthand for addListener)
9669 * @param {String} eventName The type of event to append
9670 * @param {Function} fn The method the event invokes
9671 * @param {Object} scope (optional) The scope (this object) of the fn
9672 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9675 ep.on = ep.addListener;
9677 ep.mon = ep.addListener;
9680 * Removes an event handler from this element (shorthand for removeListener)
9681 * @param {String} eventName the type of event to remove
9682 * @param {Function} fn the method the event invokes
9683 * @return {Roo.Element} this
9686 ep.un = ep.removeListener;
9689 * true to automatically adjust width and height settings for box-model issues (default to true)
9691 ep.autoBoxAdjust = true;
9694 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9697 El.addUnits = function(v, defaultUnit){
9698 if(v === "" || v == "auto"){
9701 if(v === undefined){
9704 if(typeof v == "number" || !El.unitPattern.test(v)){
9705 return v + (defaultUnit || 'px');
9710 // special markup used throughout Roo when box wrapping elements
9711 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>';
9713 * Visibility mode constant - Use visibility to hide element
9719 * Visibility mode constant - Use display to hide element
9725 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9726 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9727 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9739 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9740 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9741 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9742 * @return {Element} The Element object
9745 El.get = function(el){
9747 if(!el){ return null; }
9748 if(typeof el == "string"){ // element id
9749 if(!(elm = document.getElementById(el))){
9752 if(ex = El.cache[el]){
9755 ex = El.cache[el] = new El(elm);
9758 }else if(el.tagName){ // dom element
9762 if(ex = El.cache[id]){
9765 ex = El.cache[id] = new El(el);
9768 }else if(el instanceof El){
9770 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9771 // catch case where it hasn't been appended
9772 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9775 }else if(el.isComposite){
9777 }else if(el instanceof Array){
9778 return El.select(el);
9779 }else if(el == document){
9780 // create a bogus element object representing the document object
9782 var f = function(){};
9783 f.prototype = El.prototype;
9785 docEl.dom = document;
9793 El.uncache = function(el){
9794 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9796 delete El.cache[a[i].id || a[i]];
9802 // Garbage collection - uncache elements/purge listeners on orphaned elements
9803 // so we don't hold a reference and cause the browser to retain them
9804 El.garbageCollect = function(){
9805 if(!Roo.enableGarbageCollector){
9806 clearInterval(El.collectorThread);
9809 for(var eid in El.cache){
9810 var el = El.cache[eid], d = el.dom;
9811 // -------------------------------------------------------
9812 // Determining what is garbage:
9813 // -------------------------------------------------------
9815 // dom node is null, definitely garbage
9816 // -------------------------------------------------------
9818 // no parentNode == direct orphan, definitely garbage
9819 // -------------------------------------------------------
9820 // !d.offsetParent && !document.getElementById(eid)
9821 // display none elements have no offsetParent so we will
9822 // also try to look it up by it's id. However, check
9823 // offsetParent first so we don't do unneeded lookups.
9824 // This enables collection of elements that are not orphans
9825 // directly, but somewhere up the line they have an orphan
9827 // -------------------------------------------------------
9828 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9829 delete El.cache[eid];
9830 if(d && Roo.enableListenerCollection){
9836 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9840 El.Flyweight = function(dom){
9843 El.Flyweight.prototype = El.prototype;
9845 El._flyweights = {};
9847 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9848 * the dom node can be overwritten by other code.
9849 * @param {String/HTMLElement} el The dom node or id
9850 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9851 * prevent conflicts (e.g. internally Roo uses "_internal")
9853 * @return {Element} The shared Element object
9855 El.fly = function(el, named){
9856 named = named || '_global';
9857 el = Roo.getDom(el);
9861 if(!El._flyweights[named]){
9862 El._flyweights[named] = new El.Flyweight();
9864 El._flyweights[named].dom = el;
9865 return El._flyweights[named];
9869 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9870 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9871 * Shorthand of {@link Roo.Element#get}
9872 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9873 * @return {Element} The Element object
9879 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9880 * the dom node can be overwritten by other code.
9881 * Shorthand of {@link Roo.Element#fly}
9882 * @param {String/HTMLElement} el The dom node or id
9883 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9884 * prevent conflicts (e.g. internally Roo uses "_internal")
9886 * @return {Element} The shared Element object
9892 // speedy lookup for elements never to box adjust
9893 var noBoxAdjust = Roo.isStrict ? {
9896 input:1, select:1, textarea:1
9898 if(Roo.isIE || Roo.isGecko){
9899 noBoxAdjust['button'] = 1;
9903 Roo.EventManager.on(window, 'unload', function(){
9905 delete El._flyweights;
9913 Roo.Element.selectorFunction = Roo.DomQuery.select;
9916 Roo.Element.select = function(selector, unique, root){
9918 if(typeof selector == "string"){
9919 els = Roo.Element.selectorFunction(selector, root);
9920 }else if(selector.length !== undefined){
9923 throw "Invalid selector";
9925 if(unique === true){
9926 return new Roo.CompositeElement(els);
9928 return new Roo.CompositeElementLite(els);
9932 * Selects elements based on the passed CSS selector to enable working on them as 1.
9933 * @param {String/Array} selector The CSS selector or an array of elements
9934 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9935 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9936 * @return {CompositeElementLite/CompositeElement}
9940 Roo.select = Roo.Element.select;
9957 * Ext JS Library 1.1.1
9958 * Copyright(c) 2006-2007, Ext JS, LLC.
9960 * Originally Released Under LGPL - original licence link has changed is not relivant.
9963 * <script type="text/javascript">
9968 //Notifies Element that fx methods are available
9969 Roo.enableFx = true;
9973 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9974 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9975 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9976 * Element effects to work.</p><br/>
9978 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9979 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9980 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9981 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9982 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9983 * expected results and should be done with care.</p><br/>
9985 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9986 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9989 ----- -----------------------------
9990 tl The top left corner
9991 t The center of the top edge
9992 tr The top right corner
9993 l The center of the left edge
9994 r The center of the right edge
9995 bl The bottom left corner
9996 b The center of the bottom edge
9997 br The bottom right corner
9999 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10000 * below are common options that can be passed to any Fx method.</b>
10001 * @cfg {Function} callback A function called when the effect is finished
10002 * @cfg {Object} scope The scope of the effect function
10003 * @cfg {String} easing A valid Easing value for the effect
10004 * @cfg {String} afterCls A css class to apply after the effect
10005 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10006 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10007 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10008 * effects that end with the element being visually hidden, ignored otherwise)
10009 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10010 * a function which returns such a specification that will be applied to the Element after the effect finishes
10011 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10012 * @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
10013 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10017 * Slides the element into view. An anchor point can be optionally passed to set the point of
10018 * origin for the slide effect. This function automatically handles wrapping the element with
10019 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10022 // default: slide the element in from the top
10025 // custom: slide the element in from the right with a 2-second duration
10026 el.slideIn('r', { duration: 2 });
10028 // common config options shown with default values
10034 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10035 * @param {Object} options (optional) Object literal with any of the Fx config options
10036 * @return {Roo.Element} The Element
10038 slideIn : function(anchor, o){
10039 var el = this.getFxEl();
10042 el.queueFx(o, function(){
10044 anchor = anchor || "t";
10046 // fix display to visibility
10049 // restore values after effect
10050 var r = this.getFxRestore();
10051 var b = this.getBox();
10052 // fixed size for slide
10056 var wrap = this.fxWrap(r.pos, o, "hidden");
10058 var st = this.dom.style;
10059 st.visibility = "visible";
10060 st.position = "absolute";
10062 // clear out temp styles after slide and unwrap
10063 var after = function(){
10064 el.fxUnwrap(wrap, r.pos, o);
10065 st.width = r.width;
10066 st.height = r.height;
10069 // time to calc the positions
10070 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10072 switch(anchor.toLowerCase()){
10074 wrap.setSize(b.width, 0);
10075 st.left = st.bottom = "0";
10079 wrap.setSize(0, b.height);
10080 st.right = st.top = "0";
10084 wrap.setSize(0, b.height);
10085 wrap.setX(b.right);
10086 st.left = st.top = "0";
10087 a = {width: bw, points: pt};
10090 wrap.setSize(b.width, 0);
10091 wrap.setY(b.bottom);
10092 st.left = st.top = "0";
10093 a = {height: bh, points: pt};
10096 wrap.setSize(0, 0);
10097 st.right = st.bottom = "0";
10098 a = {width: bw, height: bh};
10101 wrap.setSize(0, 0);
10102 wrap.setY(b.y+b.height);
10103 st.right = st.top = "0";
10104 a = {width: bw, height: bh, points: pt};
10107 wrap.setSize(0, 0);
10108 wrap.setXY([b.right, b.bottom]);
10109 st.left = st.top = "0";
10110 a = {width: bw, height: bh, points: pt};
10113 wrap.setSize(0, 0);
10114 wrap.setX(b.x+b.width);
10115 st.left = st.bottom = "0";
10116 a = {width: bw, height: bh, points: pt};
10119 this.dom.style.visibility = "visible";
10122 arguments.callee.anim = wrap.fxanim(a,
10132 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10133 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10134 * 'hidden') but block elements will still take up space in the document. The element must be removed
10135 * from the DOM using the 'remove' config option if desired. This function automatically handles
10136 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10139 // default: slide the element out to the top
10142 // custom: slide the element out to the right with a 2-second duration
10143 el.slideOut('r', { duration: 2 });
10145 // common config options shown with default values
10153 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10154 * @param {Object} options (optional) Object literal with any of the Fx config options
10155 * @return {Roo.Element} The Element
10157 slideOut : function(anchor, o){
10158 var el = this.getFxEl();
10161 el.queueFx(o, function(){
10163 anchor = anchor || "t";
10165 // restore values after effect
10166 var r = this.getFxRestore();
10168 var b = this.getBox();
10169 // fixed size for slide
10173 var wrap = this.fxWrap(r.pos, o, "visible");
10175 var st = this.dom.style;
10176 st.visibility = "visible";
10177 st.position = "absolute";
10181 var after = function(){
10183 el.setDisplayed(false);
10188 el.fxUnwrap(wrap, r.pos, o);
10190 st.width = r.width;
10191 st.height = r.height;
10196 var a, zero = {to: 0};
10197 switch(anchor.toLowerCase()){
10199 st.left = st.bottom = "0";
10200 a = {height: zero};
10203 st.right = st.top = "0";
10207 st.left = st.top = "0";
10208 a = {width: zero, points: {to:[b.right, b.y]}};
10211 st.left = st.top = "0";
10212 a = {height: zero, points: {to:[b.x, b.bottom]}};
10215 st.right = st.bottom = "0";
10216 a = {width: zero, height: zero};
10219 st.right = st.top = "0";
10220 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10223 st.left = st.top = "0";
10224 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10227 st.left = st.bottom = "0";
10228 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10232 arguments.callee.anim = wrap.fxanim(a,
10242 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10243 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10244 * The element must be removed from the DOM using the 'remove' config option if desired.
10250 // common config options shown with default values
10258 * @param {Object} options (optional) Object literal with any of the Fx config options
10259 * @return {Roo.Element} The Element
10261 puff : function(o){
10262 var el = this.getFxEl();
10265 el.queueFx(o, function(){
10266 this.clearOpacity();
10269 // restore values after effect
10270 var r = this.getFxRestore();
10271 var st = this.dom.style;
10273 var after = function(){
10275 el.setDisplayed(false);
10282 el.setPositioning(r.pos);
10283 st.width = r.width;
10284 st.height = r.height;
10289 var width = this.getWidth();
10290 var height = this.getHeight();
10292 arguments.callee.anim = this.fxanim({
10293 width : {to: this.adjustWidth(width * 2)},
10294 height : {to: this.adjustHeight(height * 2)},
10295 points : {by: [-(width * .5), -(height * .5)]},
10297 fontSize: {to:200, unit: "%"}
10308 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10309 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10310 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10316 // all config options shown with default values
10324 * @param {Object} options (optional) Object literal with any of the Fx config options
10325 * @return {Roo.Element} The Element
10327 switchOff : function(o){
10328 var el = this.getFxEl();
10331 el.queueFx(o, function(){
10332 this.clearOpacity();
10335 // restore values after effect
10336 var r = this.getFxRestore();
10337 var st = this.dom.style;
10339 var after = function(){
10341 el.setDisplayed(false);
10347 el.setPositioning(r.pos);
10348 st.width = r.width;
10349 st.height = r.height;
10354 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10355 this.clearOpacity();
10359 points:{by:[0, this.getHeight() * .5]}
10360 }, o, 'motion', 0.3, 'easeIn', after);
10361 }).defer(100, this);
10368 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10369 * changed using the "attr" config option) and then fading back to the original color. If no original
10370 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10373 // default: highlight background to yellow
10376 // custom: highlight foreground text to blue for 2 seconds
10377 el.highlight("0000ff", { attr: 'color', duration: 2 });
10379 // common config options shown with default values
10380 el.highlight("ffff9c", {
10381 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10382 endColor: (current color) or "ffffff",
10387 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10388 * @param {Object} options (optional) Object literal with any of the Fx config options
10389 * @return {Roo.Element} The Element
10391 highlight : function(color, o){
10392 var el = this.getFxEl();
10395 el.queueFx(o, function(){
10396 color = color || "ffff9c";
10397 attr = o.attr || "backgroundColor";
10399 this.clearOpacity();
10402 var origColor = this.getColor(attr);
10403 var restoreColor = this.dom.style[attr];
10404 endColor = (o.endColor || origColor) || "ffffff";
10406 var after = function(){
10407 el.dom.style[attr] = restoreColor;
10412 a[attr] = {from: color, to: endColor};
10413 arguments.callee.anim = this.fxanim(a,
10423 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10426 // default: a single light blue ripple
10429 // custom: 3 red ripples lasting 3 seconds total
10430 el.frame("ff0000", 3, { duration: 3 });
10432 // common config options shown with default values
10433 el.frame("C3DAF9", 1, {
10434 duration: 1 //duration of entire animation (not each individual ripple)
10435 // Note: Easing is not configurable and will be ignored if included
10438 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10439 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10440 * @param {Object} options (optional) Object literal with any of the Fx config options
10441 * @return {Roo.Element} The Element
10443 frame : function(color, count, o){
10444 var el = this.getFxEl();
10447 el.queueFx(o, function(){
10448 color = color || "#C3DAF9";
10449 if(color.length == 6){
10450 color = "#" + color;
10452 count = count || 1;
10453 duration = o.duration || 1;
10456 var b = this.getBox();
10457 var animFn = function(){
10458 var proxy = this.createProxy({
10461 visbility:"hidden",
10462 position:"absolute",
10463 "z-index":"35000", // yee haw
10464 border:"0px solid " + color
10467 var scale = Roo.isBorderBox ? 2 : 1;
10469 top:{from:b.y, to:b.y - 20},
10470 left:{from:b.x, to:b.x - 20},
10471 borderWidth:{from:0, to:10},
10472 opacity:{from:1, to:0},
10473 height:{from:b.height, to:(b.height + (20*scale))},
10474 width:{from:b.width, to:(b.width + (20*scale))}
10475 }, duration, function(){
10479 animFn.defer((duration/2)*1000, this);
10490 * Creates a pause before any subsequent queued effects begin. If there are
10491 * no effects queued after the pause it will have no effect.
10496 * @param {Number} seconds The length of time to pause (in seconds)
10497 * @return {Roo.Element} The Element
10499 pause : function(seconds){
10500 var el = this.getFxEl();
10503 el.queueFx(o, function(){
10504 setTimeout(function(){
10506 }, seconds * 1000);
10512 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10513 * using the "endOpacity" config option.
10516 // default: fade in from opacity 0 to 100%
10519 // custom: fade in from opacity 0 to 75% over 2 seconds
10520 el.fadeIn({ endOpacity: .75, duration: 2});
10522 // common config options shown with default values
10524 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10529 * @param {Object} options (optional) Object literal with any of the Fx config options
10530 * @return {Roo.Element} The Element
10532 fadeIn : function(o){
10533 var el = this.getFxEl();
10535 el.queueFx(o, function(){
10536 this.setOpacity(0);
10538 this.dom.style.visibility = 'visible';
10539 var to = o.endOpacity || 1;
10540 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10541 o, null, .5, "easeOut", function(){
10543 this.clearOpacity();
10552 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10553 * using the "endOpacity" config option.
10556 // default: fade out from the element's current opacity to 0
10559 // custom: fade out from the element's current opacity to 25% over 2 seconds
10560 el.fadeOut({ endOpacity: .25, duration: 2});
10562 // common config options shown with default values
10564 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10571 * @param {Object} options (optional) Object literal with any of the Fx config options
10572 * @return {Roo.Element} The Element
10574 fadeOut : function(o){
10575 var el = this.getFxEl();
10577 el.queueFx(o, function(){
10578 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10579 o, null, .5, "easeOut", function(){
10580 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10581 this.dom.style.display = "none";
10583 this.dom.style.visibility = "hidden";
10585 this.clearOpacity();
10593 * Animates the transition of an element's dimensions from a starting height/width
10594 * to an ending height/width.
10597 // change height and width to 100x100 pixels
10598 el.scale(100, 100);
10600 // common config options shown with default values. The height and width will default to
10601 // the element's existing values if passed as null.
10604 [element's height], {
10609 * @param {Number} width The new width (pass undefined to keep the original width)
10610 * @param {Number} height The new height (pass undefined to keep the original height)
10611 * @param {Object} options (optional) Object literal with any of the Fx config options
10612 * @return {Roo.Element} The Element
10614 scale : function(w, h, o){
10615 this.shift(Roo.apply({}, o, {
10623 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10624 * Any of these properties not specified in the config object will not be changed. This effect
10625 * requires that at least one new dimension, position or opacity setting must be passed in on
10626 * the config object in order for the function to have any effect.
10629 // slide the element horizontally to x position 200 while changing the height and opacity
10630 el.shift({ x: 200, height: 50, opacity: .8 });
10632 // common config options shown with default values.
10634 width: [element's width],
10635 height: [element's height],
10636 x: [element's x position],
10637 y: [element's y position],
10638 opacity: [element's opacity],
10643 * @param {Object} options Object literal with any of the Fx config options
10644 * @return {Roo.Element} The Element
10646 shift : function(o){
10647 var el = this.getFxEl();
10649 el.queueFx(o, function(){
10650 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10651 if(w !== undefined){
10652 a.width = {to: this.adjustWidth(w)};
10654 if(h !== undefined){
10655 a.height = {to: this.adjustHeight(h)};
10657 if(x !== undefined || y !== undefined){
10659 x !== undefined ? x : this.getX(),
10660 y !== undefined ? y : this.getY()
10663 if(op !== undefined){
10664 a.opacity = {to: op};
10666 if(o.xy !== undefined){
10667 a.points = {to: o.xy};
10669 arguments.callee.anim = this.fxanim(a,
10670 o, 'motion', .35, "easeOut", function(){
10678 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10679 * ending point of the effect.
10682 // default: slide the element downward while fading out
10685 // custom: slide the element out to the right with a 2-second duration
10686 el.ghost('r', { duration: 2 });
10688 // common config options shown with default values
10696 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10697 * @param {Object} options (optional) Object literal with any of the Fx config options
10698 * @return {Roo.Element} The Element
10700 ghost : function(anchor, o){
10701 var el = this.getFxEl();
10704 el.queueFx(o, function(){
10705 anchor = anchor || "b";
10707 // restore values after effect
10708 var r = this.getFxRestore();
10709 var w = this.getWidth(),
10710 h = this.getHeight();
10712 var st = this.dom.style;
10714 var after = function(){
10716 el.setDisplayed(false);
10722 el.setPositioning(r.pos);
10723 st.width = r.width;
10724 st.height = r.height;
10729 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10730 switch(anchor.toLowerCase()){
10757 arguments.callee.anim = this.fxanim(a,
10767 * Ensures that all effects queued after syncFx is called on the element are
10768 * run concurrently. This is the opposite of {@link #sequenceFx}.
10769 * @return {Roo.Element} The Element
10771 syncFx : function(){
10772 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10781 * Ensures that all effects queued after sequenceFx is called on the element are
10782 * run in sequence. This is the opposite of {@link #syncFx}.
10783 * @return {Roo.Element} The Element
10785 sequenceFx : function(){
10786 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10788 concurrent : false,
10795 nextFx : function(){
10796 var ef = this.fxQueue[0];
10803 * Returns true if the element has any effects actively running or queued, else returns false.
10804 * @return {Boolean} True if element has active effects, else false
10806 hasActiveFx : function(){
10807 return this.fxQueue && this.fxQueue[0];
10811 * Stops any running effects and clears the element's internal effects queue if it contains
10812 * any additional effects that haven't started yet.
10813 * @return {Roo.Element} The Element
10815 stopFx : function(){
10816 if(this.hasActiveFx()){
10817 var cur = this.fxQueue[0];
10818 if(cur && cur.anim && cur.anim.isAnimated()){
10819 this.fxQueue = [cur]; // clear out others
10820 cur.anim.stop(true);
10827 beforeFx : function(o){
10828 if(this.hasActiveFx() && !o.concurrent){
10839 * Returns true if the element is currently blocking so that no other effect can be queued
10840 * until this effect is finished, else returns false if blocking is not set. This is commonly
10841 * used to ensure that an effect initiated by a user action runs to completion prior to the
10842 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10843 * @return {Boolean} True if blocking, else false
10845 hasFxBlock : function(){
10846 var q = this.fxQueue;
10847 return q && q[0] && q[0].block;
10851 queueFx : function(o, fn){
10855 if(!this.hasFxBlock()){
10856 Roo.applyIf(o, this.fxDefaults);
10858 var run = this.beforeFx(o);
10859 fn.block = o.block;
10860 this.fxQueue.push(fn);
10872 fxWrap : function(pos, o, vis){
10874 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10877 wrapXY = this.getXY();
10879 var div = document.createElement("div");
10880 div.style.visibility = vis;
10881 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10882 wrap.setPositioning(pos);
10883 if(wrap.getStyle("position") == "static"){
10884 wrap.position("relative");
10886 this.clearPositioning('auto');
10888 wrap.dom.appendChild(this.dom);
10890 wrap.setXY(wrapXY);
10897 fxUnwrap : function(wrap, pos, o){
10898 this.clearPositioning();
10899 this.setPositioning(pos);
10901 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10907 getFxRestore : function(){
10908 var st = this.dom.style;
10909 return {pos: this.getPositioning(), width: st.width, height : st.height};
10913 afterFx : function(o){
10915 this.applyStyles(o.afterStyle);
10918 this.addClass(o.afterCls);
10920 if(o.remove === true){
10923 Roo.callback(o.callback, o.scope, [this]);
10925 this.fxQueue.shift();
10931 getFxEl : function(){ // support for composite element fx
10932 return Roo.get(this.dom);
10936 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10937 animType = animType || 'run';
10939 var anim = Roo.lib.Anim[animType](
10941 (opt.duration || defaultDur) || .35,
10942 (opt.easing || defaultEase) || 'easeOut',
10944 Roo.callback(cb, this);
10953 // backwords compat
10954 Roo.Fx.resize = Roo.Fx.scale;
10956 //When included, Roo.Fx is automatically applied to Element so that all basic
10957 //effects are available directly via the Element API
10958 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10960 * Ext JS Library 1.1.1
10961 * Copyright(c) 2006-2007, Ext JS, LLC.
10963 * Originally Released Under LGPL - original licence link has changed is not relivant.
10966 * <script type="text/javascript">
10971 * @class Roo.CompositeElement
10972 * Standard composite class. Creates a Roo.Element for every element in the collection.
10974 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10975 * actions will be performed on all the elements in this collection.</b>
10977 * All methods return <i>this</i> and can be chained.
10979 var els = Roo.select("#some-el div.some-class", true);
10980 // or select directly from an existing element
10981 var el = Roo.get('some-el');
10982 el.select('div.some-class', true);
10984 els.setWidth(100); // all elements become 100 width
10985 els.hide(true); // all elements fade out and hide
10987 els.setWidth(100).hide(true);
10990 Roo.CompositeElement = function(els){
10991 this.elements = [];
10992 this.addElements(els);
10994 Roo.CompositeElement.prototype = {
10996 addElements : function(els){
10997 if(!els) return this;
10998 if(typeof els == "string"){
10999 els = Roo.Element.selectorFunction(els);
11001 var yels = this.elements;
11002 var index = yels.length-1;
11003 for(var i = 0, len = els.length; i < len; i++) {
11004 yels[++index] = Roo.get(els[i]);
11010 * Clears this composite and adds the elements returned by the passed selector.
11011 * @param {String/Array} els A string CSS selector, an array of elements or an element
11012 * @return {CompositeElement} this
11014 fill : function(els){
11015 this.elements = [];
11021 * Filters this composite to only elements that match the passed selector.
11022 * @param {String} selector A string CSS selector
11023 * @param {Boolean} inverse return inverse filter (not matches)
11024 * @return {CompositeElement} this
11026 filter : function(selector, inverse){
11028 inverse = inverse || false;
11029 this.each(function(el){
11030 var match = inverse ? !el.is(selector) : el.is(selector);
11032 els[els.length] = el.dom;
11039 invoke : function(fn, args){
11040 var els = this.elements;
11041 for(var i = 0, len = els.length; i < len; i++) {
11042 Roo.Element.prototype[fn].apply(els[i], args);
11047 * Adds elements to this composite.
11048 * @param {String/Array} els A string CSS selector, an array of elements or an element
11049 * @return {CompositeElement} this
11051 add : function(els){
11052 if(typeof els == "string"){
11053 this.addElements(Roo.Element.selectorFunction(els));
11054 }else if(els.length !== undefined){
11055 this.addElements(els);
11057 this.addElements([els]);
11062 * Calls the passed function passing (el, this, index) for each element in this composite.
11063 * @param {Function} fn The function to call
11064 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11065 * @return {CompositeElement} this
11067 each : function(fn, scope){
11068 var els = this.elements;
11069 for(var i = 0, len = els.length; i < len; i++){
11070 if(fn.call(scope || els[i], els[i], this, i) === false) {
11078 * Returns the Element object at the specified index
11079 * @param {Number} index
11080 * @return {Roo.Element}
11082 item : function(index){
11083 return this.elements[index] || null;
11087 * Returns the first Element
11088 * @return {Roo.Element}
11090 first : function(){
11091 return this.item(0);
11095 * Returns the last Element
11096 * @return {Roo.Element}
11099 return this.item(this.elements.length-1);
11103 * Returns the number of elements in this composite
11106 getCount : function(){
11107 return this.elements.length;
11111 * Returns true if this composite contains the passed element
11114 contains : function(el){
11115 return this.indexOf(el) !== -1;
11119 * Returns true if this composite contains the passed element
11122 indexOf : function(el){
11123 return this.elements.indexOf(Roo.get(el));
11128 * Removes the specified element(s).
11129 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11130 * or an array of any of those.
11131 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11132 * @return {CompositeElement} this
11134 removeElement : function(el, removeDom){
11135 if(el instanceof Array){
11136 for(var i = 0, len = el.length; i < len; i++){
11137 this.removeElement(el[i]);
11141 var index = typeof el == 'number' ? el : this.indexOf(el);
11144 var d = this.elements[index];
11148 d.parentNode.removeChild(d);
11151 this.elements.splice(index, 1);
11157 * Replaces the specified element with the passed element.
11158 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11160 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11161 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11162 * @return {CompositeElement} this
11164 replaceElement : function(el, replacement, domReplace){
11165 var index = typeof el == 'number' ? el : this.indexOf(el);
11168 this.elements[index].replaceWith(replacement);
11170 this.elements.splice(index, 1, Roo.get(replacement))
11177 * Removes all elements.
11179 clear : function(){
11180 this.elements = [];
11184 Roo.CompositeElement.createCall = function(proto, fnName){
11185 if(!proto[fnName]){
11186 proto[fnName] = function(){
11187 return this.invoke(fnName, arguments);
11191 for(var fnName in Roo.Element.prototype){
11192 if(typeof Roo.Element.prototype[fnName] == "function"){
11193 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11199 * Ext JS Library 1.1.1
11200 * Copyright(c) 2006-2007, Ext JS, LLC.
11202 * Originally Released Under LGPL - original licence link has changed is not relivant.
11205 * <script type="text/javascript">
11209 * @class Roo.CompositeElementLite
11210 * @extends Roo.CompositeElement
11211 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11213 var els = Roo.select("#some-el div.some-class");
11214 // or select directly from an existing element
11215 var el = Roo.get('some-el');
11216 el.select('div.some-class');
11218 els.setWidth(100); // all elements become 100 width
11219 els.hide(true); // all elements fade out and hide
11221 els.setWidth(100).hide(true);
11222 </code></pre><br><br>
11223 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11224 * actions will be performed on all the elements in this collection.</b>
11226 Roo.CompositeElementLite = function(els){
11227 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11228 this.el = new Roo.Element.Flyweight();
11230 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11231 addElements : function(els){
11233 if(els instanceof Array){
11234 this.elements = this.elements.concat(els);
11236 var yels = this.elements;
11237 var index = yels.length-1;
11238 for(var i = 0, len = els.length; i < len; i++) {
11239 yels[++index] = els[i];
11245 invoke : function(fn, args){
11246 var els = this.elements;
11248 for(var i = 0, len = els.length; i < len; i++) {
11250 Roo.Element.prototype[fn].apply(el, args);
11255 * Returns a flyweight Element of the dom element object at the specified index
11256 * @param {Number} index
11257 * @return {Roo.Element}
11259 item : function(index){
11260 if(!this.elements[index]){
11263 this.el.dom = this.elements[index];
11267 // fixes scope with flyweight
11268 addListener : function(eventName, handler, scope, opt){
11269 var els = this.elements;
11270 for(var i = 0, len = els.length; i < len; i++) {
11271 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11277 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11278 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11279 * a reference to the dom node, use el.dom.</b>
11280 * @param {Function} fn The function to call
11281 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11282 * @return {CompositeElement} this
11284 each : function(fn, scope){
11285 var els = this.elements;
11287 for(var i = 0, len = els.length; i < len; i++){
11289 if(fn.call(scope || el, el, this, i) === false){
11296 indexOf : function(el){
11297 return this.elements.indexOf(Roo.getDom(el));
11300 replaceElement : function(el, replacement, domReplace){
11301 var index = typeof el == 'number' ? el : this.indexOf(el);
11303 replacement = Roo.getDom(replacement);
11305 var d = this.elements[index];
11306 d.parentNode.insertBefore(replacement, d);
11307 d.parentNode.removeChild(d);
11309 this.elements.splice(index, 1, replacement);
11314 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11318 * Ext JS Library 1.1.1
11319 * Copyright(c) 2006-2007, Ext JS, LLC.
11321 * Originally Released Under LGPL - original licence link has changed is not relivant.
11324 * <script type="text/javascript">
11330 * @class Roo.data.Connection
11331 * @extends Roo.util.Observable
11332 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11333 * either to a configured URL, or to a URL specified at request time.<br><br>
11335 * Requests made by this class are asynchronous, and will return immediately. No data from
11336 * the server will be available to the statement immediately following the {@link #request} call.
11337 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11339 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11340 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11341 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11342 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11343 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11344 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11345 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11346 * standard DOM methods.
11348 * @param {Object} config a configuration object.
11350 Roo.data.Connection = function(config){
11351 Roo.apply(this, config);
11354 * @event beforerequest
11355 * Fires before a network request is made to retrieve a data object.
11356 * @param {Connection} conn This Connection object.
11357 * @param {Object} options The options config object passed to the {@link #request} method.
11359 "beforerequest" : true,
11361 * @event requestcomplete
11362 * Fires if the request was successfully completed.
11363 * @param {Connection} conn This Connection object.
11364 * @param {Object} response The XHR object containing the response data.
11365 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11366 * @param {Object} options The options config object passed to the {@link #request} method.
11368 "requestcomplete" : true,
11370 * @event requestexception
11371 * Fires if an error HTTP status was returned from the server.
11372 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11373 * @param {Connection} conn This Connection object.
11374 * @param {Object} response The XHR object containing the response data.
11375 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11376 * @param {Object} options The options config object passed to the {@link #request} method.
11378 "requestexception" : true
11380 Roo.data.Connection.superclass.constructor.call(this);
11383 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11385 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11388 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11389 * extra parameters to each request made by this object. (defaults to undefined)
11392 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11393 * to each request made by this object. (defaults to undefined)
11396 * @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)
11399 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11403 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11409 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11412 disableCaching: true,
11415 * Sends an HTTP request to a remote server.
11416 * @param {Object} options An object which may contain the following properties:<ul>
11417 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11418 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11419 * request, a url encoded string or a function to call to get either.</li>
11420 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11421 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11422 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11423 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11424 * <li>options {Object} The parameter to the request call.</li>
11425 * <li>success {Boolean} True if the request succeeded.</li>
11426 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11428 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11429 * The callback is passed the following parameters:<ul>
11430 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11431 * <li>options {Object} The parameter to the request call.</li>
11433 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11434 * The callback is passed the following parameters:<ul>
11435 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11436 * <li>options {Object} The parameter to the request call.</li>
11438 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11439 * for the callback function. Defaults to the browser window.</li>
11440 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11441 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11442 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11443 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11444 * params for the post data. Any params will be appended to the URL.</li>
11445 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11447 * @return {Number} transactionId
11449 request : function(o){
11450 if(this.fireEvent("beforerequest", this, o) !== false){
11453 if(typeof p == "function"){
11454 p = p.call(o.scope||window, o);
11456 if(typeof p == "object"){
11457 p = Roo.urlEncode(o.params);
11459 if(this.extraParams){
11460 var extras = Roo.urlEncode(this.extraParams);
11461 p = p ? (p + '&' + extras) : extras;
11464 var url = o.url || this.url;
11465 if(typeof url == 'function'){
11466 url = url.call(o.scope||window, o);
11470 var form = Roo.getDom(o.form);
11471 url = url || form.action;
11473 var enctype = form.getAttribute("enctype");
11474 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11475 return this.doFormUpload(o, p, url);
11477 var f = Roo.lib.Ajax.serializeForm(form);
11478 p = p ? (p + '&' + f) : f;
11481 var hs = o.headers;
11482 if(this.defaultHeaders){
11483 hs = Roo.apply(hs || {}, this.defaultHeaders);
11490 success: this.handleResponse,
11491 failure: this.handleFailure,
11493 argument: {options: o},
11494 timeout : o.timeout || this.timeout
11497 var method = o.method||this.method||(p ? "POST" : "GET");
11499 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11500 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11503 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11507 }else if(this.autoAbort !== false){
11511 if((method == 'GET' && p) || o.xmlData){
11512 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11515 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11516 return this.transId;
11518 Roo.callback(o.callback, o.scope, [o, null, null]);
11524 * Determine whether this object has a request outstanding.
11525 * @param {Number} transactionId (Optional) defaults to the last transaction
11526 * @return {Boolean} True if there is an outstanding request.
11528 isLoading : function(transId){
11530 return Roo.lib.Ajax.isCallInProgress(transId);
11532 return this.transId ? true : false;
11537 * Aborts any outstanding request.
11538 * @param {Number} transactionId (Optional) defaults to the last transaction
11540 abort : function(transId){
11541 if(transId || this.isLoading()){
11542 Roo.lib.Ajax.abort(transId || this.transId);
11547 handleResponse : function(response){
11548 this.transId = false;
11549 var options = response.argument.options;
11550 response.argument = options ? options.argument : null;
11551 this.fireEvent("requestcomplete", this, response, options);
11552 Roo.callback(options.success, options.scope, [response, options]);
11553 Roo.callback(options.callback, options.scope, [options, true, response]);
11557 handleFailure : function(response, e){
11558 this.transId = false;
11559 var options = response.argument.options;
11560 response.argument = options ? options.argument : null;
11561 this.fireEvent("requestexception", this, response, options, e);
11562 Roo.callback(options.failure, options.scope, [response, options]);
11563 Roo.callback(options.callback, options.scope, [options, false, response]);
11567 doFormUpload : function(o, ps, url){
11569 var frame = document.createElement('iframe');
11572 frame.className = 'x-hidden';
11574 frame.src = Roo.SSL_SECURE_URL;
11576 document.body.appendChild(frame);
11579 document.frames[id].name = id;
11582 var form = Roo.getDom(o.form);
11584 form.method = 'POST';
11585 form.enctype = form.encoding = 'multipart/form-data';
11591 if(ps){ // add dynamic params
11593 ps = Roo.urlDecode(ps, false);
11595 if(ps.hasOwnProperty(k)){
11596 hd = document.createElement('input');
11597 hd.type = 'hidden';
11600 form.appendChild(hd);
11607 var r = { // bogus response object
11612 r.argument = o ? o.argument : null;
11617 doc = frame.contentWindow.document;
11619 doc = (frame.contentDocument || window.frames[id].document);
11621 if(doc && doc.body){
11622 r.responseText = doc.body.innerHTML;
11624 if(doc && doc.XMLDocument){
11625 r.responseXML = doc.XMLDocument;
11627 r.responseXML = doc;
11634 Roo.EventManager.removeListener(frame, 'load', cb, this);
11636 this.fireEvent("requestcomplete", this, r, o);
11637 Roo.callback(o.success, o.scope, [r, o]);
11638 Roo.callback(o.callback, o.scope, [o, true, r]);
11640 setTimeout(function(){document.body.removeChild(frame);}, 100);
11643 Roo.EventManager.on(frame, 'load', cb, this);
11646 if(hiddens){ // remove dynamic params
11647 for(var i = 0, len = hiddens.length; i < len; i++){
11648 form.removeChild(hiddens[i]);
11655 * Ext JS Library 1.1.1
11656 * Copyright(c) 2006-2007, Ext JS, LLC.
11658 * Originally Released Under LGPL - original licence link has changed is not relivant.
11661 * <script type="text/javascript">
11665 * Global Ajax request class.
11668 * @extends Roo.data.Connection
11671 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11672 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11673 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11674 * @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)
11675 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11676 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11677 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11679 Roo.Ajax = new Roo.data.Connection({
11688 * Serialize the passed form into a url encoded string
11690 * @param {String/HTMLElement} form
11693 serializeForm : function(form){
11694 return Roo.lib.Ajax.serializeForm(form);
11698 * Ext JS Library 1.1.1
11699 * Copyright(c) 2006-2007, Ext JS, LLC.
11701 * Originally Released Under LGPL - original licence link has changed is not relivant.
11704 * <script type="text/javascript">
11709 * @class Roo.UpdateManager
11710 * @extends Roo.util.Observable
11711 * Provides AJAX-style update for Element object.<br><br>
11714 * // Get it from a Roo.Element object
11715 * var el = Roo.get("foo");
11716 * var mgr = el.getUpdateManager();
11717 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11719 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11721 * // or directly (returns the same UpdateManager instance)
11722 * var mgr = new Roo.UpdateManager("myElementId");
11723 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11724 * mgr.on("update", myFcnNeedsToKnow);
11726 // short handed call directly from the element object
11727 Roo.get("foo").load({
11731 text: "Loading Foo..."
11735 * Create new UpdateManager directly.
11736 * @param {String/HTMLElement/Roo.Element} el The element to update
11737 * @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).
11739 Roo.UpdateManager = function(el, forceNew){
11741 if(!forceNew && el.updateManager){
11742 return el.updateManager;
11745 * The Element object
11746 * @type Roo.Element
11750 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11753 this.defaultUrl = null;
11757 * @event beforeupdate
11758 * Fired before an update is made, return false from your handler and the update is cancelled.
11759 * @param {Roo.Element} el
11760 * @param {String/Object/Function} url
11761 * @param {String/Object} params
11763 "beforeupdate": true,
11766 * Fired after successful update is made.
11767 * @param {Roo.Element} el
11768 * @param {Object} oResponseObject The response Object
11773 * Fired on update failure.
11774 * @param {Roo.Element} el
11775 * @param {Object} oResponseObject The response Object
11779 var d = Roo.UpdateManager.defaults;
11781 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11784 this.sslBlankUrl = d.sslBlankUrl;
11786 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11789 this.disableCaching = d.disableCaching;
11791 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11794 this.indicatorText = d.indicatorText;
11796 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11799 this.showLoadIndicator = d.showLoadIndicator;
11801 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11804 this.timeout = d.timeout;
11807 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11810 this.loadScripts = d.loadScripts;
11813 * Transaction object of current executing transaction
11815 this.transaction = null;
11820 this.autoRefreshProcId = null;
11822 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11825 this.refreshDelegate = this.refresh.createDelegate(this);
11827 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11830 this.updateDelegate = this.update.createDelegate(this);
11832 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11835 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11839 this.successDelegate = this.processSuccess.createDelegate(this);
11843 this.failureDelegate = this.processFailure.createDelegate(this);
11845 if(!this.renderer){
11847 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11849 this.renderer = new Roo.UpdateManager.BasicRenderer();
11852 Roo.UpdateManager.superclass.constructor.call(this);
11855 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11857 * Get the Element this UpdateManager is bound to
11858 * @return {Roo.Element} The element
11860 getEl : function(){
11864 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11865 * @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:
11868 url: "your-url.php",<br/>
11869 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11870 callback: yourFunction,<br/>
11871 scope: yourObject, //(optional scope) <br/>
11872 discardUrl: false, <br/>
11873 nocache: false,<br/>
11874 text: "Loading...",<br/>
11876 scripts: false<br/>
11879 * The only required property is url. The optional properties nocache, text and scripts
11880 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11881 * @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}
11882 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11883 * @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.
11885 update : function(url, params, callback, discardUrl){
11886 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11887 var method = this.method,
11889 if(typeof url == "object"){ // must be config object
11892 params = params || cfg.params;
11893 callback = callback || cfg.callback;
11894 discardUrl = discardUrl || cfg.discardUrl;
11895 if(callback && cfg.scope){
11896 callback = callback.createDelegate(cfg.scope);
11898 if(typeof cfg.method != "undefined"){method = cfg.method;};
11899 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11900 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11901 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11902 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11904 this.showLoading();
11906 this.defaultUrl = url;
11908 if(typeof url == "function"){
11909 url = url.call(this);
11912 method = method || (params ? "POST" : "GET");
11913 if(method == "GET"){
11914 url = this.prepareUrl(url);
11917 var o = Roo.apply(cfg ||{}, {
11920 success: this.successDelegate,
11921 failure: this.failureDelegate,
11922 callback: undefined,
11923 timeout: (this.timeout*1000),
11924 argument: {"url": url, "form": null, "callback": callback, "params": params}
11926 Roo.log("updated manager called with timeout of " + o.timeout);
11927 this.transaction = Roo.Ajax.request(o);
11932 * 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.
11933 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11934 * @param {String/HTMLElement} form The form Id or form element
11935 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11936 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11937 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11939 formUpdate : function(form, url, reset, callback){
11940 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11941 if(typeof url == "function"){
11942 url = url.call(this);
11944 form = Roo.getDom(form);
11945 this.transaction = Roo.Ajax.request({
11948 success: this.successDelegate,
11949 failure: this.failureDelegate,
11950 timeout: (this.timeout*1000),
11951 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11953 this.showLoading.defer(1, this);
11958 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11959 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11961 refresh : function(callback){
11962 if(this.defaultUrl == null){
11965 this.update(this.defaultUrl, null, callback, true);
11969 * Set this element to auto refresh.
11970 * @param {Number} interval How often to update (in seconds).
11971 * @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)
11972 * @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}
11973 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11974 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11976 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11978 this.update(url || this.defaultUrl, params, callback, true);
11980 if(this.autoRefreshProcId){
11981 clearInterval(this.autoRefreshProcId);
11983 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11987 * Stop auto refresh on this element.
11989 stopAutoRefresh : function(){
11990 if(this.autoRefreshProcId){
11991 clearInterval(this.autoRefreshProcId);
11992 delete this.autoRefreshProcId;
11996 isAutoRefreshing : function(){
11997 return this.autoRefreshProcId ? true : false;
12000 * Called to update the element to "Loading" state. Override to perform custom action.
12002 showLoading : function(){
12003 if(this.showLoadIndicator){
12004 this.el.update(this.indicatorText);
12009 * Adds unique parameter to query string if disableCaching = true
12012 prepareUrl : function(url){
12013 if(this.disableCaching){
12014 var append = "_dc=" + (new Date().getTime());
12015 if(url.indexOf("?") !== -1){
12016 url += "&" + append;
12018 url += "?" + append;
12027 processSuccess : function(response){
12028 this.transaction = null;
12029 if(response.argument.form && response.argument.reset){
12030 try{ // put in try/catch since some older FF releases had problems with this
12031 response.argument.form.reset();
12034 if(this.loadScripts){
12035 this.renderer.render(this.el, response, this,
12036 this.updateComplete.createDelegate(this, [response]));
12038 this.renderer.render(this.el, response, this);
12039 this.updateComplete(response);
12043 updateComplete : function(response){
12044 this.fireEvent("update", this.el, response);
12045 if(typeof response.argument.callback == "function"){
12046 response.argument.callback(this.el, true, response);
12053 processFailure : function(response){
12054 this.transaction = null;
12055 this.fireEvent("failure", this.el, response);
12056 if(typeof response.argument.callback == "function"){
12057 response.argument.callback(this.el, false, response);
12062 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12063 * @param {Object} renderer The object implementing the render() method
12065 setRenderer : function(renderer){
12066 this.renderer = renderer;
12069 getRenderer : function(){
12070 return this.renderer;
12074 * Set the defaultUrl used for updates
12075 * @param {String/Function} defaultUrl The url or a function to call to get the url
12077 setDefaultUrl : function(defaultUrl){
12078 this.defaultUrl = defaultUrl;
12082 * Aborts the executing transaction
12084 abort : function(){
12085 if(this.transaction){
12086 Roo.Ajax.abort(this.transaction);
12091 * Returns true if an update is in progress
12092 * @return {Boolean}
12094 isUpdating : function(){
12095 if(this.transaction){
12096 return Roo.Ajax.isLoading(this.transaction);
12103 * @class Roo.UpdateManager.defaults
12104 * @static (not really - but it helps the doc tool)
12105 * The defaults collection enables customizing the default properties of UpdateManager
12107 Roo.UpdateManager.defaults = {
12109 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12115 * True to process scripts by default (Defaults to false).
12118 loadScripts : false,
12121 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12124 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12126 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12129 disableCaching : false,
12131 * Whether to show indicatorText when loading (Defaults to true).
12134 showLoadIndicator : true,
12136 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12139 indicatorText : '<div class="loading-indicator">Loading...</div>'
12143 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12145 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12146 * @param {String/HTMLElement/Roo.Element} el The element to update
12147 * @param {String} url The url
12148 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12149 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12152 * @member Roo.UpdateManager
12154 Roo.UpdateManager.updateElement = function(el, url, params, options){
12155 var um = Roo.get(el, true).getUpdateManager();
12156 Roo.apply(um, options);
12157 um.update(url, params, options ? options.callback : null);
12159 // alias for backwards compat
12160 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12162 * @class Roo.UpdateManager.BasicRenderer
12163 * Default Content renderer. Updates the elements innerHTML with the responseText.
12165 Roo.UpdateManager.BasicRenderer = function(){};
12167 Roo.UpdateManager.BasicRenderer.prototype = {
12169 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12170 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12171 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12172 * @param {Roo.Element} el The element being rendered
12173 * @param {Object} response The YUI Connect response object
12174 * @param {UpdateManager} updateManager The calling update manager
12175 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12177 render : function(el, response, updateManager, callback){
12178 el.update(response.responseText, updateManager.loadScripts, callback);
12184 * (c)) Alan Knowles
12190 * @class Roo.DomTemplate
12191 * @extends Roo.Template
12192 * An effort at a dom based template engine..
12194 * Similar to XTemplate, except it uses dom parsing to create the template..
12196 * Supported features:
12201 {a_variable} - output encoded.
12202 {a_variable.format:("Y-m-d")} - call a method on the variable
12203 {a_variable:raw} - unencoded output
12204 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12205 {a_variable:this.method_on_template(...)} - call a method on the template object.
12210 <div roo-for="a_variable or condition.."></div>
12211 <div roo-if="a_variable or condition"></div>
12212 <div roo-exec="some javascript"></div>
12213 <div roo-name="named_template"></div>
12218 Roo.DomTemplate = function()
12220 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12227 Roo.extend(Roo.DomTemplate, Roo.Template, {
12229 * id counter for sub templates.
12233 * flag to indicate if dom parser is inside a pre,
12234 * it will strip whitespace if not.
12239 * The various sub templates
12247 * basic tag replacing syntax
12250 * // you can fake an object call by doing this
12254 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12255 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12257 iterChild : function (node, method) {
12259 var oldPre = this.inPre;
12260 if (node.tagName == 'PRE') {
12263 for( var i = 0; i < node.childNodes.length; i++) {
12264 method.call(this, node.childNodes[i]);
12266 this.inPre = oldPre;
12272 * compile the template
12274 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12277 compile: function()
12281 // covert the html into DOM...
12285 doc = document.implementation.createHTMLDocument("");
12286 doc.documentElement.innerHTML = this.html ;
12287 div = doc.documentElement;
12289 // old IE... - nasty -- it causes all sorts of issues.. with
12290 // images getting pulled from server..
12291 div = document.createElement('div');
12292 div.innerHTML = this.html;
12294 //doc.documentElement.innerHTML = htmlBody
12300 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12302 var tpls = this.tpls;
12304 // create a top level template from the snippet..
12306 //Roo.log(div.innerHTML);
12313 body : div.innerHTML,
12326 Roo.each(tpls, function(tp){
12327 this.compileTpl(tp);
12328 this.tpls[tp.id] = tp;
12331 this.master = tpls[0];
12337 compileNode : function(node, istop) {
12342 // skip anything not a tag..
12343 if (node.nodeType != 1) {
12344 if (node.nodeType == 3 && !this.inPre) {
12345 // reduce white space..
12346 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12369 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12370 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12371 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12372 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12378 // just itterate children..
12379 this.iterChild(node,this.compileNode);
12382 tpl.uid = this.id++;
12383 tpl.value = node.getAttribute('roo-' + tpl.attr);
12384 node.removeAttribute('roo-'+ tpl.attr);
12385 if (tpl.attr != 'name') {
12386 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12387 node.parentNode.replaceChild(placeholder, node);
12390 var placeholder = document.createElement('span');
12391 placeholder.className = 'roo-tpl-' + tpl.value;
12392 node.parentNode.replaceChild(placeholder, node);
12395 // parent now sees '{domtplXXXX}
12396 this.iterChild(node,this.compileNode);
12398 // we should now have node body...
12399 var div = document.createElement('div');
12400 div.appendChild(node);
12402 // this has the unfortunate side effect of converting tagged attributes
12403 // eg. href="{...}" into %7C...%7D
12404 // this has been fixed by searching for those combo's although it's a bit hacky..
12407 tpl.body = div.innerHTML;
12414 switch (tpl.value) {
12415 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12416 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12417 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12422 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12426 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12430 tpl.id = tpl.value; // replace non characters???
12436 this.tpls.push(tpl);
12446 * Compile a segment of the template into a 'sub-template'
12452 compileTpl : function(tpl)
12454 var fm = Roo.util.Format;
12455 var useF = this.disableFormats !== true;
12457 var sep = Roo.isGecko ? "+\n" : ",\n";
12459 var undef = function(str) {
12460 Roo.debug && Roo.log("Property not found :" + str);
12464 //Roo.log(tpl.body);
12468 var fn = function(m, lbrace, name, format, args)
12471 //Roo.log(arguments);
12472 args = args ? args.replace(/\\'/g,"'") : args;
12473 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12474 if (typeof(format) == 'undefined') {
12475 format = 'htmlEncode';
12477 if (format == 'raw' ) {
12481 if(name.substr(0, 6) == 'domtpl'){
12482 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12485 // build an array of options to determine if value is undefined..
12487 // basically get 'xxxx.yyyy' then do
12488 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12489 // (function () { Roo.log("Property not found"); return ''; })() :
12494 Roo.each(name.split('.'), function(st) {
12495 lookfor += (lookfor.length ? '.': '') + st;
12496 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12499 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12502 if(format && useF){
12504 args = args ? ',' + args : "";
12506 if(format.substr(0, 5) != "this."){
12507 format = "fm." + format + '(';
12509 format = 'this.call("'+ format.substr(5) + '", ';
12513 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12516 if (args && args.length) {
12517 // called with xxyx.yuu:(test,test)
12519 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12521 // raw.. - :raw modifier..
12522 return "'"+ sep + udef_st + name + ")"+sep+"'";
12526 // branched to use + in gecko and [].join() in others
12528 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12529 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12532 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12533 body.push(tpl.body.replace(/(\r\n|\n)/g,
12534 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12535 body.push("'].join('');};};");
12536 body = body.join('');
12539 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12541 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12548 * same as applyTemplate, except it's done to one of the subTemplates
12549 * when using named templates, you can do:
12551 * var str = pl.applySubTemplate('your-name', values);
12554 * @param {Number} id of the template
12555 * @param {Object} values to apply to template
12556 * @param {Object} parent (normaly the instance of this object)
12558 applySubTemplate : function(id, values, parent)
12562 var t = this.tpls[id];
12566 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12567 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12571 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12578 if(t.execCall && t.execCall.call(this, values, parent)){
12582 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12588 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12589 parent = t.target ? values : parent;
12590 if(t.forCall && vs instanceof Array){
12592 for(var i = 0, len = vs.length; i < len; i++){
12594 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12596 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12598 //Roo.log(t.compiled);
12602 return buf.join('');
12605 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12610 return t.compiled.call(this, vs, parent);
12612 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12614 //Roo.log(t.compiled);
12622 applyTemplate : function(values){
12623 return this.master.compiled.call(this, values, {});
12624 //var s = this.subs;
12627 apply : function(){
12628 return this.applyTemplate.apply(this, arguments);
12633 Roo.DomTemplate.from = function(el){
12634 el = Roo.getDom(el);
12635 return new Roo.Domtemplate(el.value || el.innerHTML);
12638 * Ext JS Library 1.1.1
12639 * Copyright(c) 2006-2007, Ext JS, LLC.
12641 * Originally Released Under LGPL - original licence link has changed is not relivant.
12644 * <script type="text/javascript">
12648 * @class Roo.util.DelayedTask
12649 * Provides a convenient method of performing setTimeout where a new
12650 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12651 * You can use this class to buffer
12652 * the keypress events for a certain number of milliseconds, and perform only if they stop
12653 * for that amount of time.
12654 * @constructor The parameters to this constructor serve as defaults and are not required.
12655 * @param {Function} fn (optional) The default function to timeout
12656 * @param {Object} scope (optional) The default scope of that timeout
12657 * @param {Array} args (optional) The default Array of arguments
12659 Roo.util.DelayedTask = function(fn, scope, args){
12660 var id = null, d, t;
12662 var call = function(){
12663 var now = new Date().getTime();
12667 fn.apply(scope, args || []);
12671 * Cancels any pending timeout and queues a new one
12672 * @param {Number} delay The milliseconds to delay
12673 * @param {Function} newFn (optional) Overrides function passed to constructor
12674 * @param {Object} newScope (optional) Overrides scope passed to constructor
12675 * @param {Array} newArgs (optional) Overrides args passed to constructor
12677 this.delay = function(delay, newFn, newScope, newArgs){
12678 if(id && delay != d){
12682 t = new Date().getTime();
12684 scope = newScope || scope;
12685 args = newArgs || args;
12687 id = setInterval(call, d);
12692 * Cancel the last queued timeout
12694 this.cancel = function(){
12702 * Ext JS Library 1.1.1
12703 * Copyright(c) 2006-2007, Ext JS, LLC.
12705 * Originally Released Under LGPL - original licence link has changed is not relivant.
12708 * <script type="text/javascript">
12712 Roo.util.TaskRunner = function(interval){
12713 interval = interval || 10;
12714 var tasks = [], removeQueue = [];
12716 var running = false;
12718 var stopThread = function(){
12724 var startThread = function(){
12727 id = setInterval(runTasks, interval);
12731 var removeTask = function(task){
12732 removeQueue.push(task);
12738 var runTasks = function(){
12739 if(removeQueue.length > 0){
12740 for(var i = 0, len = removeQueue.length; i < len; i++){
12741 tasks.remove(removeQueue[i]);
12744 if(tasks.length < 1){
12749 var now = new Date().getTime();
12750 for(var i = 0, len = tasks.length; i < len; ++i){
12752 var itime = now - t.taskRunTime;
12753 if(t.interval <= itime){
12754 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12755 t.taskRunTime = now;
12756 if(rt === false || t.taskRunCount === t.repeat){
12761 if(t.duration && t.duration <= (now - t.taskStartTime)){
12768 * Queues a new task.
12769 * @param {Object} task
12771 this.start = function(task){
12773 task.taskStartTime = new Date().getTime();
12774 task.taskRunTime = 0;
12775 task.taskRunCount = 0;
12780 this.stop = function(task){
12785 this.stopAll = function(){
12787 for(var i = 0, len = tasks.length; i < len; i++){
12788 if(tasks[i].onStop){
12797 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12799 * Ext JS Library 1.1.1
12800 * Copyright(c) 2006-2007, Ext JS, LLC.
12802 * Originally Released Under LGPL - original licence link has changed is not relivant.
12805 * <script type="text/javascript">
12810 * @class Roo.util.MixedCollection
12811 * @extends Roo.util.Observable
12812 * A Collection class that maintains both numeric indexes and keys and exposes events.
12814 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12815 * collection (defaults to false)
12816 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12817 * and return the key value for that item. This is used when available to look up the key on items that
12818 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12819 * equivalent to providing an implementation for the {@link #getKey} method.
12821 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12829 * Fires when the collection is cleared.
12834 * Fires when an item is added to the collection.
12835 * @param {Number} index The index at which the item was added.
12836 * @param {Object} o The item added.
12837 * @param {String} key The key associated with the added item.
12842 * Fires when an item is replaced in the collection.
12843 * @param {String} key he key associated with the new added.
12844 * @param {Object} old The item being replaced.
12845 * @param {Object} new The new item.
12850 * Fires when an item is removed from the collection.
12851 * @param {Object} o The item being removed.
12852 * @param {String} key (optional) The key associated with the removed item.
12857 this.allowFunctions = allowFunctions === true;
12859 this.getKey = keyFn;
12861 Roo.util.MixedCollection.superclass.constructor.call(this);
12864 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12865 allowFunctions : false,
12868 * Adds an item to the collection.
12869 * @param {String} key The key to associate with the item
12870 * @param {Object} o The item to add.
12871 * @return {Object} The item added.
12873 add : function(key, o){
12874 if(arguments.length == 1){
12876 key = this.getKey(o);
12878 if(typeof key == "undefined" || key === null){
12880 this.items.push(o);
12881 this.keys.push(null);
12883 var old = this.map[key];
12885 return this.replace(key, o);
12888 this.items.push(o);
12890 this.keys.push(key);
12892 this.fireEvent("add", this.length-1, o, key);
12897 * MixedCollection has a generic way to fetch keys if you implement getKey.
12900 var mc = new Roo.util.MixedCollection();
12901 mc.add(someEl.dom.id, someEl);
12902 mc.add(otherEl.dom.id, otherEl);
12906 var mc = new Roo.util.MixedCollection();
12907 mc.getKey = function(el){
12913 // or via the constructor
12914 var mc = new Roo.util.MixedCollection(false, function(el){
12920 * @param o {Object} The item for which to find the key.
12921 * @return {Object} The key for the passed item.
12923 getKey : function(o){
12928 * Replaces an item in the collection.
12929 * @param {String} key The key associated with the item to replace, or the item to replace.
12930 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12931 * @return {Object} The new item.
12933 replace : function(key, o){
12934 if(arguments.length == 1){
12936 key = this.getKey(o);
12938 var old = this.item(key);
12939 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12940 return this.add(key, o);
12942 var index = this.indexOfKey(key);
12943 this.items[index] = o;
12945 this.fireEvent("replace", key, old, o);
12950 * Adds all elements of an Array or an Object to the collection.
12951 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12952 * an Array of values, each of which are added to the collection.
12954 addAll : function(objs){
12955 if(arguments.length > 1 || objs instanceof Array){
12956 var args = arguments.length > 1 ? arguments : objs;
12957 for(var i = 0, len = args.length; i < len; i++){
12961 for(var key in objs){
12962 if(this.allowFunctions || typeof objs[key] != "function"){
12963 this.add(key, objs[key]);
12970 * Executes the specified function once for every item in the collection, passing each
12971 * item as the first and only parameter. returning false from the function will stop the iteration.
12972 * @param {Function} fn The function to execute for each item.
12973 * @param {Object} scope (optional) The scope in which to execute the function.
12975 each : function(fn, scope){
12976 var items = [].concat(this.items); // each safe for removal
12977 for(var i = 0, len = items.length; i < len; i++){
12978 if(fn.call(scope || items[i], items[i], i, len) === false){
12985 * Executes the specified function once for every key in the collection, passing each
12986 * key, and its associated item as the first two parameters.
12987 * @param {Function} fn The function to execute for each item.
12988 * @param {Object} scope (optional) The scope in which to execute the function.
12990 eachKey : function(fn, scope){
12991 for(var i = 0, len = this.keys.length; i < len; i++){
12992 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12997 * Returns the first item in the collection which elicits a true return value from the
12998 * passed selection function.
12999 * @param {Function} fn The selection function to execute for each item.
13000 * @param {Object} scope (optional) The scope in which to execute the function.
13001 * @return {Object} The first item in the collection which returned true from the selection function.
13003 find : function(fn, scope){
13004 for(var i = 0, len = this.items.length; i < len; i++){
13005 if(fn.call(scope || window, this.items[i], this.keys[i])){
13006 return this.items[i];
13013 * Inserts an item at the specified index in the collection.
13014 * @param {Number} index The index to insert the item at.
13015 * @param {String} key The key to associate with the new item, or the item itself.
13016 * @param {Object} o (optional) If the second parameter was a key, the new item.
13017 * @return {Object} The item inserted.
13019 insert : function(index, key, o){
13020 if(arguments.length == 2){
13022 key = this.getKey(o);
13024 if(index >= this.length){
13025 return this.add(key, o);
13028 this.items.splice(index, 0, o);
13029 if(typeof key != "undefined" && key != null){
13032 this.keys.splice(index, 0, key);
13033 this.fireEvent("add", index, o, key);
13038 * Removed an item from the collection.
13039 * @param {Object} o The item to remove.
13040 * @return {Object} The item removed.
13042 remove : function(o){
13043 return this.removeAt(this.indexOf(o));
13047 * Remove an item from a specified index in the collection.
13048 * @param {Number} index The index within the collection of the item to remove.
13050 removeAt : function(index){
13051 if(index < this.length && index >= 0){
13053 var o = this.items[index];
13054 this.items.splice(index, 1);
13055 var key = this.keys[index];
13056 if(typeof key != "undefined"){
13057 delete this.map[key];
13059 this.keys.splice(index, 1);
13060 this.fireEvent("remove", o, key);
13065 * Removed an item associated with the passed key fom the collection.
13066 * @param {String} key The key of the item to remove.
13068 removeKey : function(key){
13069 return this.removeAt(this.indexOfKey(key));
13073 * Returns the number of items in the collection.
13074 * @return {Number} the number of items in the collection.
13076 getCount : function(){
13077 return this.length;
13081 * Returns index within the collection of the passed Object.
13082 * @param {Object} o The item to find the index of.
13083 * @return {Number} index of the item.
13085 indexOf : function(o){
13086 if(!this.items.indexOf){
13087 for(var i = 0, len = this.items.length; i < len; i++){
13088 if(this.items[i] == o) return i;
13092 return this.items.indexOf(o);
13097 * Returns index within the collection of the passed key.
13098 * @param {String} key The key to find the index of.
13099 * @return {Number} index of the key.
13101 indexOfKey : function(key){
13102 if(!this.keys.indexOf){
13103 for(var i = 0, len = this.keys.length; i < len; i++){
13104 if(this.keys[i] == key) return i;
13108 return this.keys.indexOf(key);
13113 * Returns the item associated with the passed key OR index. Key has priority over index.
13114 * @param {String/Number} key The key or index of the item.
13115 * @return {Object} The item associated with the passed key.
13117 item : function(key){
13118 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13119 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13123 * Returns the item at the specified index.
13124 * @param {Number} index The index of the item.
13127 itemAt : function(index){
13128 return this.items[index];
13132 * Returns the item associated with the passed key.
13133 * @param {String/Number} key The key of the item.
13134 * @return {Object} The item associated with the passed key.
13136 key : function(key){
13137 return this.map[key];
13141 * Returns true if the collection contains the passed Object as an item.
13142 * @param {Object} o The Object to look for in the collection.
13143 * @return {Boolean} True if the collection contains the Object as an item.
13145 contains : function(o){
13146 return this.indexOf(o) != -1;
13150 * Returns true if the collection contains the passed Object as a key.
13151 * @param {String} key The key to look for in the collection.
13152 * @return {Boolean} True if the collection contains the Object as a key.
13154 containsKey : function(key){
13155 return typeof this.map[key] != "undefined";
13159 * Removes all items from the collection.
13161 clear : function(){
13166 this.fireEvent("clear");
13170 * Returns the first item in the collection.
13171 * @return {Object} the first item in the collection..
13173 first : function(){
13174 return this.items[0];
13178 * Returns the last item in the collection.
13179 * @return {Object} the last item in the collection..
13182 return this.items[this.length-1];
13185 _sort : function(property, dir, fn){
13186 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13187 fn = fn || function(a, b){
13190 var c = [], k = this.keys, items = this.items;
13191 for(var i = 0, len = items.length; i < len; i++){
13192 c[c.length] = {key: k[i], value: items[i], index: i};
13194 c.sort(function(a, b){
13195 var v = fn(a[property], b[property]) * dsc;
13197 v = (a.index < b.index ? -1 : 1);
13201 for(var i = 0, len = c.length; i < len; i++){
13202 items[i] = c[i].value;
13205 this.fireEvent("sort", this);
13209 * Sorts this collection with the passed comparison function
13210 * @param {String} direction (optional) "ASC" or "DESC"
13211 * @param {Function} fn (optional) comparison function
13213 sort : function(dir, fn){
13214 this._sort("value", dir, fn);
13218 * Sorts this collection by keys
13219 * @param {String} direction (optional) "ASC" or "DESC"
13220 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13222 keySort : function(dir, fn){
13223 this._sort("key", dir, fn || function(a, b){
13224 return String(a).toUpperCase()-String(b).toUpperCase();
13229 * Returns a range of items in this collection
13230 * @param {Number} startIndex (optional) defaults to 0
13231 * @param {Number} endIndex (optional) default to the last item
13232 * @return {Array} An array of items
13234 getRange : function(start, end){
13235 var items = this.items;
13236 if(items.length < 1){
13239 start = start || 0;
13240 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13243 for(var i = start; i <= end; i++) {
13244 r[r.length] = items[i];
13247 for(var i = start; i >= end; i--) {
13248 r[r.length] = items[i];
13255 * Filter the <i>objects</i> in this collection by a specific property.
13256 * Returns a new collection that has been filtered.
13257 * @param {String} property A property on your objects
13258 * @param {String/RegExp} value Either string that the property values
13259 * should start with or a RegExp to test against the property
13260 * @return {MixedCollection} The new filtered collection
13262 filter : function(property, value){
13263 if(!value.exec){ // not a regex
13264 value = String(value);
13265 if(value.length == 0){
13266 return this.clone();
13268 value = new RegExp("^" + Roo.escapeRe(value), "i");
13270 return this.filterBy(function(o){
13271 return o && value.test(o[property]);
13276 * Filter by a function. * Returns a new collection that has been filtered.
13277 * The passed function will be called with each
13278 * object in the collection. If the function returns true, the value is included
13279 * otherwise it is filtered.
13280 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13281 * @param {Object} scope (optional) The scope of the function (defaults to this)
13282 * @return {MixedCollection} The new filtered collection
13284 filterBy : function(fn, scope){
13285 var r = new Roo.util.MixedCollection();
13286 r.getKey = this.getKey;
13287 var k = this.keys, it = this.items;
13288 for(var i = 0, len = it.length; i < len; i++){
13289 if(fn.call(scope||this, it[i], k[i])){
13290 r.add(k[i], it[i]);
13297 * Creates a duplicate of this collection
13298 * @return {MixedCollection}
13300 clone : function(){
13301 var r = new Roo.util.MixedCollection();
13302 var k = this.keys, it = this.items;
13303 for(var i = 0, len = it.length; i < len; i++){
13304 r.add(k[i], it[i]);
13306 r.getKey = this.getKey;
13311 * Returns the item associated with the passed key or index.
13313 * @param {String/Number} key The key or index of the item.
13314 * @return {Object} The item associated with the passed key.
13316 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13318 * Ext JS Library 1.1.1
13319 * Copyright(c) 2006-2007, Ext JS, LLC.
13321 * Originally Released Under LGPL - original licence link has changed is not relivant.
13324 * <script type="text/javascript">
13327 * @class Roo.util.JSON
13328 * Modified version of Douglas Crockford"s json.js that doesn"t
13329 * mess with the Object prototype
13330 * http://www.json.org/js.html
13333 Roo.util.JSON = new (function(){
13334 var useHasOwn = {}.hasOwnProperty ? true : false;
13336 // crashes Safari in some instances
13337 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13339 var pad = function(n) {
13340 return n < 10 ? "0" + n : n;
13353 var encodeString = function(s){
13354 if (/["\\\x00-\x1f]/.test(s)) {
13355 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13360 c = b.charCodeAt();
13362 Math.floor(c / 16).toString(16) +
13363 (c % 16).toString(16);
13366 return '"' + s + '"';
13369 var encodeArray = function(o){
13370 var a = ["["], b, i, l = o.length, v;
13371 for (i = 0; i < l; i += 1) {
13373 switch (typeof v) {
13382 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13390 var encodeDate = function(o){
13391 return '"' + o.getFullYear() + "-" +
13392 pad(o.getMonth() + 1) + "-" +
13393 pad(o.getDate()) + "T" +
13394 pad(o.getHours()) + ":" +
13395 pad(o.getMinutes()) + ":" +
13396 pad(o.getSeconds()) + '"';
13400 * Encodes an Object, Array or other value
13401 * @param {Mixed} o The variable to encode
13402 * @return {String} The JSON string
13404 this.encode = function(o)
13406 // should this be extended to fully wrap stringify..
13408 if(typeof o == "undefined" || o === null){
13410 }else if(o instanceof Array){
13411 return encodeArray(o);
13412 }else if(o instanceof Date){
13413 return encodeDate(o);
13414 }else if(typeof o == "string"){
13415 return encodeString(o);
13416 }else if(typeof o == "number"){
13417 return isFinite(o) ? String(o) : "null";
13418 }else if(typeof o == "boolean"){
13421 var a = ["{"], b, i, v;
13423 if(!useHasOwn || o.hasOwnProperty(i)) {
13425 switch (typeof v) {
13434 a.push(this.encode(i), ":",
13435 v === null ? "null" : this.encode(v));
13446 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13447 * @param {String} json The JSON string
13448 * @return {Object} The resulting object
13450 this.decode = function(json){
13452 return /** eval:var:json */ eval("(" + json + ')');
13456 * Shorthand for {@link Roo.util.JSON#encode}
13457 * @member Roo encode
13459 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13461 * Shorthand for {@link Roo.util.JSON#decode}
13462 * @member Roo decode
13464 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13467 * Ext JS Library 1.1.1
13468 * Copyright(c) 2006-2007, Ext JS, LLC.
13470 * Originally Released Under LGPL - original licence link has changed is not relivant.
13473 * <script type="text/javascript">
13477 * @class Roo.util.Format
13478 * Reusable data formatting functions
13481 Roo.util.Format = function(){
13482 var trimRe = /^\s+|\s+$/g;
13485 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13486 * @param {String} value The string to truncate
13487 * @param {Number} length The maximum length to allow before truncating
13488 * @return {String} The converted text
13490 ellipsis : function(value, len){
13491 if(value && value.length > len){
13492 return value.substr(0, len-3)+"...";
13498 * Checks a reference and converts it to empty string if it is undefined
13499 * @param {Mixed} value Reference to check
13500 * @return {Mixed} Empty string if converted, otherwise the original value
13502 undef : function(value){
13503 return typeof value != "undefined" ? value : "";
13507 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13508 * @param {String} value The string to encode
13509 * @return {String} The encoded text
13511 htmlEncode : function(value){
13512 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13516 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13517 * @param {String} value The string to decode
13518 * @return {String} The decoded text
13520 htmlDecode : function(value){
13521 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13525 * Trims any whitespace from either side of a string
13526 * @param {String} value The text to trim
13527 * @return {String} The trimmed text
13529 trim : function(value){
13530 return String(value).replace(trimRe, "");
13534 * Returns a substring from within an original string
13535 * @param {String} value The original text
13536 * @param {Number} start The start index of the substring
13537 * @param {Number} length The length of the substring
13538 * @return {String} The substring
13540 substr : function(value, start, length){
13541 return String(value).substr(start, length);
13545 * Converts a string to all lower case letters
13546 * @param {String} value The text to convert
13547 * @return {String} The converted text
13549 lowercase : function(value){
13550 return String(value).toLowerCase();
13554 * Converts a string to all upper case letters
13555 * @param {String} value The text to convert
13556 * @return {String} The converted text
13558 uppercase : function(value){
13559 return String(value).toUpperCase();
13563 * Converts the first character only of a string to upper case
13564 * @param {String} value The text to convert
13565 * @return {String} The converted text
13567 capitalize : function(value){
13568 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13572 call : function(value, fn){
13573 if(arguments.length > 2){
13574 var args = Array.prototype.slice.call(arguments, 2);
13575 args.unshift(value);
13577 return /** eval:var:value */ eval(fn).apply(window, args);
13579 /** eval:var:value */
13580 return /** eval:var:value */ eval(fn).call(window, value);
13586 * safer version of Math.toFixed..??/
13587 * @param {Number/String} value The numeric value to format
13588 * @param {Number/String} value Decimal places
13589 * @return {String} The formatted currency string
13591 toFixed : function(v, n)
13593 // why not use to fixed - precision is buggered???
13595 return Math.round(v-0);
13597 var fact = Math.pow(10,n+1);
13598 v = (Math.round((v-0)*fact))/fact;
13599 var z = (''+fact).substring(2);
13600 if (v == Math.floor(v)) {
13601 return Math.floor(v) + '.' + z;
13604 // now just padd decimals..
13605 var ps = String(v).split('.');
13606 var fd = (ps[1] + z);
13607 var r = fd.substring(0,n);
13608 var rm = fd.substring(n);
13610 return ps[0] + '.' + r;
13612 r*=1; // turn it into a number;
13614 if (String(r).length != n) {
13617 r = String(r).substring(1); // chop the end off.
13620 return ps[0] + '.' + r;
13625 * Format a number as US currency
13626 * @param {Number/String} value The numeric value to format
13627 * @return {String} The formatted currency string
13629 usMoney : function(v){
13630 return '$' + Roo.util.Format.number(v);
13635 * eventually this should probably emulate php's number_format
13636 * @param {Number/String} value The numeric value to format
13637 * @param {Number} decimals number of decimal places
13638 * @return {String} The formatted currency string
13640 number : function(v,decimals)
13642 // multiply and round.
13643 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13644 var mul = Math.pow(10, decimals);
13645 var zero = String(mul).substring(1);
13646 v = (Math.round((v-0)*mul))/mul;
13648 // if it's '0' number.. then
13650 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13652 var ps = v.split('.');
13656 var r = /(\d+)(\d{3})/;
13658 while (r.test(whole)) {
13659 whole = whole.replace(r, '$1' + ',' + '$2');
13665 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13666 // does not have decimals
13667 (decimals ? ('.' + zero) : '');
13670 return whole + sub ;
13674 * Parse a value into a formatted date using the specified format pattern.
13675 * @param {Mixed} value The value to format
13676 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13677 * @return {String} The formatted date string
13679 date : function(v, format){
13683 if(!(v instanceof Date)){
13684 v = new Date(Date.parse(v));
13686 return v.dateFormat(format || Roo.util.Format.defaults.date);
13690 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13691 * @param {String} format Any valid date format string
13692 * @return {Function} The date formatting function
13694 dateRenderer : function(format){
13695 return function(v){
13696 return Roo.util.Format.date(v, format);
13701 stripTagsRE : /<\/?[^>]+>/gi,
13704 * Strips all HTML tags
13705 * @param {Mixed} value The text from which to strip tags
13706 * @return {String} The stripped text
13708 stripTags : function(v){
13709 return !v ? v : String(v).replace(this.stripTagsRE, "");
13713 Roo.util.Format.defaults = {
13717 * Ext JS Library 1.1.1
13718 * Copyright(c) 2006-2007, Ext JS, LLC.
13720 * Originally Released Under LGPL - original licence link has changed is not relivant.
13723 * <script type="text/javascript">
13730 * @class Roo.MasterTemplate
13731 * @extends Roo.Template
13732 * Provides a template that can have child templates. The syntax is:
13734 var t = new Roo.MasterTemplate(
13735 '<select name="{name}">',
13736 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13739 t.add('options', {value: 'foo', text: 'bar'});
13740 // or you can add multiple child elements in one shot
13741 t.addAll('options', [
13742 {value: 'foo', text: 'bar'},
13743 {value: 'foo2', text: 'bar2'},
13744 {value: 'foo3', text: 'bar3'}
13746 // then append, applying the master template values
13747 t.append('my-form', {name: 'my-select'});
13749 * A name attribute for the child template is not required if you have only one child
13750 * template or you want to refer to them by index.
13752 Roo.MasterTemplate = function(){
13753 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13754 this.originalHtml = this.html;
13756 var m, re = this.subTemplateRe;
13759 while(m = re.exec(this.html)){
13760 var name = m[1], content = m[2];
13765 tpl : new Roo.Template(content)
13768 st[name] = st[subIndex];
13770 st[subIndex].tpl.compile();
13771 st[subIndex].tpl.call = this.call.createDelegate(this);
13774 this.subCount = subIndex;
13777 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13779 * The regular expression used to match sub templates
13783 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13786 * Applies the passed values to a child template.
13787 * @param {String/Number} name (optional) The name or index of the child template
13788 * @param {Array/Object} values The values to be applied to the template
13789 * @return {MasterTemplate} this
13791 add : function(name, values){
13792 if(arguments.length == 1){
13793 values = arguments[0];
13796 var s = this.subs[name];
13797 s.buffer[s.buffer.length] = s.tpl.apply(values);
13802 * Applies all the passed values to a child template.
13803 * @param {String/Number} name (optional) The name or index of the child template
13804 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13805 * @param {Boolean} reset (optional) True to reset the template first
13806 * @return {MasterTemplate} this
13808 fill : function(name, values, reset){
13810 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13818 for(var i = 0, len = values.length; i < len; i++){
13819 this.add(name, values[i]);
13825 * Resets the template for reuse
13826 * @return {MasterTemplate} this
13828 reset : function(){
13830 for(var i = 0; i < this.subCount; i++){
13836 applyTemplate : function(values){
13838 var replaceIndex = -1;
13839 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13840 return s[++replaceIndex].buffer.join("");
13842 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13845 apply : function(){
13846 return this.applyTemplate.apply(this, arguments);
13849 compile : function(){return this;}
13853 * Alias for fill().
13856 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13858 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13859 * var tpl = Roo.MasterTemplate.from('element-id');
13860 * @param {String/HTMLElement} el
13861 * @param {Object} config
13864 Roo.MasterTemplate.from = function(el, config){
13865 el = Roo.getDom(el);
13866 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13869 * Ext JS Library 1.1.1
13870 * Copyright(c) 2006-2007, Ext JS, LLC.
13872 * Originally Released Under LGPL - original licence link has changed is not relivant.
13875 * <script type="text/javascript">
13880 * @class Roo.util.CSS
13881 * Utility class for manipulating CSS rules
13884 Roo.util.CSS = function(){
13886 var doc = document;
13888 var camelRe = /(-[a-z])/gi;
13889 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13893 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13894 * tag and appended to the HEAD of the document.
13895 * @param {String|Object} cssText The text containing the css rules
13896 * @param {String} id An id to add to the stylesheet for later removal
13897 * @return {StyleSheet}
13899 createStyleSheet : function(cssText, id){
13901 var head = doc.getElementsByTagName("head")[0];
13902 var nrules = doc.createElement("style");
13903 nrules.setAttribute("type", "text/css");
13905 nrules.setAttribute("id", id);
13907 if (typeof(cssText) != 'string') {
13908 // support object maps..
13909 // not sure if this a good idea..
13910 // perhaps it should be merged with the general css handling
13911 // and handle js style props.
13912 var cssTextNew = [];
13913 for(var n in cssText) {
13915 for(var k in cssText[n]) {
13916 citems.push( k + ' : ' +cssText[n][k] + ';' );
13918 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13921 cssText = cssTextNew.join("\n");
13927 head.appendChild(nrules);
13928 ss = nrules.styleSheet;
13929 ss.cssText = cssText;
13932 nrules.appendChild(doc.createTextNode(cssText));
13934 nrules.cssText = cssText;
13936 head.appendChild(nrules);
13937 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13939 this.cacheStyleSheet(ss);
13944 * Removes a style or link tag by id
13945 * @param {String} id The id of the tag
13947 removeStyleSheet : function(id){
13948 var existing = doc.getElementById(id);
13950 existing.parentNode.removeChild(existing);
13955 * Dynamically swaps an existing stylesheet reference for a new one
13956 * @param {String} id The id of an existing link tag to remove
13957 * @param {String} url The href of the new stylesheet to include
13959 swapStyleSheet : function(id, url){
13960 this.removeStyleSheet(id);
13961 var ss = doc.createElement("link");
13962 ss.setAttribute("rel", "stylesheet");
13963 ss.setAttribute("type", "text/css");
13964 ss.setAttribute("id", id);
13965 ss.setAttribute("href", url);
13966 doc.getElementsByTagName("head")[0].appendChild(ss);
13970 * Refresh the rule cache if you have dynamically added stylesheets
13971 * @return {Object} An object (hash) of rules indexed by selector
13973 refreshCache : function(){
13974 return this.getRules(true);
13978 cacheStyleSheet : function(stylesheet){
13982 try{// try catch for cross domain access issue
13983 var ssRules = stylesheet.cssRules || stylesheet.rules;
13984 for(var j = ssRules.length-1; j >= 0; --j){
13985 rules[ssRules[j].selectorText] = ssRules[j];
13991 * Gets all css rules for the document
13992 * @param {Boolean} refreshCache true to refresh the internal cache
13993 * @return {Object} An object (hash) of rules indexed by selector
13995 getRules : function(refreshCache){
13996 if(rules == null || refreshCache){
13998 var ds = doc.styleSheets;
13999 for(var i =0, len = ds.length; i < len; i++){
14001 this.cacheStyleSheet(ds[i]);
14009 * Gets an an individual CSS rule by selector(s)
14010 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14011 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14012 * @return {CSSRule} The CSS rule or null if one is not found
14014 getRule : function(selector, refreshCache){
14015 var rs = this.getRules(refreshCache);
14016 if(!(selector instanceof Array)){
14017 return rs[selector];
14019 for(var i = 0; i < selector.length; i++){
14020 if(rs[selector[i]]){
14021 return rs[selector[i]];
14029 * Updates a rule property
14030 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14031 * @param {String} property The css property
14032 * @param {String} value The new value for the property
14033 * @return {Boolean} true If a rule was found and updated
14035 updateRule : function(selector, property, value){
14036 if(!(selector instanceof Array)){
14037 var rule = this.getRule(selector);
14039 rule.style[property.replace(camelRe, camelFn)] = value;
14043 for(var i = 0; i < selector.length; i++){
14044 if(this.updateRule(selector[i], property, value)){
14054 * Ext JS Library 1.1.1
14055 * Copyright(c) 2006-2007, Ext JS, LLC.
14057 * Originally Released Under LGPL - original licence link has changed is not relivant.
14060 * <script type="text/javascript">
14066 * @class Roo.util.ClickRepeater
14067 * @extends Roo.util.Observable
14069 * A wrapper class which can be applied to any element. Fires a "click" event while the
14070 * mouse is pressed. The interval between firings may be specified in the config but
14071 * defaults to 10 milliseconds.
14073 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14075 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14076 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14077 * Similar to an autorepeat key delay.
14078 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14079 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14080 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14081 * "interval" and "delay" are ignored. "immediate" is honored.
14082 * @cfg {Boolean} preventDefault True to prevent the default click event
14083 * @cfg {Boolean} stopDefault True to stop the default click event
14086 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14087 * 2007-02-02 jvs Renamed to ClickRepeater
14088 * 2007-02-03 jvs Modifications for FF Mac and Safari
14091 * @param {String/HTMLElement/Element} el The element to listen on
14092 * @param {Object} config
14094 Roo.util.ClickRepeater = function(el, config)
14096 this.el = Roo.get(el);
14097 this.el.unselectable();
14099 Roo.apply(this, config);
14104 * Fires when the mouse button is depressed.
14105 * @param {Roo.util.ClickRepeater} this
14107 "mousedown" : true,
14110 * Fires on a specified interval during the time the element is pressed.
14111 * @param {Roo.util.ClickRepeater} this
14116 * Fires when the mouse key is released.
14117 * @param {Roo.util.ClickRepeater} this
14122 this.el.on("mousedown", this.handleMouseDown, this);
14123 if(this.preventDefault || this.stopDefault){
14124 this.el.on("click", function(e){
14125 if(this.preventDefault){
14126 e.preventDefault();
14128 if(this.stopDefault){
14134 // allow inline handler
14136 this.on("click", this.handler, this.scope || this);
14139 Roo.util.ClickRepeater.superclass.constructor.call(this);
14142 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14145 preventDefault : true,
14146 stopDefault : false,
14150 handleMouseDown : function(){
14151 clearTimeout(this.timer);
14153 if(this.pressClass){
14154 this.el.addClass(this.pressClass);
14156 this.mousedownTime = new Date();
14158 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14159 this.el.on("mouseout", this.handleMouseOut, this);
14161 this.fireEvent("mousedown", this);
14162 this.fireEvent("click", this);
14164 this.timer = this.click.defer(this.delay || this.interval, this);
14168 click : function(){
14169 this.fireEvent("click", this);
14170 this.timer = this.click.defer(this.getInterval(), this);
14174 getInterval: function(){
14175 if(!this.accelerate){
14176 return this.interval;
14178 var pressTime = this.mousedownTime.getElapsed();
14179 if(pressTime < 500){
14181 }else if(pressTime < 1700){
14183 }else if(pressTime < 2600){
14185 }else if(pressTime < 3500){
14187 }else if(pressTime < 4400){
14189 }else if(pressTime < 5300){
14191 }else if(pressTime < 6200){
14199 handleMouseOut : function(){
14200 clearTimeout(this.timer);
14201 if(this.pressClass){
14202 this.el.removeClass(this.pressClass);
14204 this.el.on("mouseover", this.handleMouseReturn, this);
14208 handleMouseReturn : function(){
14209 this.el.un("mouseover", this.handleMouseReturn);
14210 if(this.pressClass){
14211 this.el.addClass(this.pressClass);
14217 handleMouseUp : function(){
14218 clearTimeout(this.timer);
14219 this.el.un("mouseover", this.handleMouseReturn);
14220 this.el.un("mouseout", this.handleMouseOut);
14221 Roo.get(document).un("mouseup", this.handleMouseUp);
14222 this.el.removeClass(this.pressClass);
14223 this.fireEvent("mouseup", this);
14227 * Ext JS Library 1.1.1
14228 * Copyright(c) 2006-2007, Ext JS, LLC.
14230 * Originally Released Under LGPL - original licence link has changed is not relivant.
14233 * <script type="text/javascript">
14238 * @class Roo.KeyNav
14239 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14240 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14241 * way to implement custom navigation schemes for any UI component.</p>
14242 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14243 * pageUp, pageDown, del, home, end. Usage:</p>
14245 var nav = new Roo.KeyNav("my-element", {
14246 "left" : function(e){
14247 this.moveLeft(e.ctrlKey);
14249 "right" : function(e){
14250 this.moveRight(e.ctrlKey);
14252 "enter" : function(e){
14259 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14260 * @param {Object} config The config
14262 Roo.KeyNav = function(el, config){
14263 this.el = Roo.get(el);
14264 Roo.apply(this, config);
14265 if(!this.disabled){
14266 this.disabled = true;
14271 Roo.KeyNav.prototype = {
14273 * @cfg {Boolean} disabled
14274 * True to disable this KeyNav instance (defaults to false)
14278 * @cfg {String} defaultEventAction
14279 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14280 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14281 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14283 defaultEventAction: "stopEvent",
14285 * @cfg {Boolean} forceKeyDown
14286 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14287 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14288 * handle keydown instead of keypress.
14290 forceKeyDown : false,
14293 prepareEvent : function(e){
14294 var k = e.getKey();
14295 var h = this.keyToHandler[k];
14296 //if(h && this[h]){
14297 // e.stopPropagation();
14299 if(Roo.isSafari && h && k >= 37 && k <= 40){
14305 relay : function(e){
14306 var k = e.getKey();
14307 var h = this.keyToHandler[k];
14309 if(this.doRelay(e, this[h], h) !== true){
14310 e[this.defaultEventAction]();
14316 doRelay : function(e, h, hname){
14317 return h.call(this.scope || this, e);
14320 // possible handlers
14334 // quick lookup hash
14351 * Enable this KeyNav
14353 enable: function(){
14355 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14356 // the EventObject will normalize Safari automatically
14357 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14358 this.el.on("keydown", this.relay, this);
14360 this.el.on("keydown", this.prepareEvent, this);
14361 this.el.on("keypress", this.relay, this);
14363 this.disabled = false;
14368 * Disable this KeyNav
14370 disable: function(){
14371 if(!this.disabled){
14372 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14373 this.el.un("keydown", this.relay);
14375 this.el.un("keydown", this.prepareEvent);
14376 this.el.un("keypress", this.relay);
14378 this.disabled = true;
14383 * Ext JS Library 1.1.1
14384 * Copyright(c) 2006-2007, Ext JS, LLC.
14386 * Originally Released Under LGPL - original licence link has changed is not relivant.
14389 * <script type="text/javascript">
14394 * @class Roo.KeyMap
14395 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14396 * The constructor accepts the same config object as defined by {@link #addBinding}.
14397 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14398 * combination it will call the function with this signature (if the match is a multi-key
14399 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14400 * A KeyMap can also handle a string representation of keys.<br />
14403 // map one key by key code
14404 var map = new Roo.KeyMap("my-element", {
14405 key: 13, // or Roo.EventObject.ENTER
14410 // map multiple keys to one action by string
14411 var map = new Roo.KeyMap("my-element", {
14417 // map multiple keys to multiple actions by strings and array of codes
14418 var map = new Roo.KeyMap("my-element", [
14421 fn: function(){ alert("Return was pressed"); }
14424 fn: function(){ alert('a, b or c was pressed'); }
14429 fn: function(){ alert('Control + shift + tab was pressed.'); }
14433 * <b>Note: A KeyMap starts enabled</b>
14435 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14436 * @param {Object} config The config (see {@link #addBinding})
14437 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14439 Roo.KeyMap = function(el, config, eventName){
14440 this.el = Roo.get(el);
14441 this.eventName = eventName || "keydown";
14442 this.bindings = [];
14444 this.addBinding(config);
14449 Roo.KeyMap.prototype = {
14451 * True to stop the event from bubbling and prevent the default browser action if the
14452 * key was handled by the KeyMap (defaults to false)
14458 * Add a new binding to this KeyMap. The following config object properties are supported:
14460 Property Type Description
14461 ---------- --------------- ----------------------------------------------------------------------
14462 key String/Array A single keycode or an array of keycodes to handle
14463 shift Boolean True to handle key only when shift is pressed (defaults to false)
14464 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14465 alt Boolean True to handle key only when alt is pressed (defaults to false)
14466 fn Function The function to call when KeyMap finds the expected key combination
14467 scope Object The scope of the callback function
14473 var map = new Roo.KeyMap(document, {
14474 key: Roo.EventObject.ENTER,
14479 //Add a new binding to the existing KeyMap later
14487 * @param {Object/Array} config A single KeyMap config or an array of configs
14489 addBinding : function(config){
14490 if(config instanceof Array){
14491 for(var i = 0, len = config.length; i < len; i++){
14492 this.addBinding(config[i]);
14496 var keyCode = config.key,
14497 shift = config.shift,
14498 ctrl = config.ctrl,
14501 scope = config.scope;
14502 if(typeof keyCode == "string"){
14504 var keyString = keyCode.toUpperCase();
14505 for(var j = 0, len = keyString.length; j < len; j++){
14506 ks.push(keyString.charCodeAt(j));
14510 var keyArray = keyCode instanceof Array;
14511 var handler = function(e){
14512 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14513 var k = e.getKey();
14515 for(var i = 0, len = keyCode.length; i < len; i++){
14516 if(keyCode[i] == k){
14517 if(this.stopEvent){
14520 fn.call(scope || window, k, e);
14526 if(this.stopEvent){
14529 fn.call(scope || window, k, e);
14534 this.bindings.push(handler);
14538 * Shorthand for adding a single key listener
14539 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14540 * following options:
14541 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14542 * @param {Function} fn The function to call
14543 * @param {Object} scope (optional) The scope of the function
14545 on : function(key, fn, scope){
14546 var keyCode, shift, ctrl, alt;
14547 if(typeof key == "object" && !(key instanceof Array)){
14566 handleKeyDown : function(e){
14567 if(this.enabled){ //just in case
14568 var b = this.bindings;
14569 for(var i = 0, len = b.length; i < len; i++){
14570 b[i].call(this, e);
14576 * Returns true if this KeyMap is enabled
14577 * @return {Boolean}
14579 isEnabled : function(){
14580 return this.enabled;
14584 * Enables this KeyMap
14586 enable: function(){
14588 this.el.on(this.eventName, this.handleKeyDown, this);
14589 this.enabled = true;
14594 * Disable this KeyMap
14596 disable: function(){
14598 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14599 this.enabled = false;
14604 * Ext JS Library 1.1.1
14605 * Copyright(c) 2006-2007, Ext JS, LLC.
14607 * Originally Released Under LGPL - original licence link has changed is not relivant.
14610 * <script type="text/javascript">
14615 * @class Roo.util.TextMetrics
14616 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14617 * wide, in pixels, a given block of text will be.
14620 Roo.util.TextMetrics = function(){
14624 * Measures the size of the specified text
14625 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14626 * that can affect the size of the rendered text
14627 * @param {String} text The text to measure
14628 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14629 * in order to accurately measure the text height
14630 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14632 measure : function(el, text, fixedWidth){
14634 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14637 shared.setFixedWidth(fixedWidth || 'auto');
14638 return shared.getSize(text);
14642 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14643 * the overhead of multiple calls to initialize the style properties on each measurement.
14644 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14645 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14646 * in order to accurately measure the text height
14647 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14649 createInstance : function(el, fixedWidth){
14650 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14657 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14658 var ml = new Roo.Element(document.createElement('div'));
14659 document.body.appendChild(ml.dom);
14660 ml.position('absolute');
14661 ml.setLeftTop(-1000, -1000);
14665 ml.setWidth(fixedWidth);
14670 * Returns the size of the specified text based on the internal element's style and width properties
14671 * @memberOf Roo.util.TextMetrics.Instance#
14672 * @param {String} text The text to measure
14673 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14675 getSize : function(text){
14677 var s = ml.getSize();
14683 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14684 * that can affect the size of the rendered text
14685 * @memberOf Roo.util.TextMetrics.Instance#
14686 * @param {String/HTMLElement} el The element, dom node or id
14688 bind : function(el){
14690 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14695 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14696 * to set a fixed width in order to accurately measure the text height.
14697 * @memberOf Roo.util.TextMetrics.Instance#
14698 * @param {Number} width The width to set on the element
14700 setFixedWidth : function(width){
14701 ml.setWidth(width);
14705 * Returns the measured width of the specified text
14706 * @memberOf Roo.util.TextMetrics.Instance#
14707 * @param {String} text The text to measure
14708 * @return {Number} width The width in pixels
14710 getWidth : function(text){
14711 ml.dom.style.width = 'auto';
14712 return this.getSize(text).width;
14716 * Returns the measured height of the specified text. For multiline text, be sure to call
14717 * {@link #setFixedWidth} if necessary.
14718 * @memberOf Roo.util.TextMetrics.Instance#
14719 * @param {String} text The text to measure
14720 * @return {Number} height The height in pixels
14722 getHeight : function(text){
14723 return this.getSize(text).height;
14727 instance.bind(bindTo);
14732 // backwards compat
14733 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14735 * Ext JS Library 1.1.1
14736 * Copyright(c) 2006-2007, Ext JS, LLC.
14738 * Originally Released Under LGPL - original licence link has changed is not relivant.
14741 * <script type="text/javascript">
14745 * @class Roo.state.Provider
14746 * Abstract base class for state provider implementations. This class provides methods
14747 * for encoding and decoding <b>typed</b> variables including dates and defines the
14748 * Provider interface.
14750 Roo.state.Provider = function(){
14752 * @event statechange
14753 * Fires when a state change occurs.
14754 * @param {Provider} this This state provider
14755 * @param {String} key The state key which was changed
14756 * @param {String} value The encoded value for the state
14759 "statechange": true
14762 Roo.state.Provider.superclass.constructor.call(this);
14764 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14766 * Returns the current value for a key
14767 * @param {String} name The key name
14768 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14769 * @return {Mixed} The state data
14771 get : function(name, defaultValue){
14772 return typeof this.state[name] == "undefined" ?
14773 defaultValue : this.state[name];
14777 * Clears a value from the state
14778 * @param {String} name The key name
14780 clear : function(name){
14781 delete this.state[name];
14782 this.fireEvent("statechange", this, name, null);
14786 * Sets the value for a key
14787 * @param {String} name The key name
14788 * @param {Mixed} value The value to set
14790 set : function(name, value){
14791 this.state[name] = value;
14792 this.fireEvent("statechange", this, name, value);
14796 * Decodes a string previously encoded with {@link #encodeValue}.
14797 * @param {String} value The value to decode
14798 * @return {Mixed} The decoded value
14800 decodeValue : function(cookie){
14801 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14802 var matches = re.exec(unescape(cookie));
14803 if(!matches || !matches[1]) return; // non state cookie
14804 var type = matches[1];
14805 var v = matches[2];
14808 return parseFloat(v);
14810 return new Date(Date.parse(v));
14815 var values = v.split("^");
14816 for(var i = 0, len = values.length; i < len; i++){
14817 all.push(this.decodeValue(values[i]));
14822 var values = v.split("^");
14823 for(var i = 0, len = values.length; i < len; i++){
14824 var kv = values[i].split("=");
14825 all[kv[0]] = this.decodeValue(kv[1]);
14834 * Encodes a value including type information. Decode with {@link #decodeValue}.
14835 * @param {Mixed} value The value to encode
14836 * @return {String} The encoded value
14838 encodeValue : function(v){
14840 if(typeof v == "number"){
14842 }else if(typeof v == "boolean"){
14843 enc = "b:" + (v ? "1" : "0");
14844 }else if(v instanceof Date){
14845 enc = "d:" + v.toGMTString();
14846 }else if(v instanceof Array){
14848 for(var i = 0, len = v.length; i < len; i++){
14849 flat += this.encodeValue(v[i]);
14850 if(i != len-1) flat += "^";
14853 }else if(typeof v == "object"){
14856 if(typeof v[key] != "function"){
14857 flat += key + "=" + this.encodeValue(v[key]) + "^";
14860 enc = "o:" + flat.substring(0, flat.length-1);
14864 return escape(enc);
14870 * Ext JS Library 1.1.1
14871 * Copyright(c) 2006-2007, Ext JS, LLC.
14873 * Originally Released Under LGPL - original licence link has changed is not relivant.
14876 * <script type="text/javascript">
14879 * @class Roo.state.Manager
14880 * This is the global state manager. By default all components that are "state aware" check this class
14881 * for state information if you don't pass them a custom state provider. In order for this class
14882 * to be useful, it must be initialized with a provider when your application initializes.
14884 // in your initialization function
14886 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14888 // supposed you have a {@link Roo.BorderLayout}
14889 var layout = new Roo.BorderLayout(...);
14890 layout.restoreState();
14891 // or a {Roo.BasicDialog}
14892 var dialog = new Roo.BasicDialog(...);
14893 dialog.restoreState();
14897 Roo.state.Manager = function(){
14898 var provider = new Roo.state.Provider();
14902 * Configures the default state provider for your application
14903 * @param {Provider} stateProvider The state provider to set
14905 setProvider : function(stateProvider){
14906 provider = stateProvider;
14910 * Returns the current value for a key
14911 * @param {String} name The key name
14912 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14913 * @return {Mixed} The state data
14915 get : function(key, defaultValue){
14916 return provider.get(key, defaultValue);
14920 * Sets the value for a key
14921 * @param {String} name The key name
14922 * @param {Mixed} value The state data
14924 set : function(key, value){
14925 provider.set(key, value);
14929 * Clears a value from the state
14930 * @param {String} name The key name
14932 clear : function(key){
14933 provider.clear(key);
14937 * Gets the currently configured state provider
14938 * @return {Provider} The state provider
14940 getProvider : function(){
14947 * Ext JS Library 1.1.1
14948 * Copyright(c) 2006-2007, Ext JS, LLC.
14950 * Originally Released Under LGPL - original licence link has changed is not relivant.
14953 * <script type="text/javascript">
14956 * @class Roo.state.CookieProvider
14957 * @extends Roo.state.Provider
14958 * The default Provider implementation which saves state via cookies.
14961 var cp = new Roo.state.CookieProvider({
14963 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14964 domain: "roojs.com"
14966 Roo.state.Manager.setProvider(cp);
14968 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14969 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14970 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14971 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14972 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14973 * domain the page is running on including the 'www' like 'www.roojs.com')
14974 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14976 * Create a new CookieProvider
14977 * @param {Object} config The configuration object
14979 Roo.state.CookieProvider = function(config){
14980 Roo.state.CookieProvider.superclass.constructor.call(this);
14982 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14983 this.domain = null;
14984 this.secure = false;
14985 Roo.apply(this, config);
14986 this.state = this.readCookies();
14989 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14991 set : function(name, value){
14992 if(typeof value == "undefined" || value === null){
14996 this.setCookie(name, value);
14997 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15001 clear : function(name){
15002 this.clearCookie(name);
15003 Roo.state.CookieProvider.superclass.clear.call(this, name);
15007 readCookies : function(){
15009 var c = document.cookie + ";";
15010 var re = /\s?(.*?)=(.*?);/g;
15012 while((matches = re.exec(c)) != null){
15013 var name = matches[1];
15014 var value = matches[2];
15015 if(name && name.substring(0,3) == "ys-"){
15016 cookies[name.substr(3)] = this.decodeValue(value);
15023 setCookie : function(name, value){
15024 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15025 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15026 ((this.path == null) ? "" : ("; path=" + this.path)) +
15027 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15028 ((this.secure == true) ? "; secure" : "");
15032 clearCookie : function(name){
15033 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15034 ((this.path == null) ? "" : ("; path=" + this.path)) +
15035 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15036 ((this.secure == true) ? "; secure" : "");
15040 * Ext JS Library 1.1.1
15041 * Copyright(c) 2006-2007, Ext JS, LLC.
15043 * Originally Released Under LGPL - original licence link has changed is not relivant.
15046 * <script type="text/javascript">
15051 * @class Roo.ComponentMgr
15052 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15055 Roo.ComponentMgr = function(){
15056 var all = new Roo.util.MixedCollection();
15060 * Registers a component.
15061 * @param {Roo.Component} c The component
15063 register : function(c){
15068 * Unregisters a component.
15069 * @param {Roo.Component} c The component
15071 unregister : function(c){
15076 * Returns a component by id
15077 * @param {String} id The component id
15079 get : function(id){
15080 return all.get(id);
15084 * Registers a function that will be called when a specified component is added to ComponentMgr
15085 * @param {String} id The component id
15086 * @param {Funtction} fn The callback function
15087 * @param {Object} scope The scope of the callback
15089 onAvailable : function(id, fn, scope){
15090 all.on("add", function(index, o){
15092 fn.call(scope || o, o);
15093 all.un("add", fn, scope);
15100 * Ext JS Library 1.1.1
15101 * Copyright(c) 2006-2007, Ext JS, LLC.
15103 * Originally Released Under LGPL - original licence link has changed is not relivant.
15106 * <script type="text/javascript">
15110 * @class Roo.Component
15111 * @extends Roo.util.Observable
15112 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15113 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15114 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15115 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15116 * All visual components (widgets) that require rendering into a layout should subclass Component.
15118 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15119 * 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
15120 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15122 Roo.Component = function(config){
15123 config = config || {};
15124 if(config.tagName || config.dom || typeof config == "string"){ // element object
15125 config = {el: config, id: config.id || config};
15127 this.initialConfig = config;
15129 Roo.apply(this, config);
15133 * Fires after the component is disabled.
15134 * @param {Roo.Component} this
15139 * Fires after the component is enabled.
15140 * @param {Roo.Component} this
15144 * @event beforeshow
15145 * Fires before the component is shown. Return false to stop the show.
15146 * @param {Roo.Component} this
15151 * Fires after the component is shown.
15152 * @param {Roo.Component} this
15156 * @event beforehide
15157 * Fires before the component is hidden. Return false to stop the hide.
15158 * @param {Roo.Component} this
15163 * Fires after the component is hidden.
15164 * @param {Roo.Component} this
15168 * @event beforerender
15169 * Fires before the component is rendered. Return false to stop the render.
15170 * @param {Roo.Component} this
15172 beforerender : true,
15175 * Fires after the component is rendered.
15176 * @param {Roo.Component} this
15180 * @event beforedestroy
15181 * Fires before the component is destroyed. Return false to stop the destroy.
15182 * @param {Roo.Component} this
15184 beforedestroy : true,
15187 * Fires after the component is destroyed.
15188 * @param {Roo.Component} this
15193 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15195 Roo.ComponentMgr.register(this);
15196 Roo.Component.superclass.constructor.call(this);
15197 this.initComponent();
15198 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15199 this.render(this.renderTo);
15200 delete this.renderTo;
15205 Roo.Component.AUTO_ID = 1000;
15207 Roo.extend(Roo.Component, Roo.util.Observable, {
15209 * @scope Roo.Component.prototype
15211 * true if this component is hidden. Read-only.
15216 * true if this component is disabled. Read-only.
15221 * true if this component has been rendered. Read-only.
15225 /** @cfg {String} disableClass
15226 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15228 disabledClass : "x-item-disabled",
15229 /** @cfg {Boolean} allowDomMove
15230 * Whether the component can move the Dom node when rendering (defaults to true).
15232 allowDomMove : true,
15233 /** @cfg {String} hideMode (display|visibility)
15234 * How this component should hidden. Supported values are
15235 * "visibility" (css visibility), "offsets" (negative offset position) and
15236 * "display" (css display) - defaults to "display".
15238 hideMode: 'display',
15241 ctype : "Roo.Component",
15244 * @cfg {String} actionMode
15245 * which property holds the element that used for hide() / show() / disable() / enable()
15251 getActionEl : function(){
15252 return this[this.actionMode];
15255 initComponent : Roo.emptyFn,
15257 * If this is a lazy rendering component, render it to its container element.
15258 * @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.
15260 render : function(container, position){
15261 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15262 if(!container && this.el){
15263 this.el = Roo.get(this.el);
15264 container = this.el.dom.parentNode;
15265 this.allowDomMove = false;
15267 this.container = Roo.get(container);
15268 this.rendered = true;
15269 if(position !== undefined){
15270 if(typeof position == 'number'){
15271 position = this.container.dom.childNodes[position];
15273 position = Roo.getDom(position);
15276 this.onRender(this.container, position || null);
15278 this.el.addClass(this.cls);
15282 this.el.applyStyles(this.style);
15285 this.fireEvent("render", this);
15286 this.afterRender(this.container);
15298 // default function is not really useful
15299 onRender : function(ct, position){
15301 this.el = Roo.get(this.el);
15302 if(this.allowDomMove !== false){
15303 ct.dom.insertBefore(this.el.dom, position);
15309 getAutoCreate : function(){
15310 var cfg = typeof this.autoCreate == "object" ?
15311 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15312 if(this.id && !cfg.id){
15319 afterRender : Roo.emptyFn,
15322 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15323 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15325 destroy : function(){
15326 if(this.fireEvent("beforedestroy", this) !== false){
15327 this.purgeListeners();
15328 this.beforeDestroy();
15330 this.el.removeAllListeners();
15332 if(this.actionMode == "container"){
15333 this.container.remove();
15337 Roo.ComponentMgr.unregister(this);
15338 this.fireEvent("destroy", this);
15343 beforeDestroy : function(){
15348 onDestroy : function(){
15353 * Returns the underlying {@link Roo.Element}.
15354 * @return {Roo.Element} The element
15356 getEl : function(){
15361 * Returns the id of this component.
15364 getId : function(){
15369 * Try to focus this component.
15370 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15371 * @return {Roo.Component} this
15373 focus : function(selectText){
15376 if(selectText === true){
15377 this.el.dom.select();
15392 * Disable this component.
15393 * @return {Roo.Component} this
15395 disable : function(){
15399 this.disabled = true;
15400 this.fireEvent("disable", this);
15405 onDisable : function(){
15406 this.getActionEl().addClass(this.disabledClass);
15407 this.el.dom.disabled = true;
15411 * Enable this component.
15412 * @return {Roo.Component} this
15414 enable : function(){
15418 this.disabled = false;
15419 this.fireEvent("enable", this);
15424 onEnable : function(){
15425 this.getActionEl().removeClass(this.disabledClass);
15426 this.el.dom.disabled = false;
15430 * Convenience function for setting disabled/enabled by boolean.
15431 * @param {Boolean} disabled
15433 setDisabled : function(disabled){
15434 this[disabled ? "disable" : "enable"]();
15438 * Show this component.
15439 * @return {Roo.Component} this
15442 if(this.fireEvent("beforeshow", this) !== false){
15443 this.hidden = false;
15447 this.fireEvent("show", this);
15453 onShow : function(){
15454 var ae = this.getActionEl();
15455 if(this.hideMode == 'visibility'){
15456 ae.dom.style.visibility = "visible";
15457 }else if(this.hideMode == 'offsets'){
15458 ae.removeClass('x-hidden');
15460 ae.dom.style.display = "";
15465 * Hide this component.
15466 * @return {Roo.Component} this
15469 if(this.fireEvent("beforehide", this) !== false){
15470 this.hidden = true;
15474 this.fireEvent("hide", this);
15480 onHide : function(){
15481 var ae = this.getActionEl();
15482 if(this.hideMode == 'visibility'){
15483 ae.dom.style.visibility = "hidden";
15484 }else if(this.hideMode == 'offsets'){
15485 ae.addClass('x-hidden');
15487 ae.dom.style.display = "none";
15492 * Convenience function to hide or show this component by boolean.
15493 * @param {Boolean} visible True to show, false to hide
15494 * @return {Roo.Component} this
15496 setVisible: function(visible){
15506 * Returns true if this component is visible.
15508 isVisible : function(){
15509 return this.getActionEl().isVisible();
15512 cloneConfig : function(overrides){
15513 overrides = overrides || {};
15514 var id = overrides.id || Roo.id();
15515 var cfg = Roo.applyIf(overrides, this.initialConfig);
15516 cfg.id = id; // prevent dup id
15517 return new this.constructor(cfg);
15521 * Ext JS Library 1.1.1
15522 * Copyright(c) 2006-2007, Ext JS, LLC.
15524 * Originally Released Under LGPL - original licence link has changed is not relivant.
15527 * <script type="text/javascript">
15531 * @class Roo.BoxComponent
15532 * @extends Roo.Component
15533 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15534 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15535 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15536 * layout containers.
15538 * @param {Roo.Element/String/Object} config The configuration options.
15540 Roo.BoxComponent = function(config){
15541 Roo.Component.call(this, config);
15545 * Fires after the component is resized.
15546 * @param {Roo.Component} this
15547 * @param {Number} adjWidth The box-adjusted width that was set
15548 * @param {Number} adjHeight The box-adjusted height that was set
15549 * @param {Number} rawWidth The width that was originally specified
15550 * @param {Number} rawHeight The height that was originally specified
15555 * Fires after the component is moved.
15556 * @param {Roo.Component} this
15557 * @param {Number} x The new x position
15558 * @param {Number} y The new y position
15564 Roo.extend(Roo.BoxComponent, Roo.Component, {
15565 // private, set in afterRender to signify that the component has been rendered
15567 // private, used to defer height settings to subclasses
15568 deferHeight: false,
15569 /** @cfg {Number} width
15570 * width (optional) size of component
15572 /** @cfg {Number} height
15573 * height (optional) size of component
15577 * Sets the width and height of the component. This method fires the resize event. This method can accept
15578 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15579 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15580 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15581 * @return {Roo.BoxComponent} this
15583 setSize : function(w, h){
15584 // support for standard size objects
15585 if(typeof w == 'object'){
15590 if(!this.boxReady){
15596 // prevent recalcs when not needed
15597 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15600 this.lastSize = {width: w, height: h};
15602 var adj = this.adjustSize(w, h);
15603 var aw = adj.width, ah = adj.height;
15604 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15605 var rz = this.getResizeEl();
15606 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15607 rz.setSize(aw, ah);
15608 }else if(!this.deferHeight && ah !== undefined){
15610 }else if(aw !== undefined){
15613 this.onResize(aw, ah, w, h);
15614 this.fireEvent('resize', this, aw, ah, w, h);
15620 * Gets the current size of the component's underlying element.
15621 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15623 getSize : function(){
15624 return this.el.getSize();
15628 * Gets the current XY position of the component's underlying element.
15629 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15630 * @return {Array} The XY position of the element (e.g., [100, 200])
15632 getPosition : function(local){
15633 if(local === true){
15634 return [this.el.getLeft(true), this.el.getTop(true)];
15636 return this.xy || this.el.getXY();
15640 * Gets the current box measurements of the component's underlying element.
15641 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15642 * @returns {Object} box An object in the format {x, y, width, height}
15644 getBox : function(local){
15645 var s = this.el.getSize();
15647 s.x = this.el.getLeft(true);
15648 s.y = this.el.getTop(true);
15650 var xy = this.xy || this.el.getXY();
15658 * Sets the current box measurements of the component's underlying element.
15659 * @param {Object} box An object in the format {x, y, width, height}
15660 * @returns {Roo.BoxComponent} this
15662 updateBox : function(box){
15663 this.setSize(box.width, box.height);
15664 this.setPagePosition(box.x, box.y);
15669 getResizeEl : function(){
15670 return this.resizeEl || this.el;
15674 getPositionEl : function(){
15675 return this.positionEl || this.el;
15679 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15680 * This method fires the move event.
15681 * @param {Number} left The new left
15682 * @param {Number} top The new top
15683 * @returns {Roo.BoxComponent} this
15685 setPosition : function(x, y){
15688 if(!this.boxReady){
15691 var adj = this.adjustPosition(x, y);
15692 var ax = adj.x, ay = adj.y;
15694 var el = this.getPositionEl();
15695 if(ax !== undefined || ay !== undefined){
15696 if(ax !== undefined && ay !== undefined){
15697 el.setLeftTop(ax, ay);
15698 }else if(ax !== undefined){
15700 }else if(ay !== undefined){
15703 this.onPosition(ax, ay);
15704 this.fireEvent('move', this, ax, ay);
15710 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15711 * This method fires the move event.
15712 * @param {Number} x The new x position
15713 * @param {Number} y The new y position
15714 * @returns {Roo.BoxComponent} this
15716 setPagePosition : function(x, y){
15719 if(!this.boxReady){
15722 if(x === undefined || y === undefined){ // cannot translate undefined points
15725 var p = this.el.translatePoints(x, y);
15726 this.setPosition(p.left, p.top);
15731 onRender : function(ct, position){
15732 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15734 this.resizeEl = Roo.get(this.resizeEl);
15736 if(this.positionEl){
15737 this.positionEl = Roo.get(this.positionEl);
15742 afterRender : function(){
15743 Roo.BoxComponent.superclass.afterRender.call(this);
15744 this.boxReady = true;
15745 this.setSize(this.width, this.height);
15746 if(this.x || this.y){
15747 this.setPosition(this.x, this.y);
15749 if(this.pageX || this.pageY){
15750 this.setPagePosition(this.pageX, this.pageY);
15755 * Force the component's size to recalculate based on the underlying element's current height and width.
15756 * @returns {Roo.BoxComponent} this
15758 syncSize : function(){
15759 delete this.lastSize;
15760 this.setSize(this.el.getWidth(), this.el.getHeight());
15765 * Called after the component is resized, this method is empty by default but can be implemented by any
15766 * subclass that needs to perform custom logic after a resize occurs.
15767 * @param {Number} adjWidth The box-adjusted width that was set
15768 * @param {Number} adjHeight The box-adjusted height that was set
15769 * @param {Number} rawWidth The width that was originally specified
15770 * @param {Number} rawHeight The height that was originally specified
15772 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15777 * Called after the component is moved, this method is empty by default but can be implemented by any
15778 * subclass that needs to perform custom logic after a move occurs.
15779 * @param {Number} x The new x position
15780 * @param {Number} y The new y position
15782 onPosition : function(x, y){
15787 adjustSize : function(w, h){
15788 if(this.autoWidth){
15791 if(this.autoHeight){
15794 return {width : w, height: h};
15798 adjustPosition : function(x, y){
15799 return {x : x, y: y};
15802 * Original code for Roojs - LGPL
15803 * <script type="text/javascript">
15807 * @class Roo.XComponent
15808 * A delayed Element creator...
15809 * Or a way to group chunks of interface together.
15810 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15811 * used in conjunction with XComponent.build() it will create an instance of each element,
15812 * then call addxtype() to build the User interface.
15814 * Mypart.xyx = new Roo.XComponent({
15816 parent : 'Mypart.xyz', // empty == document.element.!!
15820 disabled : function() {}
15822 tree : function() { // return an tree of xtype declared components
15826 xtype : 'NestedLayoutPanel',
15833 * It can be used to build a big heiracy, with parent etc.
15834 * or you can just use this to render a single compoent to a dom element
15835 * MYPART.render(Roo.Element | String(id) | dom_element )
15842 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15843 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15845 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15847 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15848 * - if mulitple topModules exist, the last one is defined as the top module.
15852 * When the top level or multiple modules are to embedded into a existing HTML page,
15853 * the parent element can container '#id' of the element where the module will be drawn.
15857 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15858 * it relies more on a include mechanism, where sub modules are included into an outer page.
15859 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15861 * Bootstrap Roo Included elements
15863 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15864 * hence confusing the component builder as it thinks there are multiple top level elements.
15868 * @extends Roo.util.Observable
15870 * @param cfg {Object} configuration of component
15873 Roo.XComponent = function(cfg) {
15874 Roo.apply(this, cfg);
15878 * Fires when this the componnt is built
15879 * @param {Roo.XComponent} c the component
15884 this.region = this.region || 'center'; // default..
15885 Roo.XComponent.register(this);
15886 this.modules = false;
15887 this.el = false; // where the layout goes..
15891 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15894 * The created element (with Roo.factory())
15895 * @type {Roo.Layout}
15901 * for BC - use el in new code
15902 * @type {Roo.Layout}
15908 * for BC - use el in new code
15909 * @type {Roo.Layout}
15914 * @cfg {Function|boolean} disabled
15915 * If this module is disabled by some rule, return true from the funtion
15920 * @cfg {String} parent
15921 * Name of parent element which it get xtype added to..
15926 * @cfg {String} order
15927 * Used to set the order in which elements are created (usefull for multiple tabs)
15932 * @cfg {String} name
15933 * String to display while loading.
15937 * @cfg {String} region
15938 * Region to render component to (defaults to center)
15943 * @cfg {Array} items
15944 * A single item array - the first element is the root of the tree..
15945 * It's done this way to stay compatible with the Xtype system...
15951 * The method that retuns the tree of parts that make up this compoennt
15958 * render element to dom or tree
15959 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15962 render : function(el)
15966 var hp = this.parent ? 1 : 0;
15967 Roo.debug && Roo.log(this);
15969 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15970 // if parent is a '#.....' string, then let's use that..
15971 var ename = this.parent.substr(1);
15972 this.parent = false;
15973 Roo.debug && Roo.log(ename);
15975 case 'bootstrap-body' :
15976 if (typeof(Roo.bootstrap.Body) != 'undefined') {
15977 this.parent = { el : new Roo.bootstrap.Body() };
15978 Roo.debug && Roo.log("setting el to doc body");
15981 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15985 this.parent = { el : true};
15988 el = Roo.get(ename);
15993 if (!el && !this.parent) {
15994 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
15998 Roo.debug && Roo.log("EL:");
15999 Roo.debug && Roo.log(el);
16000 Roo.debug && Roo.log("this.parent.el:");
16001 Roo.debug && Roo.log(this.parent.el);
16003 var tree = this._tree ? this._tree() : this.tree();
16005 // altertive root elements ??? - we need a better way to indicate these.
16006 var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16007 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16009 if (!this.parent && is_alt) {
16010 //el = Roo.get(document.body);
16011 this.parent = { el : true };
16016 if (!this.parent) {
16018 Roo.debug && Roo.log("no parent - creating one");
16020 el = el ? Roo.get(el) : false;
16022 // it's a top level one..
16024 el : new Roo.BorderLayout(el || document.body, {
16030 tabPosition: 'top',
16031 //resizeTabs: true,
16032 alwaysShowTabs: el && hp? false : true,
16033 hideTabs: el || !hp ? true : false,
16040 if (!this.parent.el) {
16041 // probably an old style ctor, which has been disabled.
16045 // The 'tree' method is '_tree now'
16047 tree.region = tree.region || this.region;
16049 if (this.parent.el === true) {
16050 // bootstrap... - body..
16051 this.parent.el = Roo.factory(tree);
16054 this.el = this.parent.el.addxtype(tree);
16055 this.fireEvent('built', this);
16057 this.panel = this.el;
16058 this.layout = this.panel.layout;
16059 this.parentLayout = this.parent.layout || false;
16065 Roo.apply(Roo.XComponent, {
16067 * @property hideProgress
16068 * true to disable the building progress bar.. usefull on single page renders.
16071 hideProgress : false,
16073 * @property buildCompleted
16074 * True when the builder has completed building the interface.
16077 buildCompleted : false,
16080 * @property topModule
16081 * the upper most module - uses document.element as it's constructor.
16088 * @property modules
16089 * array of modules to be created by registration system.
16090 * @type {Array} of Roo.XComponent
16095 * @property elmodules
16096 * array of modules to be created by which use #ID
16097 * @type {Array} of Roo.XComponent
16103 * @property build_from_html
16104 * Build elements from html - used by bootstrap HTML stuff
16105 * - this is cleared after build is completed
16106 * @type {boolean} true (default false)
16109 build_from_html : false,
16112 * Register components to be built later.
16114 * This solves the following issues
16115 * - Building is not done on page load, but after an authentication process has occured.
16116 * - Interface elements are registered on page load
16117 * - Parent Interface elements may not be loaded before child, so this handles that..
16124 module : 'Pman.Tab.projectMgr',
16126 parent : 'Pman.layout',
16127 disabled : false, // or use a function..
16130 * * @param {Object} details about module
16132 register : function(obj) {
16134 Roo.XComponent.event.fireEvent('register', obj);
16135 switch(typeof(obj.disabled) ) {
16141 if ( obj.disabled() ) {
16147 if (obj.disabled) {
16153 this.modules.push(obj);
16157 * convert a string to an object..
16158 * eg. 'AAA.BBB' -> finds AAA.BBB
16162 toObject : function(str)
16164 if (!str || typeof(str) == 'object') {
16167 if (str.substring(0,1) == '#') {
16171 var ar = str.split('.');
16176 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16178 throw "Module not found : " + str;
16182 throw "Module not found : " + str;
16184 Roo.each(ar, function(e) {
16185 if (typeof(o[e]) == 'undefined') {
16186 throw "Module not found : " + str;
16197 * move modules into their correct place in the tree..
16200 preBuild : function ()
16203 Roo.each(this.modules , function (obj)
16205 Roo.XComponent.event.fireEvent('beforebuild', obj);
16207 var opar = obj.parent;
16209 obj.parent = this.toObject(opar);
16211 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16216 Roo.debug && Roo.log("GOT top level module");
16217 Roo.debug && Roo.log(obj);
16218 obj.modules = new Roo.util.MixedCollection(false,
16219 function(o) { return o.order + '' }
16221 this.topModule = obj;
16224 // parent is a string (usually a dom element name..)
16225 if (typeof(obj.parent) == 'string') {
16226 this.elmodules.push(obj);
16229 if (obj.parent.constructor != Roo.XComponent) {
16230 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16232 if (!obj.parent.modules) {
16233 obj.parent.modules = new Roo.util.MixedCollection(false,
16234 function(o) { return o.order + '' }
16237 if (obj.parent.disabled) {
16238 obj.disabled = true;
16240 obj.parent.modules.add(obj);
16245 * make a list of modules to build.
16246 * @return {Array} list of modules.
16249 buildOrder : function()
16252 var cmp = function(a,b) {
16253 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16255 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16256 throw "No top level modules to build";
16259 // make a flat list in order of modules to build.
16260 var mods = this.topModule ? [ this.topModule ] : [];
16263 // elmodules (is a list of DOM based modules )
16264 Roo.each(this.elmodules, function(e) {
16266 if (!this.topModule &&
16267 typeof(e.parent) == 'string' &&
16268 e.parent.substring(0,1) == '#' &&
16269 Roo.get(e.parent.substr(1))
16272 _this.topModule = e;
16278 // add modules to their parents..
16279 var addMod = function(m) {
16280 Roo.debug && Roo.log("build Order: add: " + m.name);
16283 if (m.modules && !m.disabled) {
16284 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16285 m.modules.keySort('ASC', cmp );
16286 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16288 m.modules.each(addMod);
16290 Roo.debug && Roo.log("build Order: no child modules");
16292 // not sure if this is used any more..
16294 m.finalize.name = m.name + " (clean up) ";
16295 mods.push(m.finalize);
16299 if (this.topModule && this.topModule.modules) {
16300 this.topModule.modules.keySort('ASC', cmp );
16301 this.topModule.modules.each(addMod);
16307 * Build the registered modules.
16308 * @param {Object} parent element.
16309 * @param {Function} optional method to call after module has been added.
16313 build : function(opts)
16316 if (typeof(opts) != 'undefined') {
16317 Roo.apply(this,opts);
16321 var mods = this.buildOrder();
16323 //this.allmods = mods;
16324 //Roo.debug && Roo.log(mods);
16326 if (!mods.length) { // should not happen
16327 throw "NO modules!!!";
16331 var msg = "Building Interface...";
16332 // flash it up as modal - so we store the mask!?
16333 if (!this.hideProgress && Roo.MessageBox) {
16334 Roo.MessageBox.show({ title: 'loading' });
16335 Roo.MessageBox.show({
16336 title: "Please wait...",
16345 var total = mods.length;
16348 var progressRun = function() {
16349 if (!mods.length) {
16350 Roo.debug && Roo.log('hide?');
16351 if (!this.hideProgress && Roo.MessageBox) {
16352 Roo.MessageBox.hide();
16354 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16356 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16362 var m = mods.shift();
16365 Roo.debug && Roo.log(m);
16366 // not sure if this is supported any more.. - modules that are are just function
16367 if (typeof(m) == 'function') {
16369 return progressRun.defer(10, _this);
16373 msg = "Building Interface " + (total - mods.length) +
16375 (m.name ? (' - ' + m.name) : '');
16376 Roo.debug && Roo.log(msg);
16377 if (!this.hideProgress && Roo.MessageBox) {
16378 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16382 // is the module disabled?
16383 var disabled = (typeof(m.disabled) == 'function') ?
16384 m.disabled.call(m.module.disabled) : m.disabled;
16388 return progressRun(); // we do not update the display!
16396 // it's 10 on top level, and 1 on others??? why...
16397 return progressRun.defer(10, _this);
16400 progressRun.defer(1, _this);
16414 * wrapper for event.on - aliased later..
16415 * Typically use to register a event handler for register:
16417 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16426 Roo.XComponent.event = new Roo.util.Observable({
16430 * Fires when an Component is registered,
16431 * set the disable property on the Component to stop registration.
16432 * @param {Roo.XComponent} c the component being registerd.
16437 * @event beforebuild
16438 * Fires before each Component is built
16439 * can be used to apply permissions.
16440 * @param {Roo.XComponent} c the component being registerd.
16443 'beforebuild' : true,
16445 * @event buildcomplete
16446 * Fires on the top level element when all elements have been built
16447 * @param {Roo.XComponent} the top level component.
16449 'buildcomplete' : true
16454 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16457 * Ext JS Library 1.1.1
16458 * Copyright(c) 2006-2007, Ext JS, LLC.
16460 * Originally Released Under LGPL - original licence link has changed is not relivant.
16463 * <script type="text/javascript">
16469 * These classes are derivatives of the similarly named classes in the YUI Library.
16470 * The original license:
16471 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16472 * Code licensed under the BSD License:
16473 * http://developer.yahoo.net/yui/license.txt
16478 var Event=Roo.EventManager;
16479 var Dom=Roo.lib.Dom;
16482 * @class Roo.dd.DragDrop
16483 * @extends Roo.util.Observable
16484 * Defines the interface and base operation of items that that can be
16485 * dragged or can be drop targets. It was designed to be extended, overriding
16486 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16487 * Up to three html elements can be associated with a DragDrop instance:
16489 * <li>linked element: the element that is passed into the constructor.
16490 * This is the element which defines the boundaries for interaction with
16491 * other DragDrop objects.</li>
16492 * <li>handle element(s): The drag operation only occurs if the element that
16493 * was clicked matches a handle element. By default this is the linked
16494 * element, but there are times that you will want only a portion of the
16495 * linked element to initiate the drag operation, and the setHandleElId()
16496 * method provides a way to define this.</li>
16497 * <li>drag element: this represents the element that would be moved along
16498 * with the cursor during a drag operation. By default, this is the linked
16499 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16500 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16503 * This class should not be instantiated until the onload event to ensure that
16504 * the associated elements are available.
16505 * The following would define a DragDrop obj that would interact with any
16506 * other DragDrop obj in the "group1" group:
16508 * dd = new Roo.dd.DragDrop("div1", "group1");
16510 * Since none of the event handlers have been implemented, nothing would
16511 * actually happen if you were to run the code above. Normally you would
16512 * override this class or one of the default implementations, but you can
16513 * also override the methods you want on an instance of the class...
16515 * dd.onDragDrop = function(e, id) {
16516 * alert("dd was dropped on " + id);
16520 * @param {String} id of the element that is linked to this instance
16521 * @param {String} sGroup the group of related DragDrop objects
16522 * @param {object} config an object containing configurable attributes
16523 * Valid properties for DragDrop:
16524 * padding, isTarget, maintainOffset, primaryButtonOnly
16526 Roo.dd.DragDrop = function(id, sGroup, config) {
16528 this.init(id, sGroup, config);
16533 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16536 * The id of the element associated with this object. This is what we
16537 * refer to as the "linked element" because the size and position of
16538 * this element is used to determine when the drag and drop objects have
16546 * Configuration attributes passed into the constructor
16553 * The id of the element that will be dragged. By default this is same
16554 * as the linked element , but could be changed to another element. Ex:
16556 * @property dragElId
16563 * the id of the element that initiates the drag operation. By default
16564 * this is the linked element, but could be changed to be a child of this
16565 * element. This lets us do things like only starting the drag when the
16566 * header element within the linked html element is clicked.
16567 * @property handleElId
16574 * An associative array of HTML tags that will be ignored if clicked.
16575 * @property invalidHandleTypes
16576 * @type {string: string}
16578 invalidHandleTypes: null,
16581 * An associative array of ids for elements that will be ignored if clicked
16582 * @property invalidHandleIds
16583 * @type {string: string}
16585 invalidHandleIds: null,
16588 * An indexted array of css class names for elements that will be ignored
16590 * @property invalidHandleClasses
16593 invalidHandleClasses: null,
16596 * The linked element's absolute X position at the time the drag was
16598 * @property startPageX
16605 * The linked element's absolute X position at the time the drag was
16607 * @property startPageY
16614 * The group defines a logical collection of DragDrop objects that are
16615 * related. Instances only get events when interacting with other
16616 * DragDrop object in the same group. This lets us define multiple
16617 * groups using a single DragDrop subclass if we want.
16619 * @type {string: string}
16624 * Individual drag/drop instances can be locked. This will prevent
16625 * onmousedown start drag.
16633 * Lock this instance
16636 lock: function() { this.locked = true; },
16639 * Unlock this instace
16642 unlock: function() { this.locked = false; },
16645 * By default, all insances can be a drop target. This can be disabled by
16646 * setting isTarget to false.
16653 * The padding configured for this drag and drop object for calculating
16654 * the drop zone intersection with this object.
16661 * Cached reference to the linked element
16662 * @property _domRef
16668 * Internal typeof flag
16669 * @property __ygDragDrop
16672 __ygDragDrop: true,
16675 * Set to true when horizontal contraints are applied
16676 * @property constrainX
16683 * Set to true when vertical contraints are applied
16684 * @property constrainY
16691 * The left constraint
16699 * The right constraint
16707 * The up constraint
16716 * The down constraint
16724 * Maintain offsets when we resetconstraints. Set to true when you want
16725 * the position of the element relative to its parent to stay the same
16726 * when the page changes
16728 * @property maintainOffset
16731 maintainOffset: false,
16734 * Array of pixel locations the element will snap to if we specified a
16735 * horizontal graduation/interval. This array is generated automatically
16736 * when you define a tick interval.
16743 * Array of pixel locations the element will snap to if we specified a
16744 * vertical graduation/interval. This array is generated automatically
16745 * when you define a tick interval.
16752 * By default the drag and drop instance will only respond to the primary
16753 * button click (left button for a right-handed mouse). Set to true to
16754 * allow drag and drop to start with any mouse click that is propogated
16756 * @property primaryButtonOnly
16759 primaryButtonOnly: true,
16762 * The availabe property is false until the linked dom element is accessible.
16763 * @property available
16769 * By default, drags can only be initiated if the mousedown occurs in the
16770 * region the linked element is. This is done in part to work around a
16771 * bug in some browsers that mis-report the mousedown if the previous
16772 * mouseup happened outside of the window. This property is set to true
16773 * if outer handles are defined.
16775 * @property hasOuterHandles
16779 hasOuterHandles: false,
16782 * Code that executes immediately before the startDrag event
16783 * @method b4StartDrag
16786 b4StartDrag: function(x, y) { },
16789 * Abstract method called after a drag/drop object is clicked
16790 * and the drag or mousedown time thresholds have beeen met.
16791 * @method startDrag
16792 * @param {int} X click location
16793 * @param {int} Y click location
16795 startDrag: function(x, y) { /* override this */ },
16798 * Code that executes immediately before the onDrag event
16802 b4Drag: function(e) { },
16805 * Abstract method called during the onMouseMove event while dragging an
16808 * @param {Event} e the mousemove event
16810 onDrag: function(e) { /* override this */ },
16813 * Abstract method called when this element fist begins hovering over
16814 * another DragDrop obj
16815 * @method onDragEnter
16816 * @param {Event} e the mousemove event
16817 * @param {String|DragDrop[]} id In POINT mode, the element
16818 * id this is hovering over. In INTERSECT mode, an array of one or more
16819 * dragdrop items being hovered over.
16821 onDragEnter: function(e, id) { /* override this */ },
16824 * Code that executes immediately before the onDragOver event
16825 * @method b4DragOver
16828 b4DragOver: function(e) { },
16831 * Abstract method called when this element is hovering over another
16833 * @method onDragOver
16834 * @param {Event} e the mousemove event
16835 * @param {String|DragDrop[]} id In POINT mode, the element
16836 * id this is hovering over. In INTERSECT mode, an array of dd items
16837 * being hovered over.
16839 onDragOver: function(e, id) { /* override this */ },
16842 * Code that executes immediately before the onDragOut event
16843 * @method b4DragOut
16846 b4DragOut: function(e) { },
16849 * Abstract method called when we are no longer hovering over an element
16850 * @method onDragOut
16851 * @param {Event} e the mousemove event
16852 * @param {String|DragDrop[]} id In POINT mode, the element
16853 * id this was hovering over. In INTERSECT mode, an array of dd items
16854 * that the mouse is no longer over.
16856 onDragOut: function(e, id) { /* override this */ },
16859 * Code that executes immediately before the onDragDrop event
16860 * @method b4DragDrop
16863 b4DragDrop: function(e) { },
16866 * Abstract method called when this item is dropped on another DragDrop
16868 * @method onDragDrop
16869 * @param {Event} e the mouseup event
16870 * @param {String|DragDrop[]} id In POINT mode, the element
16871 * id this was dropped on. In INTERSECT mode, an array of dd items this
16874 onDragDrop: function(e, id) { /* override this */ },
16877 * Abstract method called when this item is dropped on an area with no
16879 * @method onInvalidDrop
16880 * @param {Event} e the mouseup event
16882 onInvalidDrop: function(e) { /* override this */ },
16885 * Code that executes immediately before the endDrag event
16886 * @method b4EndDrag
16889 b4EndDrag: function(e) { },
16892 * Fired when we are done dragging the object
16894 * @param {Event} e the mouseup event
16896 endDrag: function(e) { /* override this */ },
16899 * Code executed immediately before the onMouseDown event
16900 * @method b4MouseDown
16901 * @param {Event} e the mousedown event
16904 b4MouseDown: function(e) { },
16907 * Event handler that fires when a drag/drop obj gets a mousedown
16908 * @method onMouseDown
16909 * @param {Event} e the mousedown event
16911 onMouseDown: function(e) { /* override this */ },
16914 * Event handler that fires when a drag/drop obj gets a mouseup
16915 * @method onMouseUp
16916 * @param {Event} e the mouseup event
16918 onMouseUp: function(e) { /* override this */ },
16921 * Override the onAvailable method to do what is needed after the initial
16922 * position was determined.
16923 * @method onAvailable
16925 onAvailable: function () {
16929 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16932 defaultPadding : {left:0, right:0, top:0, bottom:0},
16935 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16939 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16940 { dragElId: "existingProxyDiv" });
16941 dd.startDrag = function(){
16942 this.constrainTo("parent-id");
16945 * Or you can initalize it using the {@link Roo.Element} object:
16947 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16948 startDrag : function(){
16949 this.constrainTo("parent-id");
16953 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16954 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16955 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16956 * an object containing the sides to pad. For example: {right:10, bottom:10}
16957 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16959 constrainTo : function(constrainTo, pad, inContent){
16960 if(typeof pad == "number"){
16961 pad = {left: pad, right:pad, top:pad, bottom:pad};
16963 pad = pad || this.defaultPadding;
16964 var b = Roo.get(this.getEl()).getBox();
16965 var ce = Roo.get(constrainTo);
16966 var s = ce.getScroll();
16967 var c, cd = ce.dom;
16968 if(cd == document.body){
16969 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16972 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16976 var topSpace = b.y - c.y;
16977 var leftSpace = b.x - c.x;
16979 this.resetConstraints();
16980 this.setXConstraint(leftSpace - (pad.left||0), // left
16981 c.width - leftSpace - b.width - (pad.right||0) //right
16983 this.setYConstraint(topSpace - (pad.top||0), //top
16984 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16989 * Returns a reference to the linked element
16991 * @return {HTMLElement} the html element
16993 getEl: function() {
16994 if (!this._domRef) {
16995 this._domRef = Roo.getDom(this.id);
16998 return this._domRef;
17002 * Returns a reference to the actual element to drag. By default this is
17003 * the same as the html element, but it can be assigned to another
17004 * element. An example of this can be found in Roo.dd.DDProxy
17005 * @method getDragEl
17006 * @return {HTMLElement} the html element
17008 getDragEl: function() {
17009 return Roo.getDom(this.dragElId);
17013 * Sets up the DragDrop object. Must be called in the constructor of any
17014 * Roo.dd.DragDrop subclass
17016 * @param id the id of the linked element
17017 * @param {String} sGroup the group of related items
17018 * @param {object} config configuration attributes
17020 init: function(id, sGroup, config) {
17021 this.initTarget(id, sGroup, config);
17022 if (!Roo.isTouch) {
17023 Event.on(this.id, "mousedown", this.handleMouseDown, this);
17025 Event.on(this.id, "touchstart", this.handleMouseDown, this);
17026 // Event.on(this.id, "selectstart", Event.preventDefault);
17030 * Initializes Targeting functionality only... the object does not
17031 * get a mousedown handler.
17032 * @method initTarget
17033 * @param id the id of the linked element
17034 * @param {String} sGroup the group of related items
17035 * @param {object} config configuration attributes
17037 initTarget: function(id, sGroup, config) {
17039 // configuration attributes
17040 this.config = config || {};
17042 // create a local reference to the drag and drop manager
17043 this.DDM = Roo.dd.DDM;
17044 // initialize the groups array
17047 // assume that we have an element reference instead of an id if the
17048 // parameter is not a string
17049 if (typeof id !== "string") {
17056 // add to an interaction group
17057 this.addToGroup((sGroup) ? sGroup : "default");
17059 // We don't want to register this as the handle with the manager
17060 // so we just set the id rather than calling the setter.
17061 this.handleElId = id;
17063 // the linked element is the element that gets dragged by default
17064 this.setDragElId(id);
17066 // by default, clicked anchors will not start drag operations.
17067 this.invalidHandleTypes = { A: "A" };
17068 this.invalidHandleIds = {};
17069 this.invalidHandleClasses = [];
17071 this.applyConfig();
17073 this.handleOnAvailable();
17077 * Applies the configuration parameters that were passed into the constructor.
17078 * This is supposed to happen at each level through the inheritance chain. So
17079 * a DDProxy implentation will execute apply config on DDProxy, DD, and
17080 * DragDrop in order to get all of the parameters that are available in
17082 * @method applyConfig
17084 applyConfig: function() {
17086 // configurable properties:
17087 // padding, isTarget, maintainOffset, primaryButtonOnly
17088 this.padding = this.config.padding || [0, 0, 0, 0];
17089 this.isTarget = (this.config.isTarget !== false);
17090 this.maintainOffset = (this.config.maintainOffset);
17091 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
17096 * Executed when the linked element is available
17097 * @method handleOnAvailable
17100 handleOnAvailable: function() {
17101 this.available = true;
17102 this.resetConstraints();
17103 this.onAvailable();
17107 * Configures the padding for the target zone in px. Effectively expands
17108 * (or reduces) the virtual object size for targeting calculations.
17109 * Supports css-style shorthand; if only one parameter is passed, all sides
17110 * will have that padding, and if only two are passed, the top and bottom
17111 * will have the first param, the left and right the second.
17112 * @method setPadding
17113 * @param {int} iTop Top pad
17114 * @param {int} iRight Right pad
17115 * @param {int} iBot Bot pad
17116 * @param {int} iLeft Left pad
17118 setPadding: function(iTop, iRight, iBot, iLeft) {
17119 // this.padding = [iLeft, iRight, iTop, iBot];
17120 if (!iRight && 0 !== iRight) {
17121 this.padding = [iTop, iTop, iTop, iTop];
17122 } else if (!iBot && 0 !== iBot) {
17123 this.padding = [iTop, iRight, iTop, iRight];
17125 this.padding = [iTop, iRight, iBot, iLeft];
17130 * Stores the initial placement of the linked element.
17131 * @method setInitialPosition
17132 * @param {int} diffX the X offset, default 0
17133 * @param {int} diffY the Y offset, default 0
17135 setInitPosition: function(diffX, diffY) {
17136 var el = this.getEl();
17138 if (!this.DDM.verifyEl(el)) {
17142 var dx = diffX || 0;
17143 var dy = diffY || 0;
17145 var p = Dom.getXY( el );
17147 this.initPageX = p[0] - dx;
17148 this.initPageY = p[1] - dy;
17150 this.lastPageX = p[0];
17151 this.lastPageY = p[1];
17154 this.setStartPosition(p);
17158 * Sets the start position of the element. This is set when the obj
17159 * is initialized, the reset when a drag is started.
17160 * @method setStartPosition
17161 * @param pos current position (from previous lookup)
17164 setStartPosition: function(pos) {
17165 var p = pos || Dom.getXY( this.getEl() );
17166 this.deltaSetXY = null;
17168 this.startPageX = p[0];
17169 this.startPageY = p[1];
17173 * Add this instance to a group of related drag/drop objects. All
17174 * instances belong to at least one group, and can belong to as many
17175 * groups as needed.
17176 * @method addToGroup
17177 * @param sGroup {string} the name of the group
17179 addToGroup: function(sGroup) {
17180 this.groups[sGroup] = true;
17181 this.DDM.regDragDrop(this, sGroup);
17185 * Remove's this instance from the supplied interaction group
17186 * @method removeFromGroup
17187 * @param {string} sGroup The group to drop
17189 removeFromGroup: function(sGroup) {
17190 if (this.groups[sGroup]) {
17191 delete this.groups[sGroup];
17194 this.DDM.removeDDFromGroup(this, sGroup);
17198 * Allows you to specify that an element other than the linked element
17199 * will be moved with the cursor during a drag
17200 * @method setDragElId
17201 * @param id {string} the id of the element that will be used to initiate the drag
17203 setDragElId: function(id) {
17204 this.dragElId = id;
17208 * Allows you to specify a child of the linked element that should be
17209 * used to initiate the drag operation. An example of this would be if
17210 * you have a content div with text and links. Clicking anywhere in the
17211 * content area would normally start the drag operation. Use this method
17212 * to specify that an element inside of the content div is the element
17213 * that starts the drag operation.
17214 * @method setHandleElId
17215 * @param id {string} the id of the element that will be used to
17216 * initiate the drag.
17218 setHandleElId: function(id) {
17219 if (typeof id !== "string") {
17222 this.handleElId = id;
17223 this.DDM.regHandle(this.id, id);
17227 * Allows you to set an element outside of the linked element as a drag
17229 * @method setOuterHandleElId
17230 * @param id the id of the element that will be used to initiate the drag
17232 setOuterHandleElId: function(id) {
17233 if (typeof id !== "string") {
17236 Event.on(id, "mousedown",
17237 this.handleMouseDown, this);
17238 this.setHandleElId(id);
17240 this.hasOuterHandles = true;
17244 * Remove all drag and drop hooks for this element
17247 unreg: function() {
17248 Event.un(this.id, "mousedown",
17249 this.handleMouseDown);
17250 Event.un(this.id, "touchstart",
17251 this.handleMouseDown);
17252 this._domRef = null;
17253 this.DDM._remove(this);
17256 destroy : function(){
17261 * Returns true if this instance is locked, or the drag drop mgr is locked
17262 * (meaning that all drag/drop is disabled on the page.)
17264 * @return {boolean} true if this obj or all drag/drop is locked, else
17267 isLocked: function() {
17268 return (this.DDM.isLocked() || this.locked);
17272 * Fired when this object is clicked
17273 * @method handleMouseDown
17275 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17278 handleMouseDown: function(e, oDD){
17280 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17281 //Roo.log('not touch/ button !=0');
17284 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17285 return; // double touch..
17289 if (this.isLocked()) {
17290 //Roo.log('locked');
17294 this.DDM.refreshCache(this.groups);
17295 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17296 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17297 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17298 //Roo.log('no outer handes or not over target');
17301 // Roo.log('check validator');
17302 if (this.clickValidator(e)) {
17303 // Roo.log('validate success');
17304 // set the initial element position
17305 this.setStartPosition();
17308 this.b4MouseDown(e);
17309 this.onMouseDown(e);
17311 this.DDM.handleMouseDown(e, this);
17313 this.DDM.stopEvent(e);
17321 clickValidator: function(e) {
17322 var target = e.getTarget();
17323 return ( this.isValidHandleChild(target) &&
17324 (this.id == this.handleElId ||
17325 this.DDM.handleWasClicked(target, this.id)) );
17329 * Allows you to specify a tag name that should not start a drag operation
17330 * when clicked. This is designed to facilitate embedding links within a
17331 * drag handle that do something other than start the drag.
17332 * @method addInvalidHandleType
17333 * @param {string} tagName the type of element to exclude
17335 addInvalidHandleType: function(tagName) {
17336 var type = tagName.toUpperCase();
17337 this.invalidHandleTypes[type] = type;
17341 * Lets you to specify an element id for a child of a drag handle
17342 * that should not initiate a drag
17343 * @method addInvalidHandleId
17344 * @param {string} id the element id of the element you wish to ignore
17346 addInvalidHandleId: function(id) {
17347 if (typeof id !== "string") {
17350 this.invalidHandleIds[id] = id;
17354 * Lets you specify a css class of elements that will not initiate a drag
17355 * @method addInvalidHandleClass
17356 * @param {string} cssClass the class of the elements you wish to ignore
17358 addInvalidHandleClass: function(cssClass) {
17359 this.invalidHandleClasses.push(cssClass);
17363 * Unsets an excluded tag name set by addInvalidHandleType
17364 * @method removeInvalidHandleType
17365 * @param {string} tagName the type of element to unexclude
17367 removeInvalidHandleType: function(tagName) {
17368 var type = tagName.toUpperCase();
17369 // this.invalidHandleTypes[type] = null;
17370 delete this.invalidHandleTypes[type];
17374 * Unsets an invalid handle id
17375 * @method removeInvalidHandleId
17376 * @param {string} id the id of the element to re-enable
17378 removeInvalidHandleId: function(id) {
17379 if (typeof id !== "string") {
17382 delete this.invalidHandleIds[id];
17386 * Unsets an invalid css class
17387 * @method removeInvalidHandleClass
17388 * @param {string} cssClass the class of the element(s) you wish to
17391 removeInvalidHandleClass: function(cssClass) {
17392 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17393 if (this.invalidHandleClasses[i] == cssClass) {
17394 delete this.invalidHandleClasses[i];
17400 * Checks the tag exclusion list to see if this click should be ignored
17401 * @method isValidHandleChild
17402 * @param {HTMLElement} node the HTMLElement to evaluate
17403 * @return {boolean} true if this is a valid tag type, false if not
17405 isValidHandleChild: function(node) {
17408 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17411 nodeName = node.nodeName.toUpperCase();
17413 nodeName = node.nodeName;
17415 valid = valid && !this.invalidHandleTypes[nodeName];
17416 valid = valid && !this.invalidHandleIds[node.id];
17418 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17419 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17428 * Create the array of horizontal tick marks if an interval was specified
17429 * in setXConstraint().
17430 * @method setXTicks
17433 setXTicks: function(iStartX, iTickSize) {
17435 this.xTickSize = iTickSize;
17439 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17441 this.xTicks[this.xTicks.length] = i;
17446 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17448 this.xTicks[this.xTicks.length] = i;
17453 this.xTicks.sort(this.DDM.numericSort) ;
17457 * Create the array of vertical tick marks if an interval was specified in
17458 * setYConstraint().
17459 * @method setYTicks
17462 setYTicks: function(iStartY, iTickSize) {
17464 this.yTickSize = iTickSize;
17468 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17470 this.yTicks[this.yTicks.length] = i;
17475 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17477 this.yTicks[this.yTicks.length] = i;
17482 this.yTicks.sort(this.DDM.numericSort) ;
17486 * By default, the element can be dragged any place on the screen. Use
17487 * this method to limit the horizontal travel of the element. Pass in
17488 * 0,0 for the parameters if you want to lock the drag to the y axis.
17489 * @method setXConstraint
17490 * @param {int} iLeft the number of pixels the element can move to the left
17491 * @param {int} iRight the number of pixels the element can move to the
17493 * @param {int} iTickSize optional parameter for specifying that the
17495 * should move iTickSize pixels at a time.
17497 setXConstraint: function(iLeft, iRight, iTickSize) {
17498 this.leftConstraint = iLeft;
17499 this.rightConstraint = iRight;
17501 this.minX = this.initPageX - iLeft;
17502 this.maxX = this.initPageX + iRight;
17503 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17505 this.constrainX = true;
17509 * Clears any constraints applied to this instance. Also clears ticks
17510 * since they can't exist independent of a constraint at this time.
17511 * @method clearConstraints
17513 clearConstraints: function() {
17514 this.constrainX = false;
17515 this.constrainY = false;
17520 * Clears any tick interval defined for this instance
17521 * @method clearTicks
17523 clearTicks: function() {
17524 this.xTicks = null;
17525 this.yTicks = null;
17526 this.xTickSize = 0;
17527 this.yTickSize = 0;
17531 * By default, the element can be dragged any place on the screen. Set
17532 * this to limit the vertical travel of the element. Pass in 0,0 for the
17533 * parameters if you want to lock the drag to the x axis.
17534 * @method setYConstraint
17535 * @param {int} iUp the number of pixels the element can move up
17536 * @param {int} iDown the number of pixels the element can move down
17537 * @param {int} iTickSize optional parameter for specifying that the
17538 * element should move iTickSize pixels at a time.
17540 setYConstraint: function(iUp, iDown, iTickSize) {
17541 this.topConstraint = iUp;
17542 this.bottomConstraint = iDown;
17544 this.minY = this.initPageY - iUp;
17545 this.maxY = this.initPageY + iDown;
17546 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17548 this.constrainY = true;
17553 * resetConstraints must be called if you manually reposition a dd element.
17554 * @method resetConstraints
17555 * @param {boolean} maintainOffset
17557 resetConstraints: function() {
17560 // Maintain offsets if necessary
17561 if (this.initPageX || this.initPageX === 0) {
17562 // figure out how much this thing has moved
17563 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17564 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17566 this.setInitPosition(dx, dy);
17568 // This is the first time we have detected the element's position
17570 this.setInitPosition();
17573 if (this.constrainX) {
17574 this.setXConstraint( this.leftConstraint,
17575 this.rightConstraint,
17579 if (this.constrainY) {
17580 this.setYConstraint( this.topConstraint,
17581 this.bottomConstraint,
17587 * Normally the drag element is moved pixel by pixel, but we can specify
17588 * that it move a number of pixels at a time. This method resolves the
17589 * location when we have it set up like this.
17591 * @param {int} val where we want to place the object
17592 * @param {int[]} tickArray sorted array of valid points
17593 * @return {int} the closest tick
17596 getTick: function(val, tickArray) {
17599 // If tick interval is not defined, it is effectively 1 pixel,
17600 // so we return the value passed to us.
17602 } else if (tickArray[0] >= val) {
17603 // The value is lower than the first tick, so we return the first
17605 return tickArray[0];
17607 for (var i=0, len=tickArray.length; i<len; ++i) {
17609 if (tickArray[next] && tickArray[next] >= val) {
17610 var diff1 = val - tickArray[i];
17611 var diff2 = tickArray[next] - val;
17612 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17616 // The value is larger than the last tick, so we return the last
17618 return tickArray[tickArray.length - 1];
17625 * @return {string} string representation of the dd obj
17627 toString: function() {
17628 return ("DragDrop " + this.id);
17636 * Ext JS Library 1.1.1
17637 * Copyright(c) 2006-2007, Ext JS, LLC.
17639 * Originally Released Under LGPL - original licence link has changed is not relivant.
17642 * <script type="text/javascript">
17647 * The drag and drop utility provides a framework for building drag and drop
17648 * applications. In addition to enabling drag and drop for specific elements,
17649 * the drag and drop elements are tracked by the manager class, and the
17650 * interactions between the various elements are tracked during the drag and
17651 * the implementing code is notified about these important moments.
17654 // Only load the library once. Rewriting the manager class would orphan
17655 // existing drag and drop instances.
17656 if (!Roo.dd.DragDropMgr) {
17659 * @class Roo.dd.DragDropMgr
17660 * DragDropMgr is a singleton that tracks the element interaction for
17661 * all DragDrop items in the window. Generally, you will not call
17662 * this class directly, but it does have helper methods that could
17663 * be useful in your DragDrop implementations.
17666 Roo.dd.DragDropMgr = function() {
17668 var Event = Roo.EventManager;
17673 * Two dimensional Array of registered DragDrop objects. The first
17674 * dimension is the DragDrop item group, the second the DragDrop
17677 * @type {string: string}
17684 * Array of element ids defined as drag handles. Used to determine
17685 * if the element that generated the mousedown event is actually the
17686 * handle and not the html element itself.
17687 * @property handleIds
17688 * @type {string: string}
17695 * the DragDrop object that is currently being dragged
17696 * @property dragCurrent
17704 * the DragDrop object(s) that are being hovered over
17705 * @property dragOvers
17713 * the X distance between the cursor and the object being dragged
17722 * the Y distance between the cursor and the object being dragged
17731 * Flag to determine if we should prevent the default behavior of the
17732 * events we define. By default this is true, but this can be set to
17733 * false if you need the default behavior (not recommended)
17734 * @property preventDefault
17738 preventDefault: true,
17741 * Flag to determine if we should stop the propagation of the events
17742 * we generate. This is true by default but you may want to set it to
17743 * false if the html element contains other features that require the
17745 * @property stopPropagation
17749 stopPropagation: true,
17752 * Internal flag that is set to true when drag and drop has been
17754 * @property initialized
17761 * All drag and drop can be disabled.
17769 * Called the first time an element is registered.
17775 this.initialized = true;
17779 * In point mode, drag and drop interaction is defined by the
17780 * location of the cursor during the drag/drop
17788 * In intersect mode, drag and drop interactio nis defined by the
17789 * overlap of two or more drag and drop objects.
17790 * @property INTERSECT
17797 * The current drag and drop mode. Default: POINT
17805 * Runs method on all drag and drop objects
17806 * @method _execOnAll
17810 _execOnAll: function(sMethod, args) {
17811 for (var i in this.ids) {
17812 for (var j in this.ids[i]) {
17813 var oDD = this.ids[i][j];
17814 if (! this.isTypeOfDD(oDD)) {
17817 oDD[sMethod].apply(oDD, args);
17823 * Drag and drop initialization. Sets up the global event handlers
17828 _onLoad: function() {
17832 if (!Roo.isTouch) {
17833 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17834 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17836 Event.on(document, "touchend", this.handleMouseUp, this, true);
17837 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17839 Event.on(window, "unload", this._onUnload, this, true);
17840 Event.on(window, "resize", this._onResize, this, true);
17841 // Event.on(window, "mouseout", this._test);
17846 * Reset constraints on all drag and drop objs
17847 * @method _onResize
17851 _onResize: function(e) {
17852 this._execOnAll("resetConstraints", []);
17856 * Lock all drag and drop functionality
17860 lock: function() { this.locked = true; },
17863 * Unlock all drag and drop functionality
17867 unlock: function() { this.locked = false; },
17870 * Is drag and drop locked?
17872 * @return {boolean} True if drag and drop is locked, false otherwise.
17875 isLocked: function() { return this.locked; },
17878 * Location cache that is set for all drag drop objects when a drag is
17879 * initiated, cleared when the drag is finished.
17880 * @property locationCache
17887 * Set useCache to false if you want to force object the lookup of each
17888 * drag and drop linked element constantly during a drag.
17889 * @property useCache
17896 * The number of pixels that the mouse needs to move after the
17897 * mousedown before the drag is initiated. Default=3;
17898 * @property clickPixelThresh
17902 clickPixelThresh: 3,
17905 * The number of milliseconds after the mousedown event to initiate the
17906 * drag if we don't get a mouseup event. Default=1000
17907 * @property clickTimeThresh
17911 clickTimeThresh: 350,
17914 * Flag that indicates that either the drag pixel threshold or the
17915 * mousdown time threshold has been met
17916 * @property dragThreshMet
17921 dragThreshMet: false,
17924 * Timeout used for the click time threshold
17925 * @property clickTimeout
17930 clickTimeout: null,
17933 * The X position of the mousedown event stored for later use when a
17934 * drag threshold is met.
17943 * The Y position of the mousedown event stored for later use when a
17944 * drag threshold is met.
17953 * Each DragDrop instance must be registered with the DragDropMgr.
17954 * This is executed in DragDrop.init()
17955 * @method regDragDrop
17956 * @param {DragDrop} oDD the DragDrop object to register
17957 * @param {String} sGroup the name of the group this element belongs to
17960 regDragDrop: function(oDD, sGroup) {
17961 if (!this.initialized) { this.init(); }
17963 if (!this.ids[sGroup]) {
17964 this.ids[sGroup] = {};
17966 this.ids[sGroup][oDD.id] = oDD;
17970 * Removes the supplied dd instance from the supplied group. Executed
17971 * by DragDrop.removeFromGroup, so don't call this function directly.
17972 * @method removeDDFromGroup
17976 removeDDFromGroup: function(oDD, sGroup) {
17977 if (!this.ids[sGroup]) {
17978 this.ids[sGroup] = {};
17981 var obj = this.ids[sGroup];
17982 if (obj && obj[oDD.id]) {
17983 delete obj[oDD.id];
17988 * Unregisters a drag and drop item. This is executed in
17989 * DragDrop.unreg, use that method instead of calling this directly.
17994 _remove: function(oDD) {
17995 for (var g in oDD.groups) {
17996 if (g && this.ids[g][oDD.id]) {
17997 delete this.ids[g][oDD.id];
18000 delete this.handleIds[oDD.id];
18004 * Each DragDrop handle element must be registered. This is done
18005 * automatically when executing DragDrop.setHandleElId()
18006 * @method regHandle
18007 * @param {String} sDDId the DragDrop id this element is a handle for
18008 * @param {String} sHandleId the id of the element that is the drag
18012 regHandle: function(sDDId, sHandleId) {
18013 if (!this.handleIds[sDDId]) {
18014 this.handleIds[sDDId] = {};
18016 this.handleIds[sDDId][sHandleId] = sHandleId;
18020 * Utility function to determine if a given element has been
18021 * registered as a drag drop item.
18022 * @method isDragDrop
18023 * @param {String} id the element id to check
18024 * @return {boolean} true if this element is a DragDrop item,
18028 isDragDrop: function(id) {
18029 return ( this.getDDById(id) ) ? true : false;
18033 * Returns the drag and drop instances that are in all groups the
18034 * passed in instance belongs to.
18035 * @method getRelated
18036 * @param {DragDrop} p_oDD the obj to get related data for
18037 * @param {boolean} bTargetsOnly if true, only return targetable objs
18038 * @return {DragDrop[]} the related instances
18041 getRelated: function(p_oDD, bTargetsOnly) {
18043 for (var i in p_oDD.groups) {
18044 for (j in this.ids[i]) {
18045 var dd = this.ids[i][j];
18046 if (! this.isTypeOfDD(dd)) {
18049 if (!bTargetsOnly || dd.isTarget) {
18050 oDDs[oDDs.length] = dd;
18059 * Returns true if the specified dd target is a legal target for
18060 * the specifice drag obj
18061 * @method isLegalTarget
18062 * @param {DragDrop} the drag obj
18063 * @param {DragDrop} the target
18064 * @return {boolean} true if the target is a legal target for the
18068 isLegalTarget: function (oDD, oTargetDD) {
18069 var targets = this.getRelated(oDD, true);
18070 for (var i=0, len=targets.length;i<len;++i) {
18071 if (targets[i].id == oTargetDD.id) {
18080 * My goal is to be able to transparently determine if an object is
18081 * typeof DragDrop, and the exact subclass of DragDrop. typeof
18082 * returns "object", oDD.constructor.toString() always returns
18083 * "DragDrop" and not the name of the subclass. So for now it just
18084 * evaluates a well-known variable in DragDrop.
18085 * @method isTypeOfDD
18086 * @param {Object} the object to evaluate
18087 * @return {boolean} true if typeof oDD = DragDrop
18090 isTypeOfDD: function (oDD) {
18091 return (oDD && oDD.__ygDragDrop);
18095 * Utility function to determine if a given element has been
18096 * registered as a drag drop handle for the given Drag Drop object.
18098 * @param {String} id the element id to check
18099 * @return {boolean} true if this element is a DragDrop handle, false
18103 isHandle: function(sDDId, sHandleId) {
18104 return ( this.handleIds[sDDId] &&
18105 this.handleIds[sDDId][sHandleId] );
18109 * Returns the DragDrop instance for a given id
18110 * @method getDDById
18111 * @param {String} id the id of the DragDrop object
18112 * @return {DragDrop} the drag drop object, null if it is not found
18115 getDDById: function(id) {
18116 for (var i in this.ids) {
18117 if (this.ids[i][id]) {
18118 return this.ids[i][id];
18125 * Fired after a registered DragDrop object gets the mousedown event.
18126 * Sets up the events required to track the object being dragged
18127 * @method handleMouseDown
18128 * @param {Event} e the event
18129 * @param oDD the DragDrop object being dragged
18133 handleMouseDown: function(e, oDD) {
18135 Roo.QuickTips.disable();
18137 this.currentTarget = e.getTarget();
18139 this.dragCurrent = oDD;
18141 var el = oDD.getEl();
18143 // track start position
18144 this.startX = e.getPageX();
18145 this.startY = e.getPageY();
18147 this.deltaX = this.startX - el.offsetLeft;
18148 this.deltaY = this.startY - el.offsetTop;
18150 this.dragThreshMet = false;
18152 this.clickTimeout = setTimeout(
18154 var DDM = Roo.dd.DDM;
18155 DDM.startDrag(DDM.startX, DDM.startY);
18157 this.clickTimeThresh );
18161 * Fired when either the drag pixel threshol or the mousedown hold
18162 * time threshold has been met.
18163 * @method startDrag
18164 * @param x {int} the X position of the original mousedown
18165 * @param y {int} the Y position of the original mousedown
18168 startDrag: function(x, y) {
18169 clearTimeout(this.clickTimeout);
18170 if (this.dragCurrent) {
18171 this.dragCurrent.b4StartDrag(x, y);
18172 this.dragCurrent.startDrag(x, y);
18174 this.dragThreshMet = true;
18178 * Internal function to handle the mouseup event. Will be invoked
18179 * from the context of the document.
18180 * @method handleMouseUp
18181 * @param {Event} e the event
18185 handleMouseUp: function(e) {
18188 Roo.QuickTips.enable();
18190 if (! this.dragCurrent) {
18194 clearTimeout(this.clickTimeout);
18196 if (this.dragThreshMet) {
18197 this.fireEvents(e, true);
18207 * Utility to stop event propagation and event default, if these
18208 * features are turned on.
18209 * @method stopEvent
18210 * @param {Event} e the event as returned by this.getEvent()
18213 stopEvent: function(e){
18214 if(this.stopPropagation) {
18215 e.stopPropagation();
18218 if (this.preventDefault) {
18219 e.preventDefault();
18224 * Internal function to clean up event handlers after the drag
18225 * operation is complete
18227 * @param {Event} e the event
18231 stopDrag: function(e) {
18232 // Fire the drag end event for the item that was dragged
18233 if (this.dragCurrent) {
18234 if (this.dragThreshMet) {
18235 this.dragCurrent.b4EndDrag(e);
18236 this.dragCurrent.endDrag(e);
18239 this.dragCurrent.onMouseUp(e);
18242 this.dragCurrent = null;
18243 this.dragOvers = {};
18247 * Internal function to handle the mousemove event. Will be invoked
18248 * from the context of the html element.
18250 * @TODO figure out what we can do about mouse events lost when the
18251 * user drags objects beyond the window boundary. Currently we can
18252 * detect this in internet explorer by verifying that the mouse is
18253 * down during the mousemove event. Firefox doesn't give us the
18254 * button state on the mousemove event.
18255 * @method handleMouseMove
18256 * @param {Event} e the event
18260 handleMouseMove: function(e) {
18261 if (! this.dragCurrent) {
18265 // var button = e.which || e.button;
18267 // check for IE mouseup outside of page boundary
18268 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18270 return this.handleMouseUp(e);
18273 if (!this.dragThreshMet) {
18274 var diffX = Math.abs(this.startX - e.getPageX());
18275 var diffY = Math.abs(this.startY - e.getPageY());
18276 if (diffX > this.clickPixelThresh ||
18277 diffY > this.clickPixelThresh) {
18278 this.startDrag(this.startX, this.startY);
18282 if (this.dragThreshMet) {
18283 this.dragCurrent.b4Drag(e);
18284 this.dragCurrent.onDrag(e);
18285 if(!this.dragCurrent.moveOnly){
18286 this.fireEvents(e, false);
18296 * Iterates over all of the DragDrop elements to find ones we are
18297 * hovering over or dropping on
18298 * @method fireEvents
18299 * @param {Event} e the event
18300 * @param {boolean} isDrop is this a drop op or a mouseover op?
18304 fireEvents: function(e, isDrop) {
18305 var dc = this.dragCurrent;
18307 // If the user did the mouse up outside of the window, we could
18308 // get here even though we have ended the drag.
18309 if (!dc || dc.isLocked()) {
18313 var pt = e.getPoint();
18315 // cache the previous dragOver array
18321 var enterEvts = [];
18323 // Check to see if the object(s) we were hovering over is no longer
18324 // being hovered over so we can fire the onDragOut event
18325 for (var i in this.dragOvers) {
18327 var ddo = this.dragOvers[i];
18329 if (! this.isTypeOfDD(ddo)) {
18333 if (! this.isOverTarget(pt, ddo, this.mode)) {
18334 outEvts.push( ddo );
18337 oldOvers[i] = true;
18338 delete this.dragOvers[i];
18341 for (var sGroup in dc.groups) {
18343 if ("string" != typeof sGroup) {
18347 for (i in this.ids[sGroup]) {
18348 var oDD = this.ids[sGroup][i];
18349 if (! this.isTypeOfDD(oDD)) {
18353 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18354 if (this.isOverTarget(pt, oDD, this.mode)) {
18355 // look for drop interactions
18357 dropEvts.push( oDD );
18358 // look for drag enter and drag over interactions
18361 // initial drag over: dragEnter fires
18362 if (!oldOvers[oDD.id]) {
18363 enterEvts.push( oDD );
18364 // subsequent drag overs: dragOver fires
18366 overEvts.push( oDD );
18369 this.dragOvers[oDD.id] = oDD;
18377 if (outEvts.length) {
18378 dc.b4DragOut(e, outEvts);
18379 dc.onDragOut(e, outEvts);
18382 if (enterEvts.length) {
18383 dc.onDragEnter(e, enterEvts);
18386 if (overEvts.length) {
18387 dc.b4DragOver(e, overEvts);
18388 dc.onDragOver(e, overEvts);
18391 if (dropEvts.length) {
18392 dc.b4DragDrop(e, dropEvts);
18393 dc.onDragDrop(e, dropEvts);
18397 // fire dragout events
18399 for (i=0, len=outEvts.length; i<len; ++i) {
18400 dc.b4DragOut(e, outEvts[i].id);
18401 dc.onDragOut(e, outEvts[i].id);
18404 // fire enter events
18405 for (i=0,len=enterEvts.length; i<len; ++i) {
18406 // dc.b4DragEnter(e, oDD.id);
18407 dc.onDragEnter(e, enterEvts[i].id);
18410 // fire over events
18411 for (i=0,len=overEvts.length; i<len; ++i) {
18412 dc.b4DragOver(e, overEvts[i].id);
18413 dc.onDragOver(e, overEvts[i].id);
18416 // fire drop events
18417 for (i=0, len=dropEvts.length; i<len; ++i) {
18418 dc.b4DragDrop(e, dropEvts[i].id);
18419 dc.onDragDrop(e, dropEvts[i].id);
18424 // notify about a drop that did not find a target
18425 if (isDrop && !dropEvts.length) {
18426 dc.onInvalidDrop(e);
18432 * Helper function for getting the best match from the list of drag
18433 * and drop objects returned by the drag and drop events when we are
18434 * in INTERSECT mode. It returns either the first object that the
18435 * cursor is over, or the object that has the greatest overlap with
18436 * the dragged element.
18437 * @method getBestMatch
18438 * @param {DragDrop[]} dds The array of drag and drop objects
18440 * @return {DragDrop} The best single match
18443 getBestMatch: function(dds) {
18445 // Return null if the input is not what we expect
18446 //if (!dds || !dds.length || dds.length == 0) {
18448 // If there is only one item, it wins
18449 //} else if (dds.length == 1) {
18451 var len = dds.length;
18456 // Loop through the targeted items
18457 for (var i=0; i<len; ++i) {
18459 // If the cursor is over the object, it wins. If the
18460 // cursor is over multiple matches, the first one we come
18462 if (dd.cursorIsOver) {
18465 // Otherwise the object with the most overlap wins
18468 winner.overlap.getArea() < dd.overlap.getArea()) {
18479 * Refreshes the cache of the top-left and bottom-right points of the
18480 * drag and drop objects in the specified group(s). This is in the
18481 * format that is stored in the drag and drop instance, so typical
18484 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18488 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18490 * @TODO this really should be an indexed array. Alternatively this
18491 * method could accept both.
18492 * @method refreshCache
18493 * @param {Object} groups an associative array of groups to refresh
18496 refreshCache: function(groups) {
18497 for (var sGroup in groups) {
18498 if ("string" != typeof sGroup) {
18501 for (var i in this.ids[sGroup]) {
18502 var oDD = this.ids[sGroup][i];
18504 if (this.isTypeOfDD(oDD)) {
18505 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18506 var loc = this.getLocation(oDD);
18508 this.locationCache[oDD.id] = loc;
18510 delete this.locationCache[oDD.id];
18511 // this will unregister the drag and drop object if
18512 // the element is not in a usable state
18521 * This checks to make sure an element exists and is in the DOM. The
18522 * main purpose is to handle cases where innerHTML is used to remove
18523 * drag and drop objects from the DOM. IE provides an 'unspecified
18524 * error' when trying to access the offsetParent of such an element
18526 * @param {HTMLElement} el the element to check
18527 * @return {boolean} true if the element looks usable
18530 verifyEl: function(el) {
18535 parent = el.offsetParent;
18538 parent = el.offsetParent;
18549 * Returns a Region object containing the drag and drop element's position
18550 * and size, including the padding configured for it
18551 * @method getLocation
18552 * @param {DragDrop} oDD the drag and drop object to get the
18554 * @return {Roo.lib.Region} a Region object representing the total area
18555 * the element occupies, including any padding
18556 * the instance is configured for.
18559 getLocation: function(oDD) {
18560 if (! this.isTypeOfDD(oDD)) {
18564 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18567 pos= Roo.lib.Dom.getXY(el);
18575 x2 = x1 + el.offsetWidth;
18577 y2 = y1 + el.offsetHeight;
18579 t = y1 - oDD.padding[0];
18580 r = x2 + oDD.padding[1];
18581 b = y2 + oDD.padding[2];
18582 l = x1 - oDD.padding[3];
18584 return new Roo.lib.Region( t, r, b, l );
18588 * Checks the cursor location to see if it over the target
18589 * @method isOverTarget
18590 * @param {Roo.lib.Point} pt The point to evaluate
18591 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18592 * @return {boolean} true if the mouse is over the target
18596 isOverTarget: function(pt, oTarget, intersect) {
18597 // use cache if available
18598 var loc = this.locationCache[oTarget.id];
18599 if (!loc || !this.useCache) {
18600 loc = this.getLocation(oTarget);
18601 this.locationCache[oTarget.id] = loc;
18609 oTarget.cursorIsOver = loc.contains( pt );
18611 // DragDrop is using this as a sanity check for the initial mousedown
18612 // in this case we are done. In POINT mode, if the drag obj has no
18613 // contraints, we are also done. Otherwise we need to evaluate the
18614 // location of the target as related to the actual location of the
18615 // dragged element.
18616 var dc = this.dragCurrent;
18617 if (!dc || !dc.getTargetCoord ||
18618 (!intersect && !dc.constrainX && !dc.constrainY)) {
18619 return oTarget.cursorIsOver;
18622 oTarget.overlap = null;
18624 // Get the current location of the drag element, this is the
18625 // location of the mouse event less the delta that represents
18626 // where the original mousedown happened on the element. We
18627 // need to consider constraints and ticks as well.
18628 var pos = dc.getTargetCoord(pt.x, pt.y);
18630 var el = dc.getDragEl();
18631 var curRegion = new Roo.lib.Region( pos.y,
18632 pos.x + el.offsetWidth,
18633 pos.y + el.offsetHeight,
18636 var overlap = curRegion.intersect(loc);
18639 oTarget.overlap = overlap;
18640 return (intersect) ? true : oTarget.cursorIsOver;
18647 * unload event handler
18648 * @method _onUnload
18652 _onUnload: function(e, me) {
18653 Roo.dd.DragDropMgr.unregAll();
18657 * Cleans up the drag and drop events and objects.
18662 unregAll: function() {
18664 if (this.dragCurrent) {
18666 this.dragCurrent = null;
18669 this._execOnAll("unreg", []);
18671 for (i in this.elementCache) {
18672 delete this.elementCache[i];
18675 this.elementCache = {};
18680 * A cache of DOM elements
18681 * @property elementCache
18688 * Get the wrapper for the DOM element specified
18689 * @method getElWrapper
18690 * @param {String} id the id of the element to get
18691 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18693 * @deprecated This wrapper isn't that useful
18696 getElWrapper: function(id) {
18697 var oWrapper = this.elementCache[id];
18698 if (!oWrapper || !oWrapper.el) {
18699 oWrapper = this.elementCache[id] =
18700 new this.ElementWrapper(Roo.getDom(id));
18706 * Returns the actual DOM element
18707 * @method getElement
18708 * @param {String} id the id of the elment to get
18709 * @return {Object} The element
18710 * @deprecated use Roo.getDom instead
18713 getElement: function(id) {
18714 return Roo.getDom(id);
18718 * Returns the style property for the DOM element (i.e.,
18719 * document.getElById(id).style)
18721 * @param {String} id the id of the elment to get
18722 * @return {Object} The style property of the element
18723 * @deprecated use Roo.getDom instead
18726 getCss: function(id) {
18727 var el = Roo.getDom(id);
18728 return (el) ? el.style : null;
18732 * Inner class for cached elements
18733 * @class DragDropMgr.ElementWrapper
18738 ElementWrapper: function(el) {
18743 this.el = el || null;
18748 this.id = this.el && el.id;
18750 * A reference to the style property
18753 this.css = this.el && el.style;
18757 * Returns the X position of an html element
18759 * @param el the element for which to get the position
18760 * @return {int} the X coordinate
18762 * @deprecated use Roo.lib.Dom.getX instead
18765 getPosX: function(el) {
18766 return Roo.lib.Dom.getX(el);
18770 * Returns the Y position of an html element
18772 * @param el the element for which to get the position
18773 * @return {int} the Y coordinate
18774 * @deprecated use Roo.lib.Dom.getY instead
18777 getPosY: function(el) {
18778 return Roo.lib.Dom.getY(el);
18782 * Swap two nodes. In IE, we use the native method, for others we
18783 * emulate the IE behavior
18785 * @param n1 the first node to swap
18786 * @param n2 the other node to swap
18789 swapNode: function(n1, n2) {
18793 var p = n2.parentNode;
18794 var s = n2.nextSibling;
18797 p.insertBefore(n1, n2);
18798 } else if (n2 == n1.nextSibling) {
18799 p.insertBefore(n2, n1);
18801 n1.parentNode.replaceChild(n2, n1);
18802 p.insertBefore(n1, s);
18808 * Returns the current scroll position
18809 * @method getScroll
18813 getScroll: function () {
18814 var t, l, dde=document.documentElement, db=document.body;
18815 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18817 l = dde.scrollLeft;
18824 return { top: t, left: l };
18828 * Returns the specified element style property
18830 * @param {HTMLElement} el the element
18831 * @param {string} styleProp the style property
18832 * @return {string} The value of the style property
18833 * @deprecated use Roo.lib.Dom.getStyle
18836 getStyle: function(el, styleProp) {
18837 return Roo.fly(el).getStyle(styleProp);
18841 * Gets the scrollTop
18842 * @method getScrollTop
18843 * @return {int} the document's scrollTop
18846 getScrollTop: function () { return this.getScroll().top; },
18849 * Gets the scrollLeft
18850 * @method getScrollLeft
18851 * @return {int} the document's scrollTop
18854 getScrollLeft: function () { return this.getScroll().left; },
18857 * Sets the x/y position of an element to the location of the
18860 * @param {HTMLElement} moveEl The element to move
18861 * @param {HTMLElement} targetEl The position reference element
18864 moveToEl: function (moveEl, targetEl) {
18865 var aCoord = Roo.lib.Dom.getXY(targetEl);
18866 Roo.lib.Dom.setXY(moveEl, aCoord);
18870 * Numeric array sort function
18871 * @method numericSort
18874 numericSort: function(a, b) { return (a - b); },
18878 * @property _timeoutCount
18885 * Trying to make the load order less important. Without this we get
18886 * an error if this file is loaded before the Event Utility.
18887 * @method _addListeners
18891 _addListeners: function() {
18892 var DDM = Roo.dd.DDM;
18893 if ( Roo.lib.Event && document ) {
18896 if (DDM._timeoutCount > 2000) {
18898 setTimeout(DDM._addListeners, 10);
18899 if (document && document.body) {
18900 DDM._timeoutCount += 1;
18907 * Recursively searches the immediate parent and all child nodes for
18908 * the handle element in order to determine wheter or not it was
18910 * @method handleWasClicked
18911 * @param node the html element to inspect
18914 handleWasClicked: function(node, id) {
18915 if (this.isHandle(id, node.id)) {
18918 // check to see if this is a text node child of the one we want
18919 var p = node.parentNode;
18922 if (this.isHandle(id, p.id)) {
18937 // shorter alias, save a few bytes
18938 Roo.dd.DDM = Roo.dd.DragDropMgr;
18939 Roo.dd.DDM._addListeners();
18943 * Ext JS Library 1.1.1
18944 * Copyright(c) 2006-2007, Ext JS, LLC.
18946 * Originally Released Under LGPL - original licence link has changed is not relivant.
18949 * <script type="text/javascript">
18954 * A DragDrop implementation where the linked element follows the
18955 * mouse cursor during a drag.
18956 * @extends Roo.dd.DragDrop
18958 * @param {String} id the id of the linked element
18959 * @param {String} sGroup the group of related DragDrop items
18960 * @param {object} config an object containing configurable attributes
18961 * Valid properties for DD:
18964 Roo.dd.DD = function(id, sGroup, config) {
18966 this.init(id, sGroup, config);
18970 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18973 * When set to true, the utility automatically tries to scroll the browser
18974 * window wehn a drag and drop element is dragged near the viewport boundary.
18975 * Defaults to true.
18982 * Sets the pointer offset to the distance between the linked element's top
18983 * left corner and the location the element was clicked
18984 * @method autoOffset
18985 * @param {int} iPageX the X coordinate of the click
18986 * @param {int} iPageY the Y coordinate of the click
18988 autoOffset: function(iPageX, iPageY) {
18989 var x = iPageX - this.startPageX;
18990 var y = iPageY - this.startPageY;
18991 this.setDelta(x, y);
18995 * Sets the pointer offset. You can call this directly to force the
18996 * offset to be in a particular location (e.g., pass in 0,0 to set it
18997 * to the center of the object)
18999 * @param {int} iDeltaX the distance from the left
19000 * @param {int} iDeltaY the distance from the top
19002 setDelta: function(iDeltaX, iDeltaY) {
19003 this.deltaX = iDeltaX;
19004 this.deltaY = iDeltaY;
19008 * Sets the drag element to the location of the mousedown or click event,
19009 * maintaining the cursor location relative to the location on the element
19010 * that was clicked. Override this if you want to place the element in a
19011 * location other than where the cursor is.
19012 * @method setDragElPos
19013 * @param {int} iPageX the X coordinate of the mousedown or drag event
19014 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19016 setDragElPos: function(iPageX, iPageY) {
19017 // the first time we do this, we are going to check to make sure
19018 // the element has css positioning
19020 var el = this.getDragEl();
19021 this.alignElWithMouse(el, iPageX, iPageY);
19025 * Sets the element to the location of the mousedown or click event,
19026 * maintaining the cursor location relative to the location on the element
19027 * that was clicked. Override this if you want to place the element in a
19028 * location other than where the cursor is.
19029 * @method alignElWithMouse
19030 * @param {HTMLElement} el the element to move
19031 * @param {int} iPageX the X coordinate of the mousedown or drag event
19032 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19034 alignElWithMouse: function(el, iPageX, iPageY) {
19035 var oCoord = this.getTargetCoord(iPageX, iPageY);
19036 var fly = el.dom ? el : Roo.fly(el);
19037 if (!this.deltaSetXY) {
19038 var aCoord = [oCoord.x, oCoord.y];
19040 var newLeft = fly.getLeft(true);
19041 var newTop = fly.getTop(true);
19042 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
19044 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
19047 this.cachePosition(oCoord.x, oCoord.y);
19048 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
19053 * Saves the most recent position so that we can reset the constraints and
19054 * tick marks on-demand. We need to know this so that we can calculate the
19055 * number of pixels the element is offset from its original position.
19056 * @method cachePosition
19057 * @param iPageX the current x position (optional, this just makes it so we
19058 * don't have to look it up again)
19059 * @param iPageY the current y position (optional, this just makes it so we
19060 * don't have to look it up again)
19062 cachePosition: function(iPageX, iPageY) {
19064 this.lastPageX = iPageX;
19065 this.lastPageY = iPageY;
19067 var aCoord = Roo.lib.Dom.getXY(this.getEl());
19068 this.lastPageX = aCoord[0];
19069 this.lastPageY = aCoord[1];
19074 * Auto-scroll the window if the dragged object has been moved beyond the
19075 * visible window boundary.
19076 * @method autoScroll
19077 * @param {int} x the drag element's x position
19078 * @param {int} y the drag element's y position
19079 * @param {int} h the height of the drag element
19080 * @param {int} w the width of the drag element
19083 autoScroll: function(x, y, h, w) {
19086 // The client height
19087 var clientH = Roo.lib.Dom.getViewWidth();
19089 // The client width
19090 var clientW = Roo.lib.Dom.getViewHeight();
19092 // The amt scrolled down
19093 var st = this.DDM.getScrollTop();
19095 // The amt scrolled right
19096 var sl = this.DDM.getScrollLeft();
19098 // Location of the bottom of the element
19101 // Location of the right of the element
19104 // The distance from the cursor to the bottom of the visible area,
19105 // adjusted so that we don't scroll if the cursor is beyond the
19106 // element drag constraints
19107 var toBot = (clientH + st - y - this.deltaY);
19109 // The distance from the cursor to the right of the visible area
19110 var toRight = (clientW + sl - x - this.deltaX);
19113 // How close to the edge the cursor must be before we scroll
19114 // var thresh = (document.all) ? 100 : 40;
19117 // How many pixels to scroll per autoscroll op. This helps to reduce
19118 // clunky scrolling. IE is more sensitive about this ... it needs this
19119 // value to be higher.
19120 var scrAmt = (document.all) ? 80 : 30;
19122 // Scroll down if we are near the bottom of the visible page and the
19123 // obj extends below the crease
19124 if ( bot > clientH && toBot < thresh ) {
19125 window.scrollTo(sl, st + scrAmt);
19128 // Scroll up if the window is scrolled down and the top of the object
19129 // goes above the top border
19130 if ( y < st && st > 0 && y - st < thresh ) {
19131 window.scrollTo(sl, st - scrAmt);
19134 // Scroll right if the obj is beyond the right border and the cursor is
19135 // near the border.
19136 if ( right > clientW && toRight < thresh ) {
19137 window.scrollTo(sl + scrAmt, st);
19140 // Scroll left if the window has been scrolled to the right and the obj
19141 // extends past the left border
19142 if ( x < sl && sl > 0 && x - sl < thresh ) {
19143 window.scrollTo(sl - scrAmt, st);
19149 * Finds the location the element should be placed if we want to move
19150 * it to where the mouse location less the click offset would place us.
19151 * @method getTargetCoord
19152 * @param {int} iPageX the X coordinate of the click
19153 * @param {int} iPageY the Y coordinate of the click
19154 * @return an object that contains the coordinates (Object.x and Object.y)
19157 getTargetCoord: function(iPageX, iPageY) {
19160 var x = iPageX - this.deltaX;
19161 var y = iPageY - this.deltaY;
19163 if (this.constrainX) {
19164 if (x < this.minX) { x = this.minX; }
19165 if (x > this.maxX) { x = this.maxX; }
19168 if (this.constrainY) {
19169 if (y < this.minY) { y = this.minY; }
19170 if (y > this.maxY) { y = this.maxY; }
19173 x = this.getTick(x, this.xTicks);
19174 y = this.getTick(y, this.yTicks);
19181 * Sets up config options specific to this class. Overrides
19182 * Roo.dd.DragDrop, but all versions of this method through the
19183 * inheritance chain are called
19185 applyConfig: function() {
19186 Roo.dd.DD.superclass.applyConfig.call(this);
19187 this.scroll = (this.config.scroll !== false);
19191 * Event that fires prior to the onMouseDown event. Overrides
19194 b4MouseDown: function(e) {
19195 // this.resetConstraints();
19196 this.autoOffset(e.getPageX(),
19201 * Event that fires prior to the onDrag event. Overrides
19204 b4Drag: function(e) {
19205 this.setDragElPos(e.getPageX(),
19209 toString: function() {
19210 return ("DD " + this.id);
19213 //////////////////////////////////////////////////////////////////////////
19214 // Debugging ygDragDrop events that can be overridden
19215 //////////////////////////////////////////////////////////////////////////
19217 startDrag: function(x, y) {
19220 onDrag: function(e) {
19223 onDragEnter: function(e, id) {
19226 onDragOver: function(e, id) {
19229 onDragOut: function(e, id) {
19232 onDragDrop: function(e, id) {
19235 endDrag: function(e) {
19242 * Ext JS Library 1.1.1
19243 * Copyright(c) 2006-2007, Ext JS, LLC.
19245 * Originally Released Under LGPL - original licence link has changed is not relivant.
19248 * <script type="text/javascript">
19252 * @class Roo.dd.DDProxy
19253 * A DragDrop implementation that inserts an empty, bordered div into
19254 * the document that follows the cursor during drag operations. At the time of
19255 * the click, the frame div is resized to the dimensions of the linked html
19256 * element, and moved to the exact location of the linked element.
19258 * References to the "frame" element refer to the single proxy element that
19259 * was created to be dragged in place of all DDProxy elements on the
19262 * @extends Roo.dd.DD
19264 * @param {String} id the id of the linked html element
19265 * @param {String} sGroup the group of related DragDrop objects
19266 * @param {object} config an object containing configurable attributes
19267 * Valid properties for DDProxy in addition to those in DragDrop:
19268 * resizeFrame, centerFrame, dragElId
19270 Roo.dd.DDProxy = function(id, sGroup, config) {
19272 this.init(id, sGroup, config);
19278 * The default drag frame div id
19279 * @property Roo.dd.DDProxy.dragElId
19283 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19285 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19288 * By default we resize the drag frame to be the same size as the element
19289 * we want to drag (this is to get the frame effect). We can turn it off
19290 * if we want a different behavior.
19291 * @property resizeFrame
19297 * By default the frame is positioned exactly where the drag element is, so
19298 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19299 * you do not have constraints on the obj is to have the drag frame centered
19300 * around the cursor. Set centerFrame to true for this effect.
19301 * @property centerFrame
19304 centerFrame: false,
19307 * Creates the proxy element if it does not yet exist
19308 * @method createFrame
19310 createFrame: function() {
19312 var body = document.body;
19314 if (!body || !body.firstChild) {
19315 setTimeout( function() { self.createFrame(); }, 50 );
19319 var div = this.getDragEl();
19322 div = document.createElement("div");
19323 div.id = this.dragElId;
19326 s.position = "absolute";
19327 s.visibility = "hidden";
19329 s.border = "2px solid #aaa";
19332 // appendChild can blow up IE if invoked prior to the window load event
19333 // while rendering a table. It is possible there are other scenarios
19334 // that would cause this to happen as well.
19335 body.insertBefore(div, body.firstChild);
19340 * Initialization for the drag frame element. Must be called in the
19341 * constructor of all subclasses
19342 * @method initFrame
19344 initFrame: function() {
19345 this.createFrame();
19348 applyConfig: function() {
19349 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19351 this.resizeFrame = (this.config.resizeFrame !== false);
19352 this.centerFrame = (this.config.centerFrame);
19353 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19357 * Resizes the drag frame to the dimensions of the clicked object, positions
19358 * it over the object, and finally displays it
19359 * @method showFrame
19360 * @param {int} iPageX X click position
19361 * @param {int} iPageY Y click position
19364 showFrame: function(iPageX, iPageY) {
19365 var el = this.getEl();
19366 var dragEl = this.getDragEl();
19367 var s = dragEl.style;
19369 this._resizeProxy();
19371 if (this.centerFrame) {
19372 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19373 Math.round(parseInt(s.height, 10)/2) );
19376 this.setDragElPos(iPageX, iPageY);
19378 Roo.fly(dragEl).show();
19382 * The proxy is automatically resized to the dimensions of the linked
19383 * element when a drag is initiated, unless resizeFrame is set to false
19384 * @method _resizeProxy
19387 _resizeProxy: function() {
19388 if (this.resizeFrame) {
19389 var el = this.getEl();
19390 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19394 // overrides Roo.dd.DragDrop
19395 b4MouseDown: function(e) {
19396 var x = e.getPageX();
19397 var y = e.getPageY();
19398 this.autoOffset(x, y);
19399 this.setDragElPos(x, y);
19402 // overrides Roo.dd.DragDrop
19403 b4StartDrag: function(x, y) {
19404 // show the drag frame
19405 this.showFrame(x, y);
19408 // overrides Roo.dd.DragDrop
19409 b4EndDrag: function(e) {
19410 Roo.fly(this.getDragEl()).hide();
19413 // overrides Roo.dd.DragDrop
19414 // By default we try to move the element to the last location of the frame.
19415 // This is so that the default behavior mirrors that of Roo.dd.DD.
19416 endDrag: function(e) {
19418 var lel = this.getEl();
19419 var del = this.getDragEl();
19421 // Show the drag frame briefly so we can get its position
19422 del.style.visibility = "";
19425 // Hide the linked element before the move to get around a Safari
19427 lel.style.visibility = "hidden";
19428 Roo.dd.DDM.moveToEl(lel, del);
19429 del.style.visibility = "hidden";
19430 lel.style.visibility = "";
19435 beforeMove : function(){
19439 afterDrag : function(){
19443 toString: function() {
19444 return ("DDProxy " + this.id);
19450 * Ext JS Library 1.1.1
19451 * Copyright(c) 2006-2007, Ext JS, LLC.
19453 * Originally Released Under LGPL - original licence link has changed is not relivant.
19456 * <script type="text/javascript">
19460 * @class Roo.dd.DDTarget
19461 * A DragDrop implementation that does not move, but can be a drop
19462 * target. You would get the same result by simply omitting implementation
19463 * for the event callbacks, but this way we reduce the processing cost of the
19464 * event listener and the callbacks.
19465 * @extends Roo.dd.DragDrop
19467 * @param {String} id the id of the element that is a drop target
19468 * @param {String} sGroup the group of related DragDrop objects
19469 * @param {object} config an object containing configurable attributes
19470 * Valid properties for DDTarget in addition to those in
19474 Roo.dd.DDTarget = function(id, sGroup, config) {
19476 this.initTarget(id, sGroup, config);
19478 if (config.listeners || config.events) {
19479 Roo.dd.DragDrop.superclass.constructor.call(this, {
19480 listeners : config.listeners || {},
19481 events : config.events || {}
19486 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19487 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19488 toString: function() {
19489 return ("DDTarget " + this.id);
19494 * Ext JS Library 1.1.1
19495 * Copyright(c) 2006-2007, Ext JS, LLC.
19497 * Originally Released Under LGPL - original licence link has changed is not relivant.
19500 * <script type="text/javascript">
19505 * @class Roo.dd.ScrollManager
19506 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19507 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19510 Roo.dd.ScrollManager = function(){
19511 var ddm = Roo.dd.DragDropMgr;
19518 var onStop = function(e){
19523 var triggerRefresh = function(){
19524 if(ddm.dragCurrent){
19525 ddm.refreshCache(ddm.dragCurrent.groups);
19529 var doScroll = function(){
19530 if(ddm.dragCurrent){
19531 var dds = Roo.dd.ScrollManager;
19533 if(proc.el.scroll(proc.dir, dds.increment)){
19537 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19542 var clearProc = function(){
19544 clearInterval(proc.id);
19551 var startProc = function(el, dir){
19552 Roo.log('scroll startproc');
19556 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19559 var onFire = function(e, isDrop){
19561 if(isDrop || !ddm.dragCurrent){ return; }
19562 var dds = Roo.dd.ScrollManager;
19563 if(!dragEl || dragEl != ddm.dragCurrent){
19564 dragEl = ddm.dragCurrent;
19565 // refresh regions on drag start
19566 dds.refreshCache();
19569 var xy = Roo.lib.Event.getXY(e);
19570 var pt = new Roo.lib.Point(xy[0], xy[1]);
19571 for(var id in els){
19572 var el = els[id], r = el._region;
19573 if(r && r.contains(pt) && el.isScrollable()){
19574 if(r.bottom - pt.y <= dds.thresh){
19576 startProc(el, "down");
19579 }else if(r.right - pt.x <= dds.thresh){
19581 startProc(el, "left");
19584 }else if(pt.y - r.top <= dds.thresh){
19586 startProc(el, "up");
19589 }else if(pt.x - r.left <= dds.thresh){
19591 startProc(el, "right");
19600 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19601 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19605 * Registers new overflow element(s) to auto scroll
19606 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19608 register : function(el){
19609 if(el instanceof Array){
19610 for(var i = 0, len = el.length; i < len; i++) {
19611 this.register(el[i]);
19617 Roo.dd.ScrollManager.els = els;
19621 * Unregisters overflow element(s) so they are no longer scrolled
19622 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19624 unregister : function(el){
19625 if(el instanceof Array){
19626 for(var i = 0, len = el.length; i < len; i++) {
19627 this.unregister(el[i]);
19636 * The number of pixels from the edge of a container the pointer needs to be to
19637 * trigger scrolling (defaults to 25)
19643 * The number of pixels to scroll in each scroll increment (defaults to 50)
19649 * The frequency of scrolls in milliseconds (defaults to 500)
19655 * True to animate the scroll (defaults to true)
19661 * The animation duration in seconds -
19662 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19668 * Manually trigger a cache refresh.
19670 refreshCache : function(){
19671 for(var id in els){
19672 if(typeof els[id] == 'object'){ // for people extending the object prototype
19673 els[id]._region = els[id].getRegion();
19680 * Ext JS Library 1.1.1
19681 * Copyright(c) 2006-2007, Ext JS, LLC.
19683 * Originally Released Under LGPL - original licence link has changed is not relivant.
19686 * <script type="text/javascript">
19691 * @class Roo.dd.Registry
19692 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19693 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19696 Roo.dd.Registry = function(){
19699 var autoIdSeed = 0;
19701 var getId = function(el, autogen){
19702 if(typeof el == "string"){
19706 if(!id && autogen !== false){
19707 id = "roodd-" + (++autoIdSeed);
19715 * Register a drag drop element
19716 * @param {String|HTMLElement} element The id or DOM node to register
19717 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19718 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19719 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19720 * populated in the data object (if applicable):
19722 Value Description<br />
19723 --------- ------------------------------------------<br />
19724 handles Array of DOM nodes that trigger dragging<br />
19725 for the element being registered<br />
19726 isHandle True if the element passed in triggers<br />
19727 dragging itself, else false
19730 register : function(el, data){
19732 if(typeof el == "string"){
19733 el = document.getElementById(el);
19736 elements[getId(el)] = data;
19737 if(data.isHandle !== false){
19738 handles[data.ddel.id] = data;
19741 var hs = data.handles;
19742 for(var i = 0, len = hs.length; i < len; i++){
19743 handles[getId(hs[i])] = data;
19749 * Unregister a drag drop element
19750 * @param {String|HTMLElement} element The id or DOM node to unregister
19752 unregister : function(el){
19753 var id = getId(el, false);
19754 var data = elements[id];
19756 delete elements[id];
19758 var hs = data.handles;
19759 for(var i = 0, len = hs.length; i < len; i++){
19760 delete handles[getId(hs[i], false)];
19767 * Returns the handle registered for a DOM Node by id
19768 * @param {String|HTMLElement} id The DOM node or id to look up
19769 * @return {Object} handle The custom handle data
19771 getHandle : function(id){
19772 if(typeof id != "string"){ // must be element?
19775 return handles[id];
19779 * Returns the handle that is registered for the DOM node that is the target of the event
19780 * @param {Event} e The event
19781 * @return {Object} handle The custom handle data
19783 getHandleFromEvent : function(e){
19784 var t = Roo.lib.Event.getTarget(e);
19785 return t ? handles[t.id] : null;
19789 * Returns a custom data object that is registered for a DOM node by id
19790 * @param {String|HTMLElement} id The DOM node or id to look up
19791 * @return {Object} data The custom data
19793 getTarget : function(id){
19794 if(typeof id != "string"){ // must be element?
19797 return elements[id];
19801 * Returns a custom data object that is registered for the DOM node that is the target of the event
19802 * @param {Event} e The event
19803 * @return {Object} data The custom data
19805 getTargetFromEvent : function(e){
19806 var t = Roo.lib.Event.getTarget(e);
19807 return t ? elements[t.id] || handles[t.id] : null;
19812 * Ext JS Library 1.1.1
19813 * Copyright(c) 2006-2007, Ext JS, LLC.
19815 * Originally Released Under LGPL - original licence link has changed is not relivant.
19818 * <script type="text/javascript">
19823 * @class Roo.dd.StatusProxy
19824 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19825 * default drag proxy used by all Roo.dd components.
19827 * @param {Object} config
19829 Roo.dd.StatusProxy = function(config){
19830 Roo.apply(this, config);
19831 this.id = this.id || Roo.id();
19832 this.el = new Roo.Layer({
19834 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19835 {tag: "div", cls: "x-dd-drop-icon"},
19836 {tag: "div", cls: "x-dd-drag-ghost"}
19839 shadow: !config || config.shadow !== false
19841 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19842 this.dropStatus = this.dropNotAllowed;
19845 Roo.dd.StatusProxy.prototype = {
19847 * @cfg {String} dropAllowed
19848 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19850 dropAllowed : "x-dd-drop-ok",
19852 * @cfg {String} dropNotAllowed
19853 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19855 dropNotAllowed : "x-dd-drop-nodrop",
19858 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19859 * over the current target element.
19860 * @param {String} cssClass The css class for the new drop status indicator image
19862 setStatus : function(cssClass){
19863 cssClass = cssClass || this.dropNotAllowed;
19864 if(this.dropStatus != cssClass){
19865 this.el.replaceClass(this.dropStatus, cssClass);
19866 this.dropStatus = cssClass;
19871 * Resets the status indicator to the default dropNotAllowed value
19872 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19874 reset : function(clearGhost){
19875 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19876 this.dropStatus = this.dropNotAllowed;
19878 this.ghost.update("");
19883 * Updates the contents of the ghost element
19884 * @param {String} html The html that will replace the current innerHTML of the ghost element
19886 update : function(html){
19887 if(typeof html == "string"){
19888 this.ghost.update(html);
19890 this.ghost.update("");
19891 html.style.margin = "0";
19892 this.ghost.dom.appendChild(html);
19894 // ensure float = none set?? cant remember why though.
19895 var el = this.ghost.dom.firstChild;
19897 Roo.fly(el).setStyle('float', 'none');
19902 * Returns the underlying proxy {@link Roo.Layer}
19903 * @return {Roo.Layer} el
19905 getEl : function(){
19910 * Returns the ghost element
19911 * @return {Roo.Element} el
19913 getGhost : function(){
19919 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19921 hide : function(clear){
19929 * Stops the repair animation if it's currently running
19932 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19938 * Displays this proxy
19945 * Force the Layer to sync its shadow and shim positions to the element
19952 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19953 * invalid drop operation by the item being dragged.
19954 * @param {Array} xy The XY position of the element ([x, y])
19955 * @param {Function} callback The function to call after the repair is complete
19956 * @param {Object} scope The scope in which to execute the callback
19958 repair : function(xy, callback, scope){
19959 this.callback = callback;
19960 this.scope = scope;
19961 if(xy && this.animRepair !== false){
19962 this.el.addClass("x-dd-drag-repair");
19963 this.el.hideUnders(true);
19964 this.anim = this.el.shift({
19965 duration: this.repairDuration || .5,
19969 callback: this.afterRepair,
19973 this.afterRepair();
19978 afterRepair : function(){
19980 if(typeof this.callback == "function"){
19981 this.callback.call(this.scope || this);
19983 this.callback = null;
19988 * Ext JS Library 1.1.1
19989 * Copyright(c) 2006-2007, Ext JS, LLC.
19991 * Originally Released Under LGPL - original licence link has changed is not relivant.
19994 * <script type="text/javascript">
19998 * @class Roo.dd.DragSource
19999 * @extends Roo.dd.DDProxy
20000 * A simple class that provides the basic implementation needed to make any element draggable.
20002 * @param {String/HTMLElement/Element} el The container element
20003 * @param {Object} config
20005 Roo.dd.DragSource = function(el, config){
20006 this.el = Roo.get(el);
20007 this.dragData = {};
20009 Roo.apply(this, config);
20012 this.proxy = new Roo.dd.StatusProxy();
20015 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
20016 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
20018 this.dragging = false;
20021 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
20023 * @cfg {String} dropAllowed
20024 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20026 dropAllowed : "x-dd-drop-ok",
20028 * @cfg {String} dropNotAllowed
20029 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20031 dropNotAllowed : "x-dd-drop-nodrop",
20034 * Returns the data object associated with this drag source
20035 * @return {Object} data An object containing arbitrary data
20037 getDragData : function(e){
20038 return this.dragData;
20042 onDragEnter : function(e, id){
20043 var target = Roo.dd.DragDropMgr.getDDById(id);
20044 this.cachedTarget = target;
20045 if(this.beforeDragEnter(target, e, id) !== false){
20046 if(target.isNotifyTarget){
20047 var status = target.notifyEnter(this, e, this.dragData);
20048 this.proxy.setStatus(status);
20050 this.proxy.setStatus(this.dropAllowed);
20053 if(this.afterDragEnter){
20055 * An empty function by default, but provided so that you can perform a custom action
20056 * when the dragged item enters the drop target by providing an implementation.
20057 * @param {Roo.dd.DragDrop} target The drop target
20058 * @param {Event} e The event object
20059 * @param {String} id The id of the dragged element
20060 * @method afterDragEnter
20062 this.afterDragEnter(target, e, id);
20068 * An empty function by default, but provided so that you can perform a custom action
20069 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
20070 * @param {Roo.dd.DragDrop} target The drop target
20071 * @param {Event} e The event object
20072 * @param {String} id The id of the dragged element
20073 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20075 beforeDragEnter : function(target, e, id){
20080 alignElWithMouse: function() {
20081 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
20086 onDragOver : function(e, id){
20087 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20088 if(this.beforeDragOver(target, e, id) !== false){
20089 if(target.isNotifyTarget){
20090 var status = target.notifyOver(this, e, this.dragData);
20091 this.proxy.setStatus(status);
20094 if(this.afterDragOver){
20096 * An empty function by default, but provided so that you can perform a custom action
20097 * while the dragged item is over the drop target by providing an implementation.
20098 * @param {Roo.dd.DragDrop} target The drop target
20099 * @param {Event} e The event object
20100 * @param {String} id The id of the dragged element
20101 * @method afterDragOver
20103 this.afterDragOver(target, e, id);
20109 * An empty function by default, but provided so that you can perform a custom action
20110 * while the dragged item is over the drop target and optionally cancel the onDragOver.
20111 * @param {Roo.dd.DragDrop} target The drop target
20112 * @param {Event} e The event object
20113 * @param {String} id The id of the dragged element
20114 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20116 beforeDragOver : function(target, e, id){
20121 onDragOut : function(e, id){
20122 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20123 if(this.beforeDragOut(target, e, id) !== false){
20124 if(target.isNotifyTarget){
20125 target.notifyOut(this, e, this.dragData);
20127 this.proxy.reset();
20128 if(this.afterDragOut){
20130 * An empty function by default, but provided so that you can perform a custom action
20131 * after the dragged item is dragged out of the target without dropping.
20132 * @param {Roo.dd.DragDrop} target The drop target
20133 * @param {Event} e The event object
20134 * @param {String} id The id of the dragged element
20135 * @method afterDragOut
20137 this.afterDragOut(target, e, id);
20140 this.cachedTarget = null;
20144 * An empty function by default, but provided so that you can perform a custom action before the dragged
20145 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20146 * @param {Roo.dd.DragDrop} target The drop target
20147 * @param {Event} e The event object
20148 * @param {String} id The id of the dragged element
20149 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20151 beforeDragOut : function(target, e, id){
20156 onDragDrop : function(e, id){
20157 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20158 if(this.beforeDragDrop(target, e, id) !== false){
20159 if(target.isNotifyTarget){
20160 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20161 this.onValidDrop(target, e, id);
20163 this.onInvalidDrop(target, e, id);
20166 this.onValidDrop(target, e, id);
20169 if(this.afterDragDrop){
20171 * An empty function by default, but provided so that you can perform a custom action
20172 * after a valid drag drop has occurred by providing an implementation.
20173 * @param {Roo.dd.DragDrop} target The drop target
20174 * @param {Event} e The event object
20175 * @param {String} id The id of the dropped element
20176 * @method afterDragDrop
20178 this.afterDragDrop(target, e, id);
20181 delete this.cachedTarget;
20185 * An empty function by default, but provided so that you can perform a custom action before the dragged
20186 * item is dropped onto the target and optionally cancel the onDragDrop.
20187 * @param {Roo.dd.DragDrop} target The drop target
20188 * @param {Event} e The event object
20189 * @param {String} id The id of the dragged element
20190 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20192 beforeDragDrop : function(target, e, id){
20197 onValidDrop : function(target, e, id){
20199 if(this.afterValidDrop){
20201 * An empty function by default, but provided so that you can perform a custom action
20202 * after a valid drop has occurred by providing an implementation.
20203 * @param {Object} target The target DD
20204 * @param {Event} e The event object
20205 * @param {String} id The id of the dropped element
20206 * @method afterInvalidDrop
20208 this.afterValidDrop(target, e, id);
20213 getRepairXY : function(e, data){
20214 return this.el.getXY();
20218 onInvalidDrop : function(target, e, id){
20219 this.beforeInvalidDrop(target, e, id);
20220 if(this.cachedTarget){
20221 if(this.cachedTarget.isNotifyTarget){
20222 this.cachedTarget.notifyOut(this, e, this.dragData);
20224 this.cacheTarget = null;
20226 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20228 if(this.afterInvalidDrop){
20230 * An empty function by default, but provided so that you can perform a custom action
20231 * after an invalid drop has occurred by providing an implementation.
20232 * @param {Event} e The event object
20233 * @param {String} id The id of the dropped element
20234 * @method afterInvalidDrop
20236 this.afterInvalidDrop(e, id);
20241 afterRepair : function(){
20243 this.el.highlight(this.hlColor || "c3daf9");
20245 this.dragging = false;
20249 * An empty function by default, but provided so that you can perform a custom action after an invalid
20250 * drop has occurred.
20251 * @param {Roo.dd.DragDrop} target The drop target
20252 * @param {Event} e The event object
20253 * @param {String} id The id of the dragged element
20254 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20256 beforeInvalidDrop : function(target, e, id){
20261 handleMouseDown : function(e){
20262 if(this.dragging) {
20265 var data = this.getDragData(e);
20266 if(data && this.onBeforeDrag(data, e) !== false){
20267 this.dragData = data;
20269 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20274 * An empty function by default, but provided so that you can perform a custom action before the initial
20275 * drag event begins and optionally cancel it.
20276 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20277 * @param {Event} e The event object
20278 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20280 onBeforeDrag : function(data, e){
20285 * An empty function by default, but provided so that you can perform a custom action once the initial
20286 * drag event has begun. The drag cannot be canceled from this function.
20287 * @param {Number} x The x position of the click on the dragged object
20288 * @param {Number} y The y position of the click on the dragged object
20290 onStartDrag : Roo.emptyFn,
20292 // private - YUI override
20293 startDrag : function(x, y){
20294 this.proxy.reset();
20295 this.dragging = true;
20296 this.proxy.update("");
20297 this.onInitDrag(x, y);
20302 onInitDrag : function(x, y){
20303 var clone = this.el.dom.cloneNode(true);
20304 clone.id = Roo.id(); // prevent duplicate ids
20305 this.proxy.update(clone);
20306 this.onStartDrag(x, y);
20311 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20312 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20314 getProxy : function(){
20319 * Hides the drag source's {@link Roo.dd.StatusProxy}
20321 hideProxy : function(){
20323 this.proxy.reset(true);
20324 this.dragging = false;
20328 triggerCacheRefresh : function(){
20329 Roo.dd.DDM.refreshCache(this.groups);
20332 // private - override to prevent hiding
20333 b4EndDrag: function(e) {
20336 // private - override to prevent moving
20337 endDrag : function(e){
20338 this.onEndDrag(this.dragData, e);
20342 onEndDrag : function(data, e){
20345 // private - pin to cursor
20346 autoOffset : function(x, y) {
20347 this.setDelta(-12, -20);
20351 * Ext JS Library 1.1.1
20352 * Copyright(c) 2006-2007, Ext JS, LLC.
20354 * Originally Released Under LGPL - original licence link has changed is not relivant.
20357 * <script type="text/javascript">
20362 * @class Roo.dd.DropTarget
20363 * @extends Roo.dd.DDTarget
20364 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20365 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20367 * @param {String/HTMLElement/Element} el The container element
20368 * @param {Object} config
20370 Roo.dd.DropTarget = function(el, config){
20371 this.el = Roo.get(el);
20373 var listeners = false; ;
20374 if (config && config.listeners) {
20375 listeners= config.listeners;
20376 delete config.listeners;
20378 Roo.apply(this, config);
20380 if(this.containerScroll){
20381 Roo.dd.ScrollManager.register(this.el);
20385 * @scope Roo.dd.DropTarget
20390 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20391 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20392 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20394 * IMPORTANT : it should set this.overClass and this.dropAllowed
20396 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20397 * @param {Event} e The event
20398 * @param {Object} data An object containing arbitrary data supplied by the drag source
20404 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20405 * This method will be called on every mouse movement while the drag source is over the drop target.
20406 * This default implementation simply returns the dropAllowed config value.
20408 * IMPORTANT : it should set this.dropAllowed
20410 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20411 * @param {Event} e The event
20412 * @param {Object} data An object containing arbitrary data supplied by the drag source
20418 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20419 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20420 * overClass (if any) from the drop element.
20422 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20423 * @param {Event} e The event
20424 * @param {Object} data An object containing arbitrary data supplied by the drag source
20430 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20431 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20432 * implementation that does something to process the drop event and returns true so that the drag source's
20433 * repair action does not run.
20435 * IMPORTANT : it should set this.success
20437 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20438 * @param {Event} e The event
20439 * @param {Object} data An object containing arbitrary data supplied by the drag source
20445 Roo.dd.DropTarget.superclass.constructor.call( this,
20447 this.ddGroup || this.group,
20450 listeners : listeners || {}
20458 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20460 * @cfg {String} overClass
20461 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20464 * @cfg {String} ddGroup
20465 * The drag drop group to handle drop events for
20469 * @cfg {String} dropAllowed
20470 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20472 dropAllowed : "x-dd-drop-ok",
20474 * @cfg {String} dropNotAllowed
20475 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20477 dropNotAllowed : "x-dd-drop-nodrop",
20479 * @cfg {boolean} success
20480 * set this after drop listener..
20484 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20485 * if the drop point is valid for over/enter..
20492 isNotifyTarget : true,
20497 notifyEnter : function(dd, e, data)
20500 this.fireEvent('enter', dd, e, data);
20501 if(this.overClass){
20502 this.el.addClass(this.overClass);
20504 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20505 this.valid ? this.dropAllowed : this.dropNotAllowed
20512 notifyOver : function(dd, e, data)
20515 this.fireEvent('over', dd, e, data);
20516 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20517 this.valid ? this.dropAllowed : this.dropNotAllowed
20524 notifyOut : function(dd, e, data)
20526 this.fireEvent('out', dd, e, data);
20527 if(this.overClass){
20528 this.el.removeClass(this.overClass);
20535 notifyDrop : function(dd, e, data)
20537 this.success = false;
20538 this.fireEvent('drop', dd, e, data);
20539 return this.success;
20543 * Ext JS Library 1.1.1
20544 * Copyright(c) 2006-2007, Ext JS, LLC.
20546 * Originally Released Under LGPL - original licence link has changed is not relivant.
20549 * <script type="text/javascript">
20554 * @class Roo.dd.DragZone
20555 * @extends Roo.dd.DragSource
20556 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20557 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20559 * @param {String/HTMLElement/Element} el The container element
20560 * @param {Object} config
20562 Roo.dd.DragZone = function(el, config){
20563 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20564 if(this.containerScroll){
20565 Roo.dd.ScrollManager.register(this.el);
20569 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20571 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20572 * for auto scrolling during drag operations.
20575 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20576 * method after a failed drop (defaults to "c3daf9" - light blue)
20580 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20581 * for a valid target to drag based on the mouse down. Override this method
20582 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20583 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20584 * @param {EventObject} e The mouse down event
20585 * @return {Object} The dragData
20587 getDragData : function(e){
20588 return Roo.dd.Registry.getHandleFromEvent(e);
20592 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20593 * this.dragData.ddel
20594 * @param {Number} x The x position of the click on the dragged object
20595 * @param {Number} y The y position of the click on the dragged object
20596 * @return {Boolean} true to continue the drag, false to cancel
20598 onInitDrag : function(x, y){
20599 this.proxy.update(this.dragData.ddel.cloneNode(true));
20600 this.onStartDrag(x, y);
20605 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20607 afterRepair : function(){
20609 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20611 this.dragging = false;
20615 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20616 * the XY of this.dragData.ddel
20617 * @param {EventObject} e The mouse up event
20618 * @return {Array} The xy location (e.g. [100, 200])
20620 getRepairXY : function(e){
20621 return Roo.Element.fly(this.dragData.ddel).getXY();
20625 * Ext JS Library 1.1.1
20626 * Copyright(c) 2006-2007, Ext JS, LLC.
20628 * Originally Released Under LGPL - original licence link has changed is not relivant.
20631 * <script type="text/javascript">
20634 * @class Roo.dd.DropZone
20635 * @extends Roo.dd.DropTarget
20636 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20637 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20639 * @param {String/HTMLElement/Element} el The container element
20640 * @param {Object} config
20642 Roo.dd.DropZone = function(el, config){
20643 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20646 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20648 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20649 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20650 * provide your own custom lookup.
20651 * @param {Event} e The event
20652 * @return {Object} data The custom data
20654 getTargetFromEvent : function(e){
20655 return Roo.dd.Registry.getTargetFromEvent(e);
20659 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20660 * that it has registered. This method has no default implementation and should be overridden to provide
20661 * node-specific processing if necessary.
20662 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20663 * {@link #getTargetFromEvent} for this node)
20664 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20665 * @param {Event} e The event
20666 * @param {Object} data An object containing arbitrary data supplied by the drag source
20668 onNodeEnter : function(n, dd, e, data){
20673 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20674 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20675 * overridden to provide the proper feedback.
20676 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20677 * {@link #getTargetFromEvent} for this node)
20678 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20679 * @param {Event} e The event
20680 * @param {Object} data An object containing arbitrary data supplied by the drag source
20681 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20682 * underlying {@link Roo.dd.StatusProxy} can be updated
20684 onNodeOver : function(n, dd, e, data){
20685 return this.dropAllowed;
20689 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20690 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20691 * node-specific processing if necessary.
20692 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20693 * {@link #getTargetFromEvent} for this node)
20694 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20695 * @param {Event} e The event
20696 * @param {Object} data An object containing arbitrary data supplied by the drag source
20698 onNodeOut : function(n, dd, e, data){
20703 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20704 * the drop node. The default implementation returns false, so it should be overridden to provide the
20705 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20706 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20707 * {@link #getTargetFromEvent} for this node)
20708 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20709 * @param {Event} e The event
20710 * @param {Object} data An object containing arbitrary data supplied by the drag source
20711 * @return {Boolean} True if the drop was valid, else false
20713 onNodeDrop : function(n, dd, e, data){
20718 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20719 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20720 * it should be overridden to provide the proper feedback if necessary.
20721 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20722 * @param {Event} e The event
20723 * @param {Object} data An object containing arbitrary data supplied by the drag source
20724 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20725 * underlying {@link Roo.dd.StatusProxy} can be updated
20727 onContainerOver : function(dd, e, data){
20728 return this.dropNotAllowed;
20732 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20733 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20734 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20735 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20736 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20737 * @param {Event} e The event
20738 * @param {Object} data An object containing arbitrary data supplied by the drag source
20739 * @return {Boolean} True if the drop was valid, else false
20741 onContainerDrop : function(dd, e, data){
20746 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20747 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20748 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20749 * you should override this method and provide a custom implementation.
20750 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20751 * @param {Event} e The event
20752 * @param {Object} data An object containing arbitrary data supplied by the drag source
20753 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20754 * underlying {@link Roo.dd.StatusProxy} can be updated
20756 notifyEnter : function(dd, e, data){
20757 return this.dropNotAllowed;
20761 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20762 * This method will be called on every mouse movement while the drag source is over the drop zone.
20763 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20764 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20765 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20766 * registered node, it will call {@link #onContainerOver}.
20767 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20768 * @param {Event} e The event
20769 * @param {Object} data An object containing arbitrary data supplied by the drag source
20770 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20771 * underlying {@link Roo.dd.StatusProxy} can be updated
20773 notifyOver : function(dd, e, data){
20774 var n = this.getTargetFromEvent(e);
20775 if(!n){ // not over valid drop target
20776 if(this.lastOverNode){
20777 this.onNodeOut(this.lastOverNode, dd, e, data);
20778 this.lastOverNode = null;
20780 return this.onContainerOver(dd, e, data);
20782 if(this.lastOverNode != n){
20783 if(this.lastOverNode){
20784 this.onNodeOut(this.lastOverNode, dd, e, data);
20786 this.onNodeEnter(n, dd, e, data);
20787 this.lastOverNode = n;
20789 return this.onNodeOver(n, dd, e, data);
20793 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20794 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20795 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20796 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20797 * @param {Event} e The event
20798 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20800 notifyOut : function(dd, e, data){
20801 if(this.lastOverNode){
20802 this.onNodeOut(this.lastOverNode, dd, e, data);
20803 this.lastOverNode = null;
20808 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20809 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20810 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20811 * otherwise it will call {@link #onContainerDrop}.
20812 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20813 * @param {Event} e The event
20814 * @param {Object} data An object containing arbitrary data supplied by the drag source
20815 * @return {Boolean} True if the drop was valid, else false
20817 notifyDrop : function(dd, e, data){
20818 if(this.lastOverNode){
20819 this.onNodeOut(this.lastOverNode, dd, e, data);
20820 this.lastOverNode = null;
20822 var n = this.getTargetFromEvent(e);
20824 this.onNodeDrop(n, dd, e, data) :
20825 this.onContainerDrop(dd, e, data);
20829 triggerCacheRefresh : function(){
20830 Roo.dd.DDM.refreshCache(this.groups);
20834 * Ext JS Library 1.1.1
20835 * Copyright(c) 2006-2007, Ext JS, LLC.
20837 * Originally Released Under LGPL - original licence link has changed is not relivant.
20840 * <script type="text/javascript">
20845 * @class Roo.data.SortTypes
20847 * Defines the default sorting (casting?) comparison functions used when sorting data.
20849 Roo.data.SortTypes = {
20851 * Default sort that does nothing
20852 * @param {Mixed} s The value being converted
20853 * @return {Mixed} The comparison value
20855 none : function(s){
20860 * The regular expression used to strip tags
20864 stripTagsRE : /<\/?[^>]+>/gi,
20867 * Strips all HTML tags to sort on text only
20868 * @param {Mixed} s The value being converted
20869 * @return {String} The comparison value
20871 asText : function(s){
20872 return String(s).replace(this.stripTagsRE, "");
20876 * Strips all HTML tags to sort on text only - Case insensitive
20877 * @param {Mixed} s The value being converted
20878 * @return {String} The comparison value
20880 asUCText : function(s){
20881 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20885 * Case insensitive string
20886 * @param {Mixed} s The value being converted
20887 * @return {String} The comparison value
20889 asUCString : function(s) {
20890 return String(s).toUpperCase();
20895 * @param {Mixed} s The value being converted
20896 * @return {Number} The comparison value
20898 asDate : function(s) {
20902 if(s instanceof Date){
20903 return s.getTime();
20905 return Date.parse(String(s));
20910 * @param {Mixed} s The value being converted
20911 * @return {Float} The comparison value
20913 asFloat : function(s) {
20914 var val = parseFloat(String(s).replace(/,/g, ""));
20915 if(isNaN(val)) val = 0;
20921 * @param {Mixed} s The value being converted
20922 * @return {Number} The comparison value
20924 asInt : function(s) {
20925 var val = parseInt(String(s).replace(/,/g, ""));
20926 if(isNaN(val)) val = 0;
20931 * Ext JS Library 1.1.1
20932 * Copyright(c) 2006-2007, Ext JS, LLC.
20934 * Originally Released Under LGPL - original licence link has changed is not relivant.
20937 * <script type="text/javascript">
20941 * @class Roo.data.Record
20942 * Instances of this class encapsulate both record <em>definition</em> information, and record
20943 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20944 * to access Records cached in an {@link Roo.data.Store} object.<br>
20946 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20947 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20950 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20952 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20953 * {@link #create}. The parameters are the same.
20954 * @param {Array} data An associative Array of data values keyed by the field name.
20955 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20956 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20957 * not specified an integer id is generated.
20959 Roo.data.Record = function(data, id){
20960 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20965 * Generate a constructor for a specific record layout.
20966 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20967 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20968 * Each field definition object may contain the following properties: <ul>
20969 * <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,
20970 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20971 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20972 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20973 * is being used, then this is a string containing the javascript expression to reference the data relative to
20974 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20975 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20976 * this may be omitted.</p></li>
20977 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20978 * <ul><li>auto (Default, implies no conversion)</li>
20983 * <li>date</li></ul></p></li>
20984 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20985 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20986 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20987 * by the Reader into an object that will be stored in the Record. It is passed the
20988 * following parameters:<ul>
20989 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20991 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20993 * <br>usage:<br><pre><code>
20994 var TopicRecord = Roo.data.Record.create(
20995 {name: 'title', mapping: 'topic_title'},
20996 {name: 'author', mapping: 'username'},
20997 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20998 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20999 {name: 'lastPoster', mapping: 'user2'},
21000 {name: 'excerpt', mapping: 'post_text'}
21003 var myNewRecord = new TopicRecord({
21004 title: 'Do my job please',
21007 lastPost: new Date(),
21008 lastPoster: 'Animal',
21009 excerpt: 'No way dude!'
21011 myStore.add(myNewRecord);
21016 Roo.data.Record.create = function(o){
21017 var f = function(){
21018 f.superclass.constructor.apply(this, arguments);
21020 Roo.extend(f, Roo.data.Record);
21021 var p = f.prototype;
21022 p.fields = new Roo.util.MixedCollection(false, function(field){
21025 for(var i = 0, len = o.length; i < len; i++){
21026 p.fields.add(new Roo.data.Field(o[i]));
21028 f.getField = function(name){
21029 return p.fields.get(name);
21034 Roo.data.Record.AUTO_ID = 1000;
21035 Roo.data.Record.EDIT = 'edit';
21036 Roo.data.Record.REJECT = 'reject';
21037 Roo.data.Record.COMMIT = 'commit';
21039 Roo.data.Record.prototype = {
21041 * Readonly flag - true if this record has been modified.
21050 join : function(store){
21051 this.store = store;
21055 * Set the named field to the specified value.
21056 * @param {String} name The name of the field to set.
21057 * @param {Object} value The value to set the field to.
21059 set : function(name, value){
21060 if(this.data[name] == value){
21064 if(!this.modified){
21065 this.modified = {};
21067 if(typeof this.modified[name] == 'undefined'){
21068 this.modified[name] = this.data[name];
21070 this.data[name] = value;
21071 if(!this.editing && this.store){
21072 this.store.afterEdit(this);
21077 * Get the value of the named field.
21078 * @param {String} name The name of the field to get the value of.
21079 * @return {Object} The value of the field.
21081 get : function(name){
21082 return this.data[name];
21086 beginEdit : function(){
21087 this.editing = true;
21088 this.modified = {};
21092 cancelEdit : function(){
21093 this.editing = false;
21094 delete this.modified;
21098 endEdit : function(){
21099 this.editing = false;
21100 if(this.dirty && this.store){
21101 this.store.afterEdit(this);
21106 * Usually called by the {@link Roo.data.Store} which owns the Record.
21107 * Rejects all changes made to the Record since either creation, or the last commit operation.
21108 * Modified fields are reverted to their original values.
21110 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21111 * of reject operations.
21113 reject : function(){
21114 var m = this.modified;
21116 if(typeof m[n] != "function"){
21117 this.data[n] = m[n];
21120 this.dirty = false;
21121 delete this.modified;
21122 this.editing = false;
21124 this.store.afterReject(this);
21129 * Usually called by the {@link Roo.data.Store} which owns the Record.
21130 * Commits all changes made to the Record since either creation, or the last commit operation.
21132 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21133 * of commit operations.
21135 commit : function(){
21136 this.dirty = false;
21137 delete this.modified;
21138 this.editing = false;
21140 this.store.afterCommit(this);
21145 hasError : function(){
21146 return this.error != null;
21150 clearError : function(){
21155 * Creates a copy of this record.
21156 * @param {String} id (optional) A new record id if you don't want to use this record's id
21159 copy : function(newId) {
21160 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21164 * Ext JS Library 1.1.1
21165 * Copyright(c) 2006-2007, Ext JS, LLC.
21167 * Originally Released Under LGPL - original licence link has changed is not relivant.
21170 * <script type="text/javascript">
21176 * @class Roo.data.Store
21177 * @extends Roo.util.Observable
21178 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21179 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21181 * 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
21182 * has no knowledge of the format of the data returned by the Proxy.<br>
21184 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21185 * instances from the data object. These records are cached and made available through accessor functions.
21187 * Creates a new Store.
21188 * @param {Object} config A config object containing the objects needed for the Store to access data,
21189 * and read the data into Records.
21191 Roo.data.Store = function(config){
21192 this.data = new Roo.util.MixedCollection(false);
21193 this.data.getKey = function(o){
21196 this.baseParams = {};
21198 this.paramNames = {
21203 "multisort" : "_multisort"
21206 if(config && config.data){
21207 this.inlineData = config.data;
21208 delete config.data;
21211 Roo.apply(this, config);
21213 if(this.reader){ // reader passed
21214 this.reader = Roo.factory(this.reader, Roo.data);
21215 this.reader.xmodule = this.xmodule || false;
21216 if(!this.recordType){
21217 this.recordType = this.reader.recordType;
21219 if(this.reader.onMetaChange){
21220 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21224 if(this.recordType){
21225 this.fields = this.recordType.prototype.fields;
21227 this.modified = [];
21231 * @event datachanged
21232 * Fires when the data cache has changed, and a widget which is using this Store
21233 * as a Record cache should refresh its view.
21234 * @param {Store} this
21236 datachanged : true,
21238 * @event metachange
21239 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21240 * @param {Store} this
21241 * @param {Object} meta The JSON metadata
21246 * Fires when Records have been added to the Store
21247 * @param {Store} this
21248 * @param {Roo.data.Record[]} records The array of Records added
21249 * @param {Number} index The index at which the record(s) were added
21254 * Fires when a Record has been removed from the Store
21255 * @param {Store} this
21256 * @param {Roo.data.Record} record The Record that was removed
21257 * @param {Number} index The index at which the record was removed
21262 * Fires when a Record has been updated
21263 * @param {Store} this
21264 * @param {Roo.data.Record} record The Record that was updated
21265 * @param {String} operation The update operation being performed. Value may be one of:
21267 Roo.data.Record.EDIT
21268 Roo.data.Record.REJECT
21269 Roo.data.Record.COMMIT
21275 * Fires when the data cache has been cleared.
21276 * @param {Store} this
21280 * @event beforeload
21281 * Fires before a request is made for a new data object. If the beforeload handler returns false
21282 * the load action will be canceled.
21283 * @param {Store} this
21284 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21288 * @event beforeloadadd
21289 * Fires after a new set of Records has been loaded.
21290 * @param {Store} this
21291 * @param {Roo.data.Record[]} records The Records that were loaded
21292 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21294 beforeloadadd : true,
21297 * Fires after a new set of Records has been loaded, before they are added to the store.
21298 * @param {Store} this
21299 * @param {Roo.data.Record[]} records The Records that were loaded
21300 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21301 * @params {Object} return from reader
21305 * @event loadexception
21306 * Fires if an exception occurs in the Proxy during loading.
21307 * Called with the signature of the Proxy's "loadexception" event.
21308 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21311 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21312 * @param {Object} load options
21313 * @param {Object} jsonData from your request (normally this contains the Exception)
21315 loadexception : true
21319 this.proxy = Roo.factory(this.proxy, Roo.data);
21320 this.proxy.xmodule = this.xmodule || false;
21321 this.relayEvents(this.proxy, ["loadexception"]);
21323 this.sortToggle = {};
21324 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21326 Roo.data.Store.superclass.constructor.call(this);
21328 if(this.inlineData){
21329 this.loadData(this.inlineData);
21330 delete this.inlineData;
21334 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21336 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21337 * without a remote query - used by combo/forms at present.
21341 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21344 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21347 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21348 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21351 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21352 * on any HTTP request
21355 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21358 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21362 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21363 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21365 remoteSort : false,
21368 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21369 * loaded or when a record is removed. (defaults to false).
21371 pruneModifiedRecords : false,
21374 lastOptions : null,
21377 * Add Records to the Store and fires the add event.
21378 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21380 add : function(records){
21381 records = [].concat(records);
21382 for(var i = 0, len = records.length; i < len; i++){
21383 records[i].join(this);
21385 var index = this.data.length;
21386 this.data.addAll(records);
21387 this.fireEvent("add", this, records, index);
21391 * Remove a Record from the Store and fires the remove event.
21392 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21394 remove : function(record){
21395 var index = this.data.indexOf(record);
21396 this.data.removeAt(index);
21397 if(this.pruneModifiedRecords){
21398 this.modified.remove(record);
21400 this.fireEvent("remove", this, record, index);
21404 * Remove all Records from the Store and fires the clear event.
21406 removeAll : function(){
21408 if(this.pruneModifiedRecords){
21409 this.modified = [];
21411 this.fireEvent("clear", this);
21415 * Inserts Records to the Store at the given index and fires the add event.
21416 * @param {Number} index The start index at which to insert the passed Records.
21417 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21419 insert : function(index, records){
21420 records = [].concat(records);
21421 for(var i = 0, len = records.length; i < len; i++){
21422 this.data.insert(index, records[i]);
21423 records[i].join(this);
21425 this.fireEvent("add", this, records, index);
21429 * Get the index within the cache of the passed Record.
21430 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21431 * @return {Number} The index of the passed Record. Returns -1 if not found.
21433 indexOf : function(record){
21434 return this.data.indexOf(record);
21438 * Get the index within the cache of the Record with the passed id.
21439 * @param {String} id The id of the Record to find.
21440 * @return {Number} The index of the Record. Returns -1 if not found.
21442 indexOfId : function(id){
21443 return this.data.indexOfKey(id);
21447 * Get the Record with the specified id.
21448 * @param {String} id The id of the Record to find.
21449 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21451 getById : function(id){
21452 return this.data.key(id);
21456 * Get the Record at the specified index.
21457 * @param {Number} index The index of the Record to find.
21458 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21460 getAt : function(index){
21461 return this.data.itemAt(index);
21465 * Returns a range of Records between specified indices.
21466 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21467 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21468 * @return {Roo.data.Record[]} An array of Records
21470 getRange : function(start, end){
21471 return this.data.getRange(start, end);
21475 storeOptions : function(o){
21476 o = Roo.apply({}, o);
21479 this.lastOptions = o;
21483 * Loads the Record cache from the configured Proxy using the configured Reader.
21485 * If using remote paging, then the first load call must specify the <em>start</em>
21486 * and <em>limit</em> properties in the options.params property to establish the initial
21487 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21489 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21490 * and this call will return before the new data has been loaded. Perform any post-processing
21491 * in a callback function, or in a "load" event handler.</strong>
21493 * @param {Object} options An object containing properties which control loading options:<ul>
21494 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21495 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21496 * passed the following arguments:<ul>
21497 * <li>r : Roo.data.Record[]</li>
21498 * <li>options: Options object from the load call</li>
21499 * <li>success: Boolean success indicator</li></ul></li>
21500 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21501 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21504 load : function(options){
21505 options = options || {};
21506 if(this.fireEvent("beforeload", this, options) !== false){
21507 this.storeOptions(options);
21508 var p = Roo.apply(options.params || {}, this.baseParams);
21509 // if meta was not loaded from remote source.. try requesting it.
21510 if (!this.reader.metaFromRemote) {
21511 p._requestMeta = 1;
21513 if(this.sortInfo && this.remoteSort){
21514 var pn = this.paramNames;
21515 p[pn["sort"]] = this.sortInfo.field;
21516 p[pn["dir"]] = this.sortInfo.direction;
21518 if (this.multiSort) {
21519 var pn = this.paramNames;
21520 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21523 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21528 * Reloads the Record cache from the configured Proxy using the configured Reader and
21529 * the options from the last load operation performed.
21530 * @param {Object} options (optional) An object containing properties which may override the options
21531 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21532 * the most recently used options are reused).
21534 reload : function(options){
21535 this.load(Roo.applyIf(options||{}, this.lastOptions));
21539 // Called as a callback by the Reader during a load operation.
21540 loadRecords : function(o, options, success){
21541 if(!o || success === false){
21542 if(success !== false){
21543 this.fireEvent("load", this, [], options, o);
21545 if(options.callback){
21546 options.callback.call(options.scope || this, [], options, false);
21550 // if data returned failure - throw an exception.
21551 if (o.success === false) {
21552 // show a message if no listener is registered.
21553 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21554 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21556 // loadmask wil be hooked into this..
21557 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21560 var r = o.records, t = o.totalRecords || r.length;
21562 this.fireEvent("beforeloadadd", this, r, options, o);
21564 if(!options || options.add !== true){
21565 if(this.pruneModifiedRecords){
21566 this.modified = [];
21568 for(var i = 0, len = r.length; i < len; i++){
21572 this.data = this.snapshot;
21573 delete this.snapshot;
21576 this.data.addAll(r);
21577 this.totalLength = t;
21579 this.fireEvent("datachanged", this);
21581 this.totalLength = Math.max(t, this.data.length+r.length);
21584 this.fireEvent("load", this, r, options, o);
21585 if(options.callback){
21586 options.callback.call(options.scope || this, r, options, true);
21592 * Loads data from a passed data block. A Reader which understands the format of the data
21593 * must have been configured in the constructor.
21594 * @param {Object} data The data block from which to read the Records. The format of the data expected
21595 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21596 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21598 loadData : function(o, append){
21599 var r = this.reader.readRecords(o);
21600 this.loadRecords(r, {add: append}, true);
21604 * Gets the number of cached records.
21606 * <em>If using paging, this may not be the total size of the dataset. If the data object
21607 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21608 * the data set size</em>
21610 getCount : function(){
21611 return this.data.length || 0;
21615 * Gets the total number of records in the dataset as returned by the server.
21617 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21618 * the dataset size</em>
21620 getTotalCount : function(){
21621 return this.totalLength || 0;
21625 * Returns the sort state of the Store as an object with two properties:
21627 field {String} The name of the field by which the Records are sorted
21628 direction {String} The sort order, "ASC" or "DESC"
21631 getSortState : function(){
21632 return this.sortInfo;
21636 applySort : function(){
21637 if(this.sortInfo && !this.remoteSort){
21638 var s = this.sortInfo, f = s.field;
21639 var st = this.fields.get(f).sortType;
21640 var fn = function(r1, r2){
21641 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21642 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21644 this.data.sort(s.direction, fn);
21645 if(this.snapshot && this.snapshot != this.data){
21646 this.snapshot.sort(s.direction, fn);
21652 * Sets the default sort column and order to be used by the next load operation.
21653 * @param {String} fieldName The name of the field to sort by.
21654 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21656 setDefaultSort : function(field, dir){
21657 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21661 * Sort the Records.
21662 * If remote sorting is used, the sort is performed on the server, and the cache is
21663 * reloaded. If local sorting is used, the cache is sorted internally.
21664 * @param {String} fieldName The name of the field to sort by.
21665 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21667 sort : function(fieldName, dir){
21668 var f = this.fields.get(fieldName);
21670 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21672 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21673 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21678 this.sortToggle[f.name] = dir;
21679 this.sortInfo = {field: f.name, direction: dir};
21680 if(!this.remoteSort){
21682 this.fireEvent("datachanged", this);
21684 this.load(this.lastOptions);
21689 * Calls the specified function for each of the Records in the cache.
21690 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21691 * Returning <em>false</em> aborts and exits the iteration.
21692 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21694 each : function(fn, scope){
21695 this.data.each(fn, scope);
21699 * Gets all records modified since the last commit. Modified records are persisted across load operations
21700 * (e.g., during paging).
21701 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21703 getModifiedRecords : function(){
21704 return this.modified;
21708 createFilterFn : function(property, value, anyMatch){
21709 if(!value.exec){ // not a regex
21710 value = String(value);
21711 if(value.length == 0){
21714 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21716 return function(r){
21717 return value.test(r.data[property]);
21722 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21723 * @param {String} property A field on your records
21724 * @param {Number} start The record index to start at (defaults to 0)
21725 * @param {Number} end The last record index to include (defaults to length - 1)
21726 * @return {Number} The sum
21728 sum : function(property, start, end){
21729 var rs = this.data.items, v = 0;
21730 start = start || 0;
21731 end = (end || end === 0) ? end : rs.length-1;
21733 for(var i = start; i <= end; i++){
21734 v += (rs[i].data[property] || 0);
21740 * Filter the records by a specified property.
21741 * @param {String} field A field on your records
21742 * @param {String/RegExp} value Either a string that the field
21743 * should start with or a RegExp to test against the field
21744 * @param {Boolean} anyMatch True to match any part not just the beginning
21746 filter : function(property, value, anyMatch){
21747 var fn = this.createFilterFn(property, value, anyMatch);
21748 return fn ? this.filterBy(fn) : this.clearFilter();
21752 * Filter by a function. The specified function will be called with each
21753 * record in this data source. If the function returns true the record is included,
21754 * otherwise it is filtered.
21755 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21756 * @param {Object} scope (optional) The scope of the function (defaults to this)
21758 filterBy : function(fn, scope){
21759 this.snapshot = this.snapshot || this.data;
21760 this.data = this.queryBy(fn, scope||this);
21761 this.fireEvent("datachanged", this);
21765 * Query the records by a specified property.
21766 * @param {String} field A field on your records
21767 * @param {String/RegExp} value Either a string that the field
21768 * should start with or a RegExp to test against the field
21769 * @param {Boolean} anyMatch True to match any part not just the beginning
21770 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21772 query : function(property, value, anyMatch){
21773 var fn = this.createFilterFn(property, value, anyMatch);
21774 return fn ? this.queryBy(fn) : this.data.clone();
21778 * Query by a function. The specified function will be called with each
21779 * record in this data source. If the function returns true the record is included
21781 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21782 * @param {Object} scope (optional) The scope of the function (defaults to this)
21783 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21785 queryBy : function(fn, scope){
21786 var data = this.snapshot || this.data;
21787 return data.filterBy(fn, scope||this);
21791 * Collects unique values for a particular dataIndex from this store.
21792 * @param {String} dataIndex The property to collect
21793 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21794 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21795 * @return {Array} An array of the unique values
21797 collect : function(dataIndex, allowNull, bypassFilter){
21798 var d = (bypassFilter === true && this.snapshot) ?
21799 this.snapshot.items : this.data.items;
21800 var v, sv, r = [], l = {};
21801 for(var i = 0, len = d.length; i < len; i++){
21802 v = d[i].data[dataIndex];
21804 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21813 * Revert to a view of the Record cache with no filtering applied.
21814 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21816 clearFilter : function(suppressEvent){
21817 if(this.snapshot && this.snapshot != this.data){
21818 this.data = this.snapshot;
21819 delete this.snapshot;
21820 if(suppressEvent !== true){
21821 this.fireEvent("datachanged", this);
21827 afterEdit : function(record){
21828 if(this.modified.indexOf(record) == -1){
21829 this.modified.push(record);
21831 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21835 afterReject : function(record){
21836 this.modified.remove(record);
21837 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21841 afterCommit : function(record){
21842 this.modified.remove(record);
21843 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21847 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21848 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21850 commitChanges : function(){
21851 var m = this.modified.slice(0);
21852 this.modified = [];
21853 for(var i = 0, len = m.length; i < len; i++){
21859 * Cancel outstanding changes on all changed records.
21861 rejectChanges : function(){
21862 var m = this.modified.slice(0);
21863 this.modified = [];
21864 for(var i = 0, len = m.length; i < len; i++){
21869 onMetaChange : function(meta, rtype, o){
21870 this.recordType = rtype;
21871 this.fields = rtype.prototype.fields;
21872 delete this.snapshot;
21873 this.sortInfo = meta.sortInfo || this.sortInfo;
21874 this.modified = [];
21875 this.fireEvent('metachange', this, this.reader.meta);
21878 moveIndex : function(data, type)
21880 var index = this.indexOf(data);
21882 var newIndex = index + type;
21886 this.insert(newIndex, data);
21891 * Ext JS Library 1.1.1
21892 * Copyright(c) 2006-2007, Ext JS, LLC.
21894 * Originally Released Under LGPL - original licence link has changed is not relivant.
21897 * <script type="text/javascript">
21901 * @class Roo.data.SimpleStore
21902 * @extends Roo.data.Store
21903 * Small helper class to make creating Stores from Array data easier.
21904 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21905 * @cfg {Array} fields An array of field definition objects, or field name strings.
21906 * @cfg {Array} data The multi-dimensional array of data
21908 * @param {Object} config
21910 Roo.data.SimpleStore = function(config){
21911 Roo.data.SimpleStore.superclass.constructor.call(this, {
21913 reader: new Roo.data.ArrayReader({
21916 Roo.data.Record.create(config.fields)
21918 proxy : new Roo.data.MemoryProxy(config.data)
21922 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21924 * Ext JS Library 1.1.1
21925 * Copyright(c) 2006-2007, Ext JS, LLC.
21927 * Originally Released Under LGPL - original licence link has changed is not relivant.
21930 * <script type="text/javascript">
21935 * @extends Roo.data.Store
21936 * @class Roo.data.JsonStore
21937 * Small helper class to make creating Stores for JSON data easier. <br/>
21939 var store = new Roo.data.JsonStore({
21940 url: 'get-images.php',
21942 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21945 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21946 * JsonReader and HttpProxy (unless inline data is provided).</b>
21947 * @cfg {Array} fields An array of field definition objects, or field name strings.
21949 * @param {Object} config
21951 Roo.data.JsonStore = function(c){
21952 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21953 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21954 reader: new Roo.data.JsonReader(c, c.fields)
21957 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21959 * Ext JS Library 1.1.1
21960 * Copyright(c) 2006-2007, Ext JS, LLC.
21962 * Originally Released Under LGPL - original licence link has changed is not relivant.
21965 * <script type="text/javascript">
21969 Roo.data.Field = function(config){
21970 if(typeof config == "string"){
21971 config = {name: config};
21973 Roo.apply(this, config);
21976 this.type = "auto";
21979 var st = Roo.data.SortTypes;
21980 // named sortTypes are supported, here we look them up
21981 if(typeof this.sortType == "string"){
21982 this.sortType = st[this.sortType];
21985 // set default sortType for strings and dates
21986 if(!this.sortType){
21989 this.sortType = st.asUCString;
21992 this.sortType = st.asDate;
21995 this.sortType = st.none;
22000 var stripRe = /[\$,%]/g;
22002 // prebuilt conversion function for this field, instead of
22003 // switching every time we're reading a value
22005 var cv, dateFormat = this.dateFormat;
22010 cv = function(v){ return v; };
22013 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
22017 return v !== undefined && v !== null && v !== '' ?
22018 parseInt(String(v).replace(stripRe, ""), 10) : '';
22023 return v !== undefined && v !== null && v !== '' ?
22024 parseFloat(String(v).replace(stripRe, ""), 10) : '';
22029 cv = function(v){ return v === true || v === "true" || v == 1; };
22036 if(v instanceof Date){
22040 if(dateFormat == "timestamp"){
22041 return new Date(v*1000);
22043 return Date.parseDate(v, dateFormat);
22045 var parsed = Date.parse(v);
22046 return parsed ? new Date(parsed) : null;
22055 Roo.data.Field.prototype = {
22063 * Ext JS Library 1.1.1
22064 * Copyright(c) 2006-2007, Ext JS, LLC.
22066 * Originally Released Under LGPL - original licence link has changed is not relivant.
22069 * <script type="text/javascript">
22072 // Base class for reading structured data from a data source. This class is intended to be
22073 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
22076 * @class Roo.data.DataReader
22077 * Base class for reading structured data from a data source. This class is intended to be
22078 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
22081 Roo.data.DataReader = function(meta, recordType){
22085 this.recordType = recordType instanceof Array ?
22086 Roo.data.Record.create(recordType) : recordType;
22089 Roo.data.DataReader.prototype = {
22091 * Create an empty record
22092 * @param {Object} data (optional) - overlay some values
22093 * @return {Roo.data.Record} record created.
22095 newRow : function(d) {
22097 this.recordType.prototype.fields.each(function(c) {
22099 case 'int' : da[c.name] = 0; break;
22100 case 'date' : da[c.name] = new Date(); break;
22101 case 'float' : da[c.name] = 0.0; break;
22102 case 'boolean' : da[c.name] = false; break;
22103 default : da[c.name] = ""; break;
22107 return new this.recordType(Roo.apply(da, d));
22112 * Ext JS Library 1.1.1
22113 * Copyright(c) 2006-2007, Ext JS, LLC.
22115 * Originally Released Under LGPL - original licence link has changed is not relivant.
22118 * <script type="text/javascript">
22122 * @class Roo.data.DataProxy
22123 * @extends Roo.data.Observable
22124 * This class is an abstract base class for implementations which provide retrieval of
22125 * unformatted data objects.<br>
22127 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
22128 * (of the appropriate type which knows how to parse the data object) to provide a block of
22129 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
22131 * Custom implementations must implement the load method as described in
22132 * {@link Roo.data.HttpProxy#load}.
22134 Roo.data.DataProxy = function(){
22137 * @event beforeload
22138 * Fires before a network request is made to retrieve a data object.
22139 * @param {Object} This DataProxy object.
22140 * @param {Object} params The params parameter to the load function.
22145 * Fires before the load method's callback is called.
22146 * @param {Object} This DataProxy object.
22147 * @param {Object} o The data object.
22148 * @param {Object} arg The callback argument object passed to the load function.
22152 * @event loadexception
22153 * Fires if an Exception occurs during data retrieval.
22154 * @param {Object} This DataProxy object.
22155 * @param {Object} o The data object.
22156 * @param {Object} arg The callback argument object passed to the load function.
22157 * @param {Object} e The Exception.
22159 loadexception : true
22161 Roo.data.DataProxy.superclass.constructor.call(this);
22164 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22167 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22171 * Ext JS Library 1.1.1
22172 * Copyright(c) 2006-2007, Ext JS, LLC.
22174 * Originally Released Under LGPL - original licence link has changed is not relivant.
22177 * <script type="text/javascript">
22180 * @class Roo.data.MemoryProxy
22181 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22182 * to the Reader when its load method is called.
22184 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22186 Roo.data.MemoryProxy = function(data){
22190 Roo.data.MemoryProxy.superclass.constructor.call(this);
22194 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22196 * Load data from the requested source (in this case an in-memory
22197 * data object passed to the constructor), read the data object into
22198 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22199 * process that block using the passed callback.
22200 * @param {Object} params This parameter is not used by the MemoryProxy class.
22201 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22202 * object into a block of Roo.data.Records.
22203 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22204 * The function must be passed <ul>
22205 * <li>The Record block object</li>
22206 * <li>The "arg" argument from the load function</li>
22207 * <li>A boolean success indicator</li>
22209 * @param {Object} scope The scope in which to call the callback
22210 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22212 load : function(params, reader, callback, scope, arg){
22213 params = params || {};
22216 result = reader.readRecords(this.data);
22218 this.fireEvent("loadexception", this, arg, null, e);
22219 callback.call(scope, null, arg, false);
22222 callback.call(scope, result, arg, true);
22226 update : function(params, records){
22231 * Ext JS Library 1.1.1
22232 * Copyright(c) 2006-2007, Ext JS, LLC.
22234 * Originally Released Under LGPL - original licence link has changed is not relivant.
22237 * <script type="text/javascript">
22240 * @class Roo.data.HttpProxy
22241 * @extends Roo.data.DataProxy
22242 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22243 * configured to reference a certain URL.<br><br>
22245 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22246 * from which the running page was served.<br><br>
22248 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22250 * Be aware that to enable the browser to parse an XML document, the server must set
22251 * the Content-Type header in the HTTP response to "text/xml".
22253 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22254 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22255 * will be used to make the request.
22257 Roo.data.HttpProxy = function(conn){
22258 Roo.data.HttpProxy.superclass.constructor.call(this);
22259 // is conn a conn config or a real conn?
22261 this.useAjax = !conn || !conn.events;
22265 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22266 // thse are take from connection...
22269 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22272 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22273 * extra parameters to each request made by this object. (defaults to undefined)
22276 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22277 * to each request made by this object. (defaults to undefined)
22280 * @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)
22283 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22286 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22292 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22296 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22297 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22298 * a finer-grained basis than the DataProxy events.
22300 getConnection : function(){
22301 return this.useAjax ? Roo.Ajax : this.conn;
22305 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22306 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22307 * process that block using the passed callback.
22308 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22309 * for the request to the remote server.
22310 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22311 * object into a block of Roo.data.Records.
22312 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22313 * The function must be passed <ul>
22314 * <li>The Record block object</li>
22315 * <li>The "arg" argument from the load function</li>
22316 * <li>A boolean success indicator</li>
22318 * @param {Object} scope The scope in which to call the callback
22319 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22321 load : function(params, reader, callback, scope, arg){
22322 if(this.fireEvent("beforeload", this, params) !== false){
22324 params : params || {},
22326 callback : callback,
22331 callback : this.loadResponse,
22335 Roo.applyIf(o, this.conn);
22336 if(this.activeRequest){
22337 Roo.Ajax.abort(this.activeRequest);
22339 this.activeRequest = Roo.Ajax.request(o);
22341 this.conn.request(o);
22344 callback.call(scope||this, null, arg, false);
22349 loadResponse : function(o, success, response){
22350 delete this.activeRequest;
22352 this.fireEvent("loadexception", this, o, response);
22353 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22358 result = o.reader.read(response);
22360 this.fireEvent("loadexception", this, o, response, e);
22361 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22365 this.fireEvent("load", this, o, o.request.arg);
22366 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22370 update : function(dataSet){
22375 updateResponse : function(dataSet){
22380 * Ext JS Library 1.1.1
22381 * Copyright(c) 2006-2007, Ext JS, LLC.
22383 * Originally Released Under LGPL - original licence link has changed is not relivant.
22386 * <script type="text/javascript">
22390 * @class Roo.data.ScriptTagProxy
22391 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22392 * other than the originating domain of the running page.<br><br>
22394 * <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
22395 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22397 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22398 * source code that is used as the source inside a <script> tag.<br><br>
22400 * In order for the browser to process the returned data, the server must wrap the data object
22401 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22402 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22403 * depending on whether the callback name was passed:
22406 boolean scriptTag = false;
22407 String cb = request.getParameter("callback");
22410 response.setContentType("text/javascript");
22412 response.setContentType("application/x-json");
22414 Writer out = response.getWriter();
22416 out.write(cb + "(");
22418 out.print(dataBlock.toJsonString());
22425 * @param {Object} config A configuration object.
22427 Roo.data.ScriptTagProxy = function(config){
22428 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22429 Roo.apply(this, config);
22430 this.head = document.getElementsByTagName("head")[0];
22433 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22435 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22437 * @cfg {String} url The URL from which to request the data object.
22440 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22444 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22445 * the server the name of the callback function set up by the load call to process the returned data object.
22446 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22447 * javascript output which calls this named function passing the data object as its only parameter.
22449 callbackParam : "callback",
22451 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22452 * name to the request.
22457 * Load data from the configured URL, read the data object into
22458 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22459 * process that block using the passed callback.
22460 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22461 * for the request to the remote server.
22462 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22463 * object into a block of Roo.data.Records.
22464 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22465 * The function must be passed <ul>
22466 * <li>The Record block object</li>
22467 * <li>The "arg" argument from the load function</li>
22468 * <li>A boolean success indicator</li>
22470 * @param {Object} scope The scope in which to call the callback
22471 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22473 load : function(params, reader, callback, scope, arg){
22474 if(this.fireEvent("beforeload", this, params) !== false){
22476 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22478 var url = this.url;
22479 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22481 url += "&_dc=" + (new Date().getTime());
22483 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22486 cb : "stcCallback"+transId,
22487 scriptId : "stcScript"+transId,
22491 callback : callback,
22497 window[trans.cb] = function(o){
22498 conn.handleResponse(o, trans);
22501 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22503 if(this.autoAbort !== false){
22507 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22509 var script = document.createElement("script");
22510 script.setAttribute("src", url);
22511 script.setAttribute("type", "text/javascript");
22512 script.setAttribute("id", trans.scriptId);
22513 this.head.appendChild(script);
22515 this.trans = trans;
22517 callback.call(scope||this, null, arg, false);
22522 isLoading : function(){
22523 return this.trans ? true : false;
22527 * Abort the current server request.
22529 abort : function(){
22530 if(this.isLoading()){
22531 this.destroyTrans(this.trans);
22536 destroyTrans : function(trans, isLoaded){
22537 this.head.removeChild(document.getElementById(trans.scriptId));
22538 clearTimeout(trans.timeoutId);
22540 window[trans.cb] = undefined;
22542 delete window[trans.cb];
22545 // if hasn't been loaded, wait for load to remove it to prevent script error
22546 window[trans.cb] = function(){
22547 window[trans.cb] = undefined;
22549 delete window[trans.cb];
22556 handleResponse : function(o, trans){
22557 this.trans = false;
22558 this.destroyTrans(trans, true);
22561 result = trans.reader.readRecords(o);
22563 this.fireEvent("loadexception", this, o, trans.arg, e);
22564 trans.callback.call(trans.scope||window, null, trans.arg, false);
22567 this.fireEvent("load", this, o, trans.arg);
22568 trans.callback.call(trans.scope||window, result, trans.arg, true);
22572 handleFailure : function(trans){
22573 this.trans = false;
22574 this.destroyTrans(trans, false);
22575 this.fireEvent("loadexception", this, null, trans.arg);
22576 trans.callback.call(trans.scope||window, null, trans.arg, false);
22580 * Ext JS Library 1.1.1
22581 * Copyright(c) 2006-2007, Ext JS, LLC.
22583 * Originally Released Under LGPL - original licence link has changed is not relivant.
22586 * <script type="text/javascript">
22590 * @class Roo.data.JsonReader
22591 * @extends Roo.data.DataReader
22592 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22593 * based on mappings in a provided Roo.data.Record constructor.
22595 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22596 * in the reply previously.
22601 var RecordDef = Roo.data.Record.create([
22602 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22603 {name: 'occupation'} // This field will use "occupation" as the mapping.
22605 var myReader = new Roo.data.JsonReader({
22606 totalProperty: "results", // The property which contains the total dataset size (optional)
22607 root: "rows", // The property which contains an Array of row objects
22608 id: "id" // The property within each row object that provides an ID for the record (optional)
22612 * This would consume a JSON file like this:
22614 { 'results': 2, 'rows': [
22615 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22616 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22619 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22620 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22621 * paged from the remote server.
22622 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22623 * @cfg {String} root name of the property which contains the Array of row objects.
22624 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22625 * @cfg {Array} fields Array of field definition objects
22627 * Create a new JsonReader
22628 * @param {Object} meta Metadata configuration options
22629 * @param {Object} recordType Either an Array of field definition objects,
22630 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22632 Roo.data.JsonReader = function(meta, recordType){
22635 // set some defaults:
22636 Roo.applyIf(meta, {
22637 totalProperty: 'total',
22638 successProperty : 'success',
22643 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22645 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22648 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22649 * Used by Store query builder to append _requestMeta to params.
22652 metaFromRemote : false,
22654 * This method is only used by a DataProxy which has retrieved data from a remote server.
22655 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22656 * @return {Object} data A data block which is used by an Roo.data.Store object as
22657 * a cache of Roo.data.Records.
22659 read : function(response){
22660 var json = response.responseText;
22662 var o = /* eval:var:o */ eval("("+json+")");
22664 throw {message: "JsonReader.read: Json object not found"};
22670 this.metaFromRemote = true;
22671 this.meta = o.metaData;
22672 this.recordType = Roo.data.Record.create(o.metaData.fields);
22673 this.onMetaChange(this.meta, this.recordType, o);
22675 return this.readRecords(o);
22678 // private function a store will implement
22679 onMetaChange : function(meta, recordType, o){
22686 simpleAccess: function(obj, subsc) {
22693 getJsonAccessor: function(){
22695 return function(expr) {
22697 return(re.test(expr))
22698 ? new Function("obj", "return obj." + expr)
22703 return Roo.emptyFn;
22708 * Create a data block containing Roo.data.Records from an XML document.
22709 * @param {Object} o An object which contains an Array of row objects in the property specified
22710 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22711 * which contains the total size of the dataset.
22712 * @return {Object} data A data block which is used by an Roo.data.Store object as
22713 * a cache of Roo.data.Records.
22715 readRecords : function(o){
22717 * After any data loads, the raw JSON data is available for further custom processing.
22721 var s = this.meta, Record = this.recordType,
22722 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
22724 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22726 if(s.totalProperty) {
22727 this.getTotal = this.getJsonAccessor(s.totalProperty);
22729 if(s.successProperty) {
22730 this.getSuccess = this.getJsonAccessor(s.successProperty);
22732 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22734 var g = this.getJsonAccessor(s.id);
22735 this.getId = function(rec) {
22737 return (r === undefined || r === "") ? null : r;
22740 this.getId = function(){return null;};
22743 for(var jj = 0; jj < fl; jj++){
22745 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22746 this.ef[jj] = this.getJsonAccessor(map);
22750 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22751 if(s.totalProperty){
22752 var vt = parseInt(this.getTotal(o), 10);
22757 if(s.successProperty){
22758 var vs = this.getSuccess(o);
22759 if(vs === false || vs === 'false'){
22764 for(var i = 0; i < c; i++){
22767 var id = this.getId(n);
22768 for(var j = 0; j < fl; j++){
22770 var v = this.ef[j](n);
22772 Roo.log('missing convert for ' + f.name);
22776 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22778 var record = new Record(values, id);
22780 records[i] = record;
22786 totalRecords : totalRecords
22791 * Ext JS Library 1.1.1
22792 * Copyright(c) 2006-2007, Ext JS, LLC.
22794 * Originally Released Under LGPL - original licence link has changed is not relivant.
22797 * <script type="text/javascript">
22801 * @class Roo.data.XmlReader
22802 * @extends Roo.data.DataReader
22803 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22804 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22806 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22807 * header in the HTTP response must be set to "text/xml".</em>
22811 var RecordDef = Roo.data.Record.create([
22812 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22813 {name: 'occupation'} // This field will use "occupation" as the mapping.
22815 var myReader = new Roo.data.XmlReader({
22816 totalRecords: "results", // The element which contains the total dataset size (optional)
22817 record: "row", // The repeated element which contains row information
22818 id: "id" // The element within the row that provides an ID for the record (optional)
22822 * This would consume an XML file like this:
22826 <results>2</results>
22829 <name>Bill</name>
22830 <occupation>Gardener</occupation>
22834 <name>Ben</name>
22835 <occupation>Horticulturalist</occupation>
22839 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22840 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22841 * paged from the remote server.
22842 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22843 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22844 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22845 * a record identifier value.
22847 * Create a new XmlReader
22848 * @param {Object} meta Metadata configuration options
22849 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22850 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22851 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22853 Roo.data.XmlReader = function(meta, recordType){
22855 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22857 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22859 * This method is only used by a DataProxy which has retrieved data from a remote server.
22860 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22861 * to contain a method called 'responseXML' that returns an XML document object.
22862 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22863 * a cache of Roo.data.Records.
22865 read : function(response){
22866 var doc = response.responseXML;
22868 throw {message: "XmlReader.read: XML Document not available"};
22870 return this.readRecords(doc);
22874 * Create a data block containing Roo.data.Records from an XML document.
22875 * @param {Object} doc A parsed XML document.
22876 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22877 * a cache of Roo.data.Records.
22879 readRecords : function(doc){
22881 * After any data loads/reads, the raw XML Document is available for further custom processing.
22882 * @type XMLDocument
22884 this.xmlData = doc;
22885 var root = doc.documentElement || doc;
22886 var q = Roo.DomQuery;
22887 var recordType = this.recordType, fields = recordType.prototype.fields;
22888 var sid = this.meta.id;
22889 var totalRecords = 0, success = true;
22890 if(this.meta.totalRecords){
22891 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22894 if(this.meta.success){
22895 var sv = q.selectValue(this.meta.success, root, true);
22896 success = sv !== false && sv !== 'false';
22899 var ns = q.select(this.meta.record, root);
22900 for(var i = 0, len = ns.length; i < len; i++) {
22903 var id = sid ? q.selectValue(sid, n) : undefined;
22904 for(var j = 0, jlen = fields.length; j < jlen; j++){
22905 var f = fields.items[j];
22906 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22908 values[f.name] = v;
22910 var record = new recordType(values, id);
22912 records[records.length] = record;
22918 totalRecords : totalRecords || records.length
22923 * Ext JS Library 1.1.1
22924 * Copyright(c) 2006-2007, Ext JS, LLC.
22926 * Originally Released Under LGPL - original licence link has changed is not relivant.
22929 * <script type="text/javascript">
22933 * @class Roo.data.ArrayReader
22934 * @extends Roo.data.DataReader
22935 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22936 * Each element of that Array represents a row of data fields. The
22937 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22938 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22942 var RecordDef = Roo.data.Record.create([
22943 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22944 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22946 var myReader = new Roo.data.ArrayReader({
22947 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22951 * This would consume an Array like this:
22953 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22955 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22957 * Create a new JsonReader
22958 * @param {Object} meta Metadata configuration options.
22959 * @param {Object} recordType Either an Array of field definition objects
22960 * as specified to {@link Roo.data.Record#create},
22961 * or an {@link Roo.data.Record} object
22962 * created using {@link Roo.data.Record#create}.
22964 Roo.data.ArrayReader = function(meta, recordType){
22965 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22968 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22970 * Create a data block containing Roo.data.Records from an XML document.
22971 * @param {Object} o An Array of row objects which represents the dataset.
22972 * @return {Object} data A data block which is used by an Roo.data.Store object as
22973 * a cache of Roo.data.Records.
22975 readRecords : function(o){
22976 var sid = this.meta ? this.meta.id : null;
22977 var recordType = this.recordType, fields = recordType.prototype.fields;
22980 for(var i = 0; i < root.length; i++){
22983 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22984 for(var j = 0, jlen = fields.length; j < jlen; j++){
22985 var f = fields.items[j];
22986 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22987 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22989 values[f.name] = v;
22991 var record = new recordType(values, id);
22993 records[records.length] = record;
22997 totalRecords : records.length
23002 * Ext JS Library 1.1.1
23003 * Copyright(c) 2006-2007, Ext JS, LLC.
23005 * Originally Released Under LGPL - original licence link has changed is not relivant.
23008 * <script type="text/javascript">
23013 * @class Roo.data.Tree
23014 * @extends Roo.util.Observable
23015 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
23016 * in the tree have most standard DOM functionality.
23018 * @param {Node} root (optional) The root node
23020 Roo.data.Tree = function(root){
23021 this.nodeHash = {};
23023 * The root node for this tree
23028 this.setRootNode(root);
23033 * Fires when a new child node is appended to a node in this tree.
23034 * @param {Tree} tree The owner tree
23035 * @param {Node} parent The parent node
23036 * @param {Node} node The newly appended node
23037 * @param {Number} index The index of the newly appended node
23042 * Fires when a child node is removed from a node in this tree.
23043 * @param {Tree} tree The owner tree
23044 * @param {Node} parent The parent node
23045 * @param {Node} node The child node removed
23050 * Fires when a node is moved to a new location in the tree
23051 * @param {Tree} tree The owner tree
23052 * @param {Node} node The node moved
23053 * @param {Node} oldParent The old parent of this node
23054 * @param {Node} newParent The new parent of this node
23055 * @param {Number} index The index it was moved to
23060 * Fires when a new child node is inserted in a node in this tree.
23061 * @param {Tree} tree The owner tree
23062 * @param {Node} parent The parent node
23063 * @param {Node} node The child node inserted
23064 * @param {Node} refNode The child node the node was inserted before
23068 * @event beforeappend
23069 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
23070 * @param {Tree} tree The owner tree
23071 * @param {Node} parent The parent node
23072 * @param {Node} node The child node to be appended
23074 "beforeappend" : true,
23076 * @event beforeremove
23077 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
23078 * @param {Tree} tree The owner tree
23079 * @param {Node} parent The parent node
23080 * @param {Node} node The child node to be removed
23082 "beforeremove" : true,
23084 * @event beforemove
23085 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
23086 * @param {Tree} tree The owner tree
23087 * @param {Node} node The node being moved
23088 * @param {Node} oldParent The parent of the node
23089 * @param {Node} newParent The new parent the node is moving to
23090 * @param {Number} index The index it is being moved to
23092 "beforemove" : true,
23094 * @event beforeinsert
23095 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
23096 * @param {Tree} tree The owner tree
23097 * @param {Node} parent The parent node
23098 * @param {Node} node The child node to be inserted
23099 * @param {Node} refNode The child node the node is being inserted before
23101 "beforeinsert" : true
23104 Roo.data.Tree.superclass.constructor.call(this);
23107 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
23108 pathSeparator: "/",
23110 proxyNodeEvent : function(){
23111 return this.fireEvent.apply(this, arguments);
23115 * Returns the root node for this tree.
23118 getRootNode : function(){
23123 * Sets the root node for this tree.
23124 * @param {Node} node
23127 setRootNode : function(node){
23129 node.ownerTree = this;
23130 node.isRoot = true;
23131 this.registerNode(node);
23136 * Gets a node in this tree by its id.
23137 * @param {String} id
23140 getNodeById : function(id){
23141 return this.nodeHash[id];
23144 registerNode : function(node){
23145 this.nodeHash[node.id] = node;
23148 unregisterNode : function(node){
23149 delete this.nodeHash[node.id];
23152 toString : function(){
23153 return "[Tree"+(this.id?" "+this.id:"")+"]";
23158 * @class Roo.data.Node
23159 * @extends Roo.util.Observable
23160 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23161 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23163 * @param {Object} attributes The attributes/config for the node
23165 Roo.data.Node = function(attributes){
23167 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23170 this.attributes = attributes || {};
23171 this.leaf = this.attributes.leaf;
23173 * The node id. @type String
23175 this.id = this.attributes.id;
23177 this.id = Roo.id(null, "ynode-");
23178 this.attributes.id = this.id;
23183 * All child nodes of this node. @type Array
23185 this.childNodes = [];
23186 if(!this.childNodes.indexOf){ // indexOf is a must
23187 this.childNodes.indexOf = function(o){
23188 for(var i = 0, len = this.length; i < len; i++){
23197 * The parent node for this node. @type Node
23199 this.parentNode = null;
23201 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23203 this.firstChild = null;
23205 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23207 this.lastChild = null;
23209 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23211 this.previousSibling = null;
23213 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23215 this.nextSibling = null;
23220 * Fires when a new child node is appended
23221 * @param {Tree} tree The owner tree
23222 * @param {Node} this This node
23223 * @param {Node} node The newly appended node
23224 * @param {Number} index The index of the newly appended node
23229 * Fires when a child node is removed
23230 * @param {Tree} tree The owner tree
23231 * @param {Node} this This node
23232 * @param {Node} node The removed node
23237 * Fires when this node is moved to a new location in the tree
23238 * @param {Tree} tree The owner tree
23239 * @param {Node} this This node
23240 * @param {Node} oldParent The old parent of this node
23241 * @param {Node} newParent The new parent of this node
23242 * @param {Number} index The index it was moved to
23247 * Fires when a new child node is inserted.
23248 * @param {Tree} tree The owner tree
23249 * @param {Node} this This node
23250 * @param {Node} node The child node inserted
23251 * @param {Node} refNode The child node the node was inserted before
23255 * @event beforeappend
23256 * Fires before a new child is appended, return false to cancel the append.
23257 * @param {Tree} tree The owner tree
23258 * @param {Node} this This node
23259 * @param {Node} node The child node to be appended
23261 "beforeappend" : true,
23263 * @event beforeremove
23264 * Fires before a child is removed, return false to cancel the remove.
23265 * @param {Tree} tree The owner tree
23266 * @param {Node} this This node
23267 * @param {Node} node The child node to be removed
23269 "beforeremove" : true,
23271 * @event beforemove
23272 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23273 * @param {Tree} tree The owner tree
23274 * @param {Node} this This node
23275 * @param {Node} oldParent The parent of this node
23276 * @param {Node} newParent The new parent this node is moving to
23277 * @param {Number} index The index it is being moved to
23279 "beforemove" : true,
23281 * @event beforeinsert
23282 * Fires before a new child is inserted, return false to cancel the insert.
23283 * @param {Tree} tree The owner tree
23284 * @param {Node} this This node
23285 * @param {Node} node The child node to be inserted
23286 * @param {Node} refNode The child node the node is being inserted before
23288 "beforeinsert" : true
23290 this.listeners = this.attributes.listeners;
23291 Roo.data.Node.superclass.constructor.call(this);
23294 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23295 fireEvent : function(evtName){
23296 // first do standard event for this node
23297 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23300 // then bubble it up to the tree if the event wasn't cancelled
23301 var ot = this.getOwnerTree();
23303 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23311 * Returns true if this node is a leaf
23312 * @return {Boolean}
23314 isLeaf : function(){
23315 return this.leaf === true;
23319 setFirstChild : function(node){
23320 this.firstChild = node;
23324 setLastChild : function(node){
23325 this.lastChild = node;
23330 * Returns true if this node is the last child of its parent
23331 * @return {Boolean}
23333 isLast : function(){
23334 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23338 * Returns true if this node is the first child of its parent
23339 * @return {Boolean}
23341 isFirst : function(){
23342 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23345 hasChildNodes : function(){
23346 return !this.isLeaf() && this.childNodes.length > 0;
23350 * Insert node(s) as the last child node of this node.
23351 * @param {Node/Array} node The node or Array of nodes to append
23352 * @return {Node} The appended node if single append, or null if an array was passed
23354 appendChild : function(node){
23356 if(node instanceof Array){
23358 }else if(arguments.length > 1){
23361 // if passed an array or multiple args do them one by one
23363 for(var i = 0, len = multi.length; i < len; i++) {
23364 this.appendChild(multi[i]);
23367 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23370 var index = this.childNodes.length;
23371 var oldParent = node.parentNode;
23372 // it's a move, make sure we move it cleanly
23374 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23377 oldParent.removeChild(node);
23379 index = this.childNodes.length;
23381 this.setFirstChild(node);
23383 this.childNodes.push(node);
23384 node.parentNode = this;
23385 var ps = this.childNodes[index-1];
23387 node.previousSibling = ps;
23388 ps.nextSibling = node;
23390 node.previousSibling = null;
23392 node.nextSibling = null;
23393 this.setLastChild(node);
23394 node.setOwnerTree(this.getOwnerTree());
23395 this.fireEvent("append", this.ownerTree, this, node, index);
23397 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23404 * Removes a child node from this node.
23405 * @param {Node} node The node to remove
23406 * @return {Node} The removed node
23408 removeChild : function(node){
23409 var index = this.childNodes.indexOf(node);
23413 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23417 // remove it from childNodes collection
23418 this.childNodes.splice(index, 1);
23421 if(node.previousSibling){
23422 node.previousSibling.nextSibling = node.nextSibling;
23424 if(node.nextSibling){
23425 node.nextSibling.previousSibling = node.previousSibling;
23428 // update child refs
23429 if(this.firstChild == node){
23430 this.setFirstChild(node.nextSibling);
23432 if(this.lastChild == node){
23433 this.setLastChild(node.previousSibling);
23436 node.setOwnerTree(null);
23437 // clear any references from the node
23438 node.parentNode = null;
23439 node.previousSibling = null;
23440 node.nextSibling = null;
23441 this.fireEvent("remove", this.ownerTree, this, node);
23446 * Inserts the first node before the second node in this nodes childNodes collection.
23447 * @param {Node} node The node to insert
23448 * @param {Node} refNode The node to insert before (if null the node is appended)
23449 * @return {Node} The inserted node
23451 insertBefore : function(node, refNode){
23452 if(!refNode){ // like standard Dom, refNode can be null for append
23453 return this.appendChild(node);
23456 if(node == refNode){
23460 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23463 var index = this.childNodes.indexOf(refNode);
23464 var oldParent = node.parentNode;
23465 var refIndex = index;
23467 // when moving internally, indexes will change after remove
23468 if(oldParent == this && this.childNodes.indexOf(node) < index){
23472 // it's a move, make sure we move it cleanly
23474 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23477 oldParent.removeChild(node);
23480 this.setFirstChild(node);
23482 this.childNodes.splice(refIndex, 0, node);
23483 node.parentNode = this;
23484 var ps = this.childNodes[refIndex-1];
23486 node.previousSibling = ps;
23487 ps.nextSibling = node;
23489 node.previousSibling = null;
23491 node.nextSibling = refNode;
23492 refNode.previousSibling = node;
23493 node.setOwnerTree(this.getOwnerTree());
23494 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23496 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23502 * Returns the child node at the specified index.
23503 * @param {Number} index
23506 item : function(index){
23507 return this.childNodes[index];
23511 * Replaces one child node in this node with another.
23512 * @param {Node} newChild The replacement node
23513 * @param {Node} oldChild The node to replace
23514 * @return {Node} The replaced node
23516 replaceChild : function(newChild, oldChild){
23517 this.insertBefore(newChild, oldChild);
23518 this.removeChild(oldChild);
23523 * Returns the index of a child node
23524 * @param {Node} node
23525 * @return {Number} The index of the node or -1 if it was not found
23527 indexOf : function(child){
23528 return this.childNodes.indexOf(child);
23532 * Returns the tree this node is in.
23535 getOwnerTree : function(){
23536 // if it doesn't have one, look for one
23537 if(!this.ownerTree){
23541 this.ownerTree = p.ownerTree;
23547 return this.ownerTree;
23551 * Returns depth of this node (the root node has a depth of 0)
23554 getDepth : function(){
23557 while(p.parentNode){
23565 setOwnerTree : function(tree){
23566 // if it's move, we need to update everyone
23567 if(tree != this.ownerTree){
23568 if(this.ownerTree){
23569 this.ownerTree.unregisterNode(this);
23571 this.ownerTree = tree;
23572 var cs = this.childNodes;
23573 for(var i = 0, len = cs.length; i < len; i++) {
23574 cs[i].setOwnerTree(tree);
23577 tree.registerNode(this);
23583 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23584 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23585 * @return {String} The path
23587 getPath : function(attr){
23588 attr = attr || "id";
23589 var p = this.parentNode;
23590 var b = [this.attributes[attr]];
23592 b.unshift(p.attributes[attr]);
23595 var sep = this.getOwnerTree().pathSeparator;
23596 return sep + b.join(sep);
23600 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23601 * function call will be the scope provided or the current node. The arguments to the function
23602 * will be the args provided or the current node. If the function returns false at any point,
23603 * the bubble is stopped.
23604 * @param {Function} fn The function to call
23605 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23606 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23608 bubble : function(fn, scope, args){
23611 if(fn.call(scope || p, args || p) === false){
23619 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23620 * function call will be the scope provided or the current node. The arguments to the function
23621 * will be the args provided or the current node. If the function returns false at any point,
23622 * the cascade is stopped on that branch.
23623 * @param {Function} fn The function to call
23624 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23625 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23627 cascade : function(fn, scope, args){
23628 if(fn.call(scope || this, args || this) !== false){
23629 var cs = this.childNodes;
23630 for(var i = 0, len = cs.length; i < len; i++) {
23631 cs[i].cascade(fn, scope, args);
23637 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23638 * function call will be the scope provided or the current node. The arguments to the function
23639 * will be the args provided or the current node. If the function returns false at any point,
23640 * the iteration stops.
23641 * @param {Function} fn The function to call
23642 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23643 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23645 eachChild : function(fn, scope, args){
23646 var cs = this.childNodes;
23647 for(var i = 0, len = cs.length; i < len; i++) {
23648 if(fn.call(scope || this, args || cs[i]) === false){
23655 * Finds the first child that has the attribute with the specified value.
23656 * @param {String} attribute The attribute name
23657 * @param {Mixed} value The value to search for
23658 * @return {Node} The found child or null if none was found
23660 findChild : function(attribute, value){
23661 var cs = this.childNodes;
23662 for(var i = 0, len = cs.length; i < len; i++) {
23663 if(cs[i].attributes[attribute] == value){
23671 * Finds the first child by a custom function. The child matches if the function passed
23673 * @param {Function} fn
23674 * @param {Object} scope (optional)
23675 * @return {Node} The found child or null if none was found
23677 findChildBy : function(fn, scope){
23678 var cs = this.childNodes;
23679 for(var i = 0, len = cs.length; i < len; i++) {
23680 if(fn.call(scope||cs[i], cs[i]) === true){
23688 * Sorts this nodes children using the supplied sort function
23689 * @param {Function} fn
23690 * @param {Object} scope (optional)
23692 sort : function(fn, scope){
23693 var cs = this.childNodes;
23694 var len = cs.length;
23696 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23698 for(var i = 0; i < len; i++){
23700 n.previousSibling = cs[i-1];
23701 n.nextSibling = cs[i+1];
23703 this.setFirstChild(n);
23706 this.setLastChild(n);
23713 * Returns true if this node is an ancestor (at any point) of the passed node.
23714 * @param {Node} node
23715 * @return {Boolean}
23717 contains : function(node){
23718 return node.isAncestor(this);
23722 * Returns true if the passed node is an ancestor (at any point) of this node.
23723 * @param {Node} node
23724 * @return {Boolean}
23726 isAncestor : function(node){
23727 var p = this.parentNode;
23737 toString : function(){
23738 return "[Node"+(this.id?" "+this.id:"")+"]";
23742 * Ext JS Library 1.1.1
23743 * Copyright(c) 2006-2007, Ext JS, LLC.
23745 * Originally Released Under LGPL - original licence link has changed is not relivant.
23748 * <script type="text/javascript">
23753 * @extends Roo.Element
23754 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23755 * automatic maintaining of shadow/shim positions.
23756 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23757 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23758 * you can pass a string with a CSS class name. False turns off the shadow.
23759 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23760 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23761 * @cfg {String} cls CSS class to add to the element
23762 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23763 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23765 * @param {Object} config An object with config options.
23766 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23769 Roo.Layer = function(config, existingEl){
23770 config = config || {};
23771 var dh = Roo.DomHelper;
23772 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23774 this.dom = Roo.getDom(existingEl);
23777 var o = config.dh || {tag: "div", cls: "x-layer"};
23778 this.dom = dh.append(pel, o);
23781 this.addClass(config.cls);
23783 this.constrain = config.constrain !== false;
23784 this.visibilityMode = Roo.Element.VISIBILITY;
23786 this.id = this.dom.id = config.id;
23788 this.id = Roo.id(this.dom);
23790 this.zindex = config.zindex || this.getZIndex();
23791 this.position("absolute", this.zindex);
23793 this.shadowOffset = config.shadowOffset || 4;
23794 this.shadow = new Roo.Shadow({
23795 offset : this.shadowOffset,
23796 mode : config.shadow
23799 this.shadowOffset = 0;
23801 this.useShim = config.shim !== false && Roo.useShims;
23802 this.useDisplay = config.useDisplay;
23806 var supr = Roo.Element.prototype;
23808 // shims are shared among layer to keep from having 100 iframes
23811 Roo.extend(Roo.Layer, Roo.Element, {
23813 getZIndex : function(){
23814 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23817 getShim : function(){
23824 var shim = shims.shift();
23826 shim = this.createShim();
23827 shim.enableDisplayMode('block');
23828 shim.dom.style.display = 'none';
23829 shim.dom.style.visibility = 'visible';
23831 var pn = this.dom.parentNode;
23832 if(shim.dom.parentNode != pn){
23833 pn.insertBefore(shim.dom, this.dom);
23835 shim.setStyle('z-index', this.getZIndex()-2);
23840 hideShim : function(){
23842 this.shim.setDisplayed(false);
23843 shims.push(this.shim);
23848 disableShadow : function(){
23850 this.shadowDisabled = true;
23851 this.shadow.hide();
23852 this.lastShadowOffset = this.shadowOffset;
23853 this.shadowOffset = 0;
23857 enableShadow : function(show){
23859 this.shadowDisabled = false;
23860 this.shadowOffset = this.lastShadowOffset;
23861 delete this.lastShadowOffset;
23869 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23870 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23871 sync : function(doShow){
23872 var sw = this.shadow;
23873 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23874 var sh = this.getShim();
23876 var w = this.getWidth(),
23877 h = this.getHeight();
23879 var l = this.getLeft(true),
23880 t = this.getTop(true);
23882 if(sw && !this.shadowDisabled){
23883 if(doShow && !sw.isVisible()){
23886 sw.realign(l, t, w, h);
23892 // fit the shim behind the shadow, so it is shimmed too
23893 var a = sw.adjusts, s = sh.dom.style;
23894 s.left = (Math.min(l, l+a.l))+"px";
23895 s.top = (Math.min(t, t+a.t))+"px";
23896 s.width = (w+a.w)+"px";
23897 s.height = (h+a.h)+"px";
23904 sh.setLeftTop(l, t);
23911 destroy : function(){
23914 this.shadow.hide();
23916 this.removeAllListeners();
23917 var pn = this.dom.parentNode;
23919 pn.removeChild(this.dom);
23921 Roo.Element.uncache(this.id);
23924 remove : function(){
23929 beginUpdate : function(){
23930 this.updating = true;
23934 endUpdate : function(){
23935 this.updating = false;
23940 hideUnders : function(negOffset){
23942 this.shadow.hide();
23948 constrainXY : function(){
23949 if(this.constrain){
23950 var vw = Roo.lib.Dom.getViewWidth(),
23951 vh = Roo.lib.Dom.getViewHeight();
23952 var s = Roo.get(document).getScroll();
23954 var xy = this.getXY();
23955 var x = xy[0], y = xy[1];
23956 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23957 // only move it if it needs it
23959 // first validate right/bottom
23960 if((x + w) > vw+s.left){
23961 x = vw - w - this.shadowOffset;
23964 if((y + h) > vh+s.top){
23965 y = vh - h - this.shadowOffset;
23968 // then make sure top/left isn't negative
23979 var ay = this.avoidY;
23980 if(y <= ay && (y+h) >= ay){
23986 supr.setXY.call(this, xy);
23992 isVisible : function(){
23993 return this.visible;
23997 showAction : function(){
23998 this.visible = true; // track visibility to prevent getStyle calls
23999 if(this.useDisplay === true){
24000 this.setDisplayed("");
24001 }else if(this.lastXY){
24002 supr.setXY.call(this, this.lastXY);
24003 }else if(this.lastLT){
24004 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
24009 hideAction : function(){
24010 this.visible = false;
24011 if(this.useDisplay === true){
24012 this.setDisplayed(false);
24014 this.setLeftTop(-10000,-10000);
24018 // overridden Element method
24019 setVisible : function(v, a, d, c, e){
24024 var cb = function(){
24029 }.createDelegate(this);
24030 supr.setVisible.call(this, true, true, d, cb, e);
24033 this.hideUnders(true);
24042 }.createDelegate(this);
24044 supr.setVisible.call(this, v, a, d, cb, e);
24053 storeXY : function(xy){
24054 delete this.lastLT;
24058 storeLeftTop : function(left, top){
24059 delete this.lastXY;
24060 this.lastLT = [left, top];
24064 beforeFx : function(){
24065 this.beforeAction();
24066 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
24070 afterFx : function(){
24071 Roo.Layer.superclass.afterFx.apply(this, arguments);
24072 this.sync(this.isVisible());
24076 beforeAction : function(){
24077 if(!this.updating && this.shadow){
24078 this.shadow.hide();
24082 // overridden Element method
24083 setLeft : function(left){
24084 this.storeLeftTop(left, this.getTop(true));
24085 supr.setLeft.apply(this, arguments);
24089 setTop : function(top){
24090 this.storeLeftTop(this.getLeft(true), top);
24091 supr.setTop.apply(this, arguments);
24095 setLeftTop : function(left, top){
24096 this.storeLeftTop(left, top);
24097 supr.setLeftTop.apply(this, arguments);
24101 setXY : function(xy, a, d, c, e){
24103 this.beforeAction();
24105 var cb = this.createCB(c);
24106 supr.setXY.call(this, xy, a, d, cb, e);
24113 createCB : function(c){
24124 // overridden Element method
24125 setX : function(x, a, d, c, e){
24126 this.setXY([x, this.getY()], a, d, c, e);
24129 // overridden Element method
24130 setY : function(y, a, d, c, e){
24131 this.setXY([this.getX(), y], a, d, c, e);
24134 // overridden Element method
24135 setSize : function(w, h, a, d, c, e){
24136 this.beforeAction();
24137 var cb = this.createCB(c);
24138 supr.setSize.call(this, w, h, a, d, cb, e);
24144 // overridden Element method
24145 setWidth : function(w, a, d, c, e){
24146 this.beforeAction();
24147 var cb = this.createCB(c);
24148 supr.setWidth.call(this, w, a, d, cb, e);
24154 // overridden Element method
24155 setHeight : function(h, a, d, c, e){
24156 this.beforeAction();
24157 var cb = this.createCB(c);
24158 supr.setHeight.call(this, h, a, d, cb, e);
24164 // overridden Element method
24165 setBounds : function(x, y, w, h, a, d, c, e){
24166 this.beforeAction();
24167 var cb = this.createCB(c);
24169 this.storeXY([x, y]);
24170 supr.setXY.call(this, [x, y]);
24171 supr.setSize.call(this, w, h, a, d, cb, e);
24174 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24180 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24181 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24182 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24183 * @param {Number} zindex The new z-index to set
24184 * @return {this} The Layer
24186 setZIndex : function(zindex){
24187 this.zindex = zindex;
24188 this.setStyle("z-index", zindex + 2);
24190 this.shadow.setZIndex(zindex + 1);
24193 this.shim.setStyle("z-index", zindex);
24199 * Ext JS Library 1.1.1
24200 * Copyright(c) 2006-2007, Ext JS, LLC.
24202 * Originally Released Under LGPL - original licence link has changed is not relivant.
24205 * <script type="text/javascript">
24210 * @class Roo.Shadow
24211 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24212 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24213 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24215 * Create a new Shadow
24216 * @param {Object} config The config object
24218 Roo.Shadow = function(config){
24219 Roo.apply(this, config);
24220 if(typeof this.mode != "string"){
24221 this.mode = this.defaultMode;
24223 var o = this.offset, a = {h: 0};
24224 var rad = Math.floor(this.offset/2);
24225 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24231 a.l -= this.offset + rad;
24232 a.t -= this.offset + rad;
24243 a.l -= (this.offset - rad);
24244 a.t -= this.offset + rad;
24246 a.w -= (this.offset - rad)*2;
24257 a.l -= (this.offset - rad);
24258 a.t -= (this.offset - rad);
24260 a.w -= (this.offset + rad + 1);
24261 a.h -= (this.offset + rad);
24270 Roo.Shadow.prototype = {
24272 * @cfg {String} mode
24273 * The shadow display mode. Supports the following options:<br />
24274 * sides: Shadow displays on both sides and bottom only<br />
24275 * frame: Shadow displays equally on all four sides<br />
24276 * drop: Traditional bottom-right drop shadow (default)
24279 * @cfg {String} offset
24280 * The number of pixels to offset the shadow from the element (defaults to 4)
24285 defaultMode: "drop",
24288 * Displays the shadow under the target element
24289 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24291 show : function(target){
24292 target = Roo.get(target);
24294 this.el = Roo.Shadow.Pool.pull();
24295 if(this.el.dom.nextSibling != target.dom){
24296 this.el.insertBefore(target);
24299 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24301 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24304 target.getLeft(true),
24305 target.getTop(true),
24309 this.el.dom.style.display = "block";
24313 * Returns true if the shadow is visible, else false
24315 isVisible : function(){
24316 return this.el ? true : false;
24320 * Direct alignment when values are already available. Show must be called at least once before
24321 * calling this method to ensure it is initialized.
24322 * @param {Number} left The target element left position
24323 * @param {Number} top The target element top position
24324 * @param {Number} width The target element width
24325 * @param {Number} height The target element height
24327 realign : function(l, t, w, h){
24331 var a = this.adjusts, d = this.el.dom, s = d.style;
24333 s.left = (l+a.l)+"px";
24334 s.top = (t+a.t)+"px";
24335 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24337 if(s.width != sws || s.height != shs){
24341 var cn = d.childNodes;
24342 var sww = Math.max(0, (sw-12))+"px";
24343 cn[0].childNodes[1].style.width = sww;
24344 cn[1].childNodes[1].style.width = sww;
24345 cn[2].childNodes[1].style.width = sww;
24346 cn[1].style.height = Math.max(0, (sh-12))+"px";
24352 * Hides this shadow
24356 this.el.dom.style.display = "none";
24357 Roo.Shadow.Pool.push(this.el);
24363 * Adjust the z-index of this shadow
24364 * @param {Number} zindex The new z-index
24366 setZIndex : function(z){
24369 this.el.setStyle("z-index", z);
24374 // Private utility class that manages the internal Shadow cache
24375 Roo.Shadow.Pool = function(){
24377 var markup = Roo.isIE ?
24378 '<div class="x-ie-shadow"></div>' :
24379 '<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>';
24382 var sh = p.shift();
24384 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24385 sh.autoBoxAdjust = false;
24390 push : function(sh){
24396 * Ext JS Library 1.1.1
24397 * Copyright(c) 2006-2007, Ext JS, LLC.
24399 * Originally Released Under LGPL - original licence link has changed is not relivant.
24402 * <script type="text/javascript">
24407 * @class Roo.SplitBar
24408 * @extends Roo.util.Observable
24409 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24413 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24414 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24415 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24416 split.minSize = 100;
24417 split.maxSize = 600;
24418 split.animate = true;
24419 split.on('moved', splitterMoved);
24422 * Create a new SplitBar
24423 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24424 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24425 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24426 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24427 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24428 position of the SplitBar).
24430 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24433 this.el = Roo.get(dragElement, true);
24434 this.el.dom.unselectable = "on";
24436 this.resizingEl = Roo.get(resizingElement, true);
24440 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24441 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24444 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24447 * The minimum size of the resizing element. (Defaults to 0)
24453 * The maximum size of the resizing element. (Defaults to 2000)
24456 this.maxSize = 2000;
24459 * Whether to animate the transition to the new size
24462 this.animate = false;
24465 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24468 this.useShim = false;
24473 if(!existingProxy){
24475 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24477 this.proxy = Roo.get(existingProxy).dom;
24480 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24483 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24486 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24489 this.dragSpecs = {};
24492 * @private The adapter to use to positon and resize elements
24494 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24495 this.adapter.init(this);
24497 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24499 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24500 this.el.addClass("x-splitbar-h");
24503 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24504 this.el.addClass("x-splitbar-v");
24510 * Fires when the splitter is moved (alias for {@link #event-moved})
24511 * @param {Roo.SplitBar} this
24512 * @param {Number} newSize the new width or height
24517 * Fires when the splitter is moved
24518 * @param {Roo.SplitBar} this
24519 * @param {Number} newSize the new width or height
24523 * @event beforeresize
24524 * Fires before the splitter is dragged
24525 * @param {Roo.SplitBar} this
24527 "beforeresize" : true,
24529 "beforeapply" : true
24532 Roo.util.Observable.call(this);
24535 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24536 onStartProxyDrag : function(x, y){
24537 this.fireEvent("beforeresize", this);
24539 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24541 o.enableDisplayMode("block");
24542 // all splitbars share the same overlay
24543 Roo.SplitBar.prototype.overlay = o;
24545 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24546 this.overlay.show();
24547 Roo.get(this.proxy).setDisplayed("block");
24548 var size = this.adapter.getElementSize(this);
24549 this.activeMinSize = this.getMinimumSize();;
24550 this.activeMaxSize = this.getMaximumSize();;
24551 var c1 = size - this.activeMinSize;
24552 var c2 = Math.max(this.activeMaxSize - size, 0);
24553 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24554 this.dd.resetConstraints();
24555 this.dd.setXConstraint(
24556 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24557 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24559 this.dd.setYConstraint(0, 0);
24561 this.dd.resetConstraints();
24562 this.dd.setXConstraint(0, 0);
24563 this.dd.setYConstraint(
24564 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24565 this.placement == Roo.SplitBar.TOP ? c2 : c1
24568 this.dragSpecs.startSize = size;
24569 this.dragSpecs.startPoint = [x, y];
24570 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24574 * @private Called after the drag operation by the DDProxy
24576 onEndProxyDrag : function(e){
24577 Roo.get(this.proxy).setDisplayed(false);
24578 var endPoint = Roo.lib.Event.getXY(e);
24580 this.overlay.hide();
24583 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24584 newSize = this.dragSpecs.startSize +
24585 (this.placement == Roo.SplitBar.LEFT ?
24586 endPoint[0] - this.dragSpecs.startPoint[0] :
24587 this.dragSpecs.startPoint[0] - endPoint[0]
24590 newSize = this.dragSpecs.startSize +
24591 (this.placement == Roo.SplitBar.TOP ?
24592 endPoint[1] - this.dragSpecs.startPoint[1] :
24593 this.dragSpecs.startPoint[1] - endPoint[1]
24596 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24597 if(newSize != this.dragSpecs.startSize){
24598 if(this.fireEvent('beforeapply', this, newSize) !== false){
24599 this.adapter.setElementSize(this, newSize);
24600 this.fireEvent("moved", this, newSize);
24601 this.fireEvent("resize", this, newSize);
24607 * Get the adapter this SplitBar uses
24608 * @return The adapter object
24610 getAdapter : function(){
24611 return this.adapter;
24615 * Set the adapter this SplitBar uses
24616 * @param {Object} adapter A SplitBar adapter object
24618 setAdapter : function(adapter){
24619 this.adapter = adapter;
24620 this.adapter.init(this);
24624 * Gets the minimum size for the resizing element
24625 * @return {Number} The minimum size
24627 getMinimumSize : function(){
24628 return this.minSize;
24632 * Sets the minimum size for the resizing element
24633 * @param {Number} minSize The minimum size
24635 setMinimumSize : function(minSize){
24636 this.minSize = minSize;
24640 * Gets the maximum size for the resizing element
24641 * @return {Number} The maximum size
24643 getMaximumSize : function(){
24644 return this.maxSize;
24648 * Sets the maximum size for the resizing element
24649 * @param {Number} maxSize The maximum size
24651 setMaximumSize : function(maxSize){
24652 this.maxSize = maxSize;
24656 * Sets the initialize size for the resizing element
24657 * @param {Number} size The initial size
24659 setCurrentSize : function(size){
24660 var oldAnimate = this.animate;
24661 this.animate = false;
24662 this.adapter.setElementSize(this, size);
24663 this.animate = oldAnimate;
24667 * Destroy this splitbar.
24668 * @param {Boolean} removeEl True to remove the element
24670 destroy : function(removeEl){
24672 this.shim.remove();
24675 this.proxy.parentNode.removeChild(this.proxy);
24683 * @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.
24685 Roo.SplitBar.createProxy = function(dir){
24686 var proxy = new Roo.Element(document.createElement("div"));
24687 proxy.unselectable();
24688 var cls = 'x-splitbar-proxy';
24689 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24690 document.body.appendChild(proxy.dom);
24695 * @class Roo.SplitBar.BasicLayoutAdapter
24696 * Default Adapter. It assumes the splitter and resizing element are not positioned
24697 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24699 Roo.SplitBar.BasicLayoutAdapter = function(){
24702 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24703 // do nothing for now
24704 init : function(s){
24708 * Called before drag operations to get the current size of the resizing element.
24709 * @param {Roo.SplitBar} s The SplitBar using this adapter
24711 getElementSize : function(s){
24712 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24713 return s.resizingEl.getWidth();
24715 return s.resizingEl.getHeight();
24720 * Called after drag operations to set the size of the resizing element.
24721 * @param {Roo.SplitBar} s The SplitBar using this adapter
24722 * @param {Number} newSize The new size to set
24723 * @param {Function} onComplete A function to be invoked when resizing is complete
24725 setElementSize : function(s, newSize, onComplete){
24726 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24728 s.resizingEl.setWidth(newSize);
24730 onComplete(s, newSize);
24733 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24738 s.resizingEl.setHeight(newSize);
24740 onComplete(s, newSize);
24743 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24750 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24751 * @extends Roo.SplitBar.BasicLayoutAdapter
24752 * Adapter that moves the splitter element to align with the resized sizing element.
24753 * Used with an absolute positioned SplitBar.
24754 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24755 * document.body, make sure you assign an id to the body element.
24757 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24758 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24759 this.container = Roo.get(container);
24762 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24763 init : function(s){
24764 this.basic.init(s);
24767 getElementSize : function(s){
24768 return this.basic.getElementSize(s);
24771 setElementSize : function(s, newSize, onComplete){
24772 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24775 moveSplitter : function(s){
24776 var yes = Roo.SplitBar;
24777 switch(s.placement){
24779 s.el.setX(s.resizingEl.getRight());
24782 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24785 s.el.setY(s.resizingEl.getBottom());
24788 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24795 * Orientation constant - Create a vertical SplitBar
24799 Roo.SplitBar.VERTICAL = 1;
24802 * Orientation constant - Create a horizontal SplitBar
24806 Roo.SplitBar.HORIZONTAL = 2;
24809 * Placement constant - The resizing element is to the left of the splitter element
24813 Roo.SplitBar.LEFT = 1;
24816 * Placement constant - The resizing element is to the right of the splitter element
24820 Roo.SplitBar.RIGHT = 2;
24823 * Placement constant - The resizing element is positioned above the splitter element
24827 Roo.SplitBar.TOP = 3;
24830 * Placement constant - The resizing element is positioned under splitter element
24834 Roo.SplitBar.BOTTOM = 4;
24837 * Ext JS Library 1.1.1
24838 * Copyright(c) 2006-2007, Ext JS, LLC.
24840 * Originally Released Under LGPL - original licence link has changed is not relivant.
24843 * <script type="text/javascript">
24848 * @extends Roo.util.Observable
24849 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24850 * This class also supports single and multi selection modes. <br>
24851 * Create a data model bound view:
24853 var store = new Roo.data.Store(...);
24855 var view = new Roo.View({
24857 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24859 singleSelect: true,
24860 selectedClass: "ydataview-selected",
24864 // listen for node click?
24865 view.on("click", function(vw, index, node, e){
24866 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24870 dataModel.load("foobar.xml");
24872 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24874 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24875 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24877 * Note: old style constructor is still suported (container, template, config)
24880 * Create a new View
24881 * @param {Object} config The config object
24884 Roo.View = function(config, depreciated_tpl, depreciated_config){
24886 this.parent = false;
24888 if (typeof(depreciated_tpl) == 'undefined') {
24889 // new way.. - universal constructor.
24890 Roo.apply(this, config);
24891 this.el = Roo.get(this.el);
24894 this.el = Roo.get(config);
24895 this.tpl = depreciated_tpl;
24896 Roo.apply(this, depreciated_config);
24898 this.wrapEl = this.el.wrap().wrap();
24899 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24902 if(typeof(this.tpl) == "string"){
24903 this.tpl = new Roo.Template(this.tpl);
24905 // support xtype ctors..
24906 this.tpl = new Roo.factory(this.tpl, Roo);
24910 this.tpl.compile();
24915 * @event beforeclick
24916 * Fires before a click is processed. Returns false to cancel the default action.
24917 * @param {Roo.View} this
24918 * @param {Number} index The index of the target node
24919 * @param {HTMLElement} node The target node
24920 * @param {Roo.EventObject} e The raw event object
24922 "beforeclick" : true,
24925 * Fires when a template node is clicked.
24926 * @param {Roo.View} this
24927 * @param {Number} index The index of the target node
24928 * @param {HTMLElement} node The target node
24929 * @param {Roo.EventObject} e The raw event object
24934 * Fires when a template node is double clicked.
24935 * @param {Roo.View} this
24936 * @param {Number} index The index of the target node
24937 * @param {HTMLElement} node The target node
24938 * @param {Roo.EventObject} e The raw event object
24942 * @event contextmenu
24943 * Fires when a template node is right clicked.
24944 * @param {Roo.View} this
24945 * @param {Number} index The index of the target node
24946 * @param {HTMLElement} node The target node
24947 * @param {Roo.EventObject} e The raw event object
24949 "contextmenu" : true,
24951 * @event selectionchange
24952 * Fires when the selected nodes change.
24953 * @param {Roo.View} this
24954 * @param {Array} selections Array of the selected nodes
24956 "selectionchange" : true,
24959 * @event beforeselect
24960 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24961 * @param {Roo.View} this
24962 * @param {HTMLElement} node The node to be selected
24963 * @param {Array} selections Array of currently selected nodes
24965 "beforeselect" : true,
24967 * @event preparedata
24968 * Fires on every row to render, to allow you to change the data.
24969 * @param {Roo.View} this
24970 * @param {Object} data to be rendered (change this)
24972 "preparedata" : true
24980 "click": this.onClick,
24981 "dblclick": this.onDblClick,
24982 "contextmenu": this.onContextMenu,
24986 this.selections = [];
24988 this.cmp = new Roo.CompositeElementLite([]);
24990 this.store = Roo.factory(this.store, Roo.data);
24991 this.setStore(this.store, true);
24994 if ( this.footer && this.footer.xtype) {
24996 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24998 this.footer.dataSource = this.store
24999 this.footer.container = fctr;
25000 this.footer = Roo.factory(this.footer, Roo);
25001 fctr.insertFirst(this.el);
25003 // this is a bit insane - as the paging toolbar seems to detach the el..
25004 // dom.parentNode.parentNode.parentNode
25005 // they get detached?
25009 Roo.View.superclass.constructor.call(this);
25014 Roo.extend(Roo.View, Roo.util.Observable, {
25017 * @cfg {Roo.data.Store} store Data store to load data from.
25022 * @cfg {String|Roo.Element} el The container element.
25027 * @cfg {String|Roo.Template} tpl The template used by this View
25031 * @cfg {String} dataName the named area of the template to use as the data area
25032 * Works with domtemplates roo-name="name"
25036 * @cfg {String} selectedClass The css class to add to selected nodes
25038 selectedClass : "x-view-selected",
25040 * @cfg {String} emptyText The empty text to show when nothing is loaded.
25045 * @cfg {String} text to display on mask (default Loading)
25049 * @cfg {Boolean} multiSelect Allow multiple selection
25051 multiSelect : false,
25053 * @cfg {Boolean} singleSelect Allow single selection
25055 singleSelect: false,
25058 * @cfg {Boolean} toggleSelect - selecting
25060 toggleSelect : false,
25063 * @cfg {Boolean} tickable - selecting
25068 * Returns the element this view is bound to.
25069 * @return {Roo.Element}
25071 getEl : function(){
25072 return this.wrapEl;
25078 * Refreshes the view. - called by datachanged on the store. - do not call directly.
25080 refresh : function(){
25081 //Roo.log('refresh');
25084 // if we are using something like 'domtemplate', then
25085 // the what gets used is:
25086 // t.applySubtemplate(NAME, data, wrapping data..)
25087 // the outer template then get' applied with
25088 // the store 'extra data'
25089 // and the body get's added to the
25090 // roo-name="data" node?
25091 // <span class='roo-tpl-{name}'></span> ?????
25095 this.clearSelections();
25096 this.el.update("");
25098 var records = this.store.getRange();
25099 if(records.length < 1) {
25101 // is this valid?? = should it render a template??
25103 this.el.update(this.emptyText);
25107 if (this.dataName) {
25108 this.el.update(t.apply(this.store.meta)); //????
25109 el = this.el.child('.roo-tpl-' + this.dataName);
25112 for(var i = 0, len = records.length; i < len; i++){
25113 var data = this.prepareData(records[i].data, i, records[i]);
25114 this.fireEvent("preparedata", this, data, i, records[i]);
25116 var d = Roo.apply({}, data);
25119 Roo.apply(d, {'roo-id' : Roo.id()});
25123 Roo.each(this.parent.item, function(item){
25124 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
25127 Roo.apply(d, {'roo-data-checked' : 'checked'});
25131 html[html.length] = Roo.util.Format.trim(
25133 t.applySubtemplate(this.dataName, d, this.store.meta) :
25140 el.update(html.join(""));
25141 this.nodes = el.dom.childNodes;
25142 this.updateIndexes(0);
25147 * Function to override to reformat the data that is sent to
25148 * the template for each node.
25149 * DEPRICATED - use the preparedata event handler.
25150 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25151 * a JSON object for an UpdateManager bound view).
25153 prepareData : function(data, index, record)
25155 this.fireEvent("preparedata", this, data, index, record);
25159 onUpdate : function(ds, record){
25160 // Roo.log('on update');
25161 this.clearSelections();
25162 var index = this.store.indexOf(record);
25163 var n = this.nodes[index];
25164 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25165 n.parentNode.removeChild(n);
25166 this.updateIndexes(index, index);
25172 onAdd : function(ds, records, index)
25174 //Roo.log(['on Add', ds, records, index] );
25175 this.clearSelections();
25176 if(this.nodes.length == 0){
25180 var n = this.nodes[index];
25181 for(var i = 0, len = records.length; i < len; i++){
25182 var d = this.prepareData(records[i].data, i, records[i]);
25184 this.tpl.insertBefore(n, d);
25187 this.tpl.append(this.el, d);
25190 this.updateIndexes(index);
25193 onRemove : function(ds, record, index){
25194 // Roo.log('onRemove');
25195 this.clearSelections();
25196 var el = this.dataName ?
25197 this.el.child('.roo-tpl-' + this.dataName) :
25200 el.dom.removeChild(this.nodes[index]);
25201 this.updateIndexes(index);
25205 * Refresh an individual node.
25206 * @param {Number} index
25208 refreshNode : function(index){
25209 this.onUpdate(this.store, this.store.getAt(index));
25212 updateIndexes : function(startIndex, endIndex){
25213 var ns = this.nodes;
25214 startIndex = startIndex || 0;
25215 endIndex = endIndex || ns.length - 1;
25216 for(var i = startIndex; i <= endIndex; i++){
25217 ns[i].nodeIndex = i;
25222 * Changes the data store this view uses and refresh the view.
25223 * @param {Store} store
25225 setStore : function(store, initial){
25226 if(!initial && this.store){
25227 this.store.un("datachanged", this.refresh);
25228 this.store.un("add", this.onAdd);
25229 this.store.un("remove", this.onRemove);
25230 this.store.un("update", this.onUpdate);
25231 this.store.un("clear", this.refresh);
25232 this.store.un("beforeload", this.onBeforeLoad);
25233 this.store.un("load", this.onLoad);
25234 this.store.un("loadexception", this.onLoad);
25238 store.on("datachanged", this.refresh, this);
25239 store.on("add", this.onAdd, this);
25240 store.on("remove", this.onRemove, this);
25241 store.on("update", this.onUpdate, this);
25242 store.on("clear", this.refresh, this);
25243 store.on("beforeload", this.onBeforeLoad, this);
25244 store.on("load", this.onLoad, this);
25245 store.on("loadexception", this.onLoad, this);
25253 * onbeforeLoad - masks the loading area.
25256 onBeforeLoad : function(store,opts)
25258 //Roo.log('onBeforeLoad');
25260 this.el.update("");
25262 this.el.mask(this.mask ? this.mask : "Loading" );
25264 onLoad : function ()
25271 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25272 * @param {HTMLElement} node
25273 * @return {HTMLElement} The template node
25275 findItemFromChild : function(node){
25276 var el = this.dataName ?
25277 this.el.child('.roo-tpl-' + this.dataName,true) :
25280 if(!node || node.parentNode == el){
25283 var p = node.parentNode;
25284 while(p && p != el){
25285 if(p.parentNode == el){
25294 onClick : function(e){
25295 var item = this.findItemFromChild(e.getTarget());
25297 var index = this.indexOf(item);
25298 if(this.onItemClick(item, index, e) !== false){
25299 this.fireEvent("click", this, index, item, e);
25302 this.clearSelections();
25307 onContextMenu : function(e){
25308 var item = this.findItemFromChild(e.getTarget());
25310 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25315 onDblClick : function(e){
25316 var item = this.findItemFromChild(e.getTarget());
25318 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25322 onItemClick : function(item, index, e)
25324 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25327 if (this.toggleSelect) {
25328 var m = this.isSelected(item) ? 'unselect' : 'select';
25331 _t[m](item, true, false);
25334 if(this.multiSelect || this.singleSelect){
25335 if(this.multiSelect && e.shiftKey && this.lastSelection){
25336 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25338 this.select(item, this.multiSelect && e.ctrlKey);
25339 this.lastSelection = item;
25342 if(!this.tickable){
25343 e.preventDefault();
25351 * Get the number of selected nodes.
25354 getSelectionCount : function(){
25355 return this.selections.length;
25359 * Get the currently selected nodes.
25360 * @return {Array} An array of HTMLElements
25362 getSelectedNodes : function(){
25363 return this.selections;
25367 * Get the indexes of the selected nodes.
25370 getSelectedIndexes : function(){
25371 var indexes = [], s = this.selections;
25372 for(var i = 0, len = s.length; i < len; i++){
25373 indexes.push(s[i].nodeIndex);
25379 * Clear all selections
25380 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25382 clearSelections : function(suppressEvent){
25383 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25384 this.cmp.elements = this.selections;
25385 this.cmp.removeClass(this.selectedClass);
25386 this.selections = [];
25387 if(!suppressEvent){
25388 this.fireEvent("selectionchange", this, this.selections);
25394 * Returns true if the passed node is selected
25395 * @param {HTMLElement/Number} node The node or node index
25396 * @return {Boolean}
25398 isSelected : function(node){
25399 var s = this.selections;
25403 node = this.getNode(node);
25404 return s.indexOf(node) !== -1;
25409 * @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
25410 * @param {Boolean} keepExisting (optional) true to keep existing selections
25411 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25413 select : function(nodeInfo, keepExisting, suppressEvent){
25414 if(nodeInfo instanceof Array){
25416 this.clearSelections(true);
25418 for(var i = 0, len = nodeInfo.length; i < len; i++){
25419 this.select(nodeInfo[i], true, true);
25423 var node = this.getNode(nodeInfo);
25424 if(!node || this.isSelected(node)){
25425 return; // already selected.
25428 this.clearSelections(true);
25431 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25432 Roo.fly(node).addClass(this.selectedClass);
25433 this.selections.push(node);
25434 if(!suppressEvent){
25435 this.fireEvent("selectionchange", this, this.selections);
25443 * @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
25444 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25445 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25447 unselect : function(nodeInfo, keepExisting, suppressEvent)
25449 if(nodeInfo instanceof Array){
25450 Roo.each(this.selections, function(s) {
25451 this.unselect(s, nodeInfo);
25455 var node = this.getNode(nodeInfo);
25456 if(!node || !this.isSelected(node)){
25457 //Roo.log("not selected");
25458 return; // not selected.
25462 Roo.each(this.selections, function(s) {
25464 Roo.fly(node).removeClass(this.selectedClass);
25471 this.selections= ns;
25472 this.fireEvent("selectionchange", this, this.selections);
25476 * Gets a template node.
25477 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25478 * @return {HTMLElement} The node or null if it wasn't found
25480 getNode : function(nodeInfo){
25481 if(typeof nodeInfo == "string"){
25482 return document.getElementById(nodeInfo);
25483 }else if(typeof nodeInfo == "number"){
25484 return this.nodes[nodeInfo];
25490 * Gets a range template nodes.
25491 * @param {Number} startIndex
25492 * @param {Number} endIndex
25493 * @return {Array} An array of nodes
25495 getNodes : function(start, end){
25496 var ns = this.nodes;
25497 start = start || 0;
25498 end = typeof end == "undefined" ? ns.length - 1 : end;
25501 for(var i = start; i <= end; i++){
25505 for(var i = start; i >= end; i--){
25513 * Finds the index of the passed node
25514 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25515 * @return {Number} The index of the node or -1
25517 indexOf : function(node){
25518 node = this.getNode(node);
25519 if(typeof node.nodeIndex == "number"){
25520 return node.nodeIndex;
25522 var ns = this.nodes;
25523 for(var i = 0, len = ns.length; i < len; i++){
25533 * Ext JS Library 1.1.1
25534 * Copyright(c) 2006-2007, Ext JS, LLC.
25536 * Originally Released Under LGPL - original licence link has changed is not relivant.
25539 * <script type="text/javascript">
25543 * @class Roo.JsonView
25544 * @extends Roo.View
25545 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25547 var view = new Roo.JsonView({
25548 container: "my-element",
25549 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25554 // listen for node click?
25555 view.on("click", function(vw, index, node, e){
25556 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25559 // direct load of JSON data
25560 view.load("foobar.php");
25562 // Example from my blog list
25563 var tpl = new Roo.Template(
25564 '<div class="entry">' +
25565 '<a class="entry-title" href="{link}">{title}</a>' +
25566 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25567 "</div><hr />"
25570 var moreView = new Roo.JsonView({
25571 container : "entry-list",
25575 moreView.on("beforerender", this.sortEntries, this);
25577 url: "/blog/get-posts.php",
25578 params: "allposts=true",
25579 text: "Loading Blog Entries..."
25583 * Note: old code is supported with arguments : (container, template, config)
25587 * Create a new JsonView
25589 * @param {Object} config The config object
25592 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25595 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25597 var um = this.el.getUpdateManager();
25598 um.setRenderer(this);
25599 um.on("update", this.onLoad, this);
25600 um.on("failure", this.onLoadException, this);
25603 * @event beforerender
25604 * Fires before rendering of the downloaded JSON data.
25605 * @param {Roo.JsonView} this
25606 * @param {Object} data The JSON data loaded
25610 * Fires when data is loaded.
25611 * @param {Roo.JsonView} this
25612 * @param {Object} data The JSON data loaded
25613 * @param {Object} response The raw Connect response object
25616 * @event loadexception
25617 * Fires when loading fails.
25618 * @param {Roo.JsonView} this
25619 * @param {Object} response The raw Connect response object
25622 'beforerender' : true,
25624 'loadexception' : true
25627 Roo.extend(Roo.JsonView, Roo.View, {
25629 * @type {String} The root property in the loaded JSON object that contains the data
25634 * Refreshes the view.
25636 refresh : function(){
25637 this.clearSelections();
25638 this.el.update("");
25640 var o = this.jsonData;
25641 if(o && o.length > 0){
25642 for(var i = 0, len = o.length; i < len; i++){
25643 var data = this.prepareData(o[i], i, o);
25644 html[html.length] = this.tpl.apply(data);
25647 html.push(this.emptyText);
25649 this.el.update(html.join(""));
25650 this.nodes = this.el.dom.childNodes;
25651 this.updateIndexes(0);
25655 * 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.
25656 * @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:
25659 url: "your-url.php",
25660 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25661 callback: yourFunction,
25662 scope: yourObject, //(optional scope)
25665 text: "Loading...",
25670 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25671 * 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.
25672 * @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}
25673 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25674 * @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.
25677 var um = this.el.getUpdateManager();
25678 um.update.apply(um, arguments);
25681 render : function(el, response){
25682 this.clearSelections();
25683 this.el.update("");
25686 o = Roo.util.JSON.decode(response.responseText);
25689 o = o[this.jsonRoot];
25694 * The current JSON data or null
25697 this.beforeRender();
25702 * Get the number of records in the current JSON dataset
25705 getCount : function(){
25706 return this.jsonData ? this.jsonData.length : 0;
25710 * Returns the JSON object for the specified node(s)
25711 * @param {HTMLElement/Array} node The node or an array of nodes
25712 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25713 * you get the JSON object for the node
25715 getNodeData : function(node){
25716 if(node instanceof Array){
25718 for(var i = 0, len = node.length; i < len; i++){
25719 data.push(this.getNodeData(node[i]));
25723 return this.jsonData[this.indexOf(node)] || null;
25726 beforeRender : function(){
25727 this.snapshot = this.jsonData;
25729 this.sort.apply(this, this.sortInfo);
25731 this.fireEvent("beforerender", this, this.jsonData);
25734 onLoad : function(el, o){
25735 this.fireEvent("load", this, this.jsonData, o);
25738 onLoadException : function(el, o){
25739 this.fireEvent("loadexception", this, o);
25743 * Filter the data by a specific property.
25744 * @param {String} property A property on your JSON objects
25745 * @param {String/RegExp} value Either string that the property values
25746 * should start with, or a RegExp to test against the property
25748 filter : function(property, value){
25751 var ss = this.snapshot;
25752 if(typeof value == "string"){
25753 var vlen = value.length;
25755 this.clearFilter();
25758 value = value.toLowerCase();
25759 for(var i = 0, len = ss.length; i < len; i++){
25761 if(o[property].substr(0, vlen).toLowerCase() == value){
25765 } else if(value.exec){ // regex?
25766 for(var i = 0, len = ss.length; i < len; i++){
25768 if(value.test(o[property])){
25775 this.jsonData = data;
25781 * Filter by a function. The passed function will be called with each
25782 * object in the current dataset. If the function returns true the value is kept,
25783 * otherwise it is filtered.
25784 * @param {Function} fn
25785 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25787 filterBy : function(fn, scope){
25790 var ss = this.snapshot;
25791 for(var i = 0, len = ss.length; i < len; i++){
25793 if(fn.call(scope || this, o)){
25797 this.jsonData = data;
25803 * Clears the current filter.
25805 clearFilter : function(){
25806 if(this.snapshot && this.jsonData != this.snapshot){
25807 this.jsonData = this.snapshot;
25814 * Sorts the data for this view and refreshes it.
25815 * @param {String} property A property on your JSON objects to sort on
25816 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25817 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25819 sort : function(property, dir, sortType){
25820 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25823 var dsc = dir && dir.toLowerCase() == "desc";
25824 var f = function(o1, o2){
25825 var v1 = sortType ? sortType(o1[p]) : o1[p];
25826 var v2 = sortType ? sortType(o2[p]) : o2[p];
25829 return dsc ? +1 : -1;
25830 } else if(v1 > v2){
25831 return dsc ? -1 : +1;
25836 this.jsonData.sort(f);
25838 if(this.jsonData != this.snapshot){
25839 this.snapshot.sort(f);
25845 * Ext JS Library 1.1.1
25846 * Copyright(c) 2006-2007, Ext JS, LLC.
25848 * Originally Released Under LGPL - original licence link has changed is not relivant.
25851 * <script type="text/javascript">
25856 * @class Roo.ColorPalette
25857 * @extends Roo.Component
25858 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25859 * Here's an example of typical usage:
25861 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25862 cp.render('my-div');
25864 cp.on('select', function(palette, selColor){
25865 // do something with selColor
25869 * Create a new ColorPalette
25870 * @param {Object} config The config object
25872 Roo.ColorPalette = function(config){
25873 Roo.ColorPalette.superclass.constructor.call(this, config);
25877 * Fires when a color is selected
25878 * @param {ColorPalette} this
25879 * @param {String} color The 6-digit color hex code (without the # symbol)
25885 this.on("select", this.handler, this.scope, true);
25888 Roo.extend(Roo.ColorPalette, Roo.Component, {
25890 * @cfg {String} itemCls
25891 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25893 itemCls : "x-color-palette",
25895 * @cfg {String} value
25896 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25897 * the hex codes are case-sensitive.
25900 clickEvent:'click',
25902 ctype: "Roo.ColorPalette",
25905 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25907 allowReselect : false,
25910 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25911 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25912 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25913 * of colors with the width setting until the box is symmetrical.</p>
25914 * <p>You can override individual colors if needed:</p>
25916 var cp = new Roo.ColorPalette();
25917 cp.colors[0] = "FF0000"; // change the first box to red
25920 Or you can provide a custom array of your own for complete control:
25922 var cp = new Roo.ColorPalette();
25923 cp.colors = ["000000", "993300", "333300"];
25928 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25929 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25930 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25931 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25932 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25936 onRender : function(container, position){
25937 var t = new Roo.MasterTemplate(
25938 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25940 var c = this.colors;
25941 for(var i = 0, len = c.length; i < len; i++){
25944 var el = document.createElement("div");
25945 el.className = this.itemCls;
25947 container.dom.insertBefore(el, position);
25948 this.el = Roo.get(el);
25949 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25950 if(this.clickEvent != 'click'){
25951 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25956 afterRender : function(){
25957 Roo.ColorPalette.superclass.afterRender.call(this);
25959 var s = this.value;
25966 handleClick : function(e, t){
25967 e.preventDefault();
25968 if(!this.disabled){
25969 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25970 this.select(c.toUpperCase());
25975 * Selects the specified color in the palette (fires the select event)
25976 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25978 select : function(color){
25979 color = color.replace("#", "");
25980 if(color != this.value || this.allowReselect){
25983 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25985 el.child("a.color-"+color).addClass("x-color-palette-sel");
25986 this.value = color;
25987 this.fireEvent("select", this, color);
25992 * Ext JS Library 1.1.1
25993 * Copyright(c) 2006-2007, Ext JS, LLC.
25995 * Originally Released Under LGPL - original licence link has changed is not relivant.
25998 * <script type="text/javascript">
26002 * @class Roo.DatePicker
26003 * @extends Roo.Component
26004 * Simple date picker class.
26006 * Create a new DatePicker
26007 * @param {Object} config The config object
26009 Roo.DatePicker = function(config){
26010 Roo.DatePicker.superclass.constructor.call(this, config);
26012 this.value = config && config.value ?
26013 config.value.clearTime() : new Date().clearTime();
26018 * Fires when a date is selected
26019 * @param {DatePicker} this
26020 * @param {Date} date The selected date
26024 * @event monthchange
26025 * Fires when the displayed month changes
26026 * @param {DatePicker} this
26027 * @param {Date} date The selected month
26029 'monthchange': true
26033 this.on("select", this.handler, this.scope || this);
26035 // build the disabledDatesRE
26036 if(!this.disabledDatesRE && this.disabledDates){
26037 var dd = this.disabledDates;
26039 for(var i = 0; i < dd.length; i++){
26041 if(i != dd.length-1) re += "|";
26043 this.disabledDatesRE = new RegExp(re + ")");
26047 Roo.extend(Roo.DatePicker, Roo.Component, {
26049 * @cfg {String} todayText
26050 * The text to display on the button that selects the current date (defaults to "Today")
26052 todayText : "Today",
26054 * @cfg {String} okText
26055 * The text to display on the ok button
26057 okText : " OK ", //   to give the user extra clicking room
26059 * @cfg {String} cancelText
26060 * The text to display on the cancel button
26062 cancelText : "Cancel",
26064 * @cfg {String} todayTip
26065 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
26067 todayTip : "{0} (Spacebar)",
26069 * @cfg {Date} minDate
26070 * Minimum allowable date (JavaScript date object, defaults to null)
26074 * @cfg {Date} maxDate
26075 * Maximum allowable date (JavaScript date object, defaults to null)
26079 * @cfg {String} minText
26080 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
26082 minText : "This date is before the minimum date",
26084 * @cfg {String} maxText
26085 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
26087 maxText : "This date is after the maximum date",
26089 * @cfg {String} format
26090 * The default date format string which can be overriden for localization support. The format must be
26091 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
26095 * @cfg {Array} disabledDays
26096 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
26098 disabledDays : null,
26100 * @cfg {String} disabledDaysText
26101 * The tooltip to display when the date falls on a disabled day (defaults to "")
26103 disabledDaysText : "",
26105 * @cfg {RegExp} disabledDatesRE
26106 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
26108 disabledDatesRE : null,
26110 * @cfg {String} disabledDatesText
26111 * The tooltip text to display when the date falls on a disabled date (defaults to "")
26113 disabledDatesText : "",
26115 * @cfg {Boolean} constrainToViewport
26116 * True to constrain the date picker to the viewport (defaults to true)
26118 constrainToViewport : true,
26120 * @cfg {Array} monthNames
26121 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
26123 monthNames : Date.monthNames,
26125 * @cfg {Array} dayNames
26126 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
26128 dayNames : Date.dayNames,
26130 * @cfg {String} nextText
26131 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
26133 nextText: 'Next Month (Control+Right)',
26135 * @cfg {String} prevText
26136 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
26138 prevText: 'Previous Month (Control+Left)',
26140 * @cfg {String} monthYearText
26141 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
26143 monthYearText: 'Choose a month (Control+Up/Down to move years)',
26145 * @cfg {Number} startDay
26146 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
26150 * @cfg {Bool} showClear
26151 * Show a clear button (usefull for date form elements that can be blank.)
26157 * Sets the value of the date field
26158 * @param {Date} value The date to set
26160 setValue : function(value){
26161 var old = this.value;
26163 if (typeof(value) == 'string') {
26165 value = Date.parseDate(value, this.format);
26168 value = new Date();
26171 this.value = value.clearTime(true);
26173 this.update(this.value);
26178 * Gets the current selected value of the date field
26179 * @return {Date} The selected date
26181 getValue : function(){
26186 focus : function(){
26188 this.update(this.activeDate);
26193 onRender : function(container, position){
26196 '<table cellspacing="0">',
26197 '<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>',
26198 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26199 var dn = this.dayNames;
26200 for(var i = 0; i < 7; i++){
26201 var d = this.startDay+i;
26205 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26207 m[m.length] = "</tr></thead><tbody><tr>";
26208 for(var i = 0; i < 42; i++) {
26209 if(i % 7 == 0 && i != 0){
26210 m[m.length] = "</tr><tr>";
26212 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26214 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26215 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26217 var el = document.createElement("div");
26218 el.className = "x-date-picker";
26219 el.innerHTML = m.join("");
26221 container.dom.insertBefore(el, position);
26223 this.el = Roo.get(el);
26224 this.eventEl = Roo.get(el.firstChild);
26226 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26227 handler: this.showPrevMonth,
26229 preventDefault:true,
26233 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26234 handler: this.showNextMonth,
26236 preventDefault:true,
26240 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26242 this.monthPicker = this.el.down('div.x-date-mp');
26243 this.monthPicker.enableDisplayMode('block');
26245 var kn = new Roo.KeyNav(this.eventEl, {
26246 "left" : function(e){
26248 this.showPrevMonth() :
26249 this.update(this.activeDate.add("d", -1));
26252 "right" : function(e){
26254 this.showNextMonth() :
26255 this.update(this.activeDate.add("d", 1));
26258 "up" : function(e){
26260 this.showNextYear() :
26261 this.update(this.activeDate.add("d", -7));
26264 "down" : function(e){
26266 this.showPrevYear() :
26267 this.update(this.activeDate.add("d", 7));
26270 "pageUp" : function(e){
26271 this.showNextMonth();
26274 "pageDown" : function(e){
26275 this.showPrevMonth();
26278 "enter" : function(e){
26279 e.stopPropagation();
26286 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26288 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26290 this.el.unselectable();
26292 this.cells = this.el.select("table.x-date-inner tbody td");
26293 this.textNodes = this.el.query("table.x-date-inner tbody span");
26295 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26297 tooltip: this.monthYearText
26300 this.mbtn.on('click', this.showMonthPicker, this);
26301 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26304 var today = (new Date()).dateFormat(this.format);
26306 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26307 if (this.showClear) {
26308 baseTb.add( new Roo.Toolbar.Fill());
26311 text: String.format(this.todayText, today),
26312 tooltip: String.format(this.todayTip, today),
26313 handler: this.selectToday,
26317 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26320 if (this.showClear) {
26322 baseTb.add( new Roo.Toolbar.Fill());
26325 cls: 'x-btn-icon x-btn-clear',
26326 handler: function() {
26328 this.fireEvent("select", this, '');
26338 this.update(this.value);
26341 createMonthPicker : function(){
26342 if(!this.monthPicker.dom.firstChild){
26343 var buf = ['<table border="0" cellspacing="0">'];
26344 for(var i = 0; i < 6; i++){
26346 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26347 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26349 '<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>' :
26350 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26354 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26356 '</button><button type="button" class="x-date-mp-cancel">',
26358 '</button></td></tr>',
26361 this.monthPicker.update(buf.join(''));
26362 this.monthPicker.on('click', this.onMonthClick, this);
26363 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26365 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26366 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26368 this.mpMonths.each(function(m, a, i){
26371 m.dom.xmonth = 5 + Math.round(i * .5);
26373 m.dom.xmonth = Math.round((i-1) * .5);
26379 showMonthPicker : function(){
26380 this.createMonthPicker();
26381 var size = this.el.getSize();
26382 this.monthPicker.setSize(size);
26383 this.monthPicker.child('table').setSize(size);
26385 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26386 this.updateMPMonth(this.mpSelMonth);
26387 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26388 this.updateMPYear(this.mpSelYear);
26390 this.monthPicker.slideIn('t', {duration:.2});
26393 updateMPYear : function(y){
26395 var ys = this.mpYears.elements;
26396 for(var i = 1; i <= 10; i++){
26397 var td = ys[i-1], y2;
26399 y2 = y + Math.round(i * .5);
26400 td.firstChild.innerHTML = y2;
26403 y2 = y - (5-Math.round(i * .5));
26404 td.firstChild.innerHTML = y2;
26407 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26411 updateMPMonth : function(sm){
26412 this.mpMonths.each(function(m, a, i){
26413 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26417 selectMPMonth: function(m){
26421 onMonthClick : function(e, t){
26423 var el = new Roo.Element(t), pn;
26424 if(el.is('button.x-date-mp-cancel')){
26425 this.hideMonthPicker();
26427 else if(el.is('button.x-date-mp-ok')){
26428 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26429 this.hideMonthPicker();
26431 else if(pn = el.up('td.x-date-mp-month', 2)){
26432 this.mpMonths.removeClass('x-date-mp-sel');
26433 pn.addClass('x-date-mp-sel');
26434 this.mpSelMonth = pn.dom.xmonth;
26436 else if(pn = el.up('td.x-date-mp-year', 2)){
26437 this.mpYears.removeClass('x-date-mp-sel');
26438 pn.addClass('x-date-mp-sel');
26439 this.mpSelYear = pn.dom.xyear;
26441 else if(el.is('a.x-date-mp-prev')){
26442 this.updateMPYear(this.mpyear-10);
26444 else if(el.is('a.x-date-mp-next')){
26445 this.updateMPYear(this.mpyear+10);
26449 onMonthDblClick : function(e, t){
26451 var el = new Roo.Element(t), pn;
26452 if(pn = el.up('td.x-date-mp-month', 2)){
26453 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26454 this.hideMonthPicker();
26456 else if(pn = el.up('td.x-date-mp-year', 2)){
26457 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26458 this.hideMonthPicker();
26462 hideMonthPicker : function(disableAnim){
26463 if(this.monthPicker){
26464 if(disableAnim === true){
26465 this.monthPicker.hide();
26467 this.monthPicker.slideOut('t', {duration:.2});
26473 showPrevMonth : function(e){
26474 this.update(this.activeDate.add("mo", -1));
26478 showNextMonth : function(e){
26479 this.update(this.activeDate.add("mo", 1));
26483 showPrevYear : function(){
26484 this.update(this.activeDate.add("y", -1));
26488 showNextYear : function(){
26489 this.update(this.activeDate.add("y", 1));
26493 handleMouseWheel : function(e){
26494 var delta = e.getWheelDelta();
26496 this.showPrevMonth();
26498 } else if(delta < 0){
26499 this.showNextMonth();
26505 handleDateClick : function(e, t){
26507 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26508 this.setValue(new Date(t.dateValue));
26509 this.fireEvent("select", this, this.value);
26514 selectToday : function(){
26515 this.setValue(new Date().clearTime());
26516 this.fireEvent("select", this, this.value);
26520 update : function(date)
26522 var vd = this.activeDate;
26523 this.activeDate = date;
26525 var t = date.getTime();
26526 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26527 this.cells.removeClass("x-date-selected");
26528 this.cells.each(function(c){
26529 if(c.dom.firstChild.dateValue == t){
26530 c.addClass("x-date-selected");
26531 setTimeout(function(){
26532 try{c.dom.firstChild.focus();}catch(e){}
26541 var days = date.getDaysInMonth();
26542 var firstOfMonth = date.getFirstDateOfMonth();
26543 var startingPos = firstOfMonth.getDay()-this.startDay;
26545 if(startingPos <= this.startDay){
26549 var pm = date.add("mo", -1);
26550 var prevStart = pm.getDaysInMonth()-startingPos;
26552 var cells = this.cells.elements;
26553 var textEls = this.textNodes;
26554 days += startingPos;
26556 // convert everything to numbers so it's fast
26557 var day = 86400000;
26558 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26559 var today = new Date().clearTime().getTime();
26560 var sel = date.clearTime().getTime();
26561 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26562 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26563 var ddMatch = this.disabledDatesRE;
26564 var ddText = this.disabledDatesText;
26565 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26566 var ddaysText = this.disabledDaysText;
26567 var format = this.format;
26569 var setCellClass = function(cal, cell){
26571 var t = d.getTime();
26572 cell.firstChild.dateValue = t;
26574 cell.className += " x-date-today";
26575 cell.title = cal.todayText;
26578 cell.className += " x-date-selected";
26579 setTimeout(function(){
26580 try{cell.firstChild.focus();}catch(e){}
26585 cell.className = " x-date-disabled";
26586 cell.title = cal.minText;
26590 cell.className = " x-date-disabled";
26591 cell.title = cal.maxText;
26595 if(ddays.indexOf(d.getDay()) != -1){
26596 cell.title = ddaysText;
26597 cell.className = " x-date-disabled";
26600 if(ddMatch && format){
26601 var fvalue = d.dateFormat(format);
26602 if(ddMatch.test(fvalue)){
26603 cell.title = ddText.replace("%0", fvalue);
26604 cell.className = " x-date-disabled";
26610 for(; i < startingPos; i++) {
26611 textEls[i].innerHTML = (++prevStart);
26612 d.setDate(d.getDate()+1);
26613 cells[i].className = "x-date-prevday";
26614 setCellClass(this, cells[i]);
26616 for(; i < days; i++){
26617 intDay = i - startingPos + 1;
26618 textEls[i].innerHTML = (intDay);
26619 d.setDate(d.getDate()+1);
26620 cells[i].className = "x-date-active";
26621 setCellClass(this, cells[i]);
26624 for(; i < 42; i++) {
26625 textEls[i].innerHTML = (++extraDays);
26626 d.setDate(d.getDate()+1);
26627 cells[i].className = "x-date-nextday";
26628 setCellClass(this, cells[i]);
26631 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26632 this.fireEvent('monthchange', this, date);
26634 if(!this.internalRender){
26635 var main = this.el.dom.firstChild;
26636 var w = main.offsetWidth;
26637 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26638 Roo.fly(main).setWidth(w);
26639 this.internalRender = true;
26640 // opera does not respect the auto grow header center column
26641 // then, after it gets a width opera refuses to recalculate
26642 // without a second pass
26643 if(Roo.isOpera && !this.secondPass){
26644 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26645 this.secondPass = true;
26646 this.update.defer(10, this, [date]);
26654 * Ext JS Library 1.1.1
26655 * Copyright(c) 2006-2007, Ext JS, LLC.
26657 * Originally Released Under LGPL - original licence link has changed is not relivant.
26660 * <script type="text/javascript">
26663 * @class Roo.TabPanel
26664 * @extends Roo.util.Observable
26665 * A lightweight tab container.
26669 // basic tabs 1, built from existing content
26670 var tabs = new Roo.TabPanel("tabs1");
26671 tabs.addTab("script", "View Script");
26672 tabs.addTab("markup", "View Markup");
26673 tabs.activate("script");
26675 // more advanced tabs, built from javascript
26676 var jtabs = new Roo.TabPanel("jtabs");
26677 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26679 // set up the UpdateManager
26680 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26681 var updater = tab2.getUpdateManager();
26682 updater.setDefaultUrl("ajax1.htm");
26683 tab2.on('activate', updater.refresh, updater, true);
26685 // Use setUrl for Ajax loading
26686 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26687 tab3.setUrl("ajax2.htm", null, true);
26690 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26693 jtabs.activate("jtabs-1");
26696 * Create a new TabPanel.
26697 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26698 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26700 Roo.TabPanel = function(container, config){
26702 * The container element for this TabPanel.
26703 * @type Roo.Element
26705 this.el = Roo.get(container, true);
26707 if(typeof config == "boolean"){
26708 this.tabPosition = config ? "bottom" : "top";
26710 Roo.apply(this, config);
26713 if(this.tabPosition == "bottom"){
26714 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26715 this.el.addClass("x-tabs-bottom");
26717 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26718 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26719 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26721 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26723 if(this.tabPosition != "bottom"){
26724 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26725 * @type Roo.Element
26727 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26728 this.el.addClass("x-tabs-top");
26732 this.bodyEl.setStyle("position", "relative");
26734 this.active = null;
26735 this.activateDelegate = this.activate.createDelegate(this);
26740 * Fires when the active tab changes
26741 * @param {Roo.TabPanel} this
26742 * @param {Roo.TabPanelItem} activePanel The new active tab
26746 * @event beforetabchange
26747 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26748 * @param {Roo.TabPanel} this
26749 * @param {Object} e Set cancel to true on this object to cancel the tab change
26750 * @param {Roo.TabPanelItem} tab The tab being changed to
26752 "beforetabchange" : true
26755 Roo.EventManager.onWindowResize(this.onResize, this);
26756 this.cpad = this.el.getPadding("lr");
26757 this.hiddenCount = 0;
26760 // toolbar on the tabbar support...
26761 if (this.toolbar) {
26762 var tcfg = this.toolbar;
26763 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26764 this.toolbar = new Roo.Toolbar(tcfg);
26765 if (Roo.isSafari) {
26766 var tbl = tcfg.container.child('table', true);
26767 tbl.setAttribute('width', '100%');
26774 Roo.TabPanel.superclass.constructor.call(this);
26777 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26779 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26781 tabPosition : "top",
26783 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26785 currentTabWidth : 0,
26787 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26791 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26795 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26797 preferredTabWidth : 175,
26799 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26801 resizeTabs : false,
26803 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26805 monitorResize : true,
26807 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26812 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26813 * @param {String} id The id of the div to use <b>or create</b>
26814 * @param {String} text The text for the tab
26815 * @param {String} content (optional) Content to put in the TabPanelItem body
26816 * @param {Boolean} closable (optional) True to create a close icon on the tab
26817 * @return {Roo.TabPanelItem} The created TabPanelItem
26819 addTab : function(id, text, content, closable){
26820 var item = new Roo.TabPanelItem(this, id, text, closable);
26821 this.addTabItem(item);
26823 item.setContent(content);
26829 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26830 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26831 * @return {Roo.TabPanelItem}
26833 getTab : function(id){
26834 return this.items[id];
26838 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26839 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26841 hideTab : function(id){
26842 var t = this.items[id];
26845 this.hiddenCount++;
26846 this.autoSizeTabs();
26851 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26852 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26854 unhideTab : function(id){
26855 var t = this.items[id];
26857 t.setHidden(false);
26858 this.hiddenCount--;
26859 this.autoSizeTabs();
26864 * Adds an existing {@link Roo.TabPanelItem}.
26865 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26867 addTabItem : function(item){
26868 this.items[item.id] = item;
26869 this.items.push(item);
26870 if(this.resizeTabs){
26871 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26872 this.autoSizeTabs();
26879 * Removes a {@link Roo.TabPanelItem}.
26880 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26882 removeTab : function(id){
26883 var items = this.items;
26884 var tab = items[id];
26885 if(!tab) { return; }
26886 var index = items.indexOf(tab);
26887 if(this.active == tab && items.length > 1){
26888 var newTab = this.getNextAvailable(index);
26893 this.stripEl.dom.removeChild(tab.pnode.dom);
26894 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26895 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26897 items.splice(index, 1);
26898 delete this.items[tab.id];
26899 tab.fireEvent("close", tab);
26900 tab.purgeListeners();
26901 this.autoSizeTabs();
26904 getNextAvailable : function(start){
26905 var items = this.items;
26907 // look for a next tab that will slide over to
26908 // replace the one being removed
26909 while(index < items.length){
26910 var item = items[++index];
26911 if(item && !item.isHidden()){
26915 // if one isn't found select the previous tab (on the left)
26918 var item = items[--index];
26919 if(item && !item.isHidden()){
26927 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26928 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26930 disableTab : function(id){
26931 var tab = this.items[id];
26932 if(tab && this.active != tab){
26938 * Enables a {@link Roo.TabPanelItem} that is disabled.
26939 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26941 enableTab : function(id){
26942 var tab = this.items[id];
26947 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26948 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26949 * @return {Roo.TabPanelItem} The TabPanelItem.
26951 activate : function(id){
26952 var tab = this.items[id];
26956 if(tab == this.active || tab.disabled){
26960 this.fireEvent("beforetabchange", this, e, tab);
26961 if(e.cancel !== true && !tab.disabled){
26963 this.active.hide();
26965 this.active = this.items[id];
26966 this.active.show();
26967 this.fireEvent("tabchange", this, this.active);
26973 * Gets the active {@link Roo.TabPanelItem}.
26974 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26976 getActiveTab : function(){
26977 return this.active;
26981 * Updates the tab body element to fit the height of the container element
26982 * for overflow scrolling
26983 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26985 syncHeight : function(targetHeight){
26986 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26987 var bm = this.bodyEl.getMargins();
26988 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26989 this.bodyEl.setHeight(newHeight);
26993 onResize : function(){
26994 if(this.monitorResize){
26995 this.autoSizeTabs();
27000 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
27002 beginUpdate : function(){
27003 this.updating = true;
27007 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
27009 endUpdate : function(){
27010 this.updating = false;
27011 this.autoSizeTabs();
27015 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
27017 autoSizeTabs : function(){
27018 var count = this.items.length;
27019 var vcount = count - this.hiddenCount;
27020 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
27021 var w = Math.max(this.el.getWidth() - this.cpad, 10);
27022 var availWidth = Math.floor(w / vcount);
27023 var b = this.stripBody;
27024 if(b.getWidth() > w){
27025 var tabs = this.items;
27026 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
27027 if(availWidth < this.minTabWidth){
27028 /*if(!this.sleft){ // incomplete scrolling code
27029 this.createScrollButtons();
27032 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
27035 if(this.currentTabWidth < this.preferredTabWidth){
27036 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
27042 * Returns the number of tabs in this TabPanel.
27045 getCount : function(){
27046 return this.items.length;
27050 * Resizes all the tabs to the passed width
27051 * @param {Number} The new width
27053 setTabWidth : function(width){
27054 this.currentTabWidth = width;
27055 for(var i = 0, len = this.items.length; i < len; i++) {
27056 if(!this.items[i].isHidden())this.items[i].setWidth(width);
27061 * Destroys this TabPanel
27062 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
27064 destroy : function(removeEl){
27065 Roo.EventManager.removeResizeListener(this.onResize, this);
27066 for(var i = 0, len = this.items.length; i < len; i++){
27067 this.items[i].purgeListeners();
27069 if(removeEl === true){
27070 this.el.update("");
27077 * @class Roo.TabPanelItem
27078 * @extends Roo.util.Observable
27079 * Represents an individual item (tab plus body) in a TabPanel.
27080 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
27081 * @param {String} id The id of this TabPanelItem
27082 * @param {String} text The text for the tab of this TabPanelItem
27083 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
27085 Roo.TabPanelItem = function(tabPanel, id, text, closable){
27087 * The {@link Roo.TabPanel} this TabPanelItem belongs to
27088 * @type Roo.TabPanel
27090 this.tabPanel = tabPanel;
27092 * The id for this TabPanelItem
27097 this.disabled = false;
27101 this.loaded = false;
27102 this.closable = closable;
27105 * The body element for this TabPanelItem.
27106 * @type Roo.Element
27108 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
27109 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
27110 this.bodyEl.setStyle("display", "block");
27111 this.bodyEl.setStyle("zoom", "1");
27114 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
27116 this.el = Roo.get(els.el, true);
27117 this.inner = Roo.get(els.inner, true);
27118 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
27119 this.pnode = Roo.get(els.el.parentNode, true);
27120 this.el.on("mousedown", this.onTabMouseDown, this);
27121 this.el.on("click", this.onTabClick, this);
27124 var c = Roo.get(els.close, true);
27125 c.dom.title = this.closeText;
27126 c.addClassOnOver("close-over");
27127 c.on("click", this.closeClick, this);
27133 * Fires when this tab becomes the active tab.
27134 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27135 * @param {Roo.TabPanelItem} this
27139 * @event beforeclose
27140 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
27141 * @param {Roo.TabPanelItem} this
27142 * @param {Object} e Set cancel to true on this object to cancel the close.
27144 "beforeclose": true,
27147 * Fires when this tab is closed.
27148 * @param {Roo.TabPanelItem} this
27152 * @event deactivate
27153 * Fires when this tab is no longer the active tab.
27154 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27155 * @param {Roo.TabPanelItem} this
27157 "deactivate" : true
27159 this.hidden = false;
27161 Roo.TabPanelItem.superclass.constructor.call(this);
27164 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27165 purgeListeners : function(){
27166 Roo.util.Observable.prototype.purgeListeners.call(this);
27167 this.el.removeAllListeners();
27170 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27173 this.pnode.addClass("on");
27176 this.tabPanel.stripWrap.repaint();
27178 this.fireEvent("activate", this.tabPanel, this);
27182 * Returns true if this tab is the active tab.
27183 * @return {Boolean}
27185 isActive : function(){
27186 return this.tabPanel.getActiveTab() == this;
27190 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27193 this.pnode.removeClass("on");
27195 this.fireEvent("deactivate", this.tabPanel, this);
27198 hideAction : function(){
27199 this.bodyEl.hide();
27200 this.bodyEl.setStyle("position", "absolute");
27201 this.bodyEl.setLeft("-20000px");
27202 this.bodyEl.setTop("-20000px");
27205 showAction : function(){
27206 this.bodyEl.setStyle("position", "relative");
27207 this.bodyEl.setTop("");
27208 this.bodyEl.setLeft("");
27209 this.bodyEl.show();
27213 * Set the tooltip for the tab.
27214 * @param {String} tooltip The tab's tooltip
27216 setTooltip : function(text){
27217 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27218 this.textEl.dom.qtip = text;
27219 this.textEl.dom.removeAttribute('title');
27221 this.textEl.dom.title = text;
27225 onTabClick : function(e){
27226 e.preventDefault();
27227 this.tabPanel.activate(this.id);
27230 onTabMouseDown : function(e){
27231 e.preventDefault();
27232 this.tabPanel.activate(this.id);
27235 getWidth : function(){
27236 return this.inner.getWidth();
27239 setWidth : function(width){
27240 var iwidth = width - this.pnode.getPadding("lr");
27241 this.inner.setWidth(iwidth);
27242 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27243 this.pnode.setWidth(width);
27247 * Show or hide the tab
27248 * @param {Boolean} hidden True to hide or false to show.
27250 setHidden : function(hidden){
27251 this.hidden = hidden;
27252 this.pnode.setStyle("display", hidden ? "none" : "");
27256 * Returns true if this tab is "hidden"
27257 * @return {Boolean}
27259 isHidden : function(){
27260 return this.hidden;
27264 * Returns the text for this tab
27267 getText : function(){
27271 autoSize : function(){
27272 //this.el.beginMeasure();
27273 this.textEl.setWidth(1);
27275 * #2804 [new] Tabs in Roojs
27276 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
27278 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
27279 //this.el.endMeasure();
27283 * Sets the text for the tab (Note: this also sets the tooltip text)
27284 * @param {String} text The tab's text and tooltip
27286 setText : function(text){
27288 this.textEl.update(text);
27289 this.setTooltip(text);
27290 if(!this.tabPanel.resizeTabs){
27295 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27297 activate : function(){
27298 this.tabPanel.activate(this.id);
27302 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27304 disable : function(){
27305 if(this.tabPanel.active != this){
27306 this.disabled = true;
27307 this.pnode.addClass("disabled");
27312 * Enables this TabPanelItem if it was previously disabled.
27314 enable : function(){
27315 this.disabled = false;
27316 this.pnode.removeClass("disabled");
27320 * Sets the content for this TabPanelItem.
27321 * @param {String} content The content
27322 * @param {Boolean} loadScripts true to look for and load scripts
27324 setContent : function(content, loadScripts){
27325 this.bodyEl.update(content, loadScripts);
27329 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27330 * @return {Roo.UpdateManager} The UpdateManager
27332 getUpdateManager : function(){
27333 return this.bodyEl.getUpdateManager();
27337 * Set a URL to be used to load the content for this TabPanelItem.
27338 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27339 * @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)
27340 * @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)
27341 * @return {Roo.UpdateManager} The UpdateManager
27343 setUrl : function(url, params, loadOnce){
27344 if(this.refreshDelegate){
27345 this.un('activate', this.refreshDelegate);
27347 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27348 this.on("activate", this.refreshDelegate);
27349 return this.bodyEl.getUpdateManager();
27353 _handleRefresh : function(url, params, loadOnce){
27354 if(!loadOnce || !this.loaded){
27355 var updater = this.bodyEl.getUpdateManager();
27356 updater.update(url, params, this._setLoaded.createDelegate(this));
27361 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27362 * Will fail silently if the setUrl method has not been called.
27363 * This does not activate the panel, just updates its content.
27365 refresh : function(){
27366 if(this.refreshDelegate){
27367 this.loaded = false;
27368 this.refreshDelegate();
27373 _setLoaded : function(){
27374 this.loaded = true;
27378 closeClick : function(e){
27381 this.fireEvent("beforeclose", this, o);
27382 if(o.cancel !== true){
27383 this.tabPanel.removeTab(this.id);
27387 * The text displayed in the tooltip for the close icon.
27390 closeText : "Close this tab"
27394 Roo.TabPanel.prototype.createStrip = function(container){
27395 var strip = document.createElement("div");
27396 strip.className = "x-tabs-wrap";
27397 container.appendChild(strip);
27401 Roo.TabPanel.prototype.createStripList = function(strip){
27402 // div wrapper for retard IE
27403 // returns the "tr" element.
27404 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27405 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27406 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27407 return strip.firstChild.firstChild.firstChild.firstChild;
27410 Roo.TabPanel.prototype.createBody = function(container){
27411 var body = document.createElement("div");
27412 Roo.id(body, "tab-body");
27413 Roo.fly(body).addClass("x-tabs-body");
27414 container.appendChild(body);
27418 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27419 var body = Roo.getDom(id);
27421 body = document.createElement("div");
27424 Roo.fly(body).addClass("x-tabs-item-body");
27425 bodyEl.insertBefore(body, bodyEl.firstChild);
27429 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27430 var td = document.createElement("td");
27431 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27432 //stripEl.appendChild(td);
27434 td.className = "x-tabs-closable";
27435 if(!this.closeTpl){
27436 this.closeTpl = new Roo.Template(
27437 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27438 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27439 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27442 var el = this.closeTpl.overwrite(td, {"text": text});
27443 var close = el.getElementsByTagName("div")[0];
27444 var inner = el.getElementsByTagName("em")[0];
27445 return {"el": el, "close": close, "inner": inner};
27448 this.tabTpl = new Roo.Template(
27449 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27450 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27453 var el = this.tabTpl.overwrite(td, {"text": text});
27454 var inner = el.getElementsByTagName("em")[0];
27455 return {"el": el, "inner": inner};
27459 * Ext JS Library 1.1.1
27460 * Copyright(c) 2006-2007, Ext JS, LLC.
27462 * Originally Released Under LGPL - original licence link has changed is not relivant.
27465 * <script type="text/javascript">
27469 * @class Roo.Button
27470 * @extends Roo.util.Observable
27471 * Simple Button class
27472 * @cfg {String} text The button text
27473 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27474 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27475 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27476 * @cfg {Object} scope The scope of the handler
27477 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27478 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27479 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27480 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27481 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27482 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27483 applies if enableToggle = true)
27484 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27485 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27486 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27488 * Create a new button
27489 * @param {Object} config The config object
27491 Roo.Button = function(renderTo, config)
27495 renderTo = config.renderTo || false;
27498 Roo.apply(this, config);
27502 * Fires when this button is clicked
27503 * @param {Button} this
27504 * @param {EventObject} e The click event
27509 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27510 * @param {Button} this
27511 * @param {Boolean} pressed
27516 * Fires when the mouse hovers over the button
27517 * @param {Button} this
27518 * @param {Event} e The event object
27520 'mouseover' : true,
27523 * Fires when the mouse exits the button
27524 * @param {Button} this
27525 * @param {Event} e The event object
27530 * Fires when the button is rendered
27531 * @param {Button} this
27536 this.menu = Roo.menu.MenuMgr.get(this.menu);
27538 // register listeners first!! - so render can be captured..
27539 Roo.util.Observable.call(this);
27541 this.render(renderTo);
27547 Roo.extend(Roo.Button, Roo.util.Observable, {
27553 * Read-only. True if this button is hidden
27558 * Read-only. True if this button is disabled
27563 * Read-only. True if this button is pressed (only if enableToggle = true)
27569 * @cfg {Number} tabIndex
27570 * The DOM tabIndex for this button (defaults to undefined)
27572 tabIndex : undefined,
27575 * @cfg {Boolean} enableToggle
27576 * True to enable pressed/not pressed toggling (defaults to false)
27578 enableToggle: false,
27580 * @cfg {Mixed} menu
27581 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27585 * @cfg {String} menuAlign
27586 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27588 menuAlign : "tl-bl?",
27591 * @cfg {String} iconCls
27592 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27594 iconCls : undefined,
27596 * @cfg {String} type
27597 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27602 menuClassTarget: 'tr',
27605 * @cfg {String} clickEvent
27606 * The type of event to map to the button's event handler (defaults to 'click')
27608 clickEvent : 'click',
27611 * @cfg {Boolean} handleMouseEvents
27612 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27614 handleMouseEvents : true,
27617 * @cfg {String} tooltipType
27618 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27620 tooltipType : 'qtip',
27623 * @cfg {String} cls
27624 * A CSS class to apply to the button's main element.
27628 * @cfg {Roo.Template} template (Optional)
27629 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27630 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27631 * require code modifications if required elements (e.g. a button) aren't present.
27635 render : function(renderTo){
27637 if(this.hideParent){
27638 this.parentEl = Roo.get(renderTo);
27640 if(!this.dhconfig){
27641 if(!this.template){
27642 if(!Roo.Button.buttonTemplate){
27643 // hideous table template
27644 Roo.Button.buttonTemplate = new Roo.Template(
27645 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27646 '<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>',
27647 "</tr></tbody></table>");
27649 this.template = Roo.Button.buttonTemplate;
27651 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27652 var btnEl = btn.child("button:first");
27653 btnEl.on('focus', this.onFocus, this);
27654 btnEl.on('blur', this.onBlur, this);
27656 btn.addClass(this.cls);
27659 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27662 btnEl.addClass(this.iconCls);
27664 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27667 if(this.tabIndex !== undefined){
27668 btnEl.dom.tabIndex = this.tabIndex;
27671 if(typeof this.tooltip == 'object'){
27672 Roo.QuickTips.tips(Roo.apply({
27676 btnEl.dom[this.tooltipType] = this.tooltip;
27680 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27684 this.el.dom.id = this.el.id = this.id;
27687 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27688 this.menu.on("show", this.onMenuShow, this);
27689 this.menu.on("hide", this.onMenuHide, this);
27691 btn.addClass("x-btn");
27692 if(Roo.isIE && !Roo.isIE7){
27693 this.autoWidth.defer(1, this);
27697 if(this.handleMouseEvents){
27698 btn.on("mouseover", this.onMouseOver, this);
27699 btn.on("mouseout", this.onMouseOut, this);
27700 btn.on("mousedown", this.onMouseDown, this);
27702 btn.on(this.clickEvent, this.onClick, this);
27703 //btn.on("mouseup", this.onMouseUp, this);
27710 Roo.ButtonToggleMgr.register(this);
27712 this.el.addClass("x-btn-pressed");
27715 var repeater = new Roo.util.ClickRepeater(btn,
27716 typeof this.repeat == "object" ? this.repeat : {}
27718 repeater.on("click", this.onClick, this);
27721 this.fireEvent('render', this);
27725 * Returns the button's underlying element
27726 * @return {Roo.Element} The element
27728 getEl : function(){
27733 * Destroys this Button and removes any listeners.
27735 destroy : function(){
27736 Roo.ButtonToggleMgr.unregister(this);
27737 this.el.removeAllListeners();
27738 this.purgeListeners();
27743 autoWidth : function(){
27745 this.el.setWidth("auto");
27746 if(Roo.isIE7 && Roo.isStrict){
27747 var ib = this.el.child('button');
27748 if(ib && ib.getWidth() > 20){
27750 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27755 this.el.beginMeasure();
27757 if(this.el.getWidth() < this.minWidth){
27758 this.el.setWidth(this.minWidth);
27761 this.el.endMeasure();
27768 * Assigns this button's click handler
27769 * @param {Function} handler The function to call when the button is clicked
27770 * @param {Object} scope (optional) Scope for the function passed in
27772 setHandler : function(handler, scope){
27773 this.handler = handler;
27774 this.scope = scope;
27778 * Sets this button's text
27779 * @param {String} text The button text
27781 setText : function(text){
27784 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27790 * Gets the text for this button
27791 * @return {String} The button text
27793 getText : function(){
27801 this.hidden = false;
27803 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27811 this.hidden = true;
27813 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27818 * Convenience function for boolean show/hide
27819 * @param {Boolean} visible True to show, false to hide
27821 setVisible: function(visible){
27830 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27831 * @param {Boolean} state (optional) Force a particular state
27833 toggle : function(state){
27834 state = state === undefined ? !this.pressed : state;
27835 if(state != this.pressed){
27837 this.el.addClass("x-btn-pressed");
27838 this.pressed = true;
27839 this.fireEvent("toggle", this, true);
27841 this.el.removeClass("x-btn-pressed");
27842 this.pressed = false;
27843 this.fireEvent("toggle", this, false);
27845 if(this.toggleHandler){
27846 this.toggleHandler.call(this.scope || this, this, state);
27854 focus : function(){
27855 this.el.child('button:first').focus();
27859 * Disable this button
27861 disable : function(){
27863 this.el.addClass("x-btn-disabled");
27865 this.disabled = true;
27869 * Enable this button
27871 enable : function(){
27873 this.el.removeClass("x-btn-disabled");
27875 this.disabled = false;
27879 * Convenience function for boolean enable/disable
27880 * @param {Boolean} enabled True to enable, false to disable
27882 setDisabled : function(v){
27883 this[v !== true ? "enable" : "disable"]();
27887 onClick : function(e)
27890 e.preventDefault();
27895 if(!this.disabled){
27896 if(this.enableToggle){
27899 if(this.menu && !this.menu.isVisible()){
27900 this.menu.show(this.el, this.menuAlign);
27902 this.fireEvent("click", this, e);
27904 this.el.removeClass("x-btn-over");
27905 this.handler.call(this.scope || this, this, e);
27910 onMouseOver : function(e){
27911 if(!this.disabled){
27912 this.el.addClass("x-btn-over");
27913 this.fireEvent('mouseover', this, e);
27917 onMouseOut : function(e){
27918 if(!e.within(this.el, true)){
27919 this.el.removeClass("x-btn-over");
27920 this.fireEvent('mouseout', this, e);
27924 onFocus : function(e){
27925 if(!this.disabled){
27926 this.el.addClass("x-btn-focus");
27930 onBlur : function(e){
27931 this.el.removeClass("x-btn-focus");
27934 onMouseDown : function(e){
27935 if(!this.disabled && e.button == 0){
27936 this.el.addClass("x-btn-click");
27937 Roo.get(document).on('mouseup', this.onMouseUp, this);
27941 onMouseUp : function(e){
27943 this.el.removeClass("x-btn-click");
27944 Roo.get(document).un('mouseup', this.onMouseUp, this);
27948 onMenuShow : function(e){
27949 this.el.addClass("x-btn-menu-active");
27952 onMenuHide : function(e){
27953 this.el.removeClass("x-btn-menu-active");
27957 // Private utility class used by Button
27958 Roo.ButtonToggleMgr = function(){
27961 function toggleGroup(btn, state){
27963 var g = groups[btn.toggleGroup];
27964 for(var i = 0, l = g.length; i < l; i++){
27966 g[i].toggle(false);
27973 register : function(btn){
27974 if(!btn.toggleGroup){
27977 var g = groups[btn.toggleGroup];
27979 g = groups[btn.toggleGroup] = [];
27982 btn.on("toggle", toggleGroup);
27985 unregister : function(btn){
27986 if(!btn.toggleGroup){
27989 var g = groups[btn.toggleGroup];
27992 btn.un("toggle", toggleGroup);
27998 * Ext JS Library 1.1.1
27999 * Copyright(c) 2006-2007, Ext JS, LLC.
28001 * Originally Released Under LGPL - original licence link has changed is not relivant.
28004 * <script type="text/javascript">
28008 * @class Roo.SplitButton
28009 * @extends Roo.Button
28010 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
28011 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
28012 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
28013 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
28014 * @cfg {String} arrowTooltip The title attribute of the arrow
28016 * Create a new menu button
28017 * @param {String/HTMLElement/Element} renderTo The element to append the button to
28018 * @param {Object} config The config object
28020 Roo.SplitButton = function(renderTo, config){
28021 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
28023 * @event arrowclick
28024 * Fires when this button's arrow is clicked
28025 * @param {SplitButton} this
28026 * @param {EventObject} e The click event
28028 this.addEvents({"arrowclick":true});
28031 Roo.extend(Roo.SplitButton, Roo.Button, {
28032 render : function(renderTo){
28033 // this is one sweet looking template!
28034 var tpl = new Roo.Template(
28035 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
28036 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
28037 '<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>',
28038 "</tbody></table></td><td>",
28039 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
28040 '<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>',
28041 "</tbody></table></td></tr></table>"
28043 var btn = tpl.append(renderTo, [this.text, this.type], true);
28044 var btnEl = btn.child("button");
28046 btn.addClass(this.cls);
28049 btnEl.setStyle('background-image', 'url(' +this.icon +')');
28052 btnEl.addClass(this.iconCls);
28054 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
28058 if(this.handleMouseEvents){
28059 btn.on("mouseover", this.onMouseOver, this);
28060 btn.on("mouseout", this.onMouseOut, this);
28061 btn.on("mousedown", this.onMouseDown, this);
28062 btn.on("mouseup", this.onMouseUp, this);
28064 btn.on(this.clickEvent, this.onClick, this);
28066 if(typeof this.tooltip == 'object'){
28067 Roo.QuickTips.tips(Roo.apply({
28071 btnEl.dom[this.tooltipType] = this.tooltip;
28074 if(this.arrowTooltip){
28075 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
28084 this.el.addClass("x-btn-pressed");
28086 if(Roo.isIE && !Roo.isIE7){
28087 this.autoWidth.defer(1, this);
28092 this.menu.on("show", this.onMenuShow, this);
28093 this.menu.on("hide", this.onMenuHide, this);
28095 this.fireEvent('render', this);
28099 autoWidth : function(){
28101 var tbl = this.el.child("table:first");
28102 var tbl2 = this.el.child("table:last");
28103 this.el.setWidth("auto");
28104 tbl.setWidth("auto");
28105 if(Roo.isIE7 && Roo.isStrict){
28106 var ib = this.el.child('button:first');
28107 if(ib && ib.getWidth() > 20){
28109 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
28114 this.el.beginMeasure();
28116 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
28117 tbl.setWidth(this.minWidth-tbl2.getWidth());
28120 this.el.endMeasure();
28123 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
28127 * Sets this button's click handler
28128 * @param {Function} handler The function to call when the button is clicked
28129 * @param {Object} scope (optional) Scope for the function passed above
28131 setHandler : function(handler, scope){
28132 this.handler = handler;
28133 this.scope = scope;
28137 * Sets this button's arrow click handler
28138 * @param {Function} handler The function to call when the arrow is clicked
28139 * @param {Object} scope (optional) Scope for the function passed above
28141 setArrowHandler : function(handler, scope){
28142 this.arrowHandler = handler;
28143 this.scope = scope;
28149 focus : function(){
28151 this.el.child("button:first").focus();
28156 onClick : function(e){
28157 e.preventDefault();
28158 if(!this.disabled){
28159 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28160 if(this.menu && !this.menu.isVisible()){
28161 this.menu.show(this.el, this.menuAlign);
28163 this.fireEvent("arrowclick", this, e);
28164 if(this.arrowHandler){
28165 this.arrowHandler.call(this.scope || this, this, e);
28168 this.fireEvent("click", this, e);
28170 this.handler.call(this.scope || this, this, e);
28176 onMouseDown : function(e){
28177 if(!this.disabled){
28178 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28182 onMouseUp : function(e){
28183 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28188 // backwards compat
28189 Roo.MenuButton = Roo.SplitButton;/*
28191 * Ext JS Library 1.1.1
28192 * Copyright(c) 2006-2007, Ext JS, LLC.
28194 * Originally Released Under LGPL - original licence link has changed is not relivant.
28197 * <script type="text/javascript">
28201 * @class Roo.Toolbar
28202 * Basic Toolbar class.
28204 * Creates a new Toolbar
28205 * @param {Object} container The config object
28207 Roo.Toolbar = function(container, buttons, config)
28209 /// old consturctor format still supported..
28210 if(container instanceof Array){ // omit the container for later rendering
28211 buttons = container;
28215 if (typeof(container) == 'object' && container.xtype) {
28216 config = container;
28217 container = config.container;
28218 buttons = config.buttons || []; // not really - use items!!
28221 if (config && config.items) {
28222 xitems = config.items;
28223 delete config.items;
28225 Roo.apply(this, config);
28226 this.buttons = buttons;
28229 this.render(container);
28231 this.xitems = xitems;
28232 Roo.each(xitems, function(b) {
28238 Roo.Toolbar.prototype = {
28240 * @cfg {Array} items
28241 * array of button configs or elements to add (will be converted to a MixedCollection)
28245 * @cfg {String/HTMLElement/Element} container
28246 * The id or element that will contain the toolbar
28249 render : function(ct){
28250 this.el = Roo.get(ct);
28252 this.el.addClass(this.cls);
28254 // using a table allows for vertical alignment
28255 // 100% width is needed by Safari...
28256 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28257 this.tr = this.el.child("tr", true);
28259 this.items = new Roo.util.MixedCollection(false, function(o){
28260 return o.id || ("item" + (++autoId));
28263 this.add.apply(this, this.buttons);
28264 delete this.buttons;
28269 * Adds element(s) to the toolbar -- this function takes a variable number of
28270 * arguments of mixed type and adds them to the toolbar.
28271 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28273 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28274 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28275 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28276 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28277 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28278 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28279 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28280 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28281 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28283 * @param {Mixed} arg2
28284 * @param {Mixed} etc.
28287 var a = arguments, l = a.length;
28288 for(var i = 0; i < l; i++){
28293 _add : function(el) {
28296 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28299 if (el.applyTo){ // some kind of form field
28300 return this.addField(el);
28302 if (el.render){ // some kind of Toolbar.Item
28303 return this.addItem(el);
28305 if (typeof el == "string"){ // string
28306 if(el == "separator" || el == "-"){
28307 return this.addSeparator();
28310 return this.addSpacer();
28313 return this.addFill();
28315 return this.addText(el);
28318 if(el.tagName){ // element
28319 return this.addElement(el);
28321 if(typeof el == "object"){ // must be button config?
28322 return this.addButton(el);
28324 // and now what?!?!
28330 * Add an Xtype element
28331 * @param {Object} xtype Xtype Object
28332 * @return {Object} created Object
28334 addxtype : function(e){
28335 return this.add(e);
28339 * Returns the Element for this toolbar.
28340 * @return {Roo.Element}
28342 getEl : function(){
28348 * @return {Roo.Toolbar.Item} The separator item
28350 addSeparator : function(){
28351 return this.addItem(new Roo.Toolbar.Separator());
28355 * Adds a spacer element
28356 * @return {Roo.Toolbar.Spacer} The spacer item
28358 addSpacer : function(){
28359 return this.addItem(new Roo.Toolbar.Spacer());
28363 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28364 * @return {Roo.Toolbar.Fill} The fill item
28366 addFill : function(){
28367 return this.addItem(new Roo.Toolbar.Fill());
28371 * Adds any standard HTML element to the toolbar
28372 * @param {String/HTMLElement/Element} el The element or id of the element to add
28373 * @return {Roo.Toolbar.Item} The element's item
28375 addElement : function(el){
28376 return this.addItem(new Roo.Toolbar.Item(el));
28379 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28380 * @type Roo.util.MixedCollection
28385 * Adds any Toolbar.Item or subclass
28386 * @param {Roo.Toolbar.Item} item
28387 * @return {Roo.Toolbar.Item} The item
28389 addItem : function(item){
28390 var td = this.nextBlock();
28392 this.items.add(item);
28397 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28398 * @param {Object/Array} config A button config or array of configs
28399 * @return {Roo.Toolbar.Button/Array}
28401 addButton : function(config){
28402 if(config instanceof Array){
28404 for(var i = 0, len = config.length; i < len; i++) {
28405 buttons.push(this.addButton(config[i]));
28410 if(!(config instanceof Roo.Toolbar.Button)){
28412 new Roo.Toolbar.SplitButton(config) :
28413 new Roo.Toolbar.Button(config);
28415 var td = this.nextBlock();
28422 * Adds text to the toolbar
28423 * @param {String} text The text to add
28424 * @return {Roo.Toolbar.Item} The element's item
28426 addText : function(text){
28427 return this.addItem(new Roo.Toolbar.TextItem(text));
28431 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28432 * @param {Number} index The index where the item is to be inserted
28433 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28434 * @return {Roo.Toolbar.Button/Item}
28436 insertButton : function(index, item){
28437 if(item instanceof Array){
28439 for(var i = 0, len = item.length; i < len; i++) {
28440 buttons.push(this.insertButton(index + i, item[i]));
28444 if (!(item instanceof Roo.Toolbar.Button)){
28445 item = new Roo.Toolbar.Button(item);
28447 var td = document.createElement("td");
28448 this.tr.insertBefore(td, this.tr.childNodes[index]);
28450 this.items.insert(index, item);
28455 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28456 * @param {Object} config
28457 * @return {Roo.Toolbar.Item} The element's item
28459 addDom : function(config, returnEl){
28460 var td = this.nextBlock();
28461 Roo.DomHelper.overwrite(td, config);
28462 var ti = new Roo.Toolbar.Item(td.firstChild);
28464 this.items.add(ti);
28469 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28470 * @type Roo.util.MixedCollection
28475 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28476 * Note: the field should not have been rendered yet. For a field that has already been
28477 * rendered, use {@link #addElement}.
28478 * @param {Roo.form.Field} field
28479 * @return {Roo.ToolbarItem}
28483 addField : function(field) {
28484 if (!this.fields) {
28486 this.fields = new Roo.util.MixedCollection(false, function(o){
28487 return o.id || ("item" + (++autoId));
28492 var td = this.nextBlock();
28494 var ti = new Roo.Toolbar.Item(td.firstChild);
28496 this.items.add(ti);
28497 this.fields.add(field);
28508 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28509 this.el.child('div').hide();
28517 this.el.child('div').show();
28521 nextBlock : function(){
28522 var td = document.createElement("td");
28523 this.tr.appendChild(td);
28528 destroy : function(){
28529 if(this.items){ // rendered?
28530 Roo.destroy.apply(Roo, this.items.items);
28532 if(this.fields){ // rendered?
28533 Roo.destroy.apply(Roo, this.fields.items);
28535 Roo.Element.uncache(this.el, this.tr);
28540 * @class Roo.Toolbar.Item
28541 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28543 * Creates a new Item
28544 * @param {HTMLElement} el
28546 Roo.Toolbar.Item = function(el){
28548 if (typeof (el.xtype) != 'undefined') {
28553 this.el = Roo.getDom(el);
28554 this.id = Roo.id(this.el);
28555 this.hidden = false;
28560 * Fires when the button is rendered
28561 * @param {Button} this
28565 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
28567 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
28568 //Roo.Toolbar.Item.prototype = {
28571 * Get this item's HTML Element
28572 * @return {HTMLElement}
28574 getEl : function(){
28579 render : function(td){
28582 td.appendChild(this.el);
28584 this.fireEvent('render', this);
28588 * Removes and destroys this item.
28590 destroy : function(){
28591 this.td.parentNode.removeChild(this.td);
28598 this.hidden = false;
28599 this.td.style.display = "";
28606 this.hidden = true;
28607 this.td.style.display = "none";
28611 * Convenience function for boolean show/hide.
28612 * @param {Boolean} visible true to show/false to hide
28614 setVisible: function(visible){
28623 * Try to focus this item.
28625 focus : function(){
28626 Roo.fly(this.el).focus();
28630 * Disables this item.
28632 disable : function(){
28633 Roo.fly(this.td).addClass("x-item-disabled");
28634 this.disabled = true;
28635 this.el.disabled = true;
28639 * Enables this item.
28641 enable : function(){
28642 Roo.fly(this.td).removeClass("x-item-disabled");
28643 this.disabled = false;
28644 this.el.disabled = false;
28650 * @class Roo.Toolbar.Separator
28651 * @extends Roo.Toolbar.Item
28652 * A simple toolbar separator class
28654 * Creates a new Separator
28656 Roo.Toolbar.Separator = function(cfg){
28658 var s = document.createElement("span");
28659 s.className = "ytb-sep";
28664 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
28666 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28667 enable:Roo.emptyFn,
28668 disable:Roo.emptyFn,
28673 * @class Roo.Toolbar.Spacer
28674 * @extends Roo.Toolbar.Item
28675 * A simple element that adds extra horizontal space to a toolbar.
28677 * Creates a new Spacer
28679 Roo.Toolbar.Spacer = function(cfg){
28680 var s = document.createElement("div");
28681 s.className = "ytb-spacer";
28685 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
28687 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28688 enable:Roo.emptyFn,
28689 disable:Roo.emptyFn,
28694 * @class Roo.Toolbar.Fill
28695 * @extends Roo.Toolbar.Spacer
28696 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28698 * Creates a new Spacer
28700 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28702 render : function(td){
28703 td.style.width = '100%';
28704 Roo.Toolbar.Fill.superclass.render.call(this, td);
28709 * @class Roo.Toolbar.TextItem
28710 * @extends Roo.Toolbar.Item
28711 * A simple class that renders text directly into a toolbar.
28713 * Creates a new TextItem
28714 * @param {String} text
28716 Roo.Toolbar.TextItem = function(cfg){
28717 var text = cfg || "";
28718 if (typeof(cfg) == 'object') {
28719 text = cfg.text || "";
28723 var s = document.createElement("span");
28724 s.className = "ytb-text";
28725 s.innerHTML = text;
28730 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
28732 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28735 enable:Roo.emptyFn,
28736 disable:Roo.emptyFn,
28741 * @class Roo.Toolbar.Button
28742 * @extends Roo.Button
28743 * A button that renders into a toolbar.
28745 * Creates a new Button
28746 * @param {Object} config A standard {@link Roo.Button} config object
28748 Roo.Toolbar.Button = function(config){
28749 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28751 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28752 render : function(td){
28754 Roo.Toolbar.Button.superclass.render.call(this, td);
28758 * Removes and destroys this button
28760 destroy : function(){
28761 Roo.Toolbar.Button.superclass.destroy.call(this);
28762 this.td.parentNode.removeChild(this.td);
28766 * Shows this button
28769 this.hidden = false;
28770 this.td.style.display = "";
28774 * Hides this button
28777 this.hidden = true;
28778 this.td.style.display = "none";
28782 * Disables this item
28784 disable : function(){
28785 Roo.fly(this.td).addClass("x-item-disabled");
28786 this.disabled = true;
28790 * Enables this item
28792 enable : function(){
28793 Roo.fly(this.td).removeClass("x-item-disabled");
28794 this.disabled = false;
28797 // backwards compat
28798 Roo.ToolbarButton = Roo.Toolbar.Button;
28801 * @class Roo.Toolbar.SplitButton
28802 * @extends Roo.SplitButton
28803 * A menu button that renders into a toolbar.
28805 * Creates a new SplitButton
28806 * @param {Object} config A standard {@link Roo.SplitButton} config object
28808 Roo.Toolbar.SplitButton = function(config){
28809 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28811 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28812 render : function(td){
28814 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28818 * Removes and destroys this button
28820 destroy : function(){
28821 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28822 this.td.parentNode.removeChild(this.td);
28826 * Shows this button
28829 this.hidden = false;
28830 this.td.style.display = "";
28834 * Hides this button
28837 this.hidden = true;
28838 this.td.style.display = "none";
28842 // backwards compat
28843 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28845 * Ext JS Library 1.1.1
28846 * Copyright(c) 2006-2007, Ext JS, LLC.
28848 * Originally Released Under LGPL - original licence link has changed is not relivant.
28851 * <script type="text/javascript">
28855 * @class Roo.PagingToolbar
28856 * @extends Roo.Toolbar
28857 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28859 * Create a new PagingToolbar
28860 * @param {Object} config The config object
28862 Roo.PagingToolbar = function(el, ds, config)
28864 // old args format still supported... - xtype is prefered..
28865 if (typeof(el) == 'object' && el.xtype) {
28866 // created from xtype...
28868 ds = el.dataSource;
28869 el = config.container;
28872 if (config.items) {
28873 items = config.items;
28877 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28880 this.renderButtons(this.el);
28883 // supprot items array.
28885 Roo.each(items, function(e) {
28886 this.add(Roo.factory(e));
28891 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28893 * @cfg {Roo.data.Store} dataSource
28894 * The underlying data store providing the paged data
28897 * @cfg {String/HTMLElement/Element} container
28898 * container The id or element that will contain the toolbar
28901 * @cfg {Boolean} displayInfo
28902 * True to display the displayMsg (defaults to false)
28905 * @cfg {Number} pageSize
28906 * The number of records to display per page (defaults to 20)
28910 * @cfg {String} displayMsg
28911 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28913 displayMsg : 'Displaying {0} - {1} of {2}',
28915 * @cfg {String} emptyMsg
28916 * The message to display when no records are found (defaults to "No data to display")
28918 emptyMsg : 'No data to display',
28920 * Customizable piece of the default paging text (defaults to "Page")
28923 beforePageText : "Page",
28925 * Customizable piece of the default paging text (defaults to "of %0")
28928 afterPageText : "of {0}",
28930 * Customizable piece of the default paging text (defaults to "First Page")
28933 firstText : "First Page",
28935 * Customizable piece of the default paging text (defaults to "Previous Page")
28938 prevText : "Previous Page",
28940 * Customizable piece of the default paging text (defaults to "Next Page")
28943 nextText : "Next Page",
28945 * Customizable piece of the default paging text (defaults to "Last Page")
28948 lastText : "Last Page",
28950 * Customizable piece of the default paging text (defaults to "Refresh")
28953 refreshText : "Refresh",
28956 renderButtons : function(el){
28957 Roo.PagingToolbar.superclass.render.call(this, el);
28958 this.first = this.addButton({
28959 tooltip: this.firstText,
28960 cls: "x-btn-icon x-grid-page-first",
28962 handler: this.onClick.createDelegate(this, ["first"])
28964 this.prev = this.addButton({
28965 tooltip: this.prevText,
28966 cls: "x-btn-icon x-grid-page-prev",
28968 handler: this.onClick.createDelegate(this, ["prev"])
28970 //this.addSeparator();
28971 this.add(this.beforePageText);
28972 this.field = Roo.get(this.addDom({
28977 cls: "x-grid-page-number"
28979 this.field.on("keydown", this.onPagingKeydown, this);
28980 this.field.on("focus", function(){this.dom.select();});
28981 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28982 this.field.setHeight(18);
28983 //this.addSeparator();
28984 this.next = this.addButton({
28985 tooltip: this.nextText,
28986 cls: "x-btn-icon x-grid-page-next",
28988 handler: this.onClick.createDelegate(this, ["next"])
28990 this.last = this.addButton({
28991 tooltip: this.lastText,
28992 cls: "x-btn-icon x-grid-page-last",
28994 handler: this.onClick.createDelegate(this, ["last"])
28996 //this.addSeparator();
28997 this.loading = this.addButton({
28998 tooltip: this.refreshText,
28999 cls: "x-btn-icon x-grid-loading",
29000 handler: this.onClick.createDelegate(this, ["refresh"])
29003 if(this.displayInfo){
29004 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
29009 updateInfo : function(){
29010 if(this.displayEl){
29011 var count = this.ds.getCount();
29012 var msg = count == 0 ?
29016 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
29018 this.displayEl.update(msg);
29023 onLoad : function(ds, r, o){
29024 this.cursor = o.params ? o.params.start : 0;
29025 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
29027 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
29028 this.field.dom.value = ap;
29029 this.first.setDisabled(ap == 1);
29030 this.prev.setDisabled(ap == 1);
29031 this.next.setDisabled(ap == ps);
29032 this.last.setDisabled(ap == ps);
29033 this.loading.enable();
29038 getPageData : function(){
29039 var total = this.ds.getTotalCount();
29042 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
29043 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
29048 onLoadError : function(){
29049 this.loading.enable();
29053 onPagingKeydown : function(e){
29054 var k = e.getKey();
29055 var d = this.getPageData();
29057 var v = this.field.dom.value, pageNum;
29058 if(!v || isNaN(pageNum = parseInt(v, 10))){
29059 this.field.dom.value = d.activePage;
29062 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
29063 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29066 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))
29068 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
29069 this.field.dom.value = pageNum;
29070 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
29073 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29075 var v = this.field.dom.value, pageNum;
29076 var increment = (e.shiftKey) ? 10 : 1;
29077 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29079 if(!v || isNaN(pageNum = parseInt(v, 10))) {
29080 this.field.dom.value = d.activePage;
29083 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
29085 this.field.dom.value = parseInt(v, 10) + increment;
29086 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
29087 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29094 beforeLoad : function(){
29096 this.loading.disable();
29101 onClick : function(which){
29105 ds.load({params:{start: 0, limit: this.pageSize}});
29108 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
29111 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
29114 var total = ds.getTotalCount();
29115 var extra = total % this.pageSize;
29116 var lastStart = extra ? (total - extra) : total-this.pageSize;
29117 ds.load({params:{start: lastStart, limit: this.pageSize}});
29120 ds.load({params:{start: this.cursor, limit: this.pageSize}});
29126 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
29127 * @param {Roo.data.Store} store The data store to unbind
29129 unbind : function(ds){
29130 ds.un("beforeload", this.beforeLoad, this);
29131 ds.un("load", this.onLoad, this);
29132 ds.un("loadexception", this.onLoadError, this);
29133 ds.un("remove", this.updateInfo, this);
29134 ds.un("add", this.updateInfo, this);
29135 this.ds = undefined;
29139 * Binds the paging toolbar to the specified {@link Roo.data.Store}
29140 * @param {Roo.data.Store} store The data store to bind
29142 bind : function(ds){
29143 ds.on("beforeload", this.beforeLoad, this);
29144 ds.on("load", this.onLoad, this);
29145 ds.on("loadexception", this.onLoadError, this);
29146 ds.on("remove", this.updateInfo, this);
29147 ds.on("add", this.updateInfo, this);
29152 * Ext JS Library 1.1.1
29153 * Copyright(c) 2006-2007, Ext JS, LLC.
29155 * Originally Released Under LGPL - original licence link has changed is not relivant.
29158 * <script type="text/javascript">
29162 * @class Roo.Resizable
29163 * @extends Roo.util.Observable
29164 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
29165 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
29166 * 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
29167 * the element will be wrapped for you automatically.</p>
29168 * <p>Here is the list of valid resize handles:</p>
29171 ------ -------------------
29180 'hd' horizontal drag
29183 * <p>Here's an example showing the creation of a typical Resizable:</p>
29185 var resizer = new Roo.Resizable("element-id", {
29193 resizer.on("resize", myHandler);
29195 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29196 * resizer.east.setDisplayed(false);</p>
29197 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29198 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29199 * resize operation's new size (defaults to [0, 0])
29200 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29201 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29202 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29203 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29204 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29205 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29206 * @cfg {Number} width The width of the element in pixels (defaults to null)
29207 * @cfg {Number} height The height of the element in pixels (defaults to null)
29208 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29209 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29210 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29211 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29212 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29213 * in favor of the handles config option (defaults to false)
29214 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29215 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29216 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29217 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29218 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29219 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29220 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29221 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29222 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29223 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29224 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29226 * Create a new resizable component
29227 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29228 * @param {Object} config configuration options
29230 Roo.Resizable = function(el, config)
29232 this.el = Roo.get(el);
29234 if(config && config.wrap){
29235 config.resizeChild = this.el;
29236 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29237 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29238 this.el.setStyle("overflow", "hidden");
29239 this.el.setPositioning(config.resizeChild.getPositioning());
29240 config.resizeChild.clearPositioning();
29241 if(!config.width || !config.height){
29242 var csize = config.resizeChild.getSize();
29243 this.el.setSize(csize.width, csize.height);
29245 if(config.pinned && !config.adjustments){
29246 config.adjustments = "auto";
29250 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29251 this.proxy.unselectable();
29252 this.proxy.enableDisplayMode('block');
29254 Roo.apply(this, config);
29257 this.disableTrackOver = true;
29258 this.el.addClass("x-resizable-pinned");
29260 // if the element isn't positioned, make it relative
29261 var position = this.el.getStyle("position");
29262 if(position != "absolute" && position != "fixed"){
29263 this.el.setStyle("position", "relative");
29265 if(!this.handles){ // no handles passed, must be legacy style
29266 this.handles = 's,e,se';
29267 if(this.multiDirectional){
29268 this.handles += ',n,w';
29271 if(this.handles == "all"){
29272 this.handles = "n s e w ne nw se sw";
29274 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29275 var ps = Roo.Resizable.positions;
29276 for(var i = 0, len = hs.length; i < len; i++){
29277 if(hs[i] && ps[hs[i]]){
29278 var pos = ps[hs[i]];
29279 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29283 this.corner = this.southeast;
29285 // updateBox = the box can move..
29286 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29287 this.updateBox = true;
29290 this.activeHandle = null;
29292 if(this.resizeChild){
29293 if(typeof this.resizeChild == "boolean"){
29294 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29296 this.resizeChild = Roo.get(this.resizeChild, true);
29300 if(this.adjustments == "auto"){
29301 var rc = this.resizeChild;
29302 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29303 if(rc && (hw || hn)){
29304 rc.position("relative");
29305 rc.setLeft(hw ? hw.el.getWidth() : 0);
29306 rc.setTop(hn ? hn.el.getHeight() : 0);
29308 this.adjustments = [
29309 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29310 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29314 if(this.draggable){
29315 this.dd = this.dynamic ?
29316 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29317 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29323 * @event beforeresize
29324 * Fired before resize is allowed. Set enabled to false to cancel resize.
29325 * @param {Roo.Resizable} this
29326 * @param {Roo.EventObject} e The mousedown event
29328 "beforeresize" : true,
29331 * Fired a resizing.
29332 * @param {Roo.Resizable} this
29333 * @param {Number} x The new x position
29334 * @param {Number} y The new y position
29335 * @param {Number} w The new w width
29336 * @param {Number} h The new h hight
29337 * @param {Roo.EventObject} e The mouseup event
29342 * Fired after a resize.
29343 * @param {Roo.Resizable} this
29344 * @param {Number} width The new width
29345 * @param {Number} height The new height
29346 * @param {Roo.EventObject} e The mouseup event
29351 if(this.width !== null && this.height !== null){
29352 this.resizeTo(this.width, this.height);
29354 this.updateChildSize();
29357 this.el.dom.style.zoom = 1;
29359 Roo.Resizable.superclass.constructor.call(this);
29362 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29363 resizeChild : false,
29364 adjustments : [0, 0],
29374 multiDirectional : false,
29375 disableTrackOver : false,
29376 easing : 'easeOutStrong',
29377 widthIncrement : 0,
29378 heightIncrement : 0,
29382 preserveRatio : false,
29383 transparent: false,
29389 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29391 constrainTo: undefined,
29393 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29395 resizeRegion: undefined,
29399 * Perform a manual resize
29400 * @param {Number} width
29401 * @param {Number} height
29403 resizeTo : function(width, height){
29404 this.el.setSize(width, height);
29405 this.updateChildSize();
29406 this.fireEvent("resize", this, width, height, null);
29410 startSizing : function(e, handle){
29411 this.fireEvent("beforeresize", this, e);
29412 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29415 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29416 this.overlay.unselectable();
29417 this.overlay.enableDisplayMode("block");
29418 this.overlay.on("mousemove", this.onMouseMove, this);
29419 this.overlay.on("mouseup", this.onMouseUp, this);
29421 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29423 this.resizing = true;
29424 this.startBox = this.el.getBox();
29425 this.startPoint = e.getXY();
29426 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29427 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29429 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29430 this.overlay.show();
29432 if(this.constrainTo) {
29433 var ct = Roo.get(this.constrainTo);
29434 this.resizeRegion = ct.getRegion().adjust(
29435 ct.getFrameWidth('t'),
29436 ct.getFrameWidth('l'),
29437 -ct.getFrameWidth('b'),
29438 -ct.getFrameWidth('r')
29442 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29444 this.proxy.setBox(this.startBox);
29446 this.proxy.setStyle('visibility', 'visible');
29452 onMouseDown : function(handle, e){
29455 this.activeHandle = handle;
29456 this.startSizing(e, handle);
29461 onMouseUp : function(e){
29462 var size = this.resizeElement();
29463 this.resizing = false;
29465 this.overlay.hide();
29467 this.fireEvent("resize", this, size.width, size.height, e);
29471 updateChildSize : function(){
29473 if(this.resizeChild){
29475 var child = this.resizeChild;
29476 var adj = this.adjustments;
29477 if(el.dom.offsetWidth){
29478 var b = el.getSize(true);
29479 child.setSize(b.width+adj[0], b.height+adj[1]);
29481 // Second call here for IE
29482 // The first call enables instant resizing and
29483 // the second call corrects scroll bars if they
29486 setTimeout(function(){
29487 if(el.dom.offsetWidth){
29488 var b = el.getSize(true);
29489 child.setSize(b.width+adj[0], b.height+adj[1]);
29497 snap : function(value, inc, min){
29498 if(!inc || !value) return value;
29499 var newValue = value;
29500 var m = value % inc;
29503 newValue = value + (inc-m);
29505 newValue = value - m;
29508 return Math.max(min, newValue);
29512 resizeElement : function(){
29513 var box = this.proxy.getBox();
29514 if(this.updateBox){
29515 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29517 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29519 this.updateChildSize();
29527 constrain : function(v, diff, m, mx){
29530 }else if(v - diff > mx){
29537 onMouseMove : function(e){
29540 try{// try catch so if something goes wrong the user doesn't get hung
29542 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29546 //var curXY = this.startPoint;
29547 var curSize = this.curSize || this.startBox;
29548 var x = this.startBox.x, y = this.startBox.y;
29549 var ox = x, oy = y;
29550 var w = curSize.width, h = curSize.height;
29551 var ow = w, oh = h;
29552 var mw = this.minWidth, mh = this.minHeight;
29553 var mxw = this.maxWidth, mxh = this.maxHeight;
29554 var wi = this.widthIncrement;
29555 var hi = this.heightIncrement;
29557 var eventXY = e.getXY();
29558 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29559 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29561 var pos = this.activeHandle.position;
29566 w = Math.min(Math.max(mw, w), mxw);
29571 h = Math.min(Math.max(mh, h), mxh);
29576 w = Math.min(Math.max(mw, w), mxw);
29577 h = Math.min(Math.max(mh, h), mxh);
29580 diffY = this.constrain(h, diffY, mh, mxh);
29587 var adiffX = Math.abs(diffX);
29588 var sub = (adiffX % wi); // how much
29589 if (sub > (wi/2)) { // far enough to snap
29590 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29592 // remove difference..
29593 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29597 x = Math.max(this.minX, x);
29600 diffX = this.constrain(w, diffX, mw, mxw);
29606 w = Math.min(Math.max(mw, w), mxw);
29607 diffY = this.constrain(h, diffY, mh, mxh);
29612 diffX = this.constrain(w, diffX, mw, mxw);
29613 diffY = this.constrain(h, diffY, mh, mxh);
29620 diffX = this.constrain(w, diffX, mw, mxw);
29622 h = Math.min(Math.max(mh, h), mxh);
29628 var sw = this.snap(w, wi, mw);
29629 var sh = this.snap(h, hi, mh);
29630 if(sw != w || sh != h){
29653 if(this.preserveRatio){
29658 h = Math.min(Math.max(mh, h), mxh);
29663 w = Math.min(Math.max(mw, w), mxw);
29668 w = Math.min(Math.max(mw, w), mxw);
29674 w = Math.min(Math.max(mw, w), mxw);
29680 h = Math.min(Math.max(mh, h), mxh);
29688 h = Math.min(Math.max(mh, h), mxh);
29698 h = Math.min(Math.max(mh, h), mxh);
29706 if (pos == 'hdrag') {
29709 this.proxy.setBounds(x, y, w, h);
29711 this.resizeElement();
29715 this.fireEvent("resizing", this, x, y, w, h, e);
29719 handleOver : function(){
29721 this.el.addClass("x-resizable-over");
29726 handleOut : function(){
29727 if(!this.resizing){
29728 this.el.removeClass("x-resizable-over");
29733 * Returns the element this component is bound to.
29734 * @return {Roo.Element}
29736 getEl : function(){
29741 * Returns the resizeChild element (or null).
29742 * @return {Roo.Element}
29744 getResizeChild : function(){
29745 return this.resizeChild;
29747 groupHandler : function()
29752 * Destroys this resizable. If the element was wrapped and
29753 * removeEl is not true then the element remains.
29754 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29756 destroy : function(removeEl){
29757 this.proxy.remove();
29759 this.overlay.removeAllListeners();
29760 this.overlay.remove();
29762 var ps = Roo.Resizable.positions;
29764 if(typeof ps[k] != "function" && this[ps[k]]){
29765 var h = this[ps[k]];
29766 h.el.removeAllListeners();
29771 this.el.update("");
29778 // hash to map config positions to true positions
29779 Roo.Resizable.positions = {
29780 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29785 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29787 // only initialize the template if resizable is used
29788 var tpl = Roo.DomHelper.createTemplate(
29789 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29792 Roo.Resizable.Handle.prototype.tpl = tpl;
29794 this.position = pos;
29796 // show north drag fro topdra
29797 var handlepos = pos == 'hdrag' ? 'north' : pos;
29799 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29800 if (pos == 'hdrag') {
29801 this.el.setStyle('cursor', 'pointer');
29803 this.el.unselectable();
29805 this.el.setOpacity(0);
29807 this.el.on("mousedown", this.onMouseDown, this);
29808 if(!disableTrackOver){
29809 this.el.on("mouseover", this.onMouseOver, this);
29810 this.el.on("mouseout", this.onMouseOut, this);
29815 Roo.Resizable.Handle.prototype = {
29816 afterResize : function(rz){
29821 onMouseDown : function(e){
29822 this.rz.onMouseDown(this, e);
29825 onMouseOver : function(e){
29826 this.rz.handleOver(this, e);
29829 onMouseOut : function(e){
29830 this.rz.handleOut(this, e);
29834 * Ext JS Library 1.1.1
29835 * Copyright(c) 2006-2007, Ext JS, LLC.
29837 * Originally Released Under LGPL - original licence link has changed is not relivant.
29840 * <script type="text/javascript">
29844 * @class Roo.Editor
29845 * @extends Roo.Component
29846 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29848 * Create a new Editor
29849 * @param {Roo.form.Field} field The Field object (or descendant)
29850 * @param {Object} config The config object
29852 Roo.Editor = function(field, config){
29853 Roo.Editor.superclass.constructor.call(this, config);
29854 this.field = field;
29857 * @event beforestartedit
29858 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29859 * false from the handler of this event.
29860 * @param {Editor} this
29861 * @param {Roo.Element} boundEl The underlying element bound to this editor
29862 * @param {Mixed} value The field value being set
29864 "beforestartedit" : true,
29867 * Fires when this editor is displayed
29868 * @param {Roo.Element} boundEl The underlying element bound to this editor
29869 * @param {Mixed} value The starting field value
29871 "startedit" : true,
29873 * @event beforecomplete
29874 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29875 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29876 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29877 * event will not fire since no edit actually occurred.
29878 * @param {Editor} this
29879 * @param {Mixed} value The current field value
29880 * @param {Mixed} startValue The original field value
29882 "beforecomplete" : true,
29885 * Fires after editing is complete and any changed value has been written to the underlying field.
29886 * @param {Editor} this
29887 * @param {Mixed} value The current field value
29888 * @param {Mixed} startValue The original field value
29892 * @event specialkey
29893 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29894 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29895 * @param {Roo.form.Field} this
29896 * @param {Roo.EventObject} e The event object
29898 "specialkey" : true
29902 Roo.extend(Roo.Editor, Roo.Component, {
29904 * @cfg {Boolean/String} autosize
29905 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29906 * or "height" to adopt the height only (defaults to false)
29909 * @cfg {Boolean} revertInvalid
29910 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29911 * validation fails (defaults to true)
29914 * @cfg {Boolean} ignoreNoChange
29915 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29916 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29917 * will never be ignored.
29920 * @cfg {Boolean} hideEl
29921 * False to keep the bound element visible while the editor is displayed (defaults to true)
29924 * @cfg {Mixed} value
29925 * The data value of the underlying field (defaults to "")
29929 * @cfg {String} alignment
29930 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29934 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29935 * for bottom-right shadow (defaults to "frame")
29939 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29943 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29945 completeOnEnter : false,
29947 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29949 cancelOnEsc : false,
29951 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29956 onRender : function(ct, position){
29957 this.el = new Roo.Layer({
29958 shadow: this.shadow,
29964 constrain: this.constrain
29966 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29967 if(this.field.msgTarget != 'title'){
29968 this.field.msgTarget = 'qtip';
29970 this.field.render(this.el);
29972 this.field.el.dom.setAttribute('autocomplete', 'off');
29974 this.field.on("specialkey", this.onSpecialKey, this);
29975 if(this.swallowKeys){
29976 this.field.el.swallowEvent(['keydown','keypress']);
29979 this.field.on("blur", this.onBlur, this);
29980 if(this.field.grow){
29981 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29985 onSpecialKey : function(field, e)
29987 //Roo.log('editor onSpecialKey');
29988 if(this.completeOnEnter && e.getKey() == e.ENTER){
29990 this.completeEdit();
29993 // do not fire special key otherwise it might hide close the editor...
29994 if(e.getKey() == e.ENTER){
29997 if(this.cancelOnEsc && e.getKey() == e.ESC){
30001 this.fireEvent('specialkey', field, e);
30006 * Starts the editing process and shows the editor.
30007 * @param {String/HTMLElement/Element} el The element to edit
30008 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
30009 * to the innerHTML of el.
30011 startEdit : function(el, value){
30013 this.completeEdit();
30015 this.boundEl = Roo.get(el);
30016 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
30017 if(!this.rendered){
30018 this.render(this.parentEl || document.body);
30020 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
30023 this.startValue = v;
30024 this.field.setValue(v);
30026 var sz = this.boundEl.getSize();
30027 switch(this.autoSize){
30029 this.setSize(sz.width, "");
30032 this.setSize("", sz.height);
30035 this.setSize(sz.width, sz.height);
30038 this.el.alignTo(this.boundEl, this.alignment);
30039 this.editing = true;
30041 Roo.QuickTips.disable();
30047 * Sets the height and width of this editor.
30048 * @param {Number} width The new width
30049 * @param {Number} height The new height
30051 setSize : function(w, h){
30052 this.field.setSize(w, h);
30059 * Realigns the editor to the bound field based on the current alignment config value.
30061 realign : function(){
30062 this.el.alignTo(this.boundEl, this.alignment);
30066 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
30067 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
30069 completeEdit : function(remainVisible){
30073 var v = this.getValue();
30074 if(this.revertInvalid !== false && !this.field.isValid()){
30075 v = this.startValue;
30076 this.cancelEdit(true);
30078 if(String(v) === String(this.startValue) && this.ignoreNoChange){
30079 this.editing = false;
30083 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
30084 this.editing = false;
30085 if(this.updateEl && this.boundEl){
30086 this.boundEl.update(v);
30088 if(remainVisible !== true){
30091 this.fireEvent("complete", this, v, this.startValue);
30096 onShow : function(){
30098 if(this.hideEl !== false){
30099 this.boundEl.hide();
30102 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
30103 this.fixIEFocus = true;
30104 this.deferredFocus.defer(50, this);
30106 this.field.focus();
30108 this.fireEvent("startedit", this.boundEl, this.startValue);
30111 deferredFocus : function(){
30113 this.field.focus();
30118 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
30119 * reverted to the original starting value.
30120 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
30121 * cancel (defaults to false)
30123 cancelEdit : function(remainVisible){
30125 this.setValue(this.startValue);
30126 if(remainVisible !== true){
30133 onBlur : function(){
30134 if(this.allowBlur !== true && this.editing){
30135 this.completeEdit();
30140 onHide : function(){
30142 this.completeEdit();
30146 if(this.field.collapse){
30147 this.field.collapse();
30150 if(this.hideEl !== false){
30151 this.boundEl.show();
30154 Roo.QuickTips.enable();
30159 * Sets the data value of the editor
30160 * @param {Mixed} value Any valid value supported by the underlying field
30162 setValue : function(v){
30163 this.field.setValue(v);
30167 * Gets the data value of the editor
30168 * @return {Mixed} The data value
30170 getValue : function(){
30171 return this.field.getValue();
30175 * Ext JS Library 1.1.1
30176 * Copyright(c) 2006-2007, Ext JS, LLC.
30178 * Originally Released Under LGPL - original licence link has changed is not relivant.
30181 * <script type="text/javascript">
30185 * @class Roo.BasicDialog
30186 * @extends Roo.util.Observable
30187 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
30189 var dlg = new Roo.BasicDialog("my-dlg", {
30198 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30199 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30200 dlg.addButton('Cancel', dlg.hide, dlg);
30203 <b>A Dialog should always be a direct child of the body element.</b>
30204 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30205 * @cfg {String} title Default text to display in the title bar (defaults to null)
30206 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30207 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30208 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30209 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30210 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30211 * (defaults to null with no animation)
30212 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30213 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30214 * property for valid values (defaults to 'all')
30215 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30216 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30217 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30218 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30219 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30220 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30221 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30222 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30223 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30224 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30225 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30226 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30227 * draggable = true (defaults to false)
30228 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30229 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30230 * shadow (defaults to false)
30231 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30232 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30233 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30234 * @cfg {Array} buttons Array of buttons
30235 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30237 * Create a new BasicDialog.
30238 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30239 * @param {Object} config Configuration options
30241 Roo.BasicDialog = function(el, config){
30242 this.el = Roo.get(el);
30243 var dh = Roo.DomHelper;
30244 if(!this.el && config && config.autoCreate){
30245 if(typeof config.autoCreate == "object"){
30246 if(!config.autoCreate.id){
30247 config.autoCreate.id = el;
30249 this.el = dh.append(document.body,
30250 config.autoCreate, true);
30252 this.el = dh.append(document.body,
30253 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30257 el.setDisplayed(true);
30258 el.hide = this.hideAction;
30260 el.addClass("x-dlg");
30262 Roo.apply(this, config);
30264 this.proxy = el.createProxy("x-dlg-proxy");
30265 this.proxy.hide = this.hideAction;
30266 this.proxy.setOpacity(.5);
30270 el.setWidth(config.width);
30273 el.setHeight(config.height);
30275 this.size = el.getSize();
30276 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30277 this.xy = [config.x,config.y];
30279 this.xy = el.getCenterXY(true);
30281 /** The header element @type Roo.Element */
30282 this.header = el.child("> .x-dlg-hd");
30283 /** The body element @type Roo.Element */
30284 this.body = el.child("> .x-dlg-bd");
30285 /** The footer element @type Roo.Element */
30286 this.footer = el.child("> .x-dlg-ft");
30289 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30292 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30295 this.header.unselectable();
30297 this.header.update(this.title);
30299 // this element allows the dialog to be focused for keyboard event
30300 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30301 this.focusEl.swallowEvent("click", true);
30303 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30305 // wrap the body and footer for special rendering
30306 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30308 this.bwrap.dom.appendChild(this.footer.dom);
30311 this.bg = this.el.createChild({
30312 tag: "div", cls:"x-dlg-bg",
30313 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30315 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30318 if(this.autoScroll !== false && !this.autoTabs){
30319 this.body.setStyle("overflow", "auto");
30322 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30324 if(this.closable !== false){
30325 this.el.addClass("x-dlg-closable");
30326 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30327 this.close.on("click", this.closeClick, this);
30328 this.close.addClassOnOver("x-dlg-close-over");
30330 if(this.collapsible !== false){
30331 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30332 this.collapseBtn.on("click", this.collapseClick, this);
30333 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30334 this.header.on("dblclick", this.collapseClick, this);
30336 if(this.resizable !== false){
30337 this.el.addClass("x-dlg-resizable");
30338 this.resizer = new Roo.Resizable(el, {
30339 minWidth: this.minWidth || 80,
30340 minHeight:this.minHeight || 80,
30341 handles: this.resizeHandles || "all",
30344 this.resizer.on("beforeresize", this.beforeResize, this);
30345 this.resizer.on("resize", this.onResize, this);
30347 if(this.draggable !== false){
30348 el.addClass("x-dlg-draggable");
30349 if (!this.proxyDrag) {
30350 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30353 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30355 dd.setHandleElId(this.header.id);
30356 dd.endDrag = this.endMove.createDelegate(this);
30357 dd.startDrag = this.startMove.createDelegate(this);
30358 dd.onDrag = this.onDrag.createDelegate(this);
30363 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30364 this.mask.enableDisplayMode("block");
30366 this.el.addClass("x-dlg-modal");
30369 this.shadow = new Roo.Shadow({
30370 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30371 offset : this.shadowOffset
30374 this.shadowOffset = 0;
30376 if(Roo.useShims && this.shim !== false){
30377 this.shim = this.el.createShim();
30378 this.shim.hide = this.hideAction;
30386 if (this.buttons) {
30387 var bts= this.buttons;
30389 Roo.each(bts, function(b) {
30398 * Fires when a key is pressed
30399 * @param {Roo.BasicDialog} this
30400 * @param {Roo.EventObject} e
30405 * Fires when this dialog is moved by the user.
30406 * @param {Roo.BasicDialog} this
30407 * @param {Number} x The new page X
30408 * @param {Number} y The new page Y
30413 * Fires when this dialog is resized by the user.
30414 * @param {Roo.BasicDialog} this
30415 * @param {Number} width The new width
30416 * @param {Number} height The new height
30420 * @event beforehide
30421 * Fires before this dialog is hidden.
30422 * @param {Roo.BasicDialog} this
30424 "beforehide" : true,
30427 * Fires when this dialog is hidden.
30428 * @param {Roo.BasicDialog} this
30432 * @event beforeshow
30433 * Fires before this dialog is shown.
30434 * @param {Roo.BasicDialog} this
30436 "beforeshow" : true,
30439 * Fires when this dialog is shown.
30440 * @param {Roo.BasicDialog} this
30444 el.on("keydown", this.onKeyDown, this);
30445 el.on("mousedown", this.toFront, this);
30446 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30448 Roo.DialogManager.register(this);
30449 Roo.BasicDialog.superclass.constructor.call(this);
30452 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30453 shadowOffset: Roo.isIE ? 6 : 5,
30456 minButtonWidth: 75,
30457 defaultButton: null,
30458 buttonAlign: "right",
30463 * Sets the dialog title text
30464 * @param {String} text The title text to display
30465 * @return {Roo.BasicDialog} this
30467 setTitle : function(text){
30468 this.header.update(text);
30473 closeClick : function(){
30478 collapseClick : function(){
30479 this[this.collapsed ? "expand" : "collapse"]();
30483 * Collapses the dialog to its minimized state (only the title bar is visible).
30484 * Equivalent to the user clicking the collapse dialog button.
30486 collapse : function(){
30487 if(!this.collapsed){
30488 this.collapsed = true;
30489 this.el.addClass("x-dlg-collapsed");
30490 this.restoreHeight = this.el.getHeight();
30491 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30496 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30497 * clicking the expand dialog button.
30499 expand : function(){
30500 if(this.collapsed){
30501 this.collapsed = false;
30502 this.el.removeClass("x-dlg-collapsed");
30503 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30508 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30509 * @return {Roo.TabPanel} The tabs component
30511 initTabs : function(){
30512 var tabs = this.getTabs();
30513 while(tabs.getTab(0)){
30516 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30518 tabs.addTab(Roo.id(dom), dom.title);
30526 beforeResize : function(){
30527 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30531 onResize : function(){
30532 this.refreshSize();
30533 this.syncBodyHeight();
30534 this.adjustAssets();
30536 this.fireEvent("resize", this, this.size.width, this.size.height);
30540 onKeyDown : function(e){
30541 if(this.isVisible()){
30542 this.fireEvent("keydown", this, e);
30547 * Resizes the dialog.
30548 * @param {Number} width
30549 * @param {Number} height
30550 * @return {Roo.BasicDialog} this
30552 resizeTo : function(width, height){
30553 this.el.setSize(width, height);
30554 this.size = {width: width, height: height};
30555 this.syncBodyHeight();
30556 if(this.fixedcenter){
30559 if(this.isVisible()){
30560 this.constrainXY();
30561 this.adjustAssets();
30563 this.fireEvent("resize", this, width, height);
30569 * Resizes the dialog to fit the specified content size.
30570 * @param {Number} width
30571 * @param {Number} height
30572 * @return {Roo.BasicDialog} this
30574 setContentSize : function(w, h){
30575 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30576 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30577 //if(!this.el.isBorderBox()){
30578 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30579 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30582 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30583 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30585 this.resizeTo(w, h);
30590 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30591 * executed in response to a particular key being pressed while the dialog is active.
30592 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30593 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30594 * @param {Function} fn The function to call
30595 * @param {Object} scope (optional) The scope of the function
30596 * @return {Roo.BasicDialog} this
30598 addKeyListener : function(key, fn, scope){
30599 var keyCode, shift, ctrl, alt;
30600 if(typeof key == "object" && !(key instanceof Array)){
30601 keyCode = key["key"];
30602 shift = key["shift"];
30603 ctrl = key["ctrl"];
30608 var handler = function(dlg, e){
30609 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30610 var k = e.getKey();
30611 if(keyCode instanceof Array){
30612 for(var i = 0, len = keyCode.length; i < len; i++){
30613 if(keyCode[i] == k){
30614 fn.call(scope || window, dlg, k, e);
30620 fn.call(scope || window, dlg, k, e);
30625 this.on("keydown", handler);
30630 * Returns the TabPanel component (creates it if it doesn't exist).
30631 * Note: If you wish to simply check for the existence of tabs without creating them,
30632 * check for a null 'tabs' property.
30633 * @return {Roo.TabPanel} The tabs component
30635 getTabs : function(){
30637 this.el.addClass("x-dlg-auto-tabs");
30638 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30639 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30645 * Adds a button to the footer section of the dialog.
30646 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30647 * object or a valid Roo.DomHelper element config
30648 * @param {Function} handler The function called when the button is clicked
30649 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30650 * @return {Roo.Button} The new button
30652 addButton : function(config, handler, scope){
30653 var dh = Roo.DomHelper;
30655 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30657 if(!this.btnContainer){
30658 var tb = this.footer.createChild({
30660 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30661 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30663 this.btnContainer = tb.firstChild.firstChild.firstChild;
30668 minWidth: this.minButtonWidth,
30671 if(typeof config == "string"){
30672 bconfig.text = config;
30675 bconfig.dhconfig = config;
30677 Roo.apply(bconfig, config);
30681 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30682 bconfig.position = Math.max(0, bconfig.position);
30683 fc = this.btnContainer.childNodes[bconfig.position];
30686 var btn = new Roo.Button(
30688 this.btnContainer.insertBefore(document.createElement("td"),fc)
30689 : this.btnContainer.appendChild(document.createElement("td")),
30690 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30693 this.syncBodyHeight();
30696 * Array of all the buttons that have been added to this dialog via addButton
30701 this.buttons.push(btn);
30706 * Sets the default button to be focused when the dialog is displayed.
30707 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30708 * @return {Roo.BasicDialog} this
30710 setDefaultButton : function(btn){
30711 this.defaultButton = btn;
30716 getHeaderFooterHeight : function(safe){
30719 height += this.header.getHeight();
30722 var fm = this.footer.getMargins();
30723 height += (this.footer.getHeight()+fm.top+fm.bottom);
30725 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30726 height += this.centerBg.getPadding("tb");
30731 syncBodyHeight : function()
30733 var bd = this.body, // the text
30734 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30736 var height = this.size.height - this.getHeaderFooterHeight(false);
30737 bd.setHeight(height-bd.getMargins("tb"));
30738 var hh = this.header.getHeight();
30739 var h = this.size.height-hh;
30742 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30743 bw.setHeight(h-cb.getPadding("tb"));
30745 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30746 bd.setWidth(bw.getWidth(true));
30748 this.tabs.syncHeight();
30750 this.tabs.el.repaint();
30756 * Restores the previous state of the dialog if Roo.state is configured.
30757 * @return {Roo.BasicDialog} this
30759 restoreState : function(){
30760 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30761 if(box && box.width){
30762 this.xy = [box.x, box.y];
30763 this.resizeTo(box.width, box.height);
30769 beforeShow : function(){
30771 if(this.fixedcenter){
30772 this.xy = this.el.getCenterXY(true);
30775 Roo.get(document.body).addClass("x-body-masked");
30776 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30779 this.constrainXY();
30783 animShow : function(){
30784 var b = Roo.get(this.animateTarget).getBox();
30785 this.proxy.setSize(b.width, b.height);
30786 this.proxy.setLocation(b.x, b.y);
30788 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30789 true, .35, this.showEl.createDelegate(this));
30793 * Shows the dialog.
30794 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30795 * @return {Roo.BasicDialog} this
30797 show : function(animateTarget){
30798 if (this.fireEvent("beforeshow", this) === false){
30801 if(this.syncHeightBeforeShow){
30802 this.syncBodyHeight();
30803 }else if(this.firstShow){
30804 this.firstShow = false;
30805 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30807 this.animateTarget = animateTarget || this.animateTarget;
30808 if(!this.el.isVisible()){
30810 if(this.animateTarget && Roo.get(this.animateTarget)){
30820 showEl : function(){
30822 this.el.setXY(this.xy);
30824 this.adjustAssets(true);
30827 // IE peekaboo bug - fix found by Dave Fenwick
30831 this.fireEvent("show", this);
30835 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30836 * dialog itself will receive focus.
30838 focus : function(){
30839 if(this.defaultButton){
30840 this.defaultButton.focus();
30842 this.focusEl.focus();
30847 constrainXY : function(){
30848 if(this.constraintoviewport !== false){
30849 if(!this.viewSize){
30850 if(this.container){
30851 var s = this.container.getSize();
30852 this.viewSize = [s.width, s.height];
30854 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30857 var s = Roo.get(this.container||document).getScroll();
30859 var x = this.xy[0], y = this.xy[1];
30860 var w = this.size.width, h = this.size.height;
30861 var vw = this.viewSize[0], vh = this.viewSize[1];
30862 // only move it if it needs it
30864 // first validate right/bottom
30865 if(x + w > vw+s.left){
30869 if(y + h > vh+s.top){
30873 // then make sure top/left isn't negative
30885 if(this.isVisible()){
30886 this.el.setLocation(x, y);
30887 this.adjustAssets();
30894 onDrag : function(){
30895 if(!this.proxyDrag){
30896 this.xy = this.el.getXY();
30897 this.adjustAssets();
30902 adjustAssets : function(doShow){
30903 var x = this.xy[0], y = this.xy[1];
30904 var w = this.size.width, h = this.size.height;
30905 if(doShow === true){
30907 this.shadow.show(this.el);
30913 if(this.shadow && this.shadow.isVisible()){
30914 this.shadow.show(this.el);
30916 if(this.shim && this.shim.isVisible()){
30917 this.shim.setBounds(x, y, w, h);
30922 adjustViewport : function(w, h){
30924 w = Roo.lib.Dom.getViewWidth();
30925 h = Roo.lib.Dom.getViewHeight();
30928 this.viewSize = [w, h];
30929 if(this.modal && this.mask.isVisible()){
30930 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30931 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30933 if(this.isVisible()){
30934 this.constrainXY();
30939 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30940 * shadow, proxy, mask, etc.) Also removes all event listeners.
30941 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30943 destroy : function(removeEl){
30944 if(this.isVisible()){
30945 this.animateTarget = null;
30948 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30950 this.tabs.destroy(removeEl);
30963 for(var i = 0, len = this.buttons.length; i < len; i++){
30964 this.buttons[i].destroy();
30967 this.el.removeAllListeners();
30968 if(removeEl === true){
30969 this.el.update("");
30972 Roo.DialogManager.unregister(this);
30976 startMove : function(){
30977 if(this.proxyDrag){
30980 if(this.constraintoviewport !== false){
30981 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30986 endMove : function(){
30987 if(!this.proxyDrag){
30988 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30990 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30993 this.refreshSize();
30994 this.adjustAssets();
30996 this.fireEvent("move", this, this.xy[0], this.xy[1]);
31000 * Brings this dialog to the front of any other visible dialogs
31001 * @return {Roo.BasicDialog} this
31003 toFront : function(){
31004 Roo.DialogManager.bringToFront(this);
31009 * Sends this dialog to the back (under) of any other visible dialogs
31010 * @return {Roo.BasicDialog} this
31012 toBack : function(){
31013 Roo.DialogManager.sendToBack(this);
31018 * Centers this dialog in the viewport
31019 * @return {Roo.BasicDialog} this
31021 center : function(){
31022 var xy = this.el.getCenterXY(true);
31023 this.moveTo(xy[0], xy[1]);
31028 * Moves the dialog's top-left corner to the specified point
31029 * @param {Number} x
31030 * @param {Number} y
31031 * @return {Roo.BasicDialog} this
31033 moveTo : function(x, y){
31035 if(this.isVisible()){
31036 this.el.setXY(this.xy);
31037 this.adjustAssets();
31043 * Aligns the dialog to the specified element
31044 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31045 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
31046 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31047 * @return {Roo.BasicDialog} this
31049 alignTo : function(element, position, offsets){
31050 this.xy = this.el.getAlignToXY(element, position, offsets);
31051 if(this.isVisible()){
31052 this.el.setXY(this.xy);
31053 this.adjustAssets();
31059 * Anchors an element to another element and realigns it when the window is resized.
31060 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31061 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
31062 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31063 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
31064 * is a number, it is used as the buffer delay (defaults to 50ms).
31065 * @return {Roo.BasicDialog} this
31067 anchorTo : function(el, alignment, offsets, monitorScroll){
31068 var action = function(){
31069 this.alignTo(el, alignment, offsets);
31071 Roo.EventManager.onWindowResize(action, this);
31072 var tm = typeof monitorScroll;
31073 if(tm != 'undefined'){
31074 Roo.EventManager.on(window, 'scroll', action, this,
31075 {buffer: tm == 'number' ? monitorScroll : 50});
31082 * Returns true if the dialog is visible
31083 * @return {Boolean}
31085 isVisible : function(){
31086 return this.el.isVisible();
31090 animHide : function(callback){
31091 var b = Roo.get(this.animateTarget).getBox();
31093 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
31095 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
31096 this.hideEl.createDelegate(this, [callback]));
31100 * Hides the dialog.
31101 * @param {Function} callback (optional) Function to call when the dialog is hidden
31102 * @return {Roo.BasicDialog} this
31104 hide : function(callback){
31105 if (this.fireEvent("beforehide", this) === false){
31109 this.shadow.hide();
31114 // sometimes animateTarget seems to get set.. causing problems...
31115 // this just double checks..
31116 if(this.animateTarget && Roo.get(this.animateTarget)) {
31117 this.animHide(callback);
31120 this.hideEl(callback);
31126 hideEl : function(callback){
31130 Roo.get(document.body).removeClass("x-body-masked");
31132 this.fireEvent("hide", this);
31133 if(typeof callback == "function"){
31139 hideAction : function(){
31140 this.setLeft("-10000px");
31141 this.setTop("-10000px");
31142 this.setStyle("visibility", "hidden");
31146 refreshSize : function(){
31147 this.size = this.el.getSize();
31148 this.xy = this.el.getXY();
31149 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
31153 // z-index is managed by the DialogManager and may be overwritten at any time
31154 setZIndex : function(index){
31156 this.mask.setStyle("z-index", index);
31159 this.shim.setStyle("z-index", ++index);
31162 this.shadow.setZIndex(++index);
31164 this.el.setStyle("z-index", ++index);
31166 this.proxy.setStyle("z-index", ++index);
31169 this.resizer.proxy.setStyle("z-index", ++index);
31172 this.lastZIndex = index;
31176 * Returns the element for this dialog
31177 * @return {Roo.Element} The underlying dialog Element
31179 getEl : function(){
31185 * @class Roo.DialogManager
31186 * Provides global access to BasicDialogs that have been created and
31187 * support for z-indexing (layering) multiple open dialogs.
31189 Roo.DialogManager = function(){
31191 var accessList = [];
31195 var sortDialogs = function(d1, d2){
31196 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31200 var orderDialogs = function(){
31201 accessList.sort(sortDialogs);
31202 var seed = Roo.DialogManager.zseed;
31203 for(var i = 0, len = accessList.length; i < len; i++){
31204 var dlg = accessList[i];
31206 dlg.setZIndex(seed + (i*10));
31213 * The starting z-index for BasicDialogs (defaults to 9000)
31214 * @type Number The z-index value
31219 register : function(dlg){
31220 list[dlg.id] = dlg;
31221 accessList.push(dlg);
31225 unregister : function(dlg){
31226 delete list[dlg.id];
31229 if(!accessList.indexOf){
31230 for( i = 0, len = accessList.length; i < len; i++){
31231 if(accessList[i] == dlg){
31232 accessList.splice(i, 1);
31237 i = accessList.indexOf(dlg);
31239 accessList.splice(i, 1);
31245 * Gets a registered dialog by id
31246 * @param {String/Object} id The id of the dialog or a dialog
31247 * @return {Roo.BasicDialog} this
31249 get : function(id){
31250 return typeof id == "object" ? id : list[id];
31254 * Brings the specified dialog to the front
31255 * @param {String/Object} dlg The id of the dialog or a dialog
31256 * @return {Roo.BasicDialog} this
31258 bringToFront : function(dlg){
31259 dlg = this.get(dlg);
31262 dlg._lastAccess = new Date().getTime();
31269 * Sends the specified dialog to the back
31270 * @param {String/Object} dlg The id of the dialog or a dialog
31271 * @return {Roo.BasicDialog} this
31273 sendToBack : function(dlg){
31274 dlg = this.get(dlg);
31275 dlg._lastAccess = -(new Date().getTime());
31281 * Hides all dialogs
31283 hideAll : function(){
31284 for(var id in list){
31285 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31294 * @class Roo.LayoutDialog
31295 * @extends Roo.BasicDialog
31296 * Dialog which provides adjustments for working with a layout in a Dialog.
31297 * Add your necessary layout config options to the dialog's config.<br>
31298 * Example usage (including a nested layout):
31301 dialog = new Roo.LayoutDialog("download-dlg", {
31310 // layout config merges with the dialog config
31312 tabPosition: "top",
31313 alwaysShowTabs: true
31316 dialog.addKeyListener(27, dialog.hide, dialog);
31317 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31318 dialog.addButton("Build It!", this.getDownload, this);
31320 // we can even add nested layouts
31321 var innerLayout = new Roo.BorderLayout("dl-inner", {
31331 innerLayout.beginUpdate();
31332 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31333 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31334 innerLayout.endUpdate(true);
31336 var layout = dialog.getLayout();
31337 layout.beginUpdate();
31338 layout.add("center", new Roo.ContentPanel("standard-panel",
31339 {title: "Download the Source", fitToFrame:true}));
31340 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31341 {title: "Build your own roo.js"}));
31342 layout.getRegion("center").showPanel(sp);
31343 layout.endUpdate();
31347 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31348 * @param {Object} config configuration options
31350 Roo.LayoutDialog = function(el, cfg){
31353 if (typeof(cfg) == 'undefined') {
31354 config = Roo.apply({}, el);
31355 // not sure why we use documentElement here.. - it should always be body.
31356 // IE7 borks horribly if we use documentElement.
31357 // webkit also does not like documentElement - it creates a body element...
31358 el = Roo.get( document.body || document.documentElement ).createChild();
31359 //config.autoCreate = true;
31363 config.autoTabs = false;
31364 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31365 this.body.setStyle({overflow:"hidden", position:"relative"});
31366 this.layout = new Roo.BorderLayout(this.body.dom, config);
31367 this.layout.monitorWindowResize = false;
31368 this.el.addClass("x-dlg-auto-layout");
31369 // fix case when center region overwrites center function
31370 this.center = Roo.BasicDialog.prototype.center;
31371 this.on("show", this.layout.layout, this.layout, true);
31372 if (config.items) {
31373 var xitems = config.items;
31374 delete config.items;
31375 Roo.each(xitems, this.addxtype, this);
31380 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31382 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31385 endUpdate : function(){
31386 this.layout.endUpdate();
31390 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31393 beginUpdate : function(){
31394 this.layout.beginUpdate();
31398 * Get the BorderLayout for this dialog
31399 * @return {Roo.BorderLayout}
31401 getLayout : function(){
31402 return this.layout;
31405 showEl : function(){
31406 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31408 this.layout.layout();
31413 // Use the syncHeightBeforeShow config option to control this automatically
31414 syncBodyHeight : function(){
31415 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31416 if(this.layout){this.layout.layout();}
31420 * Add an xtype element (actually adds to the layout.)
31421 * @return {Object} xdata xtype object data.
31424 addxtype : function(c) {
31425 return this.layout.addxtype(c);
31429 * Ext JS Library 1.1.1
31430 * Copyright(c) 2006-2007, Ext JS, LLC.
31432 * Originally Released Under LGPL - original licence link has changed is not relivant.
31435 * <script type="text/javascript">
31439 * @class Roo.MessageBox
31440 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31444 Roo.Msg.alert('Status', 'Changes saved successfully.');
31446 // Prompt for user data:
31447 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31449 // process text value...
31453 // Show a dialog using config options:
31455 title:'Save Changes?',
31456 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31457 buttons: Roo.Msg.YESNOCANCEL,
31464 Roo.MessageBox = function(){
31465 var dlg, opt, mask, waitTimer;
31466 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31467 var buttons, activeTextEl, bwidth;
31470 var handleButton = function(button){
31472 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31476 var handleHide = function(){
31477 if(opt && opt.cls){
31478 dlg.el.removeClass(opt.cls);
31481 Roo.TaskMgr.stop(waitTimer);
31487 var updateButtons = function(b){
31490 buttons["ok"].hide();
31491 buttons["cancel"].hide();
31492 buttons["yes"].hide();
31493 buttons["no"].hide();
31494 dlg.footer.dom.style.display = 'none';
31497 dlg.footer.dom.style.display = '';
31498 for(var k in buttons){
31499 if(typeof buttons[k] != "function"){
31502 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31503 width += buttons[k].el.getWidth()+15;
31513 var handleEsc = function(d, k, e){
31514 if(opt && opt.closable !== false){
31524 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31525 * @return {Roo.BasicDialog} The BasicDialog element
31527 getDialog : function(){
31529 dlg = new Roo.BasicDialog("x-msg-box", {
31534 constraintoviewport:false,
31536 collapsible : false,
31539 width:400, height:100,
31540 buttonAlign:"center",
31541 closeClick : function(){
31542 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31543 handleButton("no");
31545 handleButton("cancel");
31549 dlg.on("hide", handleHide);
31551 dlg.addKeyListener(27, handleEsc);
31553 var bt = this.buttonText;
31554 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31555 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31556 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31557 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31558 bodyEl = dlg.body.createChild({
31560 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>'
31562 msgEl = bodyEl.dom.firstChild;
31563 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31564 textboxEl.enableDisplayMode();
31565 textboxEl.addKeyListener([10,13], function(){
31566 if(dlg.isVisible() && opt && opt.buttons){
31567 if(opt.buttons.ok){
31568 handleButton("ok");
31569 }else if(opt.buttons.yes){
31570 handleButton("yes");
31574 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31575 textareaEl.enableDisplayMode();
31576 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31577 progressEl.enableDisplayMode();
31578 var pf = progressEl.dom.firstChild;
31580 pp = Roo.get(pf.firstChild);
31581 pp.setHeight(pf.offsetHeight);
31589 * Updates the message box body text
31590 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31591 * the XHTML-compliant non-breaking space character '&#160;')
31592 * @return {Roo.MessageBox} This message box
31594 updateText : function(text){
31595 if(!dlg.isVisible() && !opt.width){
31596 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31598 msgEl.innerHTML = text || ' ';
31600 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31601 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31603 Math.min(opt.width || cw , this.maxWidth),
31604 Math.max(opt.minWidth || this.minWidth, bwidth)
31607 activeTextEl.setWidth(w);
31609 if(dlg.isVisible()){
31610 dlg.fixedcenter = false;
31612 // to big, make it scroll. = But as usual stupid IE does not support
31615 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31616 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31617 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31619 bodyEl.dom.style.height = '';
31620 bodyEl.dom.style.overflowY = '';
31623 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31625 bodyEl.dom.style.overflowX = '';
31628 dlg.setContentSize(w, bodyEl.getHeight());
31629 if(dlg.isVisible()){
31630 dlg.fixedcenter = true;
31636 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31637 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31638 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31639 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31640 * @return {Roo.MessageBox} This message box
31642 updateProgress : function(value, text){
31644 this.updateText(text);
31646 if (pp) { // weird bug on my firefox - for some reason this is not defined
31647 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31653 * Returns true if the message box is currently displayed
31654 * @return {Boolean} True if the message box is visible, else false
31656 isVisible : function(){
31657 return dlg && dlg.isVisible();
31661 * Hides the message box if it is displayed
31664 if(this.isVisible()){
31670 * Displays a new message box, or reinitializes an existing message box, based on the config options
31671 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31672 * The following config object properties are supported:
31674 Property Type Description
31675 ---------- --------------- ------------------------------------------------------------------------------------
31676 animEl String/Element An id or Element from which the message box should animate as it opens and
31677 closes (defaults to undefined)
31678 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31679 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31680 closable Boolean False to hide the top-right close button (defaults to true). Note that
31681 progress and wait dialogs will ignore this property and always hide the
31682 close button as they can only be closed programmatically.
31683 cls String A custom CSS class to apply to the message box element
31684 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31685 displayed (defaults to 75)
31686 fn Function A callback function to execute after closing the dialog. The arguments to the
31687 function will be btn (the name of the button that was clicked, if applicable,
31688 e.g. "ok"), and text (the value of the active text field, if applicable).
31689 Progress and wait dialogs will ignore this option since they do not respond to
31690 user actions and can only be closed programmatically, so any required function
31691 should be called by the same code after it closes the dialog.
31692 icon String A CSS class that provides a background image to be used as an icon for
31693 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31694 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31695 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31696 modal Boolean False to allow user interaction with the page while the message box is
31697 displayed (defaults to true)
31698 msg String A string that will replace the existing message box body text (defaults
31699 to the XHTML-compliant non-breaking space character ' ')
31700 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31701 progress Boolean True to display a progress bar (defaults to false)
31702 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31703 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31704 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31705 title String The title text
31706 value String The string value to set into the active textbox element if displayed
31707 wait Boolean True to display a progress bar (defaults to false)
31708 width Number The width of the dialog in pixels
31715 msg: 'Please enter your address:',
31717 buttons: Roo.MessageBox.OKCANCEL,
31720 animEl: 'addAddressBtn'
31723 * @param {Object} config Configuration options
31724 * @return {Roo.MessageBox} This message box
31726 show : function(options)
31729 // this causes nightmares if you show one dialog after another
31730 // especially on callbacks..
31732 if(this.isVisible()){
31735 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31736 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31737 Roo.log("New Dialog Message:" + options.msg )
31738 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31739 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31742 var d = this.getDialog();
31744 d.setTitle(opt.title || " ");
31745 d.close.setDisplayed(opt.closable !== false);
31746 activeTextEl = textboxEl;
31747 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31752 textareaEl.setHeight(typeof opt.multiline == "number" ?
31753 opt.multiline : this.defaultTextHeight);
31754 activeTextEl = textareaEl;
31763 progressEl.setDisplayed(opt.progress === true);
31764 this.updateProgress(0);
31765 activeTextEl.dom.value = opt.value || "";
31767 dlg.setDefaultButton(activeTextEl);
31769 var bs = opt.buttons;
31772 db = buttons["ok"];
31773 }else if(bs && bs.yes){
31774 db = buttons["yes"];
31776 dlg.setDefaultButton(db);
31778 bwidth = updateButtons(opt.buttons);
31779 this.updateText(opt.msg);
31781 d.el.addClass(opt.cls);
31783 d.proxyDrag = opt.proxyDrag === true;
31784 d.modal = opt.modal !== false;
31785 d.mask = opt.modal !== false ? mask : false;
31786 if(!d.isVisible()){
31787 // force it to the end of the z-index stack so it gets a cursor in FF
31788 document.body.appendChild(dlg.el.dom);
31789 d.animateTarget = null;
31790 d.show(options.animEl);
31796 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31797 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31798 * and closing the message box when the process is complete.
31799 * @param {String} title The title bar text
31800 * @param {String} msg The message box body text
31801 * @return {Roo.MessageBox} This message box
31803 progress : function(title, msg){
31810 minWidth: this.minProgressWidth,
31817 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31818 * If a callback function is passed it will be called after the user clicks the button, and the
31819 * id of the button that was clicked will be passed as the only parameter to the callback
31820 * (could also be the top-right close button).
31821 * @param {String} title The title bar text
31822 * @param {String} msg The message box body text
31823 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31824 * @param {Object} scope (optional) The scope of the callback function
31825 * @return {Roo.MessageBox} This message box
31827 alert : function(title, msg, fn, scope){
31840 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31841 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31842 * You are responsible for closing the message box when the process is complete.
31843 * @param {String} msg The message box body text
31844 * @param {String} title (optional) The title bar text
31845 * @return {Roo.MessageBox} This message box
31847 wait : function(msg, title){
31858 waitTimer = Roo.TaskMgr.start({
31860 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31868 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31869 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31870 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31871 * @param {String} title The title bar text
31872 * @param {String} msg The message box body text
31873 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31874 * @param {Object} scope (optional) The scope of the callback function
31875 * @return {Roo.MessageBox} This message box
31877 confirm : function(title, msg, fn, scope){
31881 buttons: this.YESNO,
31890 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31891 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31892 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31893 * (could also be the top-right close button) and the text that was entered will be passed as the two
31894 * parameters to the callback.
31895 * @param {String} title The title bar text
31896 * @param {String} msg The message box body text
31897 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31898 * @param {Object} scope (optional) The scope of the callback function
31899 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31900 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31901 * @return {Roo.MessageBox} This message box
31903 prompt : function(title, msg, fn, scope, multiline){
31907 buttons: this.OKCANCEL,
31912 multiline: multiline,
31919 * Button config that displays a single OK button
31924 * Button config that displays Yes and No buttons
31927 YESNO : {yes:true, no:true},
31929 * Button config that displays OK and Cancel buttons
31932 OKCANCEL : {ok:true, cancel:true},
31934 * Button config that displays Yes, No and Cancel buttons
31937 YESNOCANCEL : {yes:true, no:true, cancel:true},
31940 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31943 defaultTextHeight : 75,
31945 * The maximum width in pixels of the message box (defaults to 600)
31950 * The minimum width in pixels of the message box (defaults to 100)
31955 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31956 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31959 minProgressWidth : 250,
31961 * An object containing the default button text strings that can be overriden for localized language support.
31962 * Supported properties are: ok, cancel, yes and no.
31963 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31976 * Shorthand for {@link Roo.MessageBox}
31978 Roo.Msg = Roo.MessageBox;/*
31980 * Ext JS Library 1.1.1
31981 * Copyright(c) 2006-2007, Ext JS, LLC.
31983 * Originally Released Under LGPL - original licence link has changed is not relivant.
31986 * <script type="text/javascript">
31989 * @class Roo.QuickTips
31990 * Provides attractive and customizable tooltips for any element.
31993 Roo.QuickTips = function(){
31994 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31995 var ce, bd, xy, dd;
31996 var visible = false, disabled = true, inited = false;
31997 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31999 var onOver = function(e){
32003 var t = e.getTarget();
32004 if(!t || t.nodeType !== 1 || t == document || t == document.body){
32007 if(ce && t == ce.el){
32008 clearTimeout(hideProc);
32011 if(t && tagEls[t.id]){
32012 tagEls[t.id].el = t;
32013 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
32016 var ttp, et = Roo.fly(t);
32017 var ns = cfg.namespace;
32018 if(tm.interceptTitles && t.title){
32021 t.removeAttribute("title");
32022 e.preventDefault();
32024 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
32027 showProc = show.defer(tm.showDelay, tm, [{
32030 width: et.getAttributeNS(ns, cfg.width),
32031 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
32032 title: et.getAttributeNS(ns, cfg.title),
32033 cls: et.getAttributeNS(ns, cfg.cls)
32038 var onOut = function(e){
32039 clearTimeout(showProc);
32040 var t = e.getTarget();
32041 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
32042 hideProc = setTimeout(hide, tm.hideDelay);
32046 var onMove = function(e){
32052 if(tm.trackMouse && ce){
32057 var onDown = function(e){
32058 clearTimeout(showProc);
32059 clearTimeout(hideProc);
32061 if(tm.hideOnClick){
32064 tm.enable.defer(100, tm);
32069 var getPad = function(){
32070 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
32073 var show = function(o){
32077 clearTimeout(dismissProc);
32079 if(removeCls){ // in case manually hidden
32080 el.removeClass(removeCls);
32084 el.addClass(ce.cls);
32085 removeCls = ce.cls;
32088 tipTitle.update(ce.title);
32091 tipTitle.update('');
32094 el.dom.style.width = tm.maxWidth+'px';
32095 //tipBody.dom.style.width = '';
32096 tipBodyText.update(o.text);
32097 var p = getPad(), w = ce.width;
32099 var td = tipBodyText.dom;
32100 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
32101 if(aw > tm.maxWidth){
32103 }else if(aw < tm.minWidth){
32109 //tipBody.setWidth(w);
32110 el.setWidth(parseInt(w, 10) + p);
32111 if(ce.autoHide === false){
32112 close.setDisplayed(true);
32117 close.setDisplayed(false);
32123 el.avoidY = xy[1]-18;
32128 el.setStyle("visibility", "visible");
32129 el.fadeIn({callback: afterShow});
32135 var afterShow = function(){
32139 if(tm.autoDismiss && ce.autoHide !== false){
32140 dismissProc = setTimeout(hide, tm.autoDismissDelay);
32145 var hide = function(noanim){
32146 clearTimeout(dismissProc);
32147 clearTimeout(hideProc);
32149 if(el.isVisible()){
32151 if(noanim !== true && tm.animate){
32152 el.fadeOut({callback: afterHide});
32159 var afterHide = function(){
32162 el.removeClass(removeCls);
32169 * @cfg {Number} minWidth
32170 * The minimum width of the quick tip (defaults to 40)
32174 * @cfg {Number} maxWidth
32175 * The maximum width of the quick tip (defaults to 300)
32179 * @cfg {Boolean} interceptTitles
32180 * True to automatically use the element's DOM title value if available (defaults to false)
32182 interceptTitles : false,
32184 * @cfg {Boolean} trackMouse
32185 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
32187 trackMouse : false,
32189 * @cfg {Boolean} hideOnClick
32190 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32192 hideOnClick : true,
32194 * @cfg {Number} showDelay
32195 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32199 * @cfg {Number} hideDelay
32200 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32204 * @cfg {Boolean} autoHide
32205 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32206 * Used in conjunction with hideDelay.
32211 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32212 * (defaults to true). Used in conjunction with autoDismissDelay.
32214 autoDismiss : true,
32217 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32219 autoDismissDelay : 5000,
32221 * @cfg {Boolean} animate
32222 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32227 * @cfg {String} title
32228 * Title text to display (defaults to ''). This can be any valid HTML markup.
32232 * @cfg {String} text
32233 * Body text to display (defaults to ''). This can be any valid HTML markup.
32237 * @cfg {String} cls
32238 * A CSS class to apply to the base quick tip element (defaults to '').
32242 * @cfg {Number} width
32243 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32244 * minWidth or maxWidth.
32249 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32250 * or display QuickTips in a page.
32253 tm = Roo.QuickTips;
32254 cfg = tm.tagConfig;
32256 if(!Roo.isReady){ // allow calling of init() before onReady
32257 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32260 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32261 el.fxDefaults = {stopFx: true};
32262 // maximum custom styling
32263 //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>');
32264 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>');
32265 tipTitle = el.child('h3');
32266 tipTitle.enableDisplayMode("block");
32267 tipBody = el.child('div.x-tip-bd');
32268 tipBodyText = el.child('div.x-tip-bd-inner');
32269 //bdLeft = el.child('div.x-tip-bd-left');
32270 //bdRight = el.child('div.x-tip-bd-right');
32271 close = el.child('div.x-tip-close');
32272 close.enableDisplayMode("block");
32273 close.on("click", hide);
32274 var d = Roo.get(document);
32275 d.on("mousedown", onDown);
32276 d.on("mouseover", onOver);
32277 d.on("mouseout", onOut);
32278 d.on("mousemove", onMove);
32279 esc = d.addKeyListener(27, hide);
32282 dd = el.initDD("default", null, {
32283 onDrag : function(){
32287 dd.setHandleElId(tipTitle.id);
32296 * Configures a new quick tip instance and assigns it to a target element. The following config options
32299 Property Type Description
32300 ---------- --------------------- ------------------------------------------------------------------------
32301 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32303 * @param {Object} config The config object
32305 register : function(config){
32306 var cs = config instanceof Array ? config : arguments;
32307 for(var i = 0, len = cs.length; i < len; i++) {
32309 var target = c.target;
32311 if(target instanceof Array){
32312 for(var j = 0, jlen = target.length; j < jlen; j++){
32313 tagEls[target[j]] = c;
32316 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32323 * Removes this quick tip from its element and destroys it.
32324 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32326 unregister : function(el){
32327 delete tagEls[Roo.id(el)];
32331 * Enable this quick tip.
32333 enable : function(){
32334 if(inited && disabled){
32336 if(locks.length < 1){
32343 * Disable this quick tip.
32345 disable : function(){
32347 clearTimeout(showProc);
32348 clearTimeout(hideProc);
32349 clearTimeout(dismissProc);
32357 * Returns true if the quick tip is enabled, else false.
32359 isEnabled : function(){
32366 attribute : "qtip",
32376 // backwards compat
32377 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32379 * Ext JS Library 1.1.1
32380 * Copyright(c) 2006-2007, Ext JS, LLC.
32382 * Originally Released Under LGPL - original licence link has changed is not relivant.
32385 * <script type="text/javascript">
32390 * @class Roo.tree.TreePanel
32391 * @extends Roo.data.Tree
32393 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32394 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32395 * @cfg {Boolean} enableDD true to enable drag and drop
32396 * @cfg {Boolean} enableDrag true to enable just drag
32397 * @cfg {Boolean} enableDrop true to enable just drop
32398 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32399 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32400 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32401 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32402 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32403 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32404 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32405 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32406 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32407 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32408 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32409 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32410 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32411 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32412 * @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>
32413 * @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>
32416 * @param {String/HTMLElement/Element} el The container element
32417 * @param {Object} config
32419 Roo.tree.TreePanel = function(el, config){
32421 var loader = false;
32423 root = config.root;
32424 delete config.root;
32426 if (config.loader) {
32427 loader = config.loader;
32428 delete config.loader;
32431 Roo.apply(this, config);
32432 Roo.tree.TreePanel.superclass.constructor.call(this);
32433 this.el = Roo.get(el);
32434 this.el.addClass('x-tree');
32435 //console.log(root);
32437 this.setRootNode( Roo.factory(root, Roo.tree));
32440 this.loader = Roo.factory(loader, Roo.tree);
32443 * Read-only. The id of the container element becomes this TreePanel's id.
32445 this.id = this.el.id;
32448 * @event beforeload
32449 * Fires before a node is loaded, return false to cancel
32450 * @param {Node} node The node being loaded
32452 "beforeload" : true,
32455 * Fires when a node is loaded
32456 * @param {Node} node The node that was loaded
32460 * @event textchange
32461 * Fires when the text for a node is changed
32462 * @param {Node} node The node
32463 * @param {String} text The new text
32464 * @param {String} oldText The old text
32466 "textchange" : true,
32468 * @event beforeexpand
32469 * Fires before a node is expanded, return false to cancel.
32470 * @param {Node} node The node
32471 * @param {Boolean} deep
32472 * @param {Boolean} anim
32474 "beforeexpand" : true,
32476 * @event beforecollapse
32477 * Fires before a node is collapsed, return false to cancel.
32478 * @param {Node} node The node
32479 * @param {Boolean} deep
32480 * @param {Boolean} anim
32482 "beforecollapse" : true,
32485 * Fires when a node is expanded
32486 * @param {Node} node The node
32490 * @event disabledchange
32491 * Fires when the disabled status of a node changes
32492 * @param {Node} node The node
32493 * @param {Boolean} disabled
32495 "disabledchange" : true,
32498 * Fires when a node is collapsed
32499 * @param {Node} node The node
32503 * @event beforeclick
32504 * Fires before click processing on a node. Return false to cancel the default action.
32505 * @param {Node} node The node
32506 * @param {Roo.EventObject} e The event object
32508 "beforeclick":true,
32510 * @event checkchange
32511 * Fires when a node with a checkbox's checked property changes
32512 * @param {Node} this This node
32513 * @param {Boolean} checked
32515 "checkchange":true,
32518 * Fires when a node is clicked
32519 * @param {Node} node The node
32520 * @param {Roo.EventObject} e The event object
32525 * Fires when a node is double clicked
32526 * @param {Node} node The node
32527 * @param {Roo.EventObject} e The event object
32531 * @event contextmenu
32532 * Fires when a node is right clicked
32533 * @param {Node} node The node
32534 * @param {Roo.EventObject} e The event object
32536 "contextmenu":true,
32538 * @event beforechildrenrendered
32539 * Fires right before the child nodes for a node are rendered
32540 * @param {Node} node The node
32542 "beforechildrenrendered":true,
32545 * Fires when a node starts being dragged
32546 * @param {Roo.tree.TreePanel} this
32547 * @param {Roo.tree.TreeNode} node
32548 * @param {event} e The raw browser event
32550 "startdrag" : true,
32553 * Fires when a drag operation is complete
32554 * @param {Roo.tree.TreePanel} this
32555 * @param {Roo.tree.TreeNode} node
32556 * @param {event} e The raw browser event
32561 * Fires when a dragged node is dropped on a valid DD target
32562 * @param {Roo.tree.TreePanel} this
32563 * @param {Roo.tree.TreeNode} node
32564 * @param {DD} dd The dd it was dropped on
32565 * @param {event} e The raw browser event
32569 * @event beforenodedrop
32570 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32571 * passed to handlers has the following properties:<br />
32572 * <ul style="padding:5px;padding-left:16px;">
32573 * <li>tree - The TreePanel</li>
32574 * <li>target - The node being targeted for the drop</li>
32575 * <li>data - The drag data from the drag source</li>
32576 * <li>point - The point of the drop - append, above or below</li>
32577 * <li>source - The drag source</li>
32578 * <li>rawEvent - Raw mouse event</li>
32579 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32580 * to be inserted by setting them on this object.</li>
32581 * <li>cancel - Set this to true to cancel the drop.</li>
32583 * @param {Object} dropEvent
32585 "beforenodedrop" : true,
32588 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32589 * passed to handlers has the following properties:<br />
32590 * <ul style="padding:5px;padding-left:16px;">
32591 * <li>tree - The TreePanel</li>
32592 * <li>target - The node being targeted for the drop</li>
32593 * <li>data - The drag data from the drag source</li>
32594 * <li>point - The point of the drop - append, above or below</li>
32595 * <li>source - The drag source</li>
32596 * <li>rawEvent - Raw mouse event</li>
32597 * <li>dropNode - Dropped node(s).</li>
32599 * @param {Object} dropEvent
32603 * @event nodedragover
32604 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32605 * passed to handlers has the following properties:<br />
32606 * <ul style="padding:5px;padding-left:16px;">
32607 * <li>tree - The TreePanel</li>
32608 * <li>target - The node being targeted for the drop</li>
32609 * <li>data - The drag data from the drag source</li>
32610 * <li>point - The point of the drop - append, above or below</li>
32611 * <li>source - The drag source</li>
32612 * <li>rawEvent - Raw mouse event</li>
32613 * <li>dropNode - Drop node(s) provided by the source.</li>
32614 * <li>cancel - Set this to true to signal drop not allowed.</li>
32616 * @param {Object} dragOverEvent
32618 "nodedragover" : true
32621 if(this.singleExpand){
32622 this.on("beforeexpand", this.restrictExpand, this);
32625 this.editor.tree = this;
32626 this.editor = Roo.factory(this.editor, Roo.tree);
32629 if (this.selModel) {
32630 this.selModel = Roo.factory(this.selModel, Roo.tree);
32634 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32635 rootVisible : true,
32636 animate: Roo.enableFx,
32639 hlDrop : Roo.enableFx,
32643 rendererTip: false,
32645 restrictExpand : function(node){
32646 var p = node.parentNode;
32648 if(p.expandedChild && p.expandedChild.parentNode == p){
32649 p.expandedChild.collapse();
32651 p.expandedChild = node;
32655 // private override
32656 setRootNode : function(node){
32657 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32658 if(!this.rootVisible){
32659 node.ui = new Roo.tree.RootTreeNodeUI(node);
32665 * Returns the container element for this TreePanel
32667 getEl : function(){
32672 * Returns the default TreeLoader for this TreePanel
32674 getLoader : function(){
32675 return this.loader;
32681 expandAll : function(){
32682 this.root.expand(true);
32686 * Collapse all nodes
32688 collapseAll : function(){
32689 this.root.collapse(true);
32693 * Returns the selection model used by this TreePanel
32695 getSelectionModel : function(){
32696 if(!this.selModel){
32697 this.selModel = new Roo.tree.DefaultSelectionModel();
32699 return this.selModel;
32703 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32704 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32705 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32708 getChecked : function(a, startNode){
32709 startNode = startNode || this.root;
32711 var f = function(){
32712 if(this.attributes.checked){
32713 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32716 startNode.cascade(f);
32721 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32722 * @param {String} path
32723 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32724 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32725 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32727 expandPath : function(path, attr, callback){
32728 attr = attr || "id";
32729 var keys = path.split(this.pathSeparator);
32730 var curNode = this.root;
32731 if(curNode.attributes[attr] != keys[1]){ // invalid root
32733 callback(false, null);
32738 var f = function(){
32739 if(++index == keys.length){
32741 callback(true, curNode);
32745 var c = curNode.findChild(attr, keys[index]);
32748 callback(false, curNode);
32753 c.expand(false, false, f);
32755 curNode.expand(false, false, f);
32759 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32760 * @param {String} path
32761 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32762 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32763 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32765 selectPath : function(path, attr, callback){
32766 attr = attr || "id";
32767 var keys = path.split(this.pathSeparator);
32768 var v = keys.pop();
32769 if(keys.length > 0){
32770 var f = function(success, node){
32771 if(success && node){
32772 var n = node.findChild(attr, v);
32778 }else if(callback){
32779 callback(false, n);
32783 callback(false, n);
32787 this.expandPath(keys.join(this.pathSeparator), attr, f);
32789 this.root.select();
32791 callback(true, this.root);
32796 getTreeEl : function(){
32801 * Trigger rendering of this TreePanel
32803 render : function(){
32804 if (this.innerCt) {
32805 return this; // stop it rendering more than once!!
32808 this.innerCt = this.el.createChild({tag:"ul",
32809 cls:"x-tree-root-ct " +
32810 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32812 if(this.containerScroll){
32813 Roo.dd.ScrollManager.register(this.el);
32815 if((this.enableDD || this.enableDrop) && !this.dropZone){
32817 * The dropZone used by this tree if drop is enabled
32818 * @type Roo.tree.TreeDropZone
32820 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32821 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32824 if((this.enableDD || this.enableDrag) && !this.dragZone){
32826 * The dragZone used by this tree if drag is enabled
32827 * @type Roo.tree.TreeDragZone
32829 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32830 ddGroup: this.ddGroup || "TreeDD",
32831 scroll: this.ddScroll
32834 this.getSelectionModel().init(this);
32836 Roo.log("ROOT not set in tree");
32839 this.root.render();
32840 if(!this.rootVisible){
32841 this.root.renderChildren();
32847 * Ext JS Library 1.1.1
32848 * Copyright(c) 2006-2007, Ext JS, LLC.
32850 * Originally Released Under LGPL - original licence link has changed is not relivant.
32853 * <script type="text/javascript">
32858 * @class Roo.tree.DefaultSelectionModel
32859 * @extends Roo.util.Observable
32860 * The default single selection for a TreePanel.
32861 * @param {Object} cfg Configuration
32863 Roo.tree.DefaultSelectionModel = function(cfg){
32864 this.selNode = null;
32870 * @event selectionchange
32871 * Fires when the selected node changes
32872 * @param {DefaultSelectionModel} this
32873 * @param {TreeNode} node the new selection
32875 "selectionchange" : true,
32878 * @event beforeselect
32879 * Fires before the selected node changes, return false to cancel the change
32880 * @param {DefaultSelectionModel} this
32881 * @param {TreeNode} node the new selection
32882 * @param {TreeNode} node the old selection
32884 "beforeselect" : true
32887 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32890 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32891 init : function(tree){
32893 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32894 tree.on("click", this.onNodeClick, this);
32897 onNodeClick : function(node, e){
32898 if (e.ctrlKey && this.selNode == node) {
32899 this.unselect(node);
32907 * @param {TreeNode} node The node to select
32908 * @return {TreeNode} The selected node
32910 select : function(node){
32911 var last = this.selNode;
32912 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32914 last.ui.onSelectedChange(false);
32916 this.selNode = node;
32917 node.ui.onSelectedChange(true);
32918 this.fireEvent("selectionchange", this, node, last);
32925 * @param {TreeNode} node The node to unselect
32927 unselect : function(node){
32928 if(this.selNode == node){
32929 this.clearSelections();
32934 * Clear all selections
32936 clearSelections : function(){
32937 var n = this.selNode;
32939 n.ui.onSelectedChange(false);
32940 this.selNode = null;
32941 this.fireEvent("selectionchange", this, null);
32947 * Get the selected node
32948 * @return {TreeNode} The selected node
32950 getSelectedNode : function(){
32951 return this.selNode;
32955 * Returns true if the node is selected
32956 * @param {TreeNode} node The node to check
32957 * @return {Boolean}
32959 isSelected : function(node){
32960 return this.selNode == node;
32964 * Selects the node above the selected node in the tree, intelligently walking the nodes
32965 * @return TreeNode The new selection
32967 selectPrevious : function(){
32968 var s = this.selNode || this.lastSelNode;
32972 var ps = s.previousSibling;
32974 if(!ps.isExpanded() || ps.childNodes.length < 1){
32975 return this.select(ps);
32977 var lc = ps.lastChild;
32978 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32981 return this.select(lc);
32983 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32984 return this.select(s.parentNode);
32990 * Selects the node above the selected node in the tree, intelligently walking the nodes
32991 * @return TreeNode The new selection
32993 selectNext : function(){
32994 var s = this.selNode || this.lastSelNode;
32998 if(s.firstChild && s.isExpanded()){
32999 return this.select(s.firstChild);
33000 }else if(s.nextSibling){
33001 return this.select(s.nextSibling);
33002 }else if(s.parentNode){
33004 s.parentNode.bubble(function(){
33005 if(this.nextSibling){
33006 newS = this.getOwnerTree().selModel.select(this.nextSibling);
33015 onKeyDown : function(e){
33016 var s = this.selNode || this.lastSelNode;
33017 // undesirable, but required
33022 var k = e.getKey();
33030 this.selectPrevious();
33033 e.preventDefault();
33034 if(s.hasChildNodes()){
33035 if(!s.isExpanded()){
33037 }else if(s.firstChild){
33038 this.select(s.firstChild, e);
33043 e.preventDefault();
33044 if(s.hasChildNodes() && s.isExpanded()){
33046 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
33047 this.select(s.parentNode, e);
33055 * @class Roo.tree.MultiSelectionModel
33056 * @extends Roo.util.Observable
33057 * Multi selection for a TreePanel.
33058 * @param {Object} cfg Configuration
33060 Roo.tree.MultiSelectionModel = function(){
33061 this.selNodes = [];
33065 * @event selectionchange
33066 * Fires when the selected nodes change
33067 * @param {MultiSelectionModel} this
33068 * @param {Array} nodes Array of the selected nodes
33070 "selectionchange" : true
33072 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
33076 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
33077 init : function(tree){
33079 tree.getTreeEl().on("keydown", this.onKeyDown, this);
33080 tree.on("click", this.onNodeClick, this);
33083 onNodeClick : function(node, e){
33084 this.select(node, e, e.ctrlKey);
33089 * @param {TreeNode} node The node to select
33090 * @param {EventObject} e (optional) An event associated with the selection
33091 * @param {Boolean} keepExisting True to retain existing selections
33092 * @return {TreeNode} The selected node
33094 select : function(node, e, keepExisting){
33095 if(keepExisting !== true){
33096 this.clearSelections(true);
33098 if(this.isSelected(node)){
33099 this.lastSelNode = node;
33102 this.selNodes.push(node);
33103 this.selMap[node.id] = node;
33104 this.lastSelNode = node;
33105 node.ui.onSelectedChange(true);
33106 this.fireEvent("selectionchange", this, this.selNodes);
33112 * @param {TreeNode} node The node to unselect
33114 unselect : function(node){
33115 if(this.selMap[node.id]){
33116 node.ui.onSelectedChange(false);
33117 var sn = this.selNodes;
33120 index = sn.indexOf(node);
33122 for(var i = 0, len = sn.length; i < len; i++){
33130 this.selNodes.splice(index, 1);
33132 delete this.selMap[node.id];
33133 this.fireEvent("selectionchange", this, this.selNodes);
33138 * Clear all selections
33140 clearSelections : function(suppressEvent){
33141 var sn = this.selNodes;
33143 for(var i = 0, len = sn.length; i < len; i++){
33144 sn[i].ui.onSelectedChange(false);
33146 this.selNodes = [];
33148 if(suppressEvent !== true){
33149 this.fireEvent("selectionchange", this, this.selNodes);
33155 * Returns true if the node is selected
33156 * @param {TreeNode} node The node to check
33157 * @return {Boolean}
33159 isSelected : function(node){
33160 return this.selMap[node.id] ? true : false;
33164 * Returns an array of the selected nodes
33167 getSelectedNodes : function(){
33168 return this.selNodes;
33171 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
33173 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
33175 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
33178 * Ext JS Library 1.1.1
33179 * Copyright(c) 2006-2007, Ext JS, LLC.
33181 * Originally Released Under LGPL - original licence link has changed is not relivant.
33184 * <script type="text/javascript">
33188 * @class Roo.tree.TreeNode
33189 * @extends Roo.data.Node
33190 * @cfg {String} text The text for this node
33191 * @cfg {Boolean} expanded true to start the node expanded
33192 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33193 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33194 * @cfg {Boolean} disabled true to start the node disabled
33195 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33196 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33197 * @cfg {String} cls A css class to be added to the node
33198 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33199 * @cfg {String} href URL of the link used for the node (defaults to #)
33200 * @cfg {String} hrefTarget target frame for the link
33201 * @cfg {String} qtip An Ext QuickTip for the node
33202 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33203 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33204 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33205 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33206 * (defaults to undefined with no checkbox rendered)
33208 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33210 Roo.tree.TreeNode = function(attributes){
33211 attributes = attributes || {};
33212 if(typeof attributes == "string"){
33213 attributes = {text: attributes};
33215 this.childrenRendered = false;
33216 this.rendered = false;
33217 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33218 this.expanded = attributes.expanded === true;
33219 this.isTarget = attributes.isTarget !== false;
33220 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33221 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33224 * Read-only. The text for this node. To change it use setText().
33227 this.text = attributes.text;
33229 * True if this node is disabled.
33232 this.disabled = attributes.disabled === true;
33236 * @event textchange
33237 * Fires when the text for this node is changed
33238 * @param {Node} this This node
33239 * @param {String} text The new text
33240 * @param {String} oldText The old text
33242 "textchange" : true,
33244 * @event beforeexpand
33245 * Fires before this node is expanded, return false to cancel.
33246 * @param {Node} this This node
33247 * @param {Boolean} deep
33248 * @param {Boolean} anim
33250 "beforeexpand" : true,
33252 * @event beforecollapse
33253 * Fires before this node is collapsed, return false to cancel.
33254 * @param {Node} this This node
33255 * @param {Boolean} deep
33256 * @param {Boolean} anim
33258 "beforecollapse" : true,
33261 * Fires when this node is expanded
33262 * @param {Node} this This node
33266 * @event disabledchange
33267 * Fires when the disabled status of this node changes
33268 * @param {Node} this This node
33269 * @param {Boolean} disabled
33271 "disabledchange" : true,
33274 * Fires when this node is collapsed
33275 * @param {Node} this This node
33279 * @event beforeclick
33280 * Fires before click processing. Return false to cancel the default action.
33281 * @param {Node} this This node
33282 * @param {Roo.EventObject} e The event object
33284 "beforeclick":true,
33286 * @event checkchange
33287 * Fires when a node with a checkbox's checked property changes
33288 * @param {Node} this This node
33289 * @param {Boolean} checked
33291 "checkchange":true,
33294 * Fires when this node is clicked
33295 * @param {Node} this This node
33296 * @param {Roo.EventObject} e The event object
33301 * Fires when this node is double clicked
33302 * @param {Node} this This node
33303 * @param {Roo.EventObject} e The event object
33307 * @event contextmenu
33308 * Fires when this node is right clicked
33309 * @param {Node} this This node
33310 * @param {Roo.EventObject} e The event object
33312 "contextmenu":true,
33314 * @event beforechildrenrendered
33315 * Fires right before the child nodes for this node are rendered
33316 * @param {Node} this This node
33318 "beforechildrenrendered":true
33321 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33324 * Read-only. The UI for this node
33327 this.ui = new uiClass(this);
33329 // finally support items[]
33330 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33335 Roo.each(this.attributes.items, function(c) {
33336 this.appendChild(Roo.factory(c,Roo.Tree));
33338 delete this.attributes.items;
33343 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33344 preventHScroll: true,
33346 * Returns true if this node is expanded
33347 * @return {Boolean}
33349 isExpanded : function(){
33350 return this.expanded;
33354 * Returns the UI object for this node
33355 * @return {TreeNodeUI}
33357 getUI : function(){
33361 // private override
33362 setFirstChild : function(node){
33363 var of = this.firstChild;
33364 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33365 if(this.childrenRendered && of && node != of){
33366 of.renderIndent(true, true);
33369 this.renderIndent(true, true);
33373 // private override
33374 setLastChild : function(node){
33375 var ol = this.lastChild;
33376 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33377 if(this.childrenRendered && ol && node != ol){
33378 ol.renderIndent(true, true);
33381 this.renderIndent(true, true);
33385 // these methods are overridden to provide lazy rendering support
33386 // private override
33387 appendChild : function()
33389 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33390 if(node && this.childrenRendered){
33393 this.ui.updateExpandIcon();
33397 // private override
33398 removeChild : function(node){
33399 this.ownerTree.getSelectionModel().unselect(node);
33400 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33401 // if it's been rendered remove dom node
33402 if(this.childrenRendered){
33405 if(this.childNodes.length < 1){
33406 this.collapse(false, false);
33408 this.ui.updateExpandIcon();
33410 if(!this.firstChild) {
33411 this.childrenRendered = false;
33416 // private override
33417 insertBefore : function(node, refNode){
33418 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33419 if(newNode && refNode && this.childrenRendered){
33422 this.ui.updateExpandIcon();
33427 * Sets the text for this node
33428 * @param {String} text
33430 setText : function(text){
33431 var oldText = this.text;
33433 this.attributes.text = text;
33434 if(this.rendered){ // event without subscribing
33435 this.ui.onTextChange(this, text, oldText);
33437 this.fireEvent("textchange", this, text, oldText);
33441 * Triggers selection of this node
33443 select : function(){
33444 this.getOwnerTree().getSelectionModel().select(this);
33448 * Triggers deselection of this node
33450 unselect : function(){
33451 this.getOwnerTree().getSelectionModel().unselect(this);
33455 * Returns true if this node is selected
33456 * @return {Boolean}
33458 isSelected : function(){
33459 return this.getOwnerTree().getSelectionModel().isSelected(this);
33463 * Expand this node.
33464 * @param {Boolean} deep (optional) True to expand all children as well
33465 * @param {Boolean} anim (optional) false to cancel the default animation
33466 * @param {Function} callback (optional) A callback to be called when
33467 * expanding this node completes (does not wait for deep expand to complete).
33468 * Called with 1 parameter, this node.
33470 expand : function(deep, anim, callback){
33471 if(!this.expanded){
33472 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33475 if(!this.childrenRendered){
33476 this.renderChildren();
33478 this.expanded = true;
33479 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33480 this.ui.animExpand(function(){
33481 this.fireEvent("expand", this);
33482 if(typeof callback == "function"){
33486 this.expandChildNodes(true);
33488 }.createDelegate(this));
33492 this.fireEvent("expand", this);
33493 if(typeof callback == "function"){
33498 if(typeof callback == "function"){
33503 this.expandChildNodes(true);
33507 isHiddenRoot : function(){
33508 return this.isRoot && !this.getOwnerTree().rootVisible;
33512 * Collapse this node.
33513 * @param {Boolean} deep (optional) True to collapse all children as well
33514 * @param {Boolean} anim (optional) false to cancel the default animation
33516 collapse : function(deep, anim){
33517 if(this.expanded && !this.isHiddenRoot()){
33518 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33521 this.expanded = false;
33522 if((this.getOwnerTree().animate && anim !== false) || anim){
33523 this.ui.animCollapse(function(){
33524 this.fireEvent("collapse", this);
33526 this.collapseChildNodes(true);
33528 }.createDelegate(this));
33531 this.ui.collapse();
33532 this.fireEvent("collapse", this);
33536 var cs = this.childNodes;
33537 for(var i = 0, len = cs.length; i < len; i++) {
33538 cs[i].collapse(true, false);
33544 delayedExpand : function(delay){
33545 if(!this.expandProcId){
33546 this.expandProcId = this.expand.defer(delay, this);
33551 cancelExpand : function(){
33552 if(this.expandProcId){
33553 clearTimeout(this.expandProcId);
33555 this.expandProcId = false;
33559 * Toggles expanded/collapsed state of the node
33561 toggle : function(){
33570 * Ensures all parent nodes are expanded
33572 ensureVisible : function(callback){
33573 var tree = this.getOwnerTree();
33574 tree.expandPath(this.parentNode.getPath(), false, function(){
33575 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33576 Roo.callback(callback);
33577 }.createDelegate(this));
33581 * Expand all child nodes
33582 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33584 expandChildNodes : function(deep){
33585 var cs = this.childNodes;
33586 for(var i = 0, len = cs.length; i < len; i++) {
33587 cs[i].expand(deep);
33592 * Collapse all child nodes
33593 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33595 collapseChildNodes : function(deep){
33596 var cs = this.childNodes;
33597 for(var i = 0, len = cs.length; i < len; i++) {
33598 cs[i].collapse(deep);
33603 * Disables this node
33605 disable : function(){
33606 this.disabled = true;
33608 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33609 this.ui.onDisableChange(this, true);
33611 this.fireEvent("disabledchange", this, true);
33615 * Enables this node
33617 enable : function(){
33618 this.disabled = false;
33619 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33620 this.ui.onDisableChange(this, false);
33622 this.fireEvent("disabledchange", this, false);
33626 renderChildren : function(suppressEvent){
33627 if(suppressEvent !== false){
33628 this.fireEvent("beforechildrenrendered", this);
33630 var cs = this.childNodes;
33631 for(var i = 0, len = cs.length; i < len; i++){
33632 cs[i].render(true);
33634 this.childrenRendered = true;
33638 sort : function(fn, scope){
33639 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33640 if(this.childrenRendered){
33641 var cs = this.childNodes;
33642 for(var i = 0, len = cs.length; i < len; i++){
33643 cs[i].render(true);
33649 render : function(bulkRender){
33650 this.ui.render(bulkRender);
33651 if(!this.rendered){
33652 this.rendered = true;
33654 this.expanded = false;
33655 this.expand(false, false);
33661 renderIndent : function(deep, refresh){
33663 this.ui.childIndent = null;
33665 this.ui.renderIndent();
33666 if(deep === true && this.childrenRendered){
33667 var cs = this.childNodes;
33668 for(var i = 0, len = cs.length; i < len; i++){
33669 cs[i].renderIndent(true, refresh);
33675 * Ext JS Library 1.1.1
33676 * Copyright(c) 2006-2007, Ext JS, LLC.
33678 * Originally Released Under LGPL - original licence link has changed is not relivant.
33681 * <script type="text/javascript">
33685 * @class Roo.tree.AsyncTreeNode
33686 * @extends Roo.tree.TreeNode
33687 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33689 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33691 Roo.tree.AsyncTreeNode = function(config){
33692 this.loaded = false;
33693 this.loading = false;
33694 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33696 * @event beforeload
33697 * Fires before this node is loaded, return false to cancel
33698 * @param {Node} this This node
33700 this.addEvents({'beforeload':true, 'load': true});
33703 * Fires when this node is loaded
33704 * @param {Node} this This node
33707 * The loader used by this node (defaults to using the tree's defined loader)
33712 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33713 expand : function(deep, anim, callback){
33714 if(this.loading){ // if an async load is already running, waiting til it's done
33716 var f = function(){
33717 if(!this.loading){ // done loading
33718 clearInterval(timer);
33719 this.expand(deep, anim, callback);
33721 }.createDelegate(this);
33722 timer = setInterval(f, 200);
33726 if(this.fireEvent("beforeload", this) === false){
33729 this.loading = true;
33730 this.ui.beforeLoad(this);
33731 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33733 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33737 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33741 * Returns true if this node is currently loading
33742 * @return {Boolean}
33744 isLoading : function(){
33745 return this.loading;
33748 loadComplete : function(deep, anim, callback){
33749 this.loading = false;
33750 this.loaded = true;
33751 this.ui.afterLoad(this);
33752 this.fireEvent("load", this);
33753 this.expand(deep, anim, callback);
33757 * Returns true if this node has been loaded
33758 * @return {Boolean}
33760 isLoaded : function(){
33761 return this.loaded;
33764 hasChildNodes : function(){
33765 if(!this.isLeaf() && !this.loaded){
33768 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33773 * Trigger a reload for this node
33774 * @param {Function} callback
33776 reload : function(callback){
33777 this.collapse(false, false);
33778 while(this.firstChild){
33779 this.removeChild(this.firstChild);
33781 this.childrenRendered = false;
33782 this.loaded = false;
33783 if(this.isHiddenRoot()){
33784 this.expanded = false;
33786 this.expand(false, false, callback);
33790 * Ext JS Library 1.1.1
33791 * Copyright(c) 2006-2007, Ext JS, LLC.
33793 * Originally Released Under LGPL - original licence link has changed is not relivant.
33796 * <script type="text/javascript">
33800 * @class Roo.tree.TreeNodeUI
33802 * @param {Object} node The node to render
33803 * The TreeNode UI implementation is separate from the
33804 * tree implementation. Unless you are customizing the tree UI,
33805 * you should never have to use this directly.
33807 Roo.tree.TreeNodeUI = function(node){
33809 this.rendered = false;
33810 this.animating = false;
33811 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33814 Roo.tree.TreeNodeUI.prototype = {
33815 removeChild : function(node){
33817 this.ctNode.removeChild(node.ui.getEl());
33821 beforeLoad : function(){
33822 this.addClass("x-tree-node-loading");
33825 afterLoad : function(){
33826 this.removeClass("x-tree-node-loading");
33829 onTextChange : function(node, text, oldText){
33831 this.textNode.innerHTML = text;
33835 onDisableChange : function(node, state){
33836 this.disabled = state;
33838 this.addClass("x-tree-node-disabled");
33840 this.removeClass("x-tree-node-disabled");
33844 onSelectedChange : function(state){
33847 this.addClass("x-tree-selected");
33850 this.removeClass("x-tree-selected");
33854 onMove : function(tree, node, oldParent, newParent, index, refNode){
33855 this.childIndent = null;
33857 var targetNode = newParent.ui.getContainer();
33858 if(!targetNode){//target not rendered
33859 this.holder = document.createElement("div");
33860 this.holder.appendChild(this.wrap);
33863 var insertBefore = refNode ? refNode.ui.getEl() : null;
33865 targetNode.insertBefore(this.wrap, insertBefore);
33867 targetNode.appendChild(this.wrap);
33869 this.node.renderIndent(true);
33873 addClass : function(cls){
33875 Roo.fly(this.elNode).addClass(cls);
33879 removeClass : function(cls){
33881 Roo.fly(this.elNode).removeClass(cls);
33885 remove : function(){
33887 this.holder = document.createElement("div");
33888 this.holder.appendChild(this.wrap);
33892 fireEvent : function(){
33893 return this.node.fireEvent.apply(this.node, arguments);
33896 initEvents : function(){
33897 this.node.on("move", this.onMove, this);
33898 var E = Roo.EventManager;
33899 var a = this.anchor;
33901 var el = Roo.fly(a, '_treeui');
33903 if(Roo.isOpera){ // opera render bug ignores the CSS
33904 el.setStyle("text-decoration", "none");
33907 el.on("click", this.onClick, this);
33908 el.on("dblclick", this.onDblClick, this);
33911 Roo.EventManager.on(this.checkbox,
33912 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33915 el.on("contextmenu", this.onContextMenu, this);
33917 var icon = Roo.fly(this.iconNode);
33918 icon.on("click", this.onClick, this);
33919 icon.on("dblclick", this.onDblClick, this);
33920 icon.on("contextmenu", this.onContextMenu, this);
33921 E.on(this.ecNode, "click", this.ecClick, this, true);
33923 if(this.node.disabled){
33924 this.addClass("x-tree-node-disabled");
33926 if(this.node.hidden){
33927 this.addClass("x-tree-node-disabled");
33929 var ot = this.node.getOwnerTree();
33930 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33931 if(dd && (!this.node.isRoot || ot.rootVisible)){
33932 Roo.dd.Registry.register(this.elNode, {
33934 handles: this.getDDHandles(),
33940 getDDHandles : function(){
33941 return [this.iconNode, this.textNode];
33946 this.wrap.style.display = "none";
33952 this.wrap.style.display = "";
33956 onContextMenu : function(e){
33957 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33958 e.preventDefault();
33960 this.fireEvent("contextmenu", this.node, e);
33964 onClick : function(e){
33969 if(this.fireEvent("beforeclick", this.node, e) !== false){
33970 if(!this.disabled && this.node.attributes.href){
33971 this.fireEvent("click", this.node, e);
33974 e.preventDefault();
33979 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33980 this.node.toggle();
33983 this.fireEvent("click", this.node, e);
33989 onDblClick : function(e){
33990 e.preventDefault();
33995 this.toggleCheck();
33997 if(!this.animating && this.node.hasChildNodes()){
33998 this.node.toggle();
34000 this.fireEvent("dblclick", this.node, e);
34003 onCheckChange : function(){
34004 var checked = this.checkbox.checked;
34005 this.node.attributes.checked = checked;
34006 this.fireEvent('checkchange', this.node, checked);
34009 ecClick : function(e){
34010 if(!this.animating && this.node.hasChildNodes()){
34011 this.node.toggle();
34015 startDrop : function(){
34016 this.dropping = true;
34019 // delayed drop so the click event doesn't get fired on a drop
34020 endDrop : function(){
34021 setTimeout(function(){
34022 this.dropping = false;
34023 }.createDelegate(this), 50);
34026 expand : function(){
34027 this.updateExpandIcon();
34028 this.ctNode.style.display = "";
34031 focus : function(){
34032 if(!this.node.preventHScroll){
34033 try{this.anchor.focus();
34035 }else if(!Roo.isIE){
34037 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
34038 var l = noscroll.scrollLeft;
34039 this.anchor.focus();
34040 noscroll.scrollLeft = l;
34045 toggleCheck : function(value){
34046 var cb = this.checkbox;
34048 cb.checked = (value === undefined ? !cb.checked : value);
34054 this.anchor.blur();
34058 animExpand : function(callback){
34059 var ct = Roo.get(this.ctNode);
34061 if(!this.node.hasChildNodes()){
34062 this.updateExpandIcon();
34063 this.ctNode.style.display = "";
34064 Roo.callback(callback);
34067 this.animating = true;
34068 this.updateExpandIcon();
34071 callback : function(){
34072 this.animating = false;
34073 Roo.callback(callback);
34076 duration: this.node.ownerTree.duration || .25
34080 highlight : function(){
34081 var tree = this.node.getOwnerTree();
34082 Roo.fly(this.wrap).highlight(
34083 tree.hlColor || "C3DAF9",
34084 {endColor: tree.hlBaseColor}
34088 collapse : function(){
34089 this.updateExpandIcon();
34090 this.ctNode.style.display = "none";
34093 animCollapse : function(callback){
34094 var ct = Roo.get(this.ctNode);
34095 ct.enableDisplayMode('block');
34098 this.animating = true;
34099 this.updateExpandIcon();
34102 callback : function(){
34103 this.animating = false;
34104 Roo.callback(callback);
34107 duration: this.node.ownerTree.duration || .25
34111 getContainer : function(){
34112 return this.ctNode;
34115 getEl : function(){
34119 appendDDGhost : function(ghostNode){
34120 ghostNode.appendChild(this.elNode.cloneNode(true));
34123 getDDRepairXY : function(){
34124 return Roo.lib.Dom.getXY(this.iconNode);
34127 onRender : function(){
34131 render : function(bulkRender){
34132 var n = this.node, a = n.attributes;
34133 var targetNode = n.parentNode ?
34134 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
34136 if(!this.rendered){
34137 this.rendered = true;
34139 this.renderElements(n, a, targetNode, bulkRender);
34142 if(this.textNode.setAttributeNS){
34143 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
34145 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
34148 this.textNode.setAttribute("ext:qtip", a.qtip);
34150 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
34153 }else if(a.qtipCfg){
34154 a.qtipCfg.target = Roo.id(this.textNode);
34155 Roo.QuickTips.register(a.qtipCfg);
34158 if(!this.node.expanded){
34159 this.updateExpandIcon();
34162 if(bulkRender === true) {
34163 targetNode.appendChild(this.wrap);
34168 renderElements : function(n, a, targetNode, bulkRender)
34170 // add some indent caching, this helps performance when rendering a large tree
34171 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34172 var t = n.getOwnerTree();
34173 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
34174 if (typeof(n.attributes.html) != 'undefined') {
34175 txt = n.attributes.html;
34177 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
34178 var cb = typeof a.checked == 'boolean';
34179 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34180 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
34181 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
34182 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
34183 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
34184 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
34185 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
34186 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
34187 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
34188 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34191 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34192 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34193 n.nextSibling.ui.getEl(), buf.join(""));
34195 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34198 this.elNode = this.wrap.childNodes[0];
34199 this.ctNode = this.wrap.childNodes[1];
34200 var cs = this.elNode.childNodes;
34201 this.indentNode = cs[0];
34202 this.ecNode = cs[1];
34203 this.iconNode = cs[2];
34206 this.checkbox = cs[3];
34209 this.anchor = cs[index];
34210 this.textNode = cs[index].firstChild;
34213 getAnchor : function(){
34214 return this.anchor;
34217 getTextEl : function(){
34218 return this.textNode;
34221 getIconEl : function(){
34222 return this.iconNode;
34225 isChecked : function(){
34226 return this.checkbox ? this.checkbox.checked : false;
34229 updateExpandIcon : function(){
34231 var n = this.node, c1, c2;
34232 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34233 var hasChild = n.hasChildNodes();
34237 c1 = "x-tree-node-collapsed";
34238 c2 = "x-tree-node-expanded";
34241 c1 = "x-tree-node-expanded";
34242 c2 = "x-tree-node-collapsed";
34245 this.removeClass("x-tree-node-leaf");
34246 this.wasLeaf = false;
34248 if(this.c1 != c1 || this.c2 != c2){
34249 Roo.fly(this.elNode).replaceClass(c1, c2);
34250 this.c1 = c1; this.c2 = c2;
34253 // this changes non-leafs into leafs if they have no children.
34254 // it's not very rational behaviour..
34256 if(!this.wasLeaf && this.node.leaf){
34257 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34260 this.wasLeaf = true;
34263 var ecc = "x-tree-ec-icon "+cls;
34264 if(this.ecc != ecc){
34265 this.ecNode.className = ecc;
34271 getChildIndent : function(){
34272 if(!this.childIndent){
34276 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34278 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34280 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34285 this.childIndent = buf.join("");
34287 return this.childIndent;
34290 renderIndent : function(){
34293 var p = this.node.parentNode;
34295 indent = p.ui.getChildIndent();
34297 if(this.indentMarkup != indent){ // don't rerender if not required
34298 this.indentNode.innerHTML = indent;
34299 this.indentMarkup = indent;
34301 this.updateExpandIcon();
34306 Roo.tree.RootTreeNodeUI = function(){
34307 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34309 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34310 render : function(){
34311 if(!this.rendered){
34312 var targetNode = this.node.ownerTree.innerCt.dom;
34313 this.node.expanded = true;
34314 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34315 this.wrap = this.ctNode = targetNode.firstChild;
34318 collapse : function(){
34320 expand : function(){
34324 * Ext JS Library 1.1.1
34325 * Copyright(c) 2006-2007, Ext JS, LLC.
34327 * Originally Released Under LGPL - original licence link has changed is not relivant.
34330 * <script type="text/javascript">
34333 * @class Roo.tree.TreeLoader
34334 * @extends Roo.util.Observable
34335 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34336 * nodes from a specified URL. The response must be a javascript Array definition
34337 * who's elements are node definition objects. eg:
34342 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34343 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34350 * The old style respose with just an array is still supported, but not recommended.
34353 * A server request is sent, and child nodes are loaded only when a node is expanded.
34354 * The loading node's id is passed to the server under the parameter name "node" to
34355 * enable the server to produce the correct child nodes.
34357 * To pass extra parameters, an event handler may be attached to the "beforeload"
34358 * event, and the parameters specified in the TreeLoader's baseParams property:
34360 myTreeLoader.on("beforeload", function(treeLoader, node) {
34361 this.baseParams.category = node.attributes.category;
34364 * This would pass an HTTP parameter called "category" to the server containing
34365 * the value of the Node's "category" attribute.
34367 * Creates a new Treeloader.
34368 * @param {Object} config A config object containing config properties.
34370 Roo.tree.TreeLoader = function(config){
34371 this.baseParams = {};
34372 this.requestMethod = "POST";
34373 Roo.apply(this, config);
34378 * @event beforeload
34379 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34380 * @param {Object} This TreeLoader object.
34381 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34382 * @param {Object} callback The callback function specified in the {@link #load} call.
34387 * Fires when the node has been successfuly loaded.
34388 * @param {Object} This TreeLoader object.
34389 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34390 * @param {Object} response The response object containing the data from the server.
34394 * @event loadexception
34395 * Fires if the network request failed.
34396 * @param {Object} This TreeLoader object.
34397 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34398 * @param {Object} response The response object containing the data from the server.
34400 loadexception : true,
34403 * Fires before a node is created, enabling you to return custom Node types
34404 * @param {Object} This TreeLoader object.
34405 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34410 Roo.tree.TreeLoader.superclass.constructor.call(this);
34413 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34415 * @cfg {String} dataUrl The URL from which to request a Json string which
34416 * specifies an array of node definition object representing the child nodes
34420 * @cfg {String} requestMethod either GET or POST
34421 * defaults to POST (due to BC)
34425 * @cfg {Object} baseParams (optional) An object containing properties which
34426 * specify HTTP parameters to be passed to each request for child nodes.
34429 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34430 * created by this loader. If the attributes sent by the server have an attribute in this object,
34431 * they take priority.
34434 * @cfg {Object} uiProviders (optional) An object containing properties which
34436 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34437 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34438 * <i>uiProvider</i> attribute of a returned child node is a string rather
34439 * than a reference to a TreeNodeUI implementation, this that string value
34440 * is used as a property name in the uiProviders object. You can define the provider named
34441 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34446 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34447 * child nodes before loading.
34449 clearOnLoad : true,
34452 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34453 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34454 * Grid query { data : [ .....] }
34459 * @cfg {String} queryParam (optional)
34460 * Name of the query as it will be passed on the querystring (defaults to 'node')
34461 * eg. the request will be ?node=[id]
34468 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34469 * This is called automatically when a node is expanded, but may be used to reload
34470 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34471 * @param {Roo.tree.TreeNode} node
34472 * @param {Function} callback
34474 load : function(node, callback){
34475 if(this.clearOnLoad){
34476 while(node.firstChild){
34477 node.removeChild(node.firstChild);
34480 if(node.attributes.children){ // preloaded json children
34481 var cs = node.attributes.children;
34482 for(var i = 0, len = cs.length; i < len; i++){
34483 node.appendChild(this.createNode(cs[i]));
34485 if(typeof callback == "function"){
34488 }else if(this.dataUrl){
34489 this.requestData(node, callback);
34493 getParams: function(node){
34494 var buf = [], bp = this.baseParams;
34495 for(var key in bp){
34496 if(typeof bp[key] != "function"){
34497 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34500 var n = this.queryParam === false ? 'node' : this.queryParam;
34501 buf.push(n + "=", encodeURIComponent(node.id));
34502 return buf.join("");
34505 requestData : function(node, callback){
34506 if(this.fireEvent("beforeload", this, node, callback) !== false){
34507 this.transId = Roo.Ajax.request({
34508 method:this.requestMethod,
34509 url: this.dataUrl||this.url,
34510 success: this.handleResponse,
34511 failure: this.handleFailure,
34513 argument: {callback: callback, node: node},
34514 params: this.getParams(node)
34517 // if the load is cancelled, make sure we notify
34518 // the node that we are done
34519 if(typeof callback == "function"){
34525 isLoading : function(){
34526 return this.transId ? true : false;
34529 abort : function(){
34530 if(this.isLoading()){
34531 Roo.Ajax.abort(this.transId);
34536 createNode : function(attr)
34538 // apply baseAttrs, nice idea Corey!
34539 if(this.baseAttrs){
34540 Roo.applyIf(attr, this.baseAttrs);
34542 if(this.applyLoader !== false){
34543 attr.loader = this;
34545 // uiProvider = depreciated..
34547 if(typeof(attr.uiProvider) == 'string'){
34548 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34549 /** eval:var:attr */ eval(attr.uiProvider);
34551 if(typeof(this.uiProviders['default']) != 'undefined') {
34552 attr.uiProvider = this.uiProviders['default'];
34555 this.fireEvent('create', this, attr);
34557 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34559 new Roo.tree.TreeNode(attr) :
34560 new Roo.tree.AsyncTreeNode(attr));
34563 processResponse : function(response, node, callback)
34565 var json = response.responseText;
34568 var o = Roo.decode(json);
34570 if (this.root === false && typeof(o.success) != undefined) {
34571 this.root = 'data'; // the default behaviour for list like data..
34574 if (this.root !== false && !o.success) {
34575 // it's a failure condition.
34576 var a = response.argument;
34577 this.fireEvent("loadexception", this, a.node, response);
34578 Roo.log("Load failed - should have a handler really");
34584 if (this.root !== false) {
34588 for(var i = 0, len = o.length; i < len; i++){
34589 var n = this.createNode(o[i]);
34591 node.appendChild(n);
34594 if(typeof callback == "function"){
34595 callback(this, node);
34598 this.handleFailure(response);
34602 handleResponse : function(response){
34603 this.transId = false;
34604 var a = response.argument;
34605 this.processResponse(response, a.node, a.callback);
34606 this.fireEvent("load", this, a.node, response);
34609 handleFailure : function(response)
34611 // should handle failure better..
34612 this.transId = false;
34613 var a = response.argument;
34614 this.fireEvent("loadexception", this, a.node, response);
34615 if(typeof a.callback == "function"){
34616 a.callback(this, a.node);
34621 * Ext JS Library 1.1.1
34622 * Copyright(c) 2006-2007, Ext JS, LLC.
34624 * Originally Released Under LGPL - original licence link has changed is not relivant.
34627 * <script type="text/javascript">
34631 * @class Roo.tree.TreeFilter
34632 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34633 * @param {TreePanel} tree
34634 * @param {Object} config (optional)
34636 Roo.tree.TreeFilter = function(tree, config){
34638 this.filtered = {};
34639 Roo.apply(this, config);
34642 Roo.tree.TreeFilter.prototype = {
34649 * Filter the data by a specific attribute.
34650 * @param {String/RegExp} value Either string that the attribute value
34651 * should start with or a RegExp to test against the attribute
34652 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34653 * @param {TreeNode} startNode (optional) The node to start the filter at.
34655 filter : function(value, attr, startNode){
34656 attr = attr || "text";
34658 if(typeof value == "string"){
34659 var vlen = value.length;
34660 // auto clear empty filter
34661 if(vlen == 0 && this.clearBlank){
34665 value = value.toLowerCase();
34667 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34669 }else if(value.exec){ // regex?
34671 return value.test(n.attributes[attr]);
34674 throw 'Illegal filter type, must be string or regex';
34676 this.filterBy(f, null, startNode);
34680 * Filter by a function. The passed function will be called with each
34681 * node in the tree (or from the startNode). If the function returns true, the node is kept
34682 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34683 * @param {Function} fn The filter function
34684 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34686 filterBy : function(fn, scope, startNode){
34687 startNode = startNode || this.tree.root;
34688 if(this.autoClear){
34691 var af = this.filtered, rv = this.reverse;
34692 var f = function(n){
34693 if(n == startNode){
34699 var m = fn.call(scope || n, n);
34707 startNode.cascade(f);
34710 if(typeof id != "function"){
34712 if(n && n.parentNode){
34713 n.parentNode.removeChild(n);
34721 * Clears the current filter. Note: with the "remove" option
34722 * set a filter cannot be cleared.
34724 clear : function(){
34726 var af = this.filtered;
34728 if(typeof id != "function"){
34735 this.filtered = {};
34740 * Ext JS Library 1.1.1
34741 * Copyright(c) 2006-2007, Ext JS, LLC.
34743 * Originally Released Under LGPL - original licence link has changed is not relivant.
34746 * <script type="text/javascript">
34751 * @class Roo.tree.TreeSorter
34752 * Provides sorting of nodes in a TreePanel
34754 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34755 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34756 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34757 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34758 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34759 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34761 * @param {TreePanel} tree
34762 * @param {Object} config
34764 Roo.tree.TreeSorter = function(tree, config){
34765 Roo.apply(this, config);
34766 tree.on("beforechildrenrendered", this.doSort, this);
34767 tree.on("append", this.updateSort, this);
34768 tree.on("insert", this.updateSort, this);
34770 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34771 var p = this.property || "text";
34772 var sortType = this.sortType;
34773 var fs = this.folderSort;
34774 var cs = this.caseSensitive === true;
34775 var leafAttr = this.leafAttr || 'leaf';
34777 this.sortFn = function(n1, n2){
34779 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34782 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34786 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34787 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34789 return dsc ? +1 : -1;
34791 return dsc ? -1 : +1;
34798 Roo.tree.TreeSorter.prototype = {
34799 doSort : function(node){
34800 node.sort(this.sortFn);
34803 compareNodes : function(n1, n2){
34804 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34807 updateSort : function(tree, node){
34808 if(node.childrenRendered){
34809 this.doSort.defer(1, this, [node]);
34814 * Ext JS Library 1.1.1
34815 * Copyright(c) 2006-2007, Ext JS, LLC.
34817 * Originally Released Under LGPL - original licence link has changed is not relivant.
34820 * <script type="text/javascript">
34823 if(Roo.dd.DropZone){
34825 Roo.tree.TreeDropZone = function(tree, config){
34826 this.allowParentInsert = false;
34827 this.allowContainerDrop = false;
34828 this.appendOnly = false;
34829 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34831 this.lastInsertClass = "x-tree-no-status";
34832 this.dragOverData = {};
34835 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34836 ddGroup : "TreeDD",
34839 expandDelay : 1000,
34841 expandNode : function(node){
34842 if(node.hasChildNodes() && !node.isExpanded()){
34843 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34847 queueExpand : function(node){
34848 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34851 cancelExpand : function(){
34852 if(this.expandProcId){
34853 clearTimeout(this.expandProcId);
34854 this.expandProcId = false;
34858 isValidDropPoint : function(n, pt, dd, e, data){
34859 if(!n || !data){ return false; }
34860 var targetNode = n.node;
34861 var dropNode = data.node;
34862 // default drop rules
34863 if(!(targetNode && targetNode.isTarget && pt)){
34866 if(pt == "append" && targetNode.allowChildren === false){
34869 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34872 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34875 // reuse the object
34876 var overEvent = this.dragOverData;
34877 overEvent.tree = this.tree;
34878 overEvent.target = targetNode;
34879 overEvent.data = data;
34880 overEvent.point = pt;
34881 overEvent.source = dd;
34882 overEvent.rawEvent = e;
34883 overEvent.dropNode = dropNode;
34884 overEvent.cancel = false;
34885 var result = this.tree.fireEvent("nodedragover", overEvent);
34886 return overEvent.cancel === false && result !== false;
34889 getDropPoint : function(e, n, dd)
34893 return tn.allowChildren !== false ? "append" : false; // always append for root
34895 var dragEl = n.ddel;
34896 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34897 var y = Roo.lib.Event.getPageY(e);
34898 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34900 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34901 var noAppend = tn.allowChildren === false;
34902 if(this.appendOnly || tn.parentNode.allowChildren === false){
34903 return noAppend ? false : "append";
34905 var noBelow = false;
34906 if(!this.allowParentInsert){
34907 noBelow = tn.hasChildNodes() && tn.isExpanded();
34909 var q = (b - t) / (noAppend ? 2 : 3);
34910 if(y >= t && y < (t + q)){
34912 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34919 onNodeEnter : function(n, dd, e, data)
34921 this.cancelExpand();
34924 onNodeOver : function(n, dd, e, data)
34927 var pt = this.getDropPoint(e, n, dd);
34930 // auto node expand check
34931 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34932 this.queueExpand(node);
34933 }else if(pt != "append"){
34934 this.cancelExpand();
34937 // set the insert point style on the target node
34938 var returnCls = this.dropNotAllowed;
34939 if(this.isValidDropPoint(n, pt, dd, e, data)){
34944 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34945 cls = "x-tree-drag-insert-above";
34946 }else if(pt == "below"){
34947 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34948 cls = "x-tree-drag-insert-below";
34950 returnCls = "x-tree-drop-ok-append";
34951 cls = "x-tree-drag-append";
34953 if(this.lastInsertClass != cls){
34954 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34955 this.lastInsertClass = cls;
34962 onNodeOut : function(n, dd, e, data){
34964 this.cancelExpand();
34965 this.removeDropIndicators(n);
34968 onNodeDrop : function(n, dd, e, data){
34969 var point = this.getDropPoint(e, n, dd);
34970 var targetNode = n.node;
34971 targetNode.ui.startDrop();
34972 if(!this.isValidDropPoint(n, point, dd, e, data)){
34973 targetNode.ui.endDrop();
34976 // first try to find the drop node
34977 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34980 target: targetNode,
34985 dropNode: dropNode,
34988 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34989 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34990 targetNode.ui.endDrop();
34993 // allow target changing
34994 targetNode = dropEvent.target;
34995 if(point == "append" && !targetNode.isExpanded()){
34996 targetNode.expand(false, null, function(){
34997 this.completeDrop(dropEvent);
34998 }.createDelegate(this));
35000 this.completeDrop(dropEvent);
35005 completeDrop : function(de){
35006 var ns = de.dropNode, p = de.point, t = de.target;
35007 if(!(ns instanceof Array)){
35011 for(var i = 0, len = ns.length; i < len; i++){
35014 t.parentNode.insertBefore(n, t);
35015 }else if(p == "below"){
35016 t.parentNode.insertBefore(n, t.nextSibling);
35022 if(this.tree.hlDrop){
35026 this.tree.fireEvent("nodedrop", de);
35029 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
35030 if(this.tree.hlDrop){
35031 dropNode.ui.focus();
35032 dropNode.ui.highlight();
35034 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
35037 getTree : function(){
35041 removeDropIndicators : function(n){
35044 Roo.fly(el).removeClass([
35045 "x-tree-drag-insert-above",
35046 "x-tree-drag-insert-below",
35047 "x-tree-drag-append"]);
35048 this.lastInsertClass = "_noclass";
35052 beforeDragDrop : function(target, e, id){
35053 this.cancelExpand();
35057 afterRepair : function(data){
35058 if(data && Roo.enableFx){
35059 data.node.ui.highlight();
35069 * Ext JS Library 1.1.1
35070 * Copyright(c) 2006-2007, Ext JS, LLC.
35072 * Originally Released Under LGPL - original licence link has changed is not relivant.
35075 * <script type="text/javascript">
35079 if(Roo.dd.DragZone){
35080 Roo.tree.TreeDragZone = function(tree, config){
35081 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
35085 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
35086 ddGroup : "TreeDD",
35088 onBeforeDrag : function(data, e){
35090 return n && n.draggable && !n.disabled;
35094 onInitDrag : function(e){
35095 var data = this.dragData;
35096 this.tree.getSelectionModel().select(data.node);
35097 this.proxy.update("");
35098 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
35099 this.tree.fireEvent("startdrag", this.tree, data.node, e);
35102 getRepairXY : function(e, data){
35103 return data.node.ui.getDDRepairXY();
35106 onEndDrag : function(data, e){
35107 this.tree.fireEvent("enddrag", this.tree, data.node, e);
35112 onValidDrop : function(dd, e, id){
35113 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
35117 beforeInvalidDrop : function(e, id){
35118 // this scrolls the original position back into view
35119 var sm = this.tree.getSelectionModel();
35120 sm.clearSelections();
35121 sm.select(this.dragData.node);
35126 * Ext JS Library 1.1.1
35127 * Copyright(c) 2006-2007, Ext JS, LLC.
35129 * Originally Released Under LGPL - original licence link has changed is not relivant.
35132 * <script type="text/javascript">
35135 * @class Roo.tree.TreeEditor
35136 * @extends Roo.Editor
35137 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
35138 * as the editor field.
35140 * @param {Object} config (used to be the tree panel.)
35141 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
35143 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
35144 * @cfg {Roo.form.TextField|Object} field The field configuration
35148 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
35151 if (oldconfig) { // old style..
35152 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
35155 tree = config.tree;
35156 config.field = config.field || {};
35157 config.field.xtype = 'TextField';
35158 field = Roo.factory(config.field, Roo.form);
35160 config = config || {};
35165 * @event beforenodeedit
35166 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
35167 * false from the handler of this event.
35168 * @param {Editor} this
35169 * @param {Roo.tree.Node} node
35171 "beforenodeedit" : true
35175 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
35179 tree.on('beforeclick', this.beforeNodeClick, this);
35180 tree.getTreeEl().on('mousedown', this.hide, this);
35181 this.on('complete', this.updateNode, this);
35182 this.on('beforestartedit', this.fitToTree, this);
35183 this.on('startedit', this.bindScroll, this, {delay:10});
35184 this.on('specialkey', this.onSpecialKey, this);
35187 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
35189 * @cfg {String} alignment
35190 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35196 * @cfg {Boolean} hideEl
35197 * True to hide the bound element while the editor is displayed (defaults to false)
35201 * @cfg {String} cls
35202 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35204 cls: "x-small-editor x-tree-editor",
35206 * @cfg {Boolean} shim
35207 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35213 * @cfg {Number} maxWidth
35214 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35215 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35216 * scroll and client offsets into account prior to each edit.
35223 fitToTree : function(ed, el){
35224 var td = this.tree.getTreeEl().dom, nd = el.dom;
35225 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35226 td.scrollLeft = nd.offsetLeft;
35230 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35231 this.setSize(w, '');
35233 return this.fireEvent('beforenodeedit', this, this.editNode);
35238 triggerEdit : function(node){
35239 this.completeEdit();
35240 this.editNode = node;
35241 this.startEdit(node.ui.textNode, node.text);
35245 bindScroll : function(){
35246 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35250 beforeNodeClick : function(node, e){
35251 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35252 this.lastClick = new Date();
35253 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35255 this.triggerEdit(node);
35262 updateNode : function(ed, value){
35263 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35264 this.editNode.setText(value);
35268 onHide : function(){
35269 Roo.tree.TreeEditor.superclass.onHide.call(this);
35271 this.editNode.ui.focus();
35276 onSpecialKey : function(field, e){
35277 var k = e.getKey();
35281 }else if(k == e.ENTER && !e.hasModifier()){
35283 this.completeEdit();
35286 });//<Script type="text/javascript">
35289 * Ext JS Library 1.1.1
35290 * Copyright(c) 2006-2007, Ext JS, LLC.
35292 * Originally Released Under LGPL - original licence link has changed is not relivant.
35295 * <script type="text/javascript">
35299 * Not documented??? - probably should be...
35302 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35303 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35305 renderElements : function(n, a, targetNode, bulkRender){
35306 //consel.log("renderElements?");
35307 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35309 var t = n.getOwnerTree();
35310 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35312 var cols = t.columns;
35313 var bw = t.borderWidth;
35315 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35316 var cb = typeof a.checked == "boolean";
35317 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35318 var colcls = 'x-t-' + tid + '-c0';
35320 '<li class="x-tree-node">',
35323 '<div class="x-tree-node-el ', a.cls,'">',
35325 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35328 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35329 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35330 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35331 (a.icon ? ' x-tree-node-inline-icon' : ''),
35332 (a.iconCls ? ' '+a.iconCls : ''),
35333 '" unselectable="on" />',
35334 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35335 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35337 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35338 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35339 '<span unselectable="on" qtip="' + tx + '">',
35343 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35344 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35346 for(var i = 1, len = cols.length; i < len; i++){
35348 colcls = 'x-t-' + tid + '-c' +i;
35349 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35350 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35351 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35357 '<div class="x-clear"></div></div>',
35358 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35361 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35362 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35363 n.nextSibling.ui.getEl(), buf.join(""));
35365 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35367 var el = this.wrap.firstChild;
35369 this.elNode = el.firstChild;
35370 this.ranchor = el.childNodes[1];
35371 this.ctNode = this.wrap.childNodes[1];
35372 var cs = el.firstChild.childNodes;
35373 this.indentNode = cs[0];
35374 this.ecNode = cs[1];
35375 this.iconNode = cs[2];
35378 this.checkbox = cs[3];
35381 this.anchor = cs[index];
35383 this.textNode = cs[index].firstChild;
35385 //el.on("click", this.onClick, this);
35386 //el.on("dblclick", this.onDblClick, this);
35389 // console.log(this);
35391 initEvents : function(){
35392 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35395 var a = this.ranchor;
35397 var el = Roo.get(a);
35399 if(Roo.isOpera){ // opera render bug ignores the CSS
35400 el.setStyle("text-decoration", "none");
35403 el.on("click", this.onClick, this);
35404 el.on("dblclick", this.onDblClick, this);
35405 el.on("contextmenu", this.onContextMenu, this);
35409 /*onSelectedChange : function(state){
35412 this.addClass("x-tree-selected");
35415 this.removeClass("x-tree-selected");
35418 addClass : function(cls){
35420 Roo.fly(this.elRow).addClass(cls);
35426 removeClass : function(cls){
35428 Roo.fly(this.elRow).removeClass(cls);
35434 });//<Script type="text/javascript">
35438 * Ext JS Library 1.1.1
35439 * Copyright(c) 2006-2007, Ext JS, LLC.
35441 * Originally Released Under LGPL - original licence link has changed is not relivant.
35444 * <script type="text/javascript">
35449 * @class Roo.tree.ColumnTree
35450 * @extends Roo.data.TreePanel
35451 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35452 * @cfg {int} borderWidth compined right/left border allowance
35454 * @param {String/HTMLElement/Element} el The container element
35455 * @param {Object} config
35457 Roo.tree.ColumnTree = function(el, config)
35459 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35463 * Fire this event on a container when it resizes
35464 * @param {int} w Width
35465 * @param {int} h Height
35469 this.on('resize', this.onResize, this);
35472 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35476 borderWidth: Roo.isBorderBox ? 0 : 2,
35479 render : function(){
35480 // add the header.....
35482 Roo.tree.ColumnTree.superclass.render.apply(this);
35484 this.el.addClass('x-column-tree');
35486 this.headers = this.el.createChild(
35487 {cls:'x-tree-headers'},this.innerCt.dom);
35489 var cols = this.columns, c;
35490 var totalWidth = 0;
35492 var len = cols.length;
35493 for(var i = 0; i < len; i++){
35495 totalWidth += c.width;
35496 this.headEls.push(this.headers.createChild({
35497 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35499 cls:'x-tree-hd-text',
35502 style:'width:'+(c.width-this.borderWidth)+'px;'
35505 this.headers.createChild({cls:'x-clear'});
35506 // prevent floats from wrapping when clipped
35507 this.headers.setWidth(totalWidth);
35508 //this.innerCt.setWidth(totalWidth);
35509 this.innerCt.setStyle({ overflow: 'auto' });
35510 this.onResize(this.width, this.height);
35514 onResize : function(w,h)
35519 this.innerCt.setWidth(this.width);
35520 this.innerCt.setHeight(this.height-20);
35523 var cols = this.columns, c;
35524 var totalWidth = 0;
35526 var len = cols.length;
35527 for(var i = 0; i < len; i++){
35529 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35530 // it's the expander..
35531 expEl = this.headEls[i];
35534 totalWidth += c.width;
35538 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35540 this.headers.setWidth(w-20);
35549 * Ext JS Library 1.1.1
35550 * Copyright(c) 2006-2007, Ext JS, LLC.
35552 * Originally Released Under LGPL - original licence link has changed is not relivant.
35555 * <script type="text/javascript">
35559 * @class Roo.menu.Menu
35560 * @extends Roo.util.Observable
35561 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35562 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35564 * Creates a new Menu
35565 * @param {Object} config Configuration options
35567 Roo.menu.Menu = function(config){
35568 Roo.apply(this, config);
35569 this.id = this.id || Roo.id();
35572 * @event beforeshow
35573 * Fires before this menu is displayed
35574 * @param {Roo.menu.Menu} this
35578 * @event beforehide
35579 * Fires before this menu is hidden
35580 * @param {Roo.menu.Menu} this
35585 * Fires after this menu is displayed
35586 * @param {Roo.menu.Menu} this
35591 * Fires after this menu is hidden
35592 * @param {Roo.menu.Menu} this
35597 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35598 * @param {Roo.menu.Menu} this
35599 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35600 * @param {Roo.EventObject} e
35605 * Fires when the mouse is hovering over this menu
35606 * @param {Roo.menu.Menu} this
35607 * @param {Roo.EventObject} e
35608 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35613 * Fires when the mouse exits this menu
35614 * @param {Roo.menu.Menu} this
35615 * @param {Roo.EventObject} e
35616 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35621 * Fires when a menu item contained in this menu is clicked
35622 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35623 * @param {Roo.EventObject} e
35627 if (this.registerMenu) {
35628 Roo.menu.MenuMgr.register(this);
35631 var mis = this.items;
35632 this.items = new Roo.util.MixedCollection();
35634 this.add.apply(this, mis);
35638 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35640 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35644 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35645 * for bottom-right shadow (defaults to "sides")
35649 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35650 * this menu (defaults to "tl-tr?")
35652 subMenuAlign : "tl-tr?",
35654 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35655 * relative to its element of origin (defaults to "tl-bl?")
35657 defaultAlign : "tl-bl?",
35659 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35661 allowOtherMenus : false,
35663 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35665 registerMenu : true,
35670 render : function(){
35674 var el = this.el = new Roo.Layer({
35676 shadow:this.shadow,
35678 parentEl: this.parentEl || document.body,
35682 this.keyNav = new Roo.menu.MenuNav(this);
35685 el.addClass("x-menu-plain");
35688 el.addClass(this.cls);
35690 // generic focus element
35691 this.focusEl = el.createChild({
35692 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35694 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35695 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35697 ul.on("mouseover", this.onMouseOver, this);
35698 ul.on("mouseout", this.onMouseOut, this);
35699 this.items.each(function(item){
35704 var li = document.createElement("li");
35705 li.className = "x-menu-list-item";
35706 ul.dom.appendChild(li);
35707 item.render(li, this);
35714 autoWidth : function(){
35715 var el = this.el, ul = this.ul;
35719 var w = this.width;
35722 }else if(Roo.isIE){
35723 el.setWidth(this.minWidth);
35724 var t = el.dom.offsetWidth; // force recalc
35725 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35730 delayAutoWidth : function(){
35733 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35735 this.awTask.delay(20);
35740 findTargetItem : function(e){
35741 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35742 if(t && t.menuItemId){
35743 return this.items.get(t.menuItemId);
35748 onClick : function(e){
35749 Roo.log("menu.onClick");
35750 var t = this.findTargetItem(e);
35755 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35756 if(t == this.activeItem && t.shouldDeactivate(e)){
35757 this.activeItem.deactivate();
35758 delete this.activeItem;
35762 this.setActiveItem(t, true);
35770 this.fireEvent("click", this, t, e);
35774 setActiveItem : function(item, autoExpand){
35775 if(item != this.activeItem){
35776 if(this.activeItem){
35777 this.activeItem.deactivate();
35779 this.activeItem = item;
35780 item.activate(autoExpand);
35781 }else if(autoExpand){
35787 tryActivate : function(start, step){
35788 var items = this.items;
35789 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35790 var item = items.get(i);
35791 if(!item.disabled && item.canActivate){
35792 this.setActiveItem(item, false);
35800 onMouseOver : function(e){
35802 if(t = this.findTargetItem(e)){
35803 if(t.canActivate && !t.disabled){
35804 this.setActiveItem(t, true);
35807 this.fireEvent("mouseover", this, e, t);
35811 onMouseOut : function(e){
35813 if(t = this.findTargetItem(e)){
35814 if(t == this.activeItem && t.shouldDeactivate(e)){
35815 this.activeItem.deactivate();
35816 delete this.activeItem;
35819 this.fireEvent("mouseout", this, e, t);
35823 * Read-only. Returns true if the menu is currently displayed, else false.
35826 isVisible : function(){
35827 return this.el && !this.hidden;
35831 * Displays this menu relative to another element
35832 * @param {String/HTMLElement/Roo.Element} element The element to align to
35833 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35834 * the element (defaults to this.defaultAlign)
35835 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35837 show : function(el, pos, parentMenu){
35838 this.parentMenu = parentMenu;
35842 this.fireEvent("beforeshow", this);
35843 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35847 * Displays this menu at a specific xy position
35848 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35849 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35851 showAt : function(xy, parentMenu, /* private: */_e){
35852 this.parentMenu = parentMenu;
35857 this.fireEvent("beforeshow", this);
35858 xy = this.el.adjustForConstraints(xy);
35862 this.hidden = false;
35864 this.fireEvent("show", this);
35867 focus : function(){
35869 this.doFocus.defer(50, this);
35873 doFocus : function(){
35875 this.focusEl.focus();
35880 * Hides this menu and optionally all parent menus
35881 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35883 hide : function(deep){
35884 if(this.el && this.isVisible()){
35885 this.fireEvent("beforehide", this);
35886 if(this.activeItem){
35887 this.activeItem.deactivate();
35888 this.activeItem = null;
35891 this.hidden = true;
35892 this.fireEvent("hide", this);
35894 if(deep === true && this.parentMenu){
35895 this.parentMenu.hide(true);
35900 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35901 * Any of the following are valid:
35903 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35904 * <li>An HTMLElement object which will be converted to a menu item</li>
35905 * <li>A menu item config object that will be created as a new menu item</li>
35906 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35907 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35912 var menu = new Roo.menu.Menu();
35914 // Create a menu item to add by reference
35915 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35917 // Add a bunch of items at once using different methods.
35918 // Only the last item added will be returned.
35919 var item = menu.add(
35920 menuItem, // add existing item by ref
35921 'Dynamic Item', // new TextItem
35922 '-', // new separator
35923 { text: 'Config Item' } // new item by config
35926 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35927 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35930 var a = arguments, l = a.length, item;
35931 for(var i = 0; i < l; i++){
35933 if ((typeof(el) == "object") && el.xtype && el.xns) {
35934 el = Roo.factory(el, Roo.menu);
35937 if(el.render){ // some kind of Item
35938 item = this.addItem(el);
35939 }else if(typeof el == "string"){ // string
35940 if(el == "separator" || el == "-"){
35941 item = this.addSeparator();
35943 item = this.addText(el);
35945 }else if(el.tagName || el.el){ // element
35946 item = this.addElement(el);
35947 }else if(typeof el == "object"){ // must be menu item config?
35948 item = this.addMenuItem(el);
35955 * Returns this menu's underlying {@link Roo.Element} object
35956 * @return {Roo.Element} The element
35958 getEl : function(){
35966 * Adds a separator bar to the menu
35967 * @return {Roo.menu.Item} The menu item that was added
35969 addSeparator : function(){
35970 return this.addItem(new Roo.menu.Separator());
35974 * Adds an {@link Roo.Element} object to the menu
35975 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35976 * @return {Roo.menu.Item} The menu item that was added
35978 addElement : function(el){
35979 return this.addItem(new Roo.menu.BaseItem(el));
35983 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35984 * @param {Roo.menu.Item} item The menu item to add
35985 * @return {Roo.menu.Item} The menu item that was added
35987 addItem : function(item){
35988 this.items.add(item);
35990 var li = document.createElement("li");
35991 li.className = "x-menu-list-item";
35992 this.ul.dom.appendChild(li);
35993 item.render(li, this);
35994 this.delayAutoWidth();
36000 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
36001 * @param {Object} config A MenuItem config object
36002 * @return {Roo.menu.Item} The menu item that was added
36004 addMenuItem : function(config){
36005 if(!(config instanceof Roo.menu.Item)){
36006 if(typeof config.checked == "boolean"){ // must be check menu item config?
36007 config = new Roo.menu.CheckItem(config);
36009 config = new Roo.menu.Item(config);
36012 return this.addItem(config);
36016 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
36017 * @param {String} text The text to display in the menu item
36018 * @return {Roo.menu.Item} The menu item that was added
36020 addText : function(text){
36021 return this.addItem(new Roo.menu.TextItem({ text : text }));
36025 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
36026 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
36027 * @param {Roo.menu.Item} item The menu item to add
36028 * @return {Roo.menu.Item} The menu item that was added
36030 insert : function(index, item){
36031 this.items.insert(index, item);
36033 var li = document.createElement("li");
36034 li.className = "x-menu-list-item";
36035 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
36036 item.render(li, this);
36037 this.delayAutoWidth();
36043 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
36044 * @param {Roo.menu.Item} item The menu item to remove
36046 remove : function(item){
36047 this.items.removeKey(item.id);
36052 * Removes and destroys all items in the menu
36054 removeAll : function(){
36056 while(f = this.items.first()){
36062 // MenuNav is a private utility class used internally by the Menu
36063 Roo.menu.MenuNav = function(menu){
36064 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
36065 this.scope = this.menu = menu;
36068 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
36069 doRelay : function(e, h){
36070 var k = e.getKey();
36071 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
36072 this.menu.tryActivate(0, 1);
36075 return h.call(this.scope || this, e, this.menu);
36078 up : function(e, m){
36079 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
36080 m.tryActivate(m.items.length-1, -1);
36084 down : function(e, m){
36085 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
36086 m.tryActivate(0, 1);
36090 right : function(e, m){
36092 m.activeItem.expandMenu(true);
36096 left : function(e, m){
36098 if(m.parentMenu && m.parentMenu.activeItem){
36099 m.parentMenu.activeItem.activate();
36103 enter : function(e, m){
36105 e.stopPropagation();
36106 m.activeItem.onClick(e);
36107 m.fireEvent("click", this, m.activeItem);
36113 * Ext JS Library 1.1.1
36114 * Copyright(c) 2006-2007, Ext JS, LLC.
36116 * Originally Released Under LGPL - original licence link has changed is not relivant.
36119 * <script type="text/javascript">
36123 * @class Roo.menu.MenuMgr
36124 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
36127 Roo.menu.MenuMgr = function(){
36128 var menus, active, groups = {}, attached = false, lastShow = new Date();
36130 // private - called when first menu is created
36133 active = new Roo.util.MixedCollection();
36134 Roo.get(document).addKeyListener(27, function(){
36135 if(active.length > 0){
36142 function hideAll(){
36143 if(active && active.length > 0){
36144 var c = active.clone();
36145 c.each(function(m){
36152 function onHide(m){
36154 if(active.length < 1){
36155 Roo.get(document).un("mousedown", onMouseDown);
36161 function onShow(m){
36162 var last = active.last();
36163 lastShow = new Date();
36166 Roo.get(document).on("mousedown", onMouseDown);
36170 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
36171 m.parentMenu.activeChild = m;
36172 }else if(last && last.isVisible()){
36173 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
36178 function onBeforeHide(m){
36180 m.activeChild.hide();
36182 if(m.autoHideTimer){
36183 clearTimeout(m.autoHideTimer);
36184 delete m.autoHideTimer;
36189 function onBeforeShow(m){
36190 var pm = m.parentMenu;
36191 if(!pm && !m.allowOtherMenus){
36193 }else if(pm && pm.activeChild && active != m){
36194 pm.activeChild.hide();
36199 function onMouseDown(e){
36200 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36206 function onBeforeCheck(mi, state){
36208 var g = groups[mi.group];
36209 for(var i = 0, l = g.length; i < l; i++){
36211 g[i].setChecked(false);
36220 * Hides all menus that are currently visible
36222 hideAll : function(){
36227 register : function(menu){
36231 menus[menu.id] = menu;
36232 menu.on("beforehide", onBeforeHide);
36233 menu.on("hide", onHide);
36234 menu.on("beforeshow", onBeforeShow);
36235 menu.on("show", onShow);
36236 var g = menu.group;
36237 if(g && menu.events["checkchange"]){
36241 groups[g].push(menu);
36242 menu.on("checkchange", onCheck);
36247 * Returns a {@link Roo.menu.Menu} object
36248 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36249 * be used to generate and return a new Menu instance.
36251 get : function(menu){
36252 if(typeof menu == "string"){ // menu id
36253 return menus[menu];
36254 }else if(menu.events){ // menu instance
36256 }else if(typeof menu.length == 'number'){ // array of menu items?
36257 return new Roo.menu.Menu({items:menu});
36258 }else{ // otherwise, must be a config
36259 return new Roo.menu.Menu(menu);
36264 unregister : function(menu){
36265 delete menus[menu.id];
36266 menu.un("beforehide", onBeforeHide);
36267 menu.un("hide", onHide);
36268 menu.un("beforeshow", onBeforeShow);
36269 menu.un("show", onShow);
36270 var g = menu.group;
36271 if(g && menu.events["checkchange"]){
36272 groups[g].remove(menu);
36273 menu.un("checkchange", onCheck);
36278 registerCheckable : function(menuItem){
36279 var g = menuItem.group;
36284 groups[g].push(menuItem);
36285 menuItem.on("beforecheckchange", onBeforeCheck);
36290 unregisterCheckable : function(menuItem){
36291 var g = menuItem.group;
36293 groups[g].remove(menuItem);
36294 menuItem.un("beforecheckchange", onBeforeCheck);
36300 * Ext JS Library 1.1.1
36301 * Copyright(c) 2006-2007, Ext JS, LLC.
36303 * Originally Released Under LGPL - original licence link has changed is not relivant.
36306 * <script type="text/javascript">
36311 * @class Roo.menu.BaseItem
36312 * @extends Roo.Component
36313 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36314 * management and base configuration options shared by all menu components.
36316 * Creates a new BaseItem
36317 * @param {Object} config Configuration options
36319 Roo.menu.BaseItem = function(config){
36320 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36325 * Fires when this item is clicked
36326 * @param {Roo.menu.BaseItem} this
36327 * @param {Roo.EventObject} e
36332 * Fires when this item is activated
36333 * @param {Roo.menu.BaseItem} this
36337 * @event deactivate
36338 * Fires when this item is deactivated
36339 * @param {Roo.menu.BaseItem} this
36345 this.on("click", this.handler, this.scope, true);
36349 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36351 * @cfg {Function} handler
36352 * A function that will handle the click event of this menu item (defaults to undefined)
36355 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36357 canActivate : false,
36360 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36365 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36367 activeClass : "x-menu-item-active",
36369 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36371 hideOnClick : true,
36373 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36378 ctype: "Roo.menu.BaseItem",
36381 actionMode : "container",
36384 render : function(container, parentMenu){
36385 this.parentMenu = parentMenu;
36386 Roo.menu.BaseItem.superclass.render.call(this, container);
36387 this.container.menuItemId = this.id;
36391 onRender : function(container, position){
36392 this.el = Roo.get(this.el);
36393 container.dom.appendChild(this.el.dom);
36397 onClick : function(e){
36398 if(!this.disabled && this.fireEvent("click", this, e) !== false
36399 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36400 this.handleClick(e);
36407 activate : function(){
36411 var li = this.container;
36412 li.addClass(this.activeClass);
36413 this.region = li.getRegion().adjust(2, 2, -2, -2);
36414 this.fireEvent("activate", this);
36419 deactivate : function(){
36420 this.container.removeClass(this.activeClass);
36421 this.fireEvent("deactivate", this);
36425 shouldDeactivate : function(e){
36426 return !this.region || !this.region.contains(e.getPoint());
36430 handleClick : function(e){
36431 if(this.hideOnClick){
36432 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36437 expandMenu : function(autoActivate){
36442 hideMenu : function(){
36447 * Ext JS Library 1.1.1
36448 * Copyright(c) 2006-2007, Ext JS, LLC.
36450 * Originally Released Under LGPL - original licence link has changed is not relivant.
36453 * <script type="text/javascript">
36457 * @class Roo.menu.Adapter
36458 * @extends Roo.menu.BaseItem
36459 * 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.
36460 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36462 * Creates a new Adapter
36463 * @param {Object} config Configuration options
36465 Roo.menu.Adapter = function(component, config){
36466 Roo.menu.Adapter.superclass.constructor.call(this, config);
36467 this.component = component;
36469 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36471 canActivate : true,
36474 onRender : function(container, position){
36475 this.component.render(container);
36476 this.el = this.component.getEl();
36480 activate : function(){
36484 this.component.focus();
36485 this.fireEvent("activate", this);
36490 deactivate : function(){
36491 this.fireEvent("deactivate", this);
36495 disable : function(){
36496 this.component.disable();
36497 Roo.menu.Adapter.superclass.disable.call(this);
36501 enable : function(){
36502 this.component.enable();
36503 Roo.menu.Adapter.superclass.enable.call(this);
36507 * Ext JS Library 1.1.1
36508 * Copyright(c) 2006-2007, Ext JS, LLC.
36510 * Originally Released Under LGPL - original licence link has changed is not relivant.
36513 * <script type="text/javascript">
36517 * @class Roo.menu.TextItem
36518 * @extends Roo.menu.BaseItem
36519 * Adds a static text string to a menu, usually used as either a heading or group separator.
36520 * Note: old style constructor with text is still supported.
36523 * Creates a new TextItem
36524 * @param {Object} cfg Configuration
36526 Roo.menu.TextItem = function(cfg){
36527 if (typeof(cfg) == 'string') {
36530 Roo.apply(this,cfg);
36533 Roo.menu.TextItem.superclass.constructor.call(this);
36536 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36538 * @cfg {Boolean} text Text to show on item.
36543 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36545 hideOnClick : false,
36547 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36549 itemCls : "x-menu-text",
36552 onRender : function(){
36553 var s = document.createElement("span");
36554 s.className = this.itemCls;
36555 s.innerHTML = this.text;
36557 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36561 * Ext JS Library 1.1.1
36562 * Copyright(c) 2006-2007, Ext JS, LLC.
36564 * Originally Released Under LGPL - original licence link has changed is not relivant.
36567 * <script type="text/javascript">
36571 * @class Roo.menu.Separator
36572 * @extends Roo.menu.BaseItem
36573 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36574 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36576 * @param {Object} config Configuration options
36578 Roo.menu.Separator = function(config){
36579 Roo.menu.Separator.superclass.constructor.call(this, config);
36582 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36584 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36586 itemCls : "x-menu-sep",
36588 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36590 hideOnClick : false,
36593 onRender : function(li){
36594 var s = document.createElement("span");
36595 s.className = this.itemCls;
36596 s.innerHTML = " ";
36598 li.addClass("x-menu-sep-li");
36599 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36603 * Ext JS Library 1.1.1
36604 * Copyright(c) 2006-2007, Ext JS, LLC.
36606 * Originally Released Under LGPL - original licence link has changed is not relivant.
36609 * <script type="text/javascript">
36612 * @class Roo.menu.Item
36613 * @extends Roo.menu.BaseItem
36614 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36615 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36616 * activation and click handling.
36618 * Creates a new Item
36619 * @param {Object} config Configuration options
36621 Roo.menu.Item = function(config){
36622 Roo.menu.Item.superclass.constructor.call(this, config);
36624 this.menu = Roo.menu.MenuMgr.get(this.menu);
36627 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36630 * @cfg {String} text
36631 * The text to show on the menu item.
36635 * @cfg {String} HTML to render in menu
36636 * The text to show on the menu item (HTML version).
36640 * @cfg {String} icon
36641 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36645 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36647 itemCls : "x-menu-item",
36649 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36651 canActivate : true,
36653 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36656 // doc'd in BaseItem
36660 ctype: "Roo.menu.Item",
36663 onRender : function(container, position){
36664 var el = document.createElement("a");
36665 el.hideFocus = true;
36666 el.unselectable = "on";
36667 el.href = this.href || "#";
36668 if(this.hrefTarget){
36669 el.target = this.hrefTarget;
36671 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36673 var html = this.html.length ? this.html : String.format('{0}',this.text);
36675 el.innerHTML = String.format(
36676 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36677 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36679 Roo.menu.Item.superclass.onRender.call(this, container, position);
36683 * Sets the text to display in this menu item
36684 * @param {String} text The text to display
36685 * @param {Boolean} isHTML true to indicate text is pure html.
36687 setText : function(text, isHTML){
36695 var html = this.html.length ? this.html : String.format('{0}',this.text);
36697 this.el.update(String.format(
36698 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36699 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36700 this.parentMenu.autoWidth();
36705 handleClick : function(e){
36706 if(!this.href){ // if no link defined, stop the event automatically
36709 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36713 activate : function(autoExpand){
36714 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36724 shouldDeactivate : function(e){
36725 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36726 if(this.menu && this.menu.isVisible()){
36727 return !this.menu.getEl().getRegion().contains(e.getPoint());
36735 deactivate : function(){
36736 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36741 expandMenu : function(autoActivate){
36742 if(!this.disabled && this.menu){
36743 clearTimeout(this.hideTimer);
36744 delete this.hideTimer;
36745 if(!this.menu.isVisible() && !this.showTimer){
36746 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36747 }else if (this.menu.isVisible() && autoActivate){
36748 this.menu.tryActivate(0, 1);
36754 deferExpand : function(autoActivate){
36755 delete this.showTimer;
36756 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36758 this.menu.tryActivate(0, 1);
36763 hideMenu : function(){
36764 clearTimeout(this.showTimer);
36765 delete this.showTimer;
36766 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36767 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36772 deferHide : function(){
36773 delete this.hideTimer;
36778 * Ext JS Library 1.1.1
36779 * Copyright(c) 2006-2007, Ext JS, LLC.
36781 * Originally Released Under LGPL - original licence link has changed is not relivant.
36784 * <script type="text/javascript">
36788 * @class Roo.menu.CheckItem
36789 * @extends Roo.menu.Item
36790 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36792 * Creates a new CheckItem
36793 * @param {Object} config Configuration options
36795 Roo.menu.CheckItem = function(config){
36796 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36799 * @event beforecheckchange
36800 * Fires before the checked value is set, providing an opportunity to cancel if needed
36801 * @param {Roo.menu.CheckItem} this
36802 * @param {Boolean} checked The new checked value that will be set
36804 "beforecheckchange" : true,
36806 * @event checkchange
36807 * Fires after the checked value has been set
36808 * @param {Roo.menu.CheckItem} this
36809 * @param {Boolean} checked The checked value that was set
36811 "checkchange" : true
36813 if(this.checkHandler){
36814 this.on('checkchange', this.checkHandler, this.scope);
36817 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36819 * @cfg {String} group
36820 * All check items with the same group name will automatically be grouped into a single-select
36821 * radio button group (defaults to '')
36824 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36826 itemCls : "x-menu-item x-menu-check-item",
36828 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36830 groupClass : "x-menu-group-item",
36833 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36834 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36835 * initialized with checked = true will be rendered as checked.
36840 ctype: "Roo.menu.CheckItem",
36843 onRender : function(c){
36844 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36846 this.el.addClass(this.groupClass);
36848 Roo.menu.MenuMgr.registerCheckable(this);
36850 this.checked = false;
36851 this.setChecked(true, true);
36856 destroy : function(){
36858 Roo.menu.MenuMgr.unregisterCheckable(this);
36860 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36864 * Set the checked state of this item
36865 * @param {Boolean} checked The new checked value
36866 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36868 setChecked : function(state, suppressEvent){
36869 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36870 if(this.container){
36871 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36873 this.checked = state;
36874 if(suppressEvent !== true){
36875 this.fireEvent("checkchange", this, state);
36881 handleClick : function(e){
36882 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36883 this.setChecked(!this.checked);
36885 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36889 * Ext JS Library 1.1.1
36890 * Copyright(c) 2006-2007, Ext JS, LLC.
36892 * Originally Released Under LGPL - original licence link has changed is not relivant.
36895 * <script type="text/javascript">
36899 * @class Roo.menu.DateItem
36900 * @extends Roo.menu.Adapter
36901 * A menu item that wraps the {@link Roo.DatPicker} component.
36903 * Creates a new DateItem
36904 * @param {Object} config Configuration options
36906 Roo.menu.DateItem = function(config){
36907 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36908 /** The Roo.DatePicker object @type Roo.DatePicker */
36909 this.picker = this.component;
36910 this.addEvents({select: true});
36912 this.picker.on("render", function(picker){
36913 picker.getEl().swallowEvent("click");
36914 picker.container.addClass("x-menu-date-item");
36917 this.picker.on("select", this.onSelect, this);
36920 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36922 onSelect : function(picker, date){
36923 this.fireEvent("select", this, date, picker);
36924 Roo.menu.DateItem.superclass.handleClick.call(this);
36928 * Ext JS Library 1.1.1
36929 * Copyright(c) 2006-2007, Ext JS, LLC.
36931 * Originally Released Under LGPL - original licence link has changed is not relivant.
36934 * <script type="text/javascript">
36938 * @class Roo.menu.ColorItem
36939 * @extends Roo.menu.Adapter
36940 * A menu item that wraps the {@link Roo.ColorPalette} component.
36942 * Creates a new ColorItem
36943 * @param {Object} config Configuration options
36945 Roo.menu.ColorItem = function(config){
36946 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36947 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36948 this.palette = this.component;
36949 this.relayEvents(this.palette, ["select"]);
36950 if(this.selectHandler){
36951 this.on('select', this.selectHandler, this.scope);
36954 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36956 * Ext JS Library 1.1.1
36957 * Copyright(c) 2006-2007, Ext JS, LLC.
36959 * Originally Released Under LGPL - original licence link has changed is not relivant.
36962 * <script type="text/javascript">
36967 * @class Roo.menu.DateMenu
36968 * @extends Roo.menu.Menu
36969 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36971 * Creates a new DateMenu
36972 * @param {Object} config Configuration options
36974 Roo.menu.DateMenu = function(config){
36975 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36977 var di = new Roo.menu.DateItem(config);
36980 * The {@link Roo.DatePicker} instance for this DateMenu
36983 this.picker = di.picker;
36986 * @param {DatePicker} picker
36987 * @param {Date} date
36989 this.relayEvents(di, ["select"]);
36990 this.on('beforeshow', function(){
36992 this.picker.hideMonthPicker(false);
36996 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
37000 * Ext JS Library 1.1.1
37001 * Copyright(c) 2006-2007, Ext JS, LLC.
37003 * Originally Released Under LGPL - original licence link has changed is not relivant.
37006 * <script type="text/javascript">
37011 * @class Roo.menu.ColorMenu
37012 * @extends Roo.menu.Menu
37013 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
37015 * Creates a new ColorMenu
37016 * @param {Object} config Configuration options
37018 Roo.menu.ColorMenu = function(config){
37019 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
37021 var ci = new Roo.menu.ColorItem(config);
37024 * The {@link Roo.ColorPalette} instance for this ColorMenu
37025 * @type ColorPalette
37027 this.palette = ci.palette;
37030 * @param {ColorPalette} palette
37031 * @param {String} color
37033 this.relayEvents(ci, ["select"]);
37035 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
37037 * Ext JS Library 1.1.1
37038 * Copyright(c) 2006-2007, Ext JS, LLC.
37040 * Originally Released Under LGPL - original licence link has changed is not relivant.
37043 * <script type="text/javascript">
37047 * @class Roo.form.Field
37048 * @extends Roo.BoxComponent
37049 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
37051 * Creates a new Field
37052 * @param {Object} config Configuration options
37054 Roo.form.Field = function(config){
37055 Roo.form.Field.superclass.constructor.call(this, config);
37058 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
37060 * @cfg {String} fieldLabel Label to use when rendering a form.
37063 * @cfg {String} qtip Mouse over tip
37067 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
37069 invalidClass : "x-form-invalid",
37071 * @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")
37073 invalidText : "The value in this field is invalid",
37075 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
37077 focusClass : "x-form-focus",
37079 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
37080 automatic validation (defaults to "keyup").
37082 validationEvent : "keyup",
37084 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
37086 validateOnBlur : true,
37088 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
37090 validationDelay : 250,
37092 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37093 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
37095 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
37097 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
37099 fieldClass : "x-form-field",
37101 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
37104 ----------- ----------------------------------------------------------------------
37105 qtip Display a quick tip when the user hovers over the field
37106 title Display a default browser title attribute popup
37107 under Add a block div beneath the field containing the error text
37108 side Add an error icon to the right of the field with a popup on hover
37109 [element id] Add the error text directly to the innerHTML of the specified element
37112 msgTarget : 'qtip',
37114 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
37119 * @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.
37124 * @cfg {Boolean} disabled True to disable the field (defaults to false).
37129 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
37131 inputType : undefined,
37134 * @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).
37136 tabIndex : undefined,
37139 isFormField : true,
37144 * @property {Roo.Element} fieldEl
37145 * Element Containing the rendered Field (with label etc.)
37148 * @cfg {Mixed} value A value to initialize this field with.
37153 * @cfg {String} name The field's HTML name attribute.
37156 * @cfg {String} cls A CSS class to apply to the field's underlying element.
37160 initComponent : function(){
37161 Roo.form.Field.superclass.initComponent.call(this);
37165 * Fires when this field receives input focus.
37166 * @param {Roo.form.Field} this
37171 * Fires when this field loses input focus.
37172 * @param {Roo.form.Field} this
37176 * @event specialkey
37177 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
37178 * {@link Roo.EventObject#getKey} to determine which key was pressed.
37179 * @param {Roo.form.Field} this
37180 * @param {Roo.EventObject} e The event object
37185 * Fires just before the field blurs if the field value has changed.
37186 * @param {Roo.form.Field} this
37187 * @param {Mixed} newValue The new value
37188 * @param {Mixed} oldValue The original value
37193 * Fires after the field has been marked as invalid.
37194 * @param {Roo.form.Field} this
37195 * @param {String} msg The validation message
37200 * Fires after the field has been validated with no errors.
37201 * @param {Roo.form.Field} this
37206 * Fires after the key up
37207 * @param {Roo.form.Field} this
37208 * @param {Roo.EventObject} e The event Object
37215 * Returns the name attribute of the field if available
37216 * @return {String} name The field name
37218 getName: function(){
37219 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37223 onRender : function(ct, position){
37224 Roo.form.Field.superclass.onRender.call(this, ct, position);
37226 var cfg = this.getAutoCreate();
37228 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37230 if (!cfg.name.length) {
37233 if(this.inputType){
37234 cfg.type = this.inputType;
37236 this.el = ct.createChild(cfg, position);
37238 var type = this.el.dom.type;
37240 if(type == 'password'){
37243 this.el.addClass('x-form-'+type);
37246 this.el.dom.readOnly = true;
37248 if(this.tabIndex !== undefined){
37249 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37252 this.el.addClass([this.fieldClass, this.cls]);
37257 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37258 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37259 * @return {Roo.form.Field} this
37261 applyTo : function(target){
37262 this.allowDomMove = false;
37263 this.el = Roo.get(target);
37264 this.render(this.el.dom.parentNode);
37269 initValue : function(){
37270 if(this.value !== undefined){
37271 this.setValue(this.value);
37272 }else if(this.el.dom.value.length > 0){
37273 this.setValue(this.el.dom.value);
37278 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37280 isDirty : function() {
37281 if(this.disabled) {
37284 return String(this.getValue()) !== String(this.originalValue);
37288 afterRender : function(){
37289 Roo.form.Field.superclass.afterRender.call(this);
37294 fireKey : function(e){
37295 //Roo.log('field ' + e.getKey());
37296 if(e.isNavKeyPress()){
37297 this.fireEvent("specialkey", this, e);
37302 * Resets the current field value to the originally loaded value and clears any validation messages
37304 reset : function(){
37305 this.setValue(this.resetValue);
37306 this.clearInvalid();
37310 initEvents : function(){
37311 // safari killled keypress - so keydown is now used..
37312 this.el.on("keydown" , this.fireKey, this);
37313 this.el.on("focus", this.onFocus, this);
37314 this.el.on("blur", this.onBlur, this);
37315 this.el.relayEvent('keyup', this);
37317 // reference to original value for reset
37318 this.originalValue = this.getValue();
37319 this.resetValue = this.getValue();
37323 onFocus : function(){
37324 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37325 this.el.addClass(this.focusClass);
37327 if(!this.hasFocus){
37328 this.hasFocus = true;
37329 this.startValue = this.getValue();
37330 this.fireEvent("focus", this);
37334 beforeBlur : Roo.emptyFn,
37337 onBlur : function(){
37339 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37340 this.el.removeClass(this.focusClass);
37342 this.hasFocus = false;
37343 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37346 var v = this.getValue();
37347 if(String(v) !== String(this.startValue)){
37348 this.fireEvent('change', this, v, this.startValue);
37350 this.fireEvent("blur", this);
37354 * Returns whether or not the field value is currently valid
37355 * @param {Boolean} preventMark True to disable marking the field invalid
37356 * @return {Boolean} True if the value is valid, else false
37358 isValid : function(preventMark){
37362 var restore = this.preventMark;
37363 this.preventMark = preventMark === true;
37364 var v = this.validateValue(this.processValue(this.getRawValue()));
37365 this.preventMark = restore;
37370 * Validates the field value
37371 * @return {Boolean} True if the value is valid, else false
37373 validate : function(){
37374 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37375 this.clearInvalid();
37381 processValue : function(value){
37386 // Subclasses should provide the validation implementation by overriding this
37387 validateValue : function(value){
37392 * Mark this field as invalid
37393 * @param {String} msg The validation message
37395 markInvalid : function(msg){
37396 if(!this.rendered || this.preventMark){ // not rendered
37400 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37402 obj.el.addClass(this.invalidClass);
37403 msg = msg || this.invalidText;
37404 switch(this.msgTarget){
37406 obj.el.dom.qtip = msg;
37407 obj.el.dom.qclass = 'x-form-invalid-tip';
37408 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37409 Roo.QuickTips.enable();
37413 this.el.dom.title = msg;
37417 var elp = this.el.findParent('.x-form-element', 5, true);
37418 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37419 this.errorEl.setWidth(elp.getWidth(true)-20);
37421 this.errorEl.update(msg);
37422 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37425 if(!this.errorIcon){
37426 var elp = this.el.findParent('.x-form-element', 5, true);
37427 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37429 this.alignErrorIcon();
37430 this.errorIcon.dom.qtip = msg;
37431 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37432 this.errorIcon.show();
37433 this.on('resize', this.alignErrorIcon, this);
37436 var t = Roo.getDom(this.msgTarget);
37438 t.style.display = this.msgDisplay;
37441 this.fireEvent('invalid', this, msg);
37445 alignErrorIcon : function(){
37446 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37450 * Clear any invalid styles/messages for this field
37452 clearInvalid : function(){
37453 if(!this.rendered || this.preventMark){ // not rendered
37456 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37458 obj.el.removeClass(this.invalidClass);
37459 switch(this.msgTarget){
37461 obj.el.dom.qtip = '';
37464 this.el.dom.title = '';
37468 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37472 if(this.errorIcon){
37473 this.errorIcon.dom.qtip = '';
37474 this.errorIcon.hide();
37475 this.un('resize', this.alignErrorIcon, this);
37479 var t = Roo.getDom(this.msgTarget);
37481 t.style.display = 'none';
37484 this.fireEvent('valid', this);
37488 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37489 * @return {Mixed} value The field value
37491 getRawValue : function(){
37492 var v = this.el.getValue();
37498 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37499 * @return {Mixed} value The field value
37501 getValue : function(){
37502 var v = this.el.getValue();
37508 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37509 * @param {Mixed} value The value to set
37511 setRawValue : function(v){
37512 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37516 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37517 * @param {Mixed} value The value to set
37519 setValue : function(v){
37522 this.el.dom.value = (v === null || v === undefined ? '' : v);
37527 adjustSize : function(w, h){
37528 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37529 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37533 adjustWidth : function(tag, w){
37534 tag = tag.toLowerCase();
37535 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37536 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37537 if(tag == 'input'){
37540 if(tag == 'textarea'){
37543 }else if(Roo.isOpera){
37544 if(tag == 'input'){
37547 if(tag == 'textarea'){
37557 // anything other than normal should be considered experimental
37558 Roo.form.Field.msgFx = {
37560 show: function(msgEl, f){
37561 msgEl.setDisplayed('block');
37564 hide : function(msgEl, f){
37565 msgEl.setDisplayed(false).update('');
37570 show: function(msgEl, f){
37571 msgEl.slideIn('t', {stopFx:true});
37574 hide : function(msgEl, f){
37575 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37580 show: function(msgEl, f){
37581 msgEl.fixDisplay();
37582 msgEl.alignTo(f.el, 'tl-tr');
37583 msgEl.slideIn('l', {stopFx:true});
37586 hide : function(msgEl, f){
37587 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37592 * Ext JS Library 1.1.1
37593 * Copyright(c) 2006-2007, Ext JS, LLC.
37595 * Originally Released Under LGPL - original licence link has changed is not relivant.
37598 * <script type="text/javascript">
37603 * @class Roo.form.TextField
37604 * @extends Roo.form.Field
37605 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37606 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37608 * Creates a new TextField
37609 * @param {Object} config Configuration options
37611 Roo.form.TextField = function(config){
37612 Roo.form.TextField.superclass.constructor.call(this, config);
37616 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37617 * according to the default logic, but this event provides a hook for the developer to apply additional
37618 * logic at runtime to resize the field if needed.
37619 * @param {Roo.form.Field} this This text field
37620 * @param {Number} width The new field width
37626 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37628 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37632 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37636 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37640 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37644 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37648 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37650 disableKeyFilter : false,
37652 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37656 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37660 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37662 maxLength : Number.MAX_VALUE,
37664 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37666 minLengthText : "The minimum length for this field is {0}",
37668 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37670 maxLengthText : "The maximum length for this field is {0}",
37672 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37674 selectOnFocus : false,
37676 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37678 blankText : "This field is required",
37680 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37681 * If available, this function will be called only after the basic validators all return true, and will be passed the
37682 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37686 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37687 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37688 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37692 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37696 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37702 initEvents : function()
37704 if (this.emptyText) {
37705 this.el.attr('placeholder', this.emptyText);
37708 Roo.form.TextField.superclass.initEvents.call(this);
37709 if(this.validationEvent == 'keyup'){
37710 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37711 this.el.on('keyup', this.filterValidation, this);
37713 else if(this.validationEvent !== false){
37714 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37717 if(this.selectOnFocus){
37718 this.on("focus", this.preFocus, this);
37721 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37722 this.el.on("keypress", this.filterKeys, this);
37725 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37726 this.el.on("click", this.autoSize, this);
37728 if(this.el.is('input[type=password]') && Roo.isSafari){
37729 this.el.on('keydown', this.SafariOnKeyDown, this);
37733 processValue : function(value){
37734 if(this.stripCharsRe){
37735 var newValue = value.replace(this.stripCharsRe, '');
37736 if(newValue !== value){
37737 this.setRawValue(newValue);
37744 filterValidation : function(e){
37745 if(!e.isNavKeyPress()){
37746 this.validationTask.delay(this.validationDelay);
37751 onKeyUp : function(e){
37752 if(!e.isNavKeyPress()){
37758 * Resets the current field value to the originally-loaded value and clears any validation messages.
37761 reset : function(){
37762 Roo.form.TextField.superclass.reset.call(this);
37768 preFocus : function(){
37770 if(this.selectOnFocus){
37771 this.el.dom.select();
37777 filterKeys : function(e){
37778 var k = e.getKey();
37779 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37782 var c = e.getCharCode(), cc = String.fromCharCode(c);
37783 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37786 if(!this.maskRe.test(cc)){
37791 setValue : function(v){
37793 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37799 * Validates a value according to the field's validation rules and marks the field as invalid
37800 * if the validation fails
37801 * @param {Mixed} value The value to validate
37802 * @return {Boolean} True if the value is valid, else false
37804 validateValue : function(value){
37805 if(value.length < 1) { // if it's blank
37806 if(this.allowBlank){
37807 this.clearInvalid();
37810 this.markInvalid(this.blankText);
37814 if(value.length < this.minLength){
37815 this.markInvalid(String.format(this.minLengthText, this.minLength));
37818 if(value.length > this.maxLength){
37819 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37823 var vt = Roo.form.VTypes;
37824 if(!vt[this.vtype](value, this)){
37825 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37829 if(typeof this.validator == "function"){
37830 var msg = this.validator(value);
37832 this.markInvalid(msg);
37836 if(this.regex && !this.regex.test(value)){
37837 this.markInvalid(this.regexText);
37844 * Selects text in this field
37845 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37846 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37848 selectText : function(start, end){
37849 var v = this.getRawValue();
37851 start = start === undefined ? 0 : start;
37852 end = end === undefined ? v.length : end;
37853 var d = this.el.dom;
37854 if(d.setSelectionRange){
37855 d.setSelectionRange(start, end);
37856 }else if(d.createTextRange){
37857 var range = d.createTextRange();
37858 range.moveStart("character", start);
37859 range.moveEnd("character", v.length-end);
37866 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37867 * This only takes effect if grow = true, and fires the autosize event.
37869 autoSize : function(){
37870 if(!this.grow || !this.rendered){
37874 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37877 var v = el.dom.value;
37878 var d = document.createElement('div');
37879 d.appendChild(document.createTextNode(v));
37883 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37884 this.el.setWidth(w);
37885 this.fireEvent("autosize", this, w);
37889 SafariOnKeyDown : function(event)
37891 // this is a workaround for a password hang bug on chrome/ webkit.
37893 var isSelectAll = false;
37895 if(this.el.dom.selectionEnd > 0){
37896 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37898 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37899 event.preventDefault();
37904 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
37906 event.preventDefault();
37907 // this is very hacky as keydown always get's upper case.
37909 var cc = String.fromCharCode(event.getCharCode());
37912 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37920 * Ext JS Library 1.1.1
37921 * Copyright(c) 2006-2007, Ext JS, LLC.
37923 * Originally Released Under LGPL - original licence link has changed is not relivant.
37926 * <script type="text/javascript">
37930 * @class Roo.form.Hidden
37931 * @extends Roo.form.TextField
37932 * Simple Hidden element used on forms
37934 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37937 * Creates a new Hidden form element.
37938 * @param {Object} config Configuration options
37943 // easy hidden field...
37944 Roo.form.Hidden = function(config){
37945 Roo.form.Hidden.superclass.constructor.call(this, config);
37948 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37950 inputType: 'hidden',
37953 labelSeparator: '',
37955 itemCls : 'x-form-item-display-none'
37963 * Ext JS Library 1.1.1
37964 * Copyright(c) 2006-2007, Ext JS, LLC.
37966 * Originally Released Under LGPL - original licence link has changed is not relivant.
37969 * <script type="text/javascript">
37973 * @class Roo.form.TriggerField
37974 * @extends Roo.form.TextField
37975 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37976 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37977 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37978 * for which you can provide a custom implementation. For example:
37980 var trigger = new Roo.form.TriggerField();
37981 trigger.onTriggerClick = myTriggerFn;
37982 trigger.applyTo('my-field');
37985 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37986 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37987 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37988 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37990 * Create a new TriggerField.
37991 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37992 * to the base TextField)
37994 Roo.form.TriggerField = function(config){
37995 this.mimicing = false;
37996 Roo.form.TriggerField.superclass.constructor.call(this, config);
37999 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
38001 * @cfg {String} triggerClass A CSS class to apply to the trigger
38004 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38005 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
38007 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
38009 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
38013 /** @cfg {Boolean} grow @hide */
38014 /** @cfg {Number} growMin @hide */
38015 /** @cfg {Number} growMax @hide */
38021 autoSize: Roo.emptyFn,
38025 deferHeight : true,
38028 actionMode : 'wrap',
38030 onResize : function(w, h){
38031 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
38032 if(typeof w == 'number'){
38033 var x = w - this.trigger.getWidth();
38034 this.el.setWidth(this.adjustWidth('input', x));
38035 this.trigger.setStyle('left', x+'px');
38040 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38043 getResizeEl : function(){
38048 getPositionEl : function(){
38053 alignErrorIcon : function(){
38054 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
38058 onRender : function(ct, position){
38059 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
38060 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
38061 this.trigger = this.wrap.createChild(this.triggerConfig ||
38062 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
38063 if(this.hideTrigger){
38064 this.trigger.setDisplayed(false);
38066 this.initTrigger();
38068 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
38073 initTrigger : function(){
38074 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
38075 this.trigger.addClassOnOver('x-form-trigger-over');
38076 this.trigger.addClassOnClick('x-form-trigger-click');
38080 onDestroy : function(){
38082 this.trigger.removeAllListeners();
38083 this.trigger.remove();
38086 this.wrap.remove();
38088 Roo.form.TriggerField.superclass.onDestroy.call(this);
38092 onFocus : function(){
38093 Roo.form.TriggerField.superclass.onFocus.call(this);
38094 if(!this.mimicing){
38095 this.wrap.addClass('x-trigger-wrap-focus');
38096 this.mimicing = true;
38097 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
38098 if(this.monitorTab){
38099 this.el.on("keydown", this.checkTab, this);
38105 checkTab : function(e){
38106 if(e.getKey() == e.TAB){
38107 this.triggerBlur();
38112 onBlur : function(){
38117 mimicBlur : function(e, t){
38118 if(!this.wrap.contains(t) && this.validateBlur()){
38119 this.triggerBlur();
38124 triggerBlur : function(){
38125 this.mimicing = false;
38126 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
38127 if(this.monitorTab){
38128 this.el.un("keydown", this.checkTab, this);
38130 this.wrap.removeClass('x-trigger-wrap-focus');
38131 Roo.form.TriggerField.superclass.onBlur.call(this);
38135 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
38136 validateBlur : function(e, t){
38141 onDisable : function(){
38142 Roo.form.TriggerField.superclass.onDisable.call(this);
38144 this.wrap.addClass('x-item-disabled');
38149 onEnable : function(){
38150 Roo.form.TriggerField.superclass.onEnable.call(this);
38152 this.wrap.removeClass('x-item-disabled');
38157 onShow : function(){
38158 var ae = this.getActionEl();
38161 ae.dom.style.display = '';
38162 ae.dom.style.visibility = 'visible';
38168 onHide : function(){
38169 var ae = this.getActionEl();
38170 ae.dom.style.display = 'none';
38174 * The function that should handle the trigger's click event. This method does nothing by default until overridden
38175 * by an implementing function.
38177 * @param {EventObject} e
38179 onTriggerClick : Roo.emptyFn
38182 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
38183 // to be extended by an implementing class. For an example of implementing this class, see the custom
38184 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
38185 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
38186 initComponent : function(){
38187 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
38189 this.triggerConfig = {
38190 tag:'span', cls:'x-form-twin-triggers', cn:[
38191 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38192 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38196 getTrigger : function(index){
38197 return this.triggers[index];
38200 initTrigger : function(){
38201 var ts = this.trigger.select('.x-form-trigger', true);
38202 this.wrap.setStyle('overflow', 'hidden');
38203 var triggerField = this;
38204 ts.each(function(t, all, index){
38205 t.hide = function(){
38206 var w = triggerField.wrap.getWidth();
38207 this.dom.style.display = 'none';
38208 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38210 t.show = function(){
38211 var w = triggerField.wrap.getWidth();
38212 this.dom.style.display = '';
38213 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38215 var triggerIndex = 'Trigger'+(index+1);
38217 if(this['hide'+triggerIndex]){
38218 t.dom.style.display = 'none';
38220 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38221 t.addClassOnOver('x-form-trigger-over');
38222 t.addClassOnClick('x-form-trigger-click');
38224 this.triggers = ts.elements;
38227 onTrigger1Click : Roo.emptyFn,
38228 onTrigger2Click : Roo.emptyFn
38231 * Ext JS Library 1.1.1
38232 * Copyright(c) 2006-2007, Ext JS, LLC.
38234 * Originally Released Under LGPL - original licence link has changed is not relivant.
38237 * <script type="text/javascript">
38241 * @class Roo.form.TextArea
38242 * @extends Roo.form.TextField
38243 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38244 * support for auto-sizing.
38246 * Creates a new TextArea
38247 * @param {Object} config Configuration options
38249 Roo.form.TextArea = function(config){
38250 Roo.form.TextArea.superclass.constructor.call(this, config);
38251 // these are provided exchanges for backwards compat
38252 // minHeight/maxHeight were replaced by growMin/growMax to be
38253 // compatible with TextField growing config values
38254 if(this.minHeight !== undefined){
38255 this.growMin = this.minHeight;
38257 if(this.maxHeight !== undefined){
38258 this.growMax = this.maxHeight;
38262 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38264 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38268 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38272 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38273 * in the field (equivalent to setting overflow: hidden, defaults to false)
38275 preventScrollbars: false,
38277 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38278 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38282 onRender : function(ct, position){
38284 this.defaultAutoCreate = {
38286 style:"width:300px;height:60px;",
38287 autocomplete: "new-password"
38290 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38292 this.textSizeEl = Roo.DomHelper.append(document.body, {
38293 tag: "pre", cls: "x-form-grow-sizer"
38295 if(this.preventScrollbars){
38296 this.el.setStyle("overflow", "hidden");
38298 this.el.setHeight(this.growMin);
38302 onDestroy : function(){
38303 if(this.textSizeEl){
38304 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38306 Roo.form.TextArea.superclass.onDestroy.call(this);
38310 onKeyUp : function(e){
38311 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38317 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38318 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38320 autoSize : function(){
38321 if(!this.grow || !this.textSizeEl){
38325 var v = el.dom.value;
38326 var ts = this.textSizeEl;
38329 ts.appendChild(document.createTextNode(v));
38332 Roo.fly(ts).setWidth(this.el.getWidth());
38334 v = "  ";
38337 v = v.replace(/\n/g, '<p> </p>');
38339 v += " \n ";
38342 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38343 if(h != this.lastHeight){
38344 this.lastHeight = h;
38345 this.el.setHeight(h);
38346 this.fireEvent("autosize", this, h);
38351 * Ext JS Library 1.1.1
38352 * Copyright(c) 2006-2007, Ext JS, LLC.
38354 * Originally Released Under LGPL - original licence link has changed is not relivant.
38357 * <script type="text/javascript">
38362 * @class Roo.form.NumberField
38363 * @extends Roo.form.TextField
38364 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38366 * Creates a new NumberField
38367 * @param {Object} config Configuration options
38369 Roo.form.NumberField = function(config){
38370 Roo.form.NumberField.superclass.constructor.call(this, config);
38373 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38375 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38377 fieldClass: "x-form-field x-form-num-field",
38379 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38381 allowDecimals : true,
38383 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38385 decimalSeparator : ".",
38387 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38389 decimalPrecision : 2,
38391 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38393 allowNegative : true,
38395 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38397 minValue : Number.NEGATIVE_INFINITY,
38399 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38401 maxValue : Number.MAX_VALUE,
38403 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38405 minText : "The minimum value for this field is {0}",
38407 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38409 maxText : "The maximum value for this field is {0}",
38411 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38412 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38414 nanText : "{0} is not a valid number",
38417 initEvents : function(){
38418 Roo.form.NumberField.superclass.initEvents.call(this);
38419 var allowed = "0123456789";
38420 if(this.allowDecimals){
38421 allowed += this.decimalSeparator;
38423 if(this.allowNegative){
38426 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38427 var keyPress = function(e){
38428 var k = e.getKey();
38429 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38432 var c = e.getCharCode();
38433 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38437 this.el.on("keypress", keyPress, this);
38441 validateValue : function(value){
38442 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38445 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38448 var num = this.parseValue(value);
38450 this.markInvalid(String.format(this.nanText, value));
38453 if(num < this.minValue){
38454 this.markInvalid(String.format(this.minText, this.minValue));
38457 if(num > this.maxValue){
38458 this.markInvalid(String.format(this.maxText, this.maxValue));
38464 getValue : function(){
38465 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38469 parseValue : function(value){
38470 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38471 return isNaN(value) ? '' : value;
38475 fixPrecision : function(value){
38476 var nan = isNaN(value);
38477 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38478 return nan ? '' : value;
38480 return parseFloat(value).toFixed(this.decimalPrecision);
38483 setValue : function(v){
38484 v = this.fixPrecision(v);
38485 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38489 decimalPrecisionFcn : function(v){
38490 return Math.floor(v);
38493 beforeBlur : function(){
38494 var v = this.parseValue(this.getRawValue());
38501 * Ext JS Library 1.1.1
38502 * Copyright(c) 2006-2007, Ext JS, LLC.
38504 * Originally Released Under LGPL - original licence link has changed is not relivant.
38507 * <script type="text/javascript">
38511 * @class Roo.form.DateField
38512 * @extends Roo.form.TriggerField
38513 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38515 * Create a new DateField
38516 * @param {Object} config
38518 Roo.form.DateField = function(config){
38519 Roo.form.DateField.superclass.constructor.call(this, config);
38525 * Fires when a date is selected
38526 * @param {Roo.form.DateField} combo This combo box
38527 * @param {Date} date The date selected
38534 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38535 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38536 this.ddMatch = null;
38537 if(this.disabledDates){
38538 var dd = this.disabledDates;
38540 for(var i = 0; i < dd.length; i++){
38542 if(i != dd.length-1) re += "|";
38544 this.ddMatch = new RegExp(re + ")");
38548 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38550 * @cfg {String} format
38551 * The default date format string which can be overriden for localization support. The format must be
38552 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38556 * @cfg {String} altFormats
38557 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38558 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38560 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38562 * @cfg {Array} disabledDays
38563 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38565 disabledDays : null,
38567 * @cfg {String} disabledDaysText
38568 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38570 disabledDaysText : "Disabled",
38572 * @cfg {Array} disabledDates
38573 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38574 * expression so they are very powerful. Some examples:
38576 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38577 * <li>["03/08", "09/16"] would disable those days for every year</li>
38578 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38579 * <li>["03/../2006"] would disable every day in March 2006</li>
38580 * <li>["^03"] would disable every day in every March</li>
38582 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38583 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38585 disabledDates : null,
38587 * @cfg {String} disabledDatesText
38588 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38590 disabledDatesText : "Disabled",
38592 * @cfg {Date/String} minValue
38593 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38594 * valid format (defaults to null).
38598 * @cfg {Date/String} maxValue
38599 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38600 * valid format (defaults to null).
38604 * @cfg {String} minText
38605 * The error text to display when the date in the cell is before minValue (defaults to
38606 * 'The date in this field must be after {minValue}').
38608 minText : "The date in this field must be equal to or after {0}",
38610 * @cfg {String} maxText
38611 * The error text to display when the date in the cell is after maxValue (defaults to
38612 * 'The date in this field must be before {maxValue}').
38614 maxText : "The date in this field must be equal to or before {0}",
38616 * @cfg {String} invalidText
38617 * The error text to display when the date in the field is invalid (defaults to
38618 * '{value} is not a valid date - it must be in the format {format}').
38620 invalidText : "{0} is not a valid date - it must be in the format {1}",
38622 * @cfg {String} triggerClass
38623 * An additional CSS class used to style the trigger button. The trigger will always get the
38624 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38625 * which displays a calendar icon).
38627 triggerClass : 'x-form-date-trigger',
38631 * @cfg {Boolean} useIso
38632 * if enabled, then the date field will use a hidden field to store the
38633 * real value as iso formated date. default (false)
38637 * @cfg {String/Object} autoCreate
38638 * A DomHelper element spec, or true for a default element spec (defaults to
38639 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38642 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38645 hiddenField: false,
38647 onRender : function(ct, position)
38649 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38651 //this.el.dom.removeAttribute('name');
38652 Roo.log("Changing name?");
38653 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38654 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38656 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38657 // prevent input submission
38658 this.hiddenName = this.name;
38665 validateValue : function(value)
38667 value = this.formatDate(value);
38668 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38669 Roo.log('super failed');
38672 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38675 var svalue = value;
38676 value = this.parseDate(value);
38678 Roo.log('parse date failed' + svalue);
38679 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38682 var time = value.getTime();
38683 if(this.minValue && time < this.minValue.getTime()){
38684 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38687 if(this.maxValue && time > this.maxValue.getTime()){
38688 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38691 if(this.disabledDays){
38692 var day = value.getDay();
38693 for(var i = 0; i < this.disabledDays.length; i++) {
38694 if(day === this.disabledDays[i]){
38695 this.markInvalid(this.disabledDaysText);
38700 var fvalue = this.formatDate(value);
38701 if(this.ddMatch && this.ddMatch.test(fvalue)){
38702 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38709 // Provides logic to override the default TriggerField.validateBlur which just returns true
38710 validateBlur : function(){
38711 return !this.menu || !this.menu.isVisible();
38714 getName: function()
38716 // returns hidden if it's set..
38717 if (!this.rendered) {return ''};
38718 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38723 * Returns the current date value of the date field.
38724 * @return {Date} The date value
38726 getValue : function(){
38728 return this.hiddenField ?
38729 this.hiddenField.value :
38730 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38734 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38735 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38736 * (the default format used is "m/d/y").
38739 //All of these calls set the same date value (May 4, 2006)
38741 //Pass a date object:
38742 var dt = new Date('5/4/06');
38743 dateField.setValue(dt);
38745 //Pass a date string (default format):
38746 dateField.setValue('5/4/06');
38748 //Pass a date string (custom format):
38749 dateField.format = 'Y-m-d';
38750 dateField.setValue('2006-5-4');
38752 * @param {String/Date} date The date or valid date string
38754 setValue : function(date){
38755 if (this.hiddenField) {
38756 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38758 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38759 // make sure the value field is always stored as a date..
38760 this.value = this.parseDate(date);
38766 parseDate : function(value){
38767 if(!value || value instanceof Date){
38770 var v = Date.parseDate(value, this.format);
38771 if (!v && this.useIso) {
38772 v = Date.parseDate(value, 'Y-m-d');
38774 if(!v && this.altFormats){
38775 if(!this.altFormatsArray){
38776 this.altFormatsArray = this.altFormats.split("|");
38778 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38779 v = Date.parseDate(value, this.altFormatsArray[i]);
38786 formatDate : function(date, fmt){
38787 return (!date || !(date instanceof Date)) ?
38788 date : date.dateFormat(fmt || this.format);
38793 select: function(m, d){
38796 this.fireEvent('select', this, d);
38798 show : function(){ // retain focus styling
38802 this.focus.defer(10, this);
38803 var ml = this.menuListeners;
38804 this.menu.un("select", ml.select, this);
38805 this.menu.un("show", ml.show, this);
38806 this.menu.un("hide", ml.hide, this);
38811 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38812 onTriggerClick : function(){
38816 if(this.menu == null){
38817 this.menu = new Roo.menu.DateMenu();
38819 Roo.apply(this.menu.picker, {
38820 showClear: this.allowBlank,
38821 minDate : this.minValue,
38822 maxDate : this.maxValue,
38823 disabledDatesRE : this.ddMatch,
38824 disabledDatesText : this.disabledDatesText,
38825 disabledDays : this.disabledDays,
38826 disabledDaysText : this.disabledDaysText,
38827 format : this.useIso ? 'Y-m-d' : this.format,
38828 minText : String.format(this.minText, this.formatDate(this.minValue)),
38829 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38831 this.menu.on(Roo.apply({}, this.menuListeners, {
38834 this.menu.picker.setValue(this.getValue() || new Date());
38835 this.menu.show(this.el, "tl-bl?");
38838 beforeBlur : function(){
38839 var v = this.parseDate(this.getRawValue());
38849 isDirty : function() {
38850 if(this.disabled) {
38854 if(typeof(this.startValue) === 'undefined'){
38858 return String(this.getValue()) !== String(this.startValue);
38863 * Ext JS Library 1.1.1
38864 * Copyright(c) 2006-2007, Ext JS, LLC.
38866 * Originally Released Under LGPL - original licence link has changed is not relivant.
38869 * <script type="text/javascript">
38873 * @class Roo.form.MonthField
38874 * @extends Roo.form.TriggerField
38875 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38877 * Create a new MonthField
38878 * @param {Object} config
38880 Roo.form.MonthField = function(config){
38882 Roo.form.MonthField.superclass.constructor.call(this, config);
38888 * Fires when a date is selected
38889 * @param {Roo.form.MonthFieeld} combo This combo box
38890 * @param {Date} date The date selected
38897 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38898 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38899 this.ddMatch = null;
38900 if(this.disabledDates){
38901 var dd = this.disabledDates;
38903 for(var i = 0; i < dd.length; i++){
38905 if(i != dd.length-1) re += "|";
38907 this.ddMatch = new RegExp(re + ")");
38911 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38913 * @cfg {String} format
38914 * The default date format string which can be overriden for localization support. The format must be
38915 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38919 * @cfg {String} altFormats
38920 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38921 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38923 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38925 * @cfg {Array} disabledDays
38926 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38928 disabledDays : [0,1,2,3,4,5,6],
38930 * @cfg {String} disabledDaysText
38931 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38933 disabledDaysText : "Disabled",
38935 * @cfg {Array} disabledDates
38936 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38937 * expression so they are very powerful. Some examples:
38939 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38940 * <li>["03/08", "09/16"] would disable those days for every year</li>
38941 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38942 * <li>["03/../2006"] would disable every day in March 2006</li>
38943 * <li>["^03"] would disable every day in every March</li>
38945 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38946 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38948 disabledDates : null,
38950 * @cfg {String} disabledDatesText
38951 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38953 disabledDatesText : "Disabled",
38955 * @cfg {Date/String} minValue
38956 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38957 * valid format (defaults to null).
38961 * @cfg {Date/String} maxValue
38962 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38963 * valid format (defaults to null).
38967 * @cfg {String} minText
38968 * The error text to display when the date in the cell is before minValue (defaults to
38969 * 'The date in this field must be after {minValue}').
38971 minText : "The date in this field must be equal to or after {0}",
38973 * @cfg {String} maxTextf
38974 * The error text to display when the date in the cell is after maxValue (defaults to
38975 * 'The date in this field must be before {maxValue}').
38977 maxText : "The date in this field must be equal to or before {0}",
38979 * @cfg {String} invalidText
38980 * The error text to display when the date in the field is invalid (defaults to
38981 * '{value} is not a valid date - it must be in the format {format}').
38983 invalidText : "{0} is not a valid date - it must be in the format {1}",
38985 * @cfg {String} triggerClass
38986 * An additional CSS class used to style the trigger button. The trigger will always get the
38987 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38988 * which displays a calendar icon).
38990 triggerClass : 'x-form-date-trigger',
38994 * @cfg {Boolean} useIso
38995 * if enabled, then the date field will use a hidden field to store the
38996 * real value as iso formated date. default (true)
39000 * @cfg {String/Object} autoCreate
39001 * A DomHelper element spec, or true for a default element spec (defaults to
39002 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
39005 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
39008 hiddenField: false,
39010 hideMonthPicker : false,
39012 onRender : function(ct, position)
39014 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
39016 this.el.dom.removeAttribute('name');
39017 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
39019 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
39020 // prevent input submission
39021 this.hiddenName = this.name;
39028 validateValue : function(value)
39030 value = this.formatDate(value);
39031 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
39034 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39037 var svalue = value;
39038 value = this.parseDate(value);
39040 this.markInvalid(String.format(this.invalidText, svalue, this.format));
39043 var time = value.getTime();
39044 if(this.minValue && time < this.minValue.getTime()){
39045 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
39048 if(this.maxValue && time > this.maxValue.getTime()){
39049 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
39052 /*if(this.disabledDays){
39053 var day = value.getDay();
39054 for(var i = 0; i < this.disabledDays.length; i++) {
39055 if(day === this.disabledDays[i]){
39056 this.markInvalid(this.disabledDaysText);
39062 var fvalue = this.formatDate(value);
39063 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
39064 this.markInvalid(String.format(this.disabledDatesText, fvalue));
39072 // Provides logic to override the default TriggerField.validateBlur which just returns true
39073 validateBlur : function(){
39074 return !this.menu || !this.menu.isVisible();
39078 * Returns the current date value of the date field.
39079 * @return {Date} The date value
39081 getValue : function(){
39085 return this.hiddenField ?
39086 this.hiddenField.value :
39087 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
39091 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
39092 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
39093 * (the default format used is "m/d/y").
39096 //All of these calls set the same date value (May 4, 2006)
39098 //Pass a date object:
39099 var dt = new Date('5/4/06');
39100 monthField.setValue(dt);
39102 //Pass a date string (default format):
39103 monthField.setValue('5/4/06');
39105 //Pass a date string (custom format):
39106 monthField.format = 'Y-m-d';
39107 monthField.setValue('2006-5-4');
39109 * @param {String/Date} date The date or valid date string
39111 setValue : function(date){
39112 Roo.log('month setValue' + date);
39113 // can only be first of month..
39115 var val = this.parseDate(date);
39117 if (this.hiddenField) {
39118 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
39120 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
39121 this.value = this.parseDate(date);
39125 parseDate : function(value){
39126 if(!value || value instanceof Date){
39127 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
39130 var v = Date.parseDate(value, this.format);
39131 if (!v && this.useIso) {
39132 v = Date.parseDate(value, 'Y-m-d');
39136 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
39140 if(!v && this.altFormats){
39141 if(!this.altFormatsArray){
39142 this.altFormatsArray = this.altFormats.split("|");
39144 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
39145 v = Date.parseDate(value, this.altFormatsArray[i]);
39152 formatDate : function(date, fmt){
39153 return (!date || !(date instanceof Date)) ?
39154 date : date.dateFormat(fmt || this.format);
39159 select: function(m, d){
39161 this.fireEvent('select', this, d);
39163 show : function(){ // retain focus styling
39167 this.focus.defer(10, this);
39168 var ml = this.menuListeners;
39169 this.menu.un("select", ml.select, this);
39170 this.menu.un("show", ml.show, this);
39171 this.menu.un("hide", ml.hide, this);
39175 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
39176 onTriggerClick : function(){
39180 if(this.menu == null){
39181 this.menu = new Roo.menu.DateMenu();
39185 Roo.apply(this.menu.picker, {
39187 showClear: this.allowBlank,
39188 minDate : this.minValue,
39189 maxDate : this.maxValue,
39190 disabledDatesRE : this.ddMatch,
39191 disabledDatesText : this.disabledDatesText,
39193 format : this.useIso ? 'Y-m-d' : this.format,
39194 minText : String.format(this.minText, this.formatDate(this.minValue)),
39195 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39198 this.menu.on(Roo.apply({}, this.menuListeners, {
39206 // hide month picker get's called when we called by 'before hide';
39208 var ignorehide = true;
39209 p.hideMonthPicker = function(disableAnim){
39213 if(this.monthPicker){
39214 Roo.log("hideMonthPicker called");
39215 if(disableAnim === true){
39216 this.monthPicker.hide();
39218 this.monthPicker.slideOut('t', {duration:.2});
39219 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39220 p.fireEvent("select", this, this.value);
39226 Roo.log('picker set value');
39227 Roo.log(this.getValue());
39228 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39229 m.show(this.el, 'tl-bl?');
39230 ignorehide = false;
39231 // this will trigger hideMonthPicker..
39234 // hidden the day picker
39235 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39241 p.showMonthPicker.defer(100, p);
39247 beforeBlur : function(){
39248 var v = this.parseDate(this.getRawValue());
39254 /** @cfg {Boolean} grow @hide */
39255 /** @cfg {Number} growMin @hide */
39256 /** @cfg {Number} growMax @hide */
39263 * Ext JS Library 1.1.1
39264 * Copyright(c) 2006-2007, Ext JS, LLC.
39266 * Originally Released Under LGPL - original licence link has changed is not relivant.
39269 * <script type="text/javascript">
39274 * @class Roo.form.ComboBox
39275 * @extends Roo.form.TriggerField
39276 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39278 * Create a new ComboBox.
39279 * @param {Object} config Configuration options
39281 Roo.form.ComboBox = function(config){
39282 Roo.form.ComboBox.superclass.constructor.call(this, config);
39286 * Fires when the dropdown list is expanded
39287 * @param {Roo.form.ComboBox} combo This combo box
39292 * Fires when the dropdown list is collapsed
39293 * @param {Roo.form.ComboBox} combo This combo box
39297 * @event beforeselect
39298 * Fires before a list item is selected. Return false to cancel the selection.
39299 * @param {Roo.form.ComboBox} combo This combo box
39300 * @param {Roo.data.Record} record The data record returned from the underlying store
39301 * @param {Number} index The index of the selected item in the dropdown list
39303 'beforeselect' : true,
39306 * Fires when a list item is selected
39307 * @param {Roo.form.ComboBox} combo This combo box
39308 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39309 * @param {Number} index The index of the selected item in the dropdown list
39313 * @event beforequery
39314 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39315 * The event object passed has these properties:
39316 * @param {Roo.form.ComboBox} combo This combo box
39317 * @param {String} query The query
39318 * @param {Boolean} forceAll true to force "all" query
39319 * @param {Boolean} cancel true to cancel the query
39320 * @param {Object} e The query event object
39322 'beforequery': true,
39325 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39326 * @param {Roo.form.ComboBox} combo This combo box
39331 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39332 * @param {Roo.form.ComboBox} combo This combo box
39333 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39339 if(this.transform){
39340 this.allowDomMove = false;
39341 var s = Roo.getDom(this.transform);
39342 if(!this.hiddenName){
39343 this.hiddenName = s.name;
39346 this.mode = 'local';
39347 var d = [], opts = s.options;
39348 for(var i = 0, len = opts.length;i < len; i++){
39350 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39352 this.value = value;
39354 d.push([value, o.text]);
39356 this.store = new Roo.data.SimpleStore({
39358 fields: ['value', 'text'],
39361 this.valueField = 'value';
39362 this.displayField = 'text';
39364 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39365 if(!this.lazyRender){
39366 this.target = true;
39367 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39368 s.parentNode.removeChild(s); // remove it
39369 this.render(this.el.parentNode);
39371 s.parentNode.removeChild(s); // remove it
39376 this.store = Roo.factory(this.store, Roo.data);
39379 this.selectedIndex = -1;
39380 if(this.mode == 'local'){
39381 if(config.queryDelay === undefined){
39382 this.queryDelay = 10;
39384 if(config.minChars === undefined){
39390 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39392 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39395 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39396 * rendering into an Roo.Editor, defaults to false)
39399 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39400 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39403 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39406 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39407 * the dropdown list (defaults to undefined, with no header element)
39411 * @cfg {String/Roo.Template} tpl The template to use to render the output
39415 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39417 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39419 listWidth: undefined,
39421 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39422 * mode = 'remote' or 'text' if mode = 'local')
39424 displayField: undefined,
39426 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39427 * mode = 'remote' or 'value' if mode = 'local').
39428 * Note: use of a valueField requires the user make a selection
39429 * in order for a value to be mapped.
39431 valueField: undefined,
39435 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39436 * field's data value (defaults to the underlying DOM element's name)
39438 hiddenName: undefined,
39440 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39444 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39446 selectedClass: 'x-combo-selected',
39448 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39449 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39450 * which displays a downward arrow icon).
39452 triggerClass : 'x-form-arrow-trigger',
39454 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39458 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39459 * anchor positions (defaults to 'tl-bl')
39461 listAlign: 'tl-bl?',
39463 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39467 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39468 * query specified by the allQuery config option (defaults to 'query')
39470 triggerAction: 'query',
39472 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39473 * (defaults to 4, does not apply if editable = false)
39477 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39478 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39482 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39483 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39487 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39488 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39492 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39493 * when editable = true (defaults to false)
39495 selectOnFocus:false,
39497 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39499 queryParam: 'query',
39501 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39502 * when mode = 'remote' (defaults to 'Loading...')
39504 loadingText: 'Loading...',
39506 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39510 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39514 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39515 * traditional select (defaults to true)
39519 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39523 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39527 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39528 * listWidth has a higher value)
39532 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39533 * allow the user to set arbitrary text into the field (defaults to false)
39535 forceSelection:false,
39537 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39538 * if typeAhead = true (defaults to 250)
39540 typeAheadDelay : 250,
39542 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39543 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39545 valueNotFoundText : undefined,
39547 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39549 blockFocus : false,
39552 * @cfg {Boolean} disableClear Disable showing of clear button.
39554 disableClear : false,
39556 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39558 alwaysQuery : false,
39564 // element that contains real text value.. (when hidden is used..)
39567 onRender : function(ct, position){
39568 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39569 if(this.hiddenName){
39570 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39572 this.hiddenField.value =
39573 this.hiddenValue !== undefined ? this.hiddenValue :
39574 this.value !== undefined ? this.value : '';
39576 // prevent input submission
39577 this.el.dom.removeAttribute('name');
39582 this.el.dom.setAttribute('autocomplete', 'off');
39585 var cls = 'x-combo-list';
39587 this.list = new Roo.Layer({
39588 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39591 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39592 this.list.setWidth(lw);
39593 this.list.swallowEvent('mousewheel');
39594 this.assetHeight = 0;
39597 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39598 this.assetHeight += this.header.getHeight();
39601 this.innerList = this.list.createChild({cls:cls+'-inner'});
39602 this.innerList.on('mouseover', this.onViewOver, this);
39603 this.innerList.on('mousemove', this.onViewMove, this);
39604 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39606 if(this.allowBlank && !this.pageSize && !this.disableClear){
39607 this.footer = this.list.createChild({cls:cls+'-ft'});
39608 this.pageTb = new Roo.Toolbar(this.footer);
39612 this.footer = this.list.createChild({cls:cls+'-ft'});
39613 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39614 {pageSize: this.pageSize});
39618 if (this.pageTb && this.allowBlank && !this.disableClear) {
39620 this.pageTb.add(new Roo.Toolbar.Fill(), {
39621 cls: 'x-btn-icon x-btn-clear',
39623 handler: function()
39626 _this.clearValue();
39627 _this.onSelect(false, -1);
39632 this.assetHeight += this.footer.getHeight();
39637 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39640 this.view = new Roo.View(this.innerList, this.tpl, {
39641 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39644 this.view.on('click', this.onViewClick, this);
39646 this.store.on('beforeload', this.onBeforeLoad, this);
39647 this.store.on('load', this.onLoad, this);
39648 this.store.on('loadexception', this.onLoadException, this);
39650 if(this.resizable){
39651 this.resizer = new Roo.Resizable(this.list, {
39652 pinned:true, handles:'se'
39654 this.resizer.on('resize', function(r, w, h){
39655 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39656 this.listWidth = w;
39657 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39658 this.restrictHeight();
39660 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39662 if(!this.editable){
39663 this.editable = true;
39664 this.setEditable(false);
39668 if (typeof(this.events.add.listeners) != 'undefined') {
39670 this.addicon = this.wrap.createChild(
39671 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39673 this.addicon.on('click', function(e) {
39674 this.fireEvent('add', this);
39677 if (typeof(this.events.edit.listeners) != 'undefined') {
39679 this.editicon = this.wrap.createChild(
39680 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39681 if (this.addicon) {
39682 this.editicon.setStyle('margin-left', '40px');
39684 this.editicon.on('click', function(e) {
39686 // we fire even if inothing is selected..
39687 this.fireEvent('edit', this, this.lastData );
39697 initEvents : function(){
39698 Roo.form.ComboBox.superclass.initEvents.call(this);
39700 this.keyNav = new Roo.KeyNav(this.el, {
39701 "up" : function(e){
39702 this.inKeyMode = true;
39706 "down" : function(e){
39707 if(!this.isExpanded()){
39708 this.onTriggerClick();
39710 this.inKeyMode = true;
39715 "enter" : function(e){
39716 this.onViewClick();
39720 "esc" : function(e){
39724 "tab" : function(e){
39725 this.onViewClick(false);
39726 this.fireEvent("specialkey", this, e);
39732 doRelay : function(foo, bar, hname){
39733 if(hname == 'down' || this.scope.isExpanded()){
39734 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39741 this.queryDelay = Math.max(this.queryDelay || 10,
39742 this.mode == 'local' ? 10 : 250);
39743 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39744 if(this.typeAhead){
39745 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39747 if(this.editable !== false){
39748 this.el.on("keyup", this.onKeyUp, this);
39750 if(this.forceSelection){
39751 this.on('blur', this.doForce, this);
39755 onDestroy : function(){
39757 this.view.setStore(null);
39758 this.view.el.removeAllListeners();
39759 this.view.el.remove();
39760 this.view.purgeListeners();
39763 this.list.destroy();
39766 this.store.un('beforeload', this.onBeforeLoad, this);
39767 this.store.un('load', this.onLoad, this);
39768 this.store.un('loadexception', this.onLoadException, this);
39770 Roo.form.ComboBox.superclass.onDestroy.call(this);
39774 fireKey : function(e){
39775 if(e.isNavKeyPress() && !this.list.isVisible()){
39776 this.fireEvent("specialkey", this, e);
39781 onResize: function(w, h){
39782 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39784 if(typeof w != 'number'){
39785 // we do not handle it!?!?
39788 var tw = this.trigger.getWidth();
39789 tw += this.addicon ? this.addicon.getWidth() : 0;
39790 tw += this.editicon ? this.editicon.getWidth() : 0;
39792 this.el.setWidth( this.adjustWidth('input', x));
39794 this.trigger.setStyle('left', x+'px');
39796 if(this.list && this.listWidth === undefined){
39797 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39798 this.list.setWidth(lw);
39799 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39807 * Allow or prevent the user from directly editing the field text. If false is passed,
39808 * the user will only be able to select from the items defined in the dropdown list. This method
39809 * is the runtime equivalent of setting the 'editable' config option at config time.
39810 * @param {Boolean} value True to allow the user to directly edit the field text
39812 setEditable : function(value){
39813 if(value == this.editable){
39816 this.editable = value;
39818 this.el.dom.setAttribute('readOnly', true);
39819 this.el.on('mousedown', this.onTriggerClick, this);
39820 this.el.addClass('x-combo-noedit');
39822 this.el.dom.setAttribute('readOnly', false);
39823 this.el.un('mousedown', this.onTriggerClick, this);
39824 this.el.removeClass('x-combo-noedit');
39829 onBeforeLoad : function(){
39830 if(!this.hasFocus){
39833 this.innerList.update(this.loadingText ?
39834 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39835 this.restrictHeight();
39836 this.selectedIndex = -1;
39840 onLoad : function(){
39841 if(!this.hasFocus){
39844 if(this.store.getCount() > 0){
39846 this.restrictHeight();
39847 if(this.lastQuery == this.allQuery){
39849 this.el.dom.select();
39851 if(!this.selectByValue(this.value, true)){
39852 this.select(0, true);
39856 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39857 this.taTask.delay(this.typeAheadDelay);
39861 this.onEmptyResults();
39866 onLoadException : function()
39869 Roo.log(this.store.reader.jsonData);
39870 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39871 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39877 onTypeAhead : function(){
39878 if(this.store.getCount() > 0){
39879 var r = this.store.getAt(0);
39880 var newValue = r.data[this.displayField];
39881 var len = newValue.length;
39882 var selStart = this.getRawValue().length;
39883 if(selStart != len){
39884 this.setRawValue(newValue);
39885 this.selectText(selStart, newValue.length);
39891 onSelect : function(record, index){
39892 if(this.fireEvent('beforeselect', this, record, index) !== false){
39893 this.setFromData(index > -1 ? record.data : false);
39895 this.fireEvent('select', this, record, index);
39900 * Returns the currently selected field value or empty string if no value is set.
39901 * @return {String} value The selected value
39903 getValue : function(){
39904 if(this.valueField){
39905 return typeof this.value != 'undefined' ? this.value : '';
39907 return Roo.form.ComboBox.superclass.getValue.call(this);
39911 * Clears any text/value currently set in the field
39913 clearValue : function(){
39914 if(this.hiddenField){
39915 this.hiddenField.value = '';
39918 this.setRawValue('');
39919 this.lastSelectionText = '';
39924 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39925 * will be displayed in the field. If the value does not match the data value of an existing item,
39926 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39927 * Otherwise the field will be blank (although the value will still be set).
39928 * @param {String} value The value to match
39930 setValue : function(v){
39932 if(this.valueField){
39933 var r = this.findRecord(this.valueField, v);
39935 text = r.data[this.displayField];
39936 }else if(this.valueNotFoundText !== undefined){
39937 text = this.valueNotFoundText;
39940 this.lastSelectionText = text;
39941 if(this.hiddenField){
39942 this.hiddenField.value = v;
39944 Roo.form.ComboBox.superclass.setValue.call(this, text);
39948 * @property {Object} the last set data for the element
39953 * Sets the value of the field based on a object which is related to the record format for the store.
39954 * @param {Object} value the value to set as. or false on reset?
39956 setFromData : function(o){
39957 var dv = ''; // display value
39958 var vv = ''; // value value..
39960 if (this.displayField) {
39961 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39963 // this is an error condition!!!
39964 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39967 if(this.valueField){
39968 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39970 if(this.hiddenField){
39971 this.hiddenField.value = vv;
39973 this.lastSelectionText = dv;
39974 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39978 // no hidden field.. - we store the value in 'value', but still display
39979 // display field!!!!
39980 this.lastSelectionText = dv;
39981 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39987 reset : function(){
39988 // overridden so that last data is reset..
39989 this.setValue(this.resetValue);
39990 this.clearInvalid();
39991 this.lastData = false;
39993 this.view.clearSelections();
39997 findRecord : function(prop, value){
39999 if(this.store.getCount() > 0){
40000 this.store.each(function(r){
40001 if(r.data[prop] == value){
40011 getName: function()
40013 // returns hidden if it's set..
40014 if (!this.rendered) {return ''};
40015 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40019 onViewMove : function(e, t){
40020 this.inKeyMode = false;
40024 onViewOver : function(e, t){
40025 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
40028 var item = this.view.findItemFromChild(t);
40030 var index = this.view.indexOf(item);
40031 this.select(index, false);
40036 onViewClick : function(doFocus)
40038 var index = this.view.getSelectedIndexes()[0];
40039 var r = this.store.getAt(index);
40041 this.onSelect(r, index);
40043 if(doFocus !== false && !this.blockFocus){
40049 restrictHeight : function(){
40050 this.innerList.dom.style.height = '';
40051 var inner = this.innerList.dom;
40052 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
40053 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
40054 this.list.beginUpdate();
40055 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
40056 this.list.alignTo(this.el, this.listAlign);
40057 this.list.endUpdate();
40061 onEmptyResults : function(){
40066 * Returns true if the dropdown list is expanded, else false.
40068 isExpanded : function(){
40069 return this.list.isVisible();
40073 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
40074 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40075 * @param {String} value The data value of the item to select
40076 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40077 * selected item if it is not currently in view (defaults to true)
40078 * @return {Boolean} True if the value matched an item in the list, else false
40080 selectByValue : function(v, scrollIntoView){
40081 if(v !== undefined && v !== null){
40082 var r = this.findRecord(this.valueField || this.displayField, v);
40084 this.select(this.store.indexOf(r), scrollIntoView);
40092 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
40093 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40094 * @param {Number} index The zero-based index of the list item to select
40095 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40096 * selected item if it is not currently in view (defaults to true)
40098 select : function(index, scrollIntoView){
40099 this.selectedIndex = index;
40100 this.view.select(index);
40101 if(scrollIntoView !== false){
40102 var el = this.view.getNode(index);
40104 this.innerList.scrollChildIntoView(el, false);
40110 selectNext : function(){
40111 var ct = this.store.getCount();
40113 if(this.selectedIndex == -1){
40115 }else if(this.selectedIndex < ct-1){
40116 this.select(this.selectedIndex+1);
40122 selectPrev : function(){
40123 var ct = this.store.getCount();
40125 if(this.selectedIndex == -1){
40127 }else if(this.selectedIndex != 0){
40128 this.select(this.selectedIndex-1);
40134 onKeyUp : function(e){
40135 if(this.editable !== false && !e.isSpecialKey()){
40136 this.lastKey = e.getKey();
40137 this.dqTask.delay(this.queryDelay);
40142 validateBlur : function(){
40143 return !this.list || !this.list.isVisible();
40147 initQuery : function(){
40148 this.doQuery(this.getRawValue());
40152 doForce : function(){
40153 if(this.el.dom.value.length > 0){
40154 this.el.dom.value =
40155 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
40161 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
40162 * query allowing the query action to be canceled if needed.
40163 * @param {String} query The SQL query to execute
40164 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
40165 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
40166 * saved in the current store (defaults to false)
40168 doQuery : function(q, forceAll){
40169 if(q === undefined || q === null){
40174 forceAll: forceAll,
40178 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
40182 forceAll = qe.forceAll;
40183 if(forceAll === true || (q.length >= this.minChars)){
40184 if(this.lastQuery != q || this.alwaysQuery){
40185 this.lastQuery = q;
40186 if(this.mode == 'local'){
40187 this.selectedIndex = -1;
40189 this.store.clearFilter();
40191 this.store.filter(this.displayField, q);
40195 this.store.baseParams[this.queryParam] = q;
40197 params: this.getParams(q)
40202 this.selectedIndex = -1;
40209 getParams : function(q){
40211 //p[this.queryParam] = q;
40214 p.limit = this.pageSize;
40220 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40222 collapse : function(){
40223 if(!this.isExpanded()){
40227 Roo.get(document).un('mousedown', this.collapseIf, this);
40228 Roo.get(document).un('mousewheel', this.collapseIf, this);
40229 if (!this.editable) {
40230 Roo.get(document).un('keydown', this.listKeyPress, this);
40232 this.fireEvent('collapse', this);
40236 collapseIf : function(e){
40237 if(!e.within(this.wrap) && !e.within(this.list)){
40243 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40245 expand : function(){
40246 if(this.isExpanded() || !this.hasFocus){
40249 this.list.alignTo(this.el, this.listAlign);
40251 Roo.get(document).on('mousedown', this.collapseIf, this);
40252 Roo.get(document).on('mousewheel', this.collapseIf, this);
40253 if (!this.editable) {
40254 Roo.get(document).on('keydown', this.listKeyPress, this);
40257 this.fireEvent('expand', this);
40261 // Implements the default empty TriggerField.onTriggerClick function
40262 onTriggerClick : function(){
40266 if(this.isExpanded()){
40268 if (!this.blockFocus) {
40273 this.hasFocus = true;
40274 if(this.triggerAction == 'all') {
40275 this.doQuery(this.allQuery, true);
40277 this.doQuery(this.getRawValue());
40279 if (!this.blockFocus) {
40284 listKeyPress : function(e)
40286 //Roo.log('listkeypress');
40287 // scroll to first matching element based on key pres..
40288 if (e.isSpecialKey()) {
40291 var k = String.fromCharCode(e.getKey()).toUpperCase();
40294 var csel = this.view.getSelectedNodes();
40295 var cselitem = false;
40297 var ix = this.view.indexOf(csel[0]);
40298 cselitem = this.store.getAt(ix);
40299 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40305 this.store.each(function(v) {
40307 // start at existing selection.
40308 if (cselitem.id == v.id) {
40314 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40315 match = this.store.indexOf(v);
40320 if (match === false) {
40321 return true; // no more action?
40324 this.view.select(match);
40325 var sn = Roo.get(this.view.getSelectedNodes()[0])
40326 sn.scrollIntoView(sn.dom.parentNode, false);
40330 * @cfg {Boolean} grow
40334 * @cfg {Number} growMin
40338 * @cfg {Number} growMax
40346 * Copyright(c) 2010-2012, Roo J Solutions Limited
40353 * @class Roo.form.ComboBoxArray
40354 * @extends Roo.form.TextField
40355 * A facebook style adder... for lists of email / people / countries etc...
40356 * pick multiple items from a combo box, and shows each one.
40358 * Fred [x] Brian [x] [Pick another |v]
40361 * For this to work: it needs various extra information
40362 * - normal combo problay has
40364 * + displayField, valueField
40366 * For our purpose...
40369 * If we change from 'extends' to wrapping...
40376 * Create a new ComboBoxArray.
40377 * @param {Object} config Configuration options
40381 Roo.form.ComboBoxArray = function(config)
40385 * @event beforeremove
40386 * Fires before remove the value from the list
40387 * @param {Roo.form.ComboBoxArray} _self This combo box array
40388 * @param {Roo.form.ComboBoxArray.Item} item removed item
40390 'beforeremove' : true,
40393 * Fires when remove the value from the list
40394 * @param {Roo.form.ComboBoxArray} _self This combo box array
40395 * @param {Roo.form.ComboBoxArray.Item} item removed item
40402 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40404 this.items = new Roo.util.MixedCollection(false);
40406 // construct the child combo...
40416 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40419 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40424 // behavies liek a hiddne field
40425 inputType: 'hidden',
40427 * @cfg {Number} width The width of the box that displays the selected element
40434 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40438 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40440 hiddenName : false,
40443 // private the array of items that are displayed..
40445 // private - the hidden field el.
40447 // private - the filed el..
40450 //validateValue : function() { return true; }, // all values are ok!
40451 //onAddClick: function() { },
40453 onRender : function(ct, position)
40456 // create the standard hidden element
40457 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40460 // give fake names to child combo;
40461 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40462 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40464 this.combo = Roo.factory(this.combo, Roo.form);
40465 this.combo.onRender(ct, position);
40466 if (typeof(this.combo.width) != 'undefined') {
40467 this.combo.onResize(this.combo.width,0);
40470 this.combo.initEvents();
40472 // assigned so form know we need to do this..
40473 this.store = this.combo.store;
40474 this.valueField = this.combo.valueField;
40475 this.displayField = this.combo.displayField ;
40478 this.combo.wrap.addClass('x-cbarray-grp');
40480 var cbwrap = this.combo.wrap.createChild(
40481 {tag: 'div', cls: 'x-cbarray-cb'},
40486 this.hiddenEl = this.combo.wrap.createChild({
40487 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40489 this.el = this.combo.wrap.createChild({
40490 tag: 'input', type:'hidden' , name: this.name, value : ''
40492 // this.el.dom.removeAttribute("name");
40495 this.outerWrap = this.combo.wrap;
40496 this.wrap = cbwrap;
40498 this.outerWrap.setWidth(this.width);
40499 this.outerWrap.dom.removeChild(this.el.dom);
40501 this.wrap.dom.appendChild(this.el.dom);
40502 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40503 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40505 this.combo.trigger.setStyle('position','relative');
40506 this.combo.trigger.setStyle('left', '0px');
40507 this.combo.trigger.setStyle('top', '2px');
40509 this.combo.el.setStyle('vertical-align', 'text-bottom');
40511 //this.trigger.setStyle('vertical-align', 'top');
40513 // this should use the code from combo really... on('add' ....)
40517 this.adder = this.outerWrap.createChild(
40518 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40520 this.adder.on('click', function(e) {
40521 _t.fireEvent('adderclick', this, e);
40525 //this.adder.on('click', this.onAddClick, _t);
40528 this.combo.on('select', function(cb, rec, ix) {
40529 this.addItem(rec.data);
40532 cb.el.dom.value = '';
40533 //cb.lastData = rec.data;
40542 getName: function()
40544 // returns hidden if it's set..
40545 if (!this.rendered) {return ''};
40546 return this.hiddenName ? this.hiddenName : this.name;
40551 onResize: function(w, h){
40554 // not sure if this is needed..
40555 //this.combo.onResize(w,h);
40557 if(typeof w != 'number'){
40558 // we do not handle it!?!?
40561 var tw = this.combo.trigger.getWidth();
40562 tw += this.addicon ? this.addicon.getWidth() : 0;
40563 tw += this.editicon ? this.editicon.getWidth() : 0;
40565 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40567 this.combo.trigger.setStyle('left', '0px');
40569 if(this.list && this.listWidth === undefined){
40570 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40571 this.list.setWidth(lw);
40572 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40579 addItem: function(rec)
40581 var valueField = this.combo.valueField;
40582 var displayField = this.combo.displayField;
40583 if (this.items.indexOfKey(rec[valueField]) > -1) {
40584 //console.log("GOT " + rec.data.id);
40588 var x = new Roo.form.ComboBoxArray.Item({
40589 //id : rec[this.idField],
40591 displayField : displayField ,
40592 tipField : displayField ,
40596 this.items.add(rec[valueField],x);
40597 // add it before the element..
40598 this.updateHiddenEl();
40599 x.render(this.outerWrap, this.wrap.dom);
40600 // add the image handler..
40603 updateHiddenEl : function()
40606 if (!this.hiddenEl) {
40610 var idField = this.combo.valueField;
40612 this.items.each(function(f) {
40613 ar.push(f.data[idField]);
40616 this.hiddenEl.dom.value = ar.join(',');
40622 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40623 this.items.each(function(f) {
40626 this.el.dom.value = '';
40627 if (this.hiddenEl) {
40628 this.hiddenEl.dom.value = '';
40632 getValue: function()
40634 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40636 setValue: function(v) // not a valid action - must use addItems..
40643 if (this.store.isLocal && (typeof(v) == 'string')) {
40644 // then we can use the store to find the values..
40645 // comma seperated at present.. this needs to allow JSON based encoding..
40646 this.hiddenEl.value = v;
40648 Roo.each(v.split(','), function(k) {
40649 Roo.log("CHECK " + this.valueField + ',' + k);
40650 var li = this.store.query(this.valueField, k);
40655 add[this.valueField] = k;
40656 add[this.displayField] = li.item(0).data[this.displayField];
40662 if (typeof(v) == 'object' ) {
40663 // then let's assume it's an array of objects..
40664 Roo.each(v, function(l) {
40672 setFromData: function(v)
40674 // this recieves an object, if setValues is called.
40676 this.el.dom.value = v[this.displayField];
40677 this.hiddenEl.dom.value = v[this.valueField];
40678 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40681 var kv = v[this.valueField];
40682 var dv = v[this.displayField];
40683 kv = typeof(kv) != 'string' ? '' : kv;
40684 dv = typeof(dv) != 'string' ? '' : dv;
40687 var keys = kv.split(',');
40688 var display = dv.split(',');
40689 for (var i = 0 ; i < keys.length; i++) {
40692 add[this.valueField] = keys[i];
40693 add[this.displayField] = display[i];
40701 * Validates the combox array value
40702 * @return {Boolean} True if the value is valid, else false
40704 validate : function(){
40705 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40706 this.clearInvalid();
40712 validateValue : function(value){
40713 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40721 isDirty : function() {
40722 if(this.disabled) {
40727 var d = Roo.decode(String(this.originalValue));
40729 return String(this.getValue()) !== String(this.originalValue);
40732 var originalValue = [];
40734 for (var i = 0; i < d.length; i++){
40735 originalValue.push(d[i][this.valueField]);
40738 return String(this.getValue()) !== String(originalValue.join(','));
40747 * @class Roo.form.ComboBoxArray.Item
40748 * @extends Roo.BoxComponent
40749 * A selected item in the list
40750 * Fred [x] Brian [x] [Pick another |v]
40753 * Create a new item.
40754 * @param {Object} config Configuration options
40757 Roo.form.ComboBoxArray.Item = function(config) {
40758 config.id = Roo.id();
40759 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40762 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40765 displayField : false,
40769 defaultAutoCreate : {
40771 cls: 'x-cbarray-item',
40778 src : Roo.BLANK_IMAGE_URL ,
40786 onRender : function(ct, position)
40788 Roo.form.Field.superclass.onRender.call(this, ct, position);
40791 var cfg = this.getAutoCreate();
40792 this.el = ct.createChild(cfg, position);
40795 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40797 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40798 this.cb.renderer(this.data) :
40799 String.format('{0}',this.data[this.displayField]);
40802 this.el.child('div').dom.setAttribute('qtip',
40803 String.format('{0}',this.data[this.tipField])
40806 this.el.child('img').on('click', this.remove, this);
40810 remove : function()
40812 if(this.cb.disabled){
40816 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
40817 this.cb.items.remove(this);
40818 this.el.child('img').un('click', this.remove, this);
40820 this.cb.updateHiddenEl();
40822 this.cb.fireEvent('remove', this.cb, this);
40828 * Ext JS Library 1.1.1
40829 * Copyright(c) 2006-2007, Ext JS, LLC.
40831 * Originally Released Under LGPL - original licence link has changed is not relivant.
40834 * <script type="text/javascript">
40837 * @class Roo.form.Checkbox
40838 * @extends Roo.form.Field
40839 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40841 * Creates a new Checkbox
40842 * @param {Object} config Configuration options
40844 Roo.form.Checkbox = function(config){
40845 Roo.form.Checkbox.superclass.constructor.call(this, config);
40849 * Fires when the checkbox is checked or unchecked.
40850 * @param {Roo.form.Checkbox} this This checkbox
40851 * @param {Boolean} checked The new checked value
40857 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40859 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40861 focusClass : undefined,
40863 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40865 fieldClass: "x-form-field",
40867 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40871 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40872 * {tag: "input", type: "checkbox", autocomplete: "off"})
40874 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40876 * @cfg {String} boxLabel The text that appears beside the checkbox
40880 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40884 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40886 valueOff: '0', // value when not checked..
40888 actionMode : 'viewEl',
40891 itemCls : 'x-menu-check-item x-form-item',
40892 groupClass : 'x-menu-group-item',
40893 inputType : 'hidden',
40896 inSetChecked: false, // check that we are not calling self...
40898 inputElement: false, // real input element?
40899 basedOn: false, // ????
40901 isFormField: true, // not sure where this is needed!!!!
40903 onResize : function(){
40904 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40905 if(!this.boxLabel){
40906 this.el.alignTo(this.wrap, 'c-c');
40910 initEvents : function(){
40911 Roo.form.Checkbox.superclass.initEvents.call(this);
40912 this.el.on("click", this.onClick, this);
40913 this.el.on("change", this.onClick, this);
40917 getResizeEl : function(){
40921 getPositionEl : function(){
40926 onRender : function(ct, position){
40927 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40929 if(this.inputValue !== undefined){
40930 this.el.dom.value = this.inputValue;
40933 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40934 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40935 var viewEl = this.wrap.createChild({
40936 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40937 this.viewEl = viewEl;
40938 this.wrap.on('click', this.onClick, this);
40940 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40941 this.el.on('propertychange', this.setFromHidden, this); //ie
40946 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40947 // viewEl.on('click', this.onClick, this);
40949 //if(this.checked){
40950 this.setChecked(this.checked);
40952 //this.checked = this.el.dom;
40958 initValue : Roo.emptyFn,
40961 * Returns the checked state of the checkbox.
40962 * @return {Boolean} True if checked, else false
40964 getValue : function(){
40966 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40968 return this.valueOff;
40973 onClick : function(){
40974 if (this.disabled) {
40977 this.setChecked(!this.checked);
40979 //if(this.el.dom.checked != this.checked){
40980 // this.setValue(this.el.dom.checked);
40985 * Sets the checked state of the checkbox.
40986 * On is always based on a string comparison between inputValue and the param.
40987 * @param {Boolean/String} value - the value to set
40988 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40990 setValue : function(v,suppressEvent){
40993 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40994 //if(this.el && this.el.dom){
40995 // this.el.dom.checked = this.checked;
40996 // this.el.dom.defaultChecked = this.checked;
40998 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40999 //this.fireEvent("check", this, this.checked);
41002 setChecked : function(state,suppressEvent)
41004 if (this.inSetChecked) {
41005 this.checked = state;
41011 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
41013 this.checked = state;
41014 if(suppressEvent !== true){
41015 this.fireEvent('check', this, state);
41017 this.inSetChecked = true;
41018 this.el.dom.value = state ? this.inputValue : this.valueOff;
41019 this.inSetChecked = false;
41022 // handle setting of hidden value by some other method!!?!?
41023 setFromHidden: function()
41028 //console.log("SET FROM HIDDEN");
41029 //alert('setFrom hidden');
41030 this.setValue(this.el.dom.value);
41033 onDestroy : function()
41036 Roo.get(this.viewEl).remove();
41039 Roo.form.Checkbox.superclass.onDestroy.call(this);
41044 * Ext JS Library 1.1.1
41045 * Copyright(c) 2006-2007, Ext JS, LLC.
41047 * Originally Released Under LGPL - original licence link has changed is not relivant.
41050 * <script type="text/javascript">
41054 * @class Roo.form.Radio
41055 * @extends Roo.form.Checkbox
41056 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
41057 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
41059 * Creates a new Radio
41060 * @param {Object} config Configuration options
41062 Roo.form.Radio = function(){
41063 Roo.form.Radio.superclass.constructor.apply(this, arguments);
41065 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
41066 inputType: 'radio',
41069 * If this radio is part of a group, it will return the selected value
41072 getGroupValue : function(){
41073 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
41077 onRender : function(ct, position){
41078 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
41080 if(this.inputValue !== undefined){
41081 this.el.dom.value = this.inputValue;
41084 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
41085 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
41086 //var viewEl = this.wrap.createChild({
41087 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
41088 //this.viewEl = viewEl;
41089 //this.wrap.on('click', this.onClick, this);
41091 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
41092 //this.el.on('propertychange', this.setFromHidden, this); //ie
41097 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
41098 // viewEl.on('click', this.onClick, this);
41101 this.el.dom.checked = 'checked' ;
41107 });//<script type="text/javascript">
41110 * Based Ext JS Library 1.1.1
41111 * Copyright(c) 2006-2007, Ext JS, LLC.
41117 * @class Roo.HtmlEditorCore
41118 * @extends Roo.Component
41119 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
41121 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
41124 Roo.HtmlEditorCore = function(config){
41127 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
41132 * @event initialize
41133 * Fires when the editor is fully initialized (including the iframe)
41134 * @param {Roo.HtmlEditorCore} this
41139 * Fires when the editor is first receives the focus. Any insertion must wait
41140 * until after this event.
41141 * @param {Roo.HtmlEditorCore} this
41145 * @event beforesync
41146 * Fires before the textarea is updated with content from the editor iframe. Return false
41147 * to cancel the sync.
41148 * @param {Roo.HtmlEditorCore} this
41149 * @param {String} html
41153 * @event beforepush
41154 * Fires before the iframe editor is updated with content from the textarea. Return false
41155 * to cancel the push.
41156 * @param {Roo.HtmlEditorCore} this
41157 * @param {String} html
41162 * Fires when the textarea is updated with content from the editor iframe.
41163 * @param {Roo.HtmlEditorCore} this
41164 * @param {String} html
41169 * Fires when the iframe editor is updated with content from the textarea.
41170 * @param {Roo.HtmlEditorCore} this
41171 * @param {String} html
41176 * @event editorevent
41177 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41178 * @param {Roo.HtmlEditorCore} this
41184 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
41186 // defaults : white / black...
41187 this.applyBlacklists();
41194 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41198 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41204 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41209 * @cfg {Number} height (in pixels)
41213 * @cfg {Number} width (in pixels)
41218 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41221 stylesheets: false,
41226 // private properties
41227 validationEvent : false,
41229 initialized : false,
41231 sourceEditMode : false,
41232 onFocus : Roo.emptyFn,
41234 hideMode:'offsets',
41238 // blacklist + whitelisted elements..
41245 * Protected method that will not generally be called directly. It
41246 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41247 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41249 getDocMarkup : function(){
41253 // inherit styels from page...??
41254 if (this.stylesheets === false) {
41256 Roo.get(document.head).select('style').each(function(node) {
41257 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41260 Roo.get(document.head).select('link').each(function(node) {
41261 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41264 } else if (!this.stylesheets.length) {
41266 st = '<style type="text/css">' +
41267 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41273 st += '<style type="text/css">' +
41274 'IMG { cursor: pointer } ' +
41278 return '<html><head>' + st +
41279 //<style type="text/css">' +
41280 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41282 ' </head><body class="roo-htmleditor-body"></body></html>';
41286 onRender : function(ct, position)
41289 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41290 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41293 this.el.dom.style.border = '0 none';
41294 this.el.dom.setAttribute('tabIndex', -1);
41295 this.el.addClass('x-hidden hide');
41299 if(Roo.isIE){ // fix IE 1px bogus margin
41300 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41304 this.frameId = Roo.id();
41308 var iframe = this.owner.wrap.createChild({
41310 cls: 'form-control', // bootstrap..
41312 name: this.frameId,
41313 frameBorder : 'no',
41314 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41319 this.iframe = iframe.dom;
41321 this.assignDocWin();
41323 this.doc.designMode = 'on';
41326 this.doc.write(this.getDocMarkup());
41330 var task = { // must defer to wait for browser to be ready
41332 //console.log("run task?" + this.doc.readyState);
41333 this.assignDocWin();
41334 if(this.doc.body || this.doc.readyState == 'complete'){
41336 this.doc.designMode="on";
41340 Roo.TaskMgr.stop(task);
41341 this.initEditor.defer(10, this);
41348 Roo.TaskMgr.start(task);
41353 onResize : function(w, h)
41355 Roo.log('resize: ' +w + ',' + h );
41356 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41360 if(typeof w == 'number'){
41362 this.iframe.style.width = w + 'px';
41364 if(typeof h == 'number'){
41366 this.iframe.style.height = h + 'px';
41368 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41375 * Toggles the editor between standard and source edit mode.
41376 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41378 toggleSourceEdit : function(sourceEditMode){
41380 this.sourceEditMode = sourceEditMode === true;
41382 if(this.sourceEditMode){
41384 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41387 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41388 //this.iframe.className = '';
41391 //this.setSize(this.owner.wrap.getSize());
41392 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41399 * Protected method that will not generally be called directly. If you need/want
41400 * custom HTML cleanup, this is the method you should override.
41401 * @param {String} html The HTML to be cleaned
41402 * return {String} The cleaned HTML
41404 cleanHtml : function(html){
41405 html = String(html);
41406 if(html.length > 5){
41407 if(Roo.isSafari){ // strip safari nonsense
41408 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41411 if(html == ' '){
41418 * HTML Editor -> Textarea
41419 * Protected method that will not generally be called directly. Syncs the contents
41420 * of the editor iframe with the textarea.
41422 syncValue : function(){
41423 if(this.initialized){
41424 var bd = (this.doc.body || this.doc.documentElement);
41425 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41426 var html = bd.innerHTML;
41428 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41429 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41431 html = '<div style="'+m[0]+'">' + html + '</div>';
41434 html = this.cleanHtml(html);
41435 // fix up the special chars.. normaly like back quotes in word...
41436 // however we do not want to do this with chinese..
41437 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41438 var cc = b.charCodeAt();
41440 (cc >= 0x4E00 && cc < 0xA000 ) ||
41441 (cc >= 0x3400 && cc < 0x4E00 ) ||
41442 (cc >= 0xf900 && cc < 0xfb00 )
41448 if(this.owner.fireEvent('beforesync', this, html) !== false){
41449 this.el.dom.value = html;
41450 this.owner.fireEvent('sync', this, html);
41456 * Protected method that will not generally be called directly. Pushes the value of the textarea
41457 * into the iframe editor.
41459 pushValue : function(){
41460 if(this.initialized){
41461 var v = this.el.dom.value.trim();
41463 // if(v.length < 1){
41467 if(this.owner.fireEvent('beforepush', this, v) !== false){
41468 var d = (this.doc.body || this.doc.documentElement);
41470 this.cleanUpPaste();
41471 this.el.dom.value = d.innerHTML;
41472 this.owner.fireEvent('push', this, v);
41478 deferFocus : function(){
41479 this.focus.defer(10, this);
41483 focus : function(){
41484 if(this.win && !this.sourceEditMode){
41491 assignDocWin: function()
41493 var iframe = this.iframe;
41496 this.doc = iframe.contentWindow.document;
41497 this.win = iframe.contentWindow;
41499 // if (!Roo.get(this.frameId)) {
41502 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41503 // this.win = Roo.get(this.frameId).dom.contentWindow;
41505 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
41509 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41510 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
41515 initEditor : function(){
41516 //console.log("INIT EDITOR");
41517 this.assignDocWin();
41521 this.doc.designMode="on";
41523 this.doc.write(this.getDocMarkup());
41526 var dbody = (this.doc.body || this.doc.documentElement);
41527 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41528 // this copies styles from the containing element into thsi one..
41529 // not sure why we need all of this..
41530 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41532 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41533 //ss['background-attachment'] = 'fixed'; // w3c
41534 dbody.bgProperties = 'fixed'; // ie
41535 //Roo.DomHelper.applyStyles(dbody, ss);
41536 Roo.EventManager.on(this.doc, {
41537 //'mousedown': this.onEditorEvent,
41538 'mouseup': this.onEditorEvent,
41539 'dblclick': this.onEditorEvent,
41540 'click': this.onEditorEvent,
41541 'keyup': this.onEditorEvent,
41546 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41548 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41549 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41551 this.initialized = true;
41553 this.owner.fireEvent('initialize', this);
41558 onDestroy : function(){
41564 //for (var i =0; i < this.toolbars.length;i++) {
41565 // // fixme - ask toolbars for heights?
41566 // this.toolbars[i].onDestroy();
41569 //this.wrap.dom.innerHTML = '';
41570 //this.wrap.remove();
41575 onFirstFocus : function(){
41577 this.assignDocWin();
41580 this.activated = true;
41583 if(Roo.isGecko){ // prevent silly gecko errors
41585 var s = this.win.getSelection();
41586 if(!s.focusNode || s.focusNode.nodeType != 3){
41587 var r = s.getRangeAt(0);
41588 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41593 this.execCmd('useCSS', true);
41594 this.execCmd('styleWithCSS', false);
41597 this.owner.fireEvent('activate', this);
41601 adjustFont: function(btn){
41602 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41603 //if(Roo.isSafari){ // safari
41606 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41607 if(Roo.isSafari){ // safari
41608 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41609 v = (v < 10) ? 10 : v;
41610 v = (v > 48) ? 48 : v;
41611 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41616 v = Math.max(1, v+adjust);
41618 this.execCmd('FontSize', v );
41621 onEditorEvent : function(e)
41623 this.owner.fireEvent('editorevent', this, e);
41624 // this.updateToolbar();
41625 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41628 insertTag : function(tg)
41630 // could be a bit smarter... -> wrap the current selected tRoo..
41631 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41633 range = this.createRange(this.getSelection());
41634 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41635 wrappingNode.appendChild(range.extractContents());
41636 range.insertNode(wrappingNode);
41643 this.execCmd("formatblock", tg);
41647 insertText : function(txt)
41651 var range = this.createRange();
41652 range.deleteContents();
41653 //alert(Sender.getAttribute('label'));
41655 range.insertNode(this.doc.createTextNode(txt));
41661 * Executes a Midas editor command on the editor document and performs necessary focus and
41662 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41663 * @param {String} cmd The Midas command
41664 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41666 relayCmd : function(cmd, value){
41668 this.execCmd(cmd, value);
41669 this.owner.fireEvent('editorevent', this);
41670 //this.updateToolbar();
41671 this.owner.deferFocus();
41675 * Executes a Midas editor command directly on the editor document.
41676 * For visual commands, you should use {@link #relayCmd} instead.
41677 * <b>This should only be called after the editor is initialized.</b>
41678 * @param {String} cmd The Midas command
41679 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41681 execCmd : function(cmd, value){
41682 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41689 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41691 * @param {String} text | dom node..
41693 insertAtCursor : function(text)
41698 if(!this.activated){
41704 var r = this.doc.selection.createRange();
41715 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41719 // from jquery ui (MIT licenced)
41721 var win = this.win;
41723 if (win.getSelection && win.getSelection().getRangeAt) {
41724 range = win.getSelection().getRangeAt(0);
41725 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41726 range.insertNode(node);
41727 } else if (win.document.selection && win.document.selection.createRange) {
41728 // no firefox support
41729 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41730 win.document.selection.createRange().pasteHTML(txt);
41732 // no firefox support
41733 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41734 this.execCmd('InsertHTML', txt);
41743 mozKeyPress : function(e){
41745 var c = e.getCharCode(), cmd;
41748 c = String.fromCharCode(c).toLowerCase();
41762 this.cleanUpPaste.defer(100, this);
41770 e.preventDefault();
41778 fixKeys : function(){ // load time branching for fastest keydown performance
41780 return function(e){
41781 var k = e.getKey(), r;
41784 r = this.doc.selection.createRange();
41787 r.pasteHTML('    ');
41794 r = this.doc.selection.createRange();
41796 var target = r.parentElement();
41797 if(!target || target.tagName.toLowerCase() != 'li'){
41799 r.pasteHTML('<br />');
41805 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41806 this.cleanUpPaste.defer(100, this);
41812 }else if(Roo.isOpera){
41813 return function(e){
41814 var k = e.getKey();
41818 this.execCmd('InsertHTML','    ');
41821 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41822 this.cleanUpPaste.defer(100, this);
41827 }else if(Roo.isSafari){
41828 return function(e){
41829 var k = e.getKey();
41833 this.execCmd('InsertText','\t');
41837 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41838 this.cleanUpPaste.defer(100, this);
41846 getAllAncestors: function()
41848 var p = this.getSelectedNode();
41851 a.push(p); // push blank onto stack..
41852 p = this.getParentElement();
41856 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41860 a.push(this.doc.body);
41864 lastSelNode : false,
41867 getSelection : function()
41869 this.assignDocWin();
41870 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41873 getSelectedNode: function()
41875 // this may only work on Gecko!!!
41877 // should we cache this!!!!
41882 var range = this.createRange(this.getSelection()).cloneRange();
41885 var parent = range.parentElement();
41887 var testRange = range.duplicate();
41888 testRange.moveToElementText(parent);
41889 if (testRange.inRange(range)) {
41892 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41895 parent = parent.parentElement;
41900 // is ancestor a text element.
41901 var ac = range.commonAncestorContainer;
41902 if (ac.nodeType == 3) {
41903 ac = ac.parentNode;
41906 var ar = ac.childNodes;
41909 var other_nodes = [];
41910 var has_other_nodes = false;
41911 for (var i=0;i<ar.length;i++) {
41912 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41915 // fullly contained node.
41917 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41922 // probably selected..
41923 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41924 other_nodes.push(ar[i]);
41928 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41933 has_other_nodes = true;
41935 if (!nodes.length && other_nodes.length) {
41936 nodes= other_nodes;
41938 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41944 createRange: function(sel)
41946 // this has strange effects when using with
41947 // top toolbar - not sure if it's a great idea.
41948 //this.editor.contentWindow.focus();
41949 if (typeof sel != "undefined") {
41951 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41953 return this.doc.createRange();
41956 return this.doc.createRange();
41959 getParentElement: function()
41962 this.assignDocWin();
41963 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41965 var range = this.createRange(sel);
41968 var p = range.commonAncestorContainer;
41969 while (p.nodeType == 3) { // text node
41980 * Range intersection.. the hard stuff...
41984 * [ -- selected range --- ]
41988 * if end is before start or hits it. fail.
41989 * if start is after end or hits it fail.
41991 * if either hits (but other is outside. - then it's not
41997 // @see http://www.thismuchiknow.co.uk/?p=64.
41998 rangeIntersectsNode : function(range, node)
42000 var nodeRange = node.ownerDocument.createRange();
42002 nodeRange.selectNode(node);
42004 nodeRange.selectNodeContents(node);
42007 var rangeStartRange = range.cloneRange();
42008 rangeStartRange.collapse(true);
42010 var rangeEndRange = range.cloneRange();
42011 rangeEndRange.collapse(false);
42013 var nodeStartRange = nodeRange.cloneRange();
42014 nodeStartRange.collapse(true);
42016 var nodeEndRange = nodeRange.cloneRange();
42017 nodeEndRange.collapse(false);
42019 return rangeStartRange.compareBoundaryPoints(
42020 Range.START_TO_START, nodeEndRange) == -1 &&
42021 rangeEndRange.compareBoundaryPoints(
42022 Range.START_TO_START, nodeStartRange) == 1;
42026 rangeCompareNode : function(range, node)
42028 var nodeRange = node.ownerDocument.createRange();
42030 nodeRange.selectNode(node);
42032 nodeRange.selectNodeContents(node);
42036 range.collapse(true);
42038 nodeRange.collapse(true);
42040 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
42041 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
42043 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
42045 var nodeIsBefore = ss == 1;
42046 var nodeIsAfter = ee == -1;
42048 if (nodeIsBefore && nodeIsAfter)
42050 if (!nodeIsBefore && nodeIsAfter)
42051 return 1; //right trailed.
42053 if (nodeIsBefore && !nodeIsAfter)
42054 return 2; // left trailed.
42059 // private? - in a new class?
42060 cleanUpPaste : function()
42062 // cleans up the whole document..
42063 Roo.log('cleanuppaste');
42065 this.cleanUpChildren(this.doc.body);
42066 var clean = this.cleanWordChars(this.doc.body.innerHTML);
42067 if (clean != this.doc.body.innerHTML) {
42068 this.doc.body.innerHTML = clean;
42073 cleanWordChars : function(input) {// change the chars to hex code
42074 var he = Roo.HtmlEditorCore;
42076 var output = input;
42077 Roo.each(he.swapCodes, function(sw) {
42078 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
42080 output = output.replace(swapper, sw[1]);
42087 cleanUpChildren : function (n)
42089 if (!n.childNodes.length) {
42092 for (var i = n.childNodes.length-1; i > -1 ; i--) {
42093 this.cleanUpChild(n.childNodes[i]);
42100 cleanUpChild : function (node)
42103 //console.log(node);
42104 if (node.nodeName == "#text") {
42105 // clean up silly Windows -- stuff?
42108 if (node.nodeName == "#comment") {
42109 node.parentNode.removeChild(node);
42110 // clean up silly Windows -- stuff?
42113 var lcname = node.tagName.toLowerCase();
42114 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
42115 // whitelist of tags..
42117 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
42119 node.parentNode.removeChild(node);
42124 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
42126 // remove <a name=....> as rendering on yahoo mailer is borked with this.
42127 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
42129 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
42130 // remove_keep_children = true;
42133 if (remove_keep_children) {
42134 this.cleanUpChildren(node);
42135 // inserts everything just before this node...
42136 while (node.childNodes.length) {
42137 var cn = node.childNodes[0];
42138 node.removeChild(cn);
42139 node.parentNode.insertBefore(cn, node);
42141 node.parentNode.removeChild(node);
42145 if (!node.attributes || !node.attributes.length) {
42146 this.cleanUpChildren(node);
42150 function cleanAttr(n,v)
42153 if (v.match(/^\./) || v.match(/^\//)) {
42156 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
42159 if (v.match(/^#/)) {
42162 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
42163 node.removeAttribute(n);
42167 var cwhite = this.cwhite;
42168 var cblack = this.cblack;
42170 function cleanStyle(n,v)
42172 if (v.match(/expression/)) { //XSS?? should we even bother..
42173 node.removeAttribute(n);
42177 var parts = v.split(/;/);
42180 Roo.each(parts, function(p) {
42181 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42185 var l = p.split(':').shift().replace(/\s+/g,'');
42186 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42188 if ( cwhite.length && cblack.indexOf(l) > -1) {
42189 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42190 //node.removeAttribute(n);
42194 // only allow 'c whitelisted system attributes'
42195 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42196 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42197 //node.removeAttribute(n);
42207 if (clean.length) {
42208 node.setAttribute(n, clean.join(';'));
42210 node.removeAttribute(n);
42216 for (var i = node.attributes.length-1; i > -1 ; i--) {
42217 var a = node.attributes[i];
42220 if (a.name.toLowerCase().substr(0,2)=='on') {
42221 node.removeAttribute(a.name);
42224 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42225 node.removeAttribute(a.name);
42228 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42229 cleanAttr(a.name,a.value); // fixme..
42232 if (a.name == 'style') {
42233 cleanStyle(a.name,a.value);
42236 /// clean up MS crap..
42237 // tecnically this should be a list of valid class'es..
42240 if (a.name == 'class') {
42241 if (a.value.match(/^Mso/)) {
42242 node.className = '';
42245 if (a.value.match(/body/)) {
42246 node.className = '';
42257 this.cleanUpChildren(node);
42263 * Clean up MS wordisms...
42265 cleanWord : function(node)
42270 this.cleanWord(this.doc.body);
42273 if (node.nodeName == "#text") {
42274 // clean up silly Windows -- stuff?
42277 if (node.nodeName == "#comment") {
42278 node.parentNode.removeChild(node);
42279 // clean up silly Windows -- stuff?
42283 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42284 node.parentNode.removeChild(node);
42288 // remove - but keep children..
42289 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42290 while (node.childNodes.length) {
42291 var cn = node.childNodes[0];
42292 node.removeChild(cn);
42293 node.parentNode.insertBefore(cn, node);
42295 node.parentNode.removeChild(node);
42296 this.iterateChildren(node, this.cleanWord);
42300 if (node.className.length) {
42302 var cn = node.className.split(/\W+/);
42304 Roo.each(cn, function(cls) {
42305 if (cls.match(/Mso[a-zA-Z]+/)) {
42310 node.className = cna.length ? cna.join(' ') : '';
42312 node.removeAttribute("class");
42316 if (node.hasAttribute("lang")) {
42317 node.removeAttribute("lang");
42320 if (node.hasAttribute("style")) {
42322 var styles = node.getAttribute("style").split(";");
42324 Roo.each(styles, function(s) {
42325 if (!s.match(/:/)) {
42328 var kv = s.split(":");
42329 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42332 // what ever is left... we allow.
42335 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42336 if (!nstyle.length) {
42337 node.removeAttribute('style');
42340 this.iterateChildren(node, this.cleanWord);
42346 * iterateChildren of a Node, calling fn each time, using this as the scole..
42347 * @param {DomNode} node node to iterate children of.
42348 * @param {Function} fn method of this class to call on each item.
42350 iterateChildren : function(node, fn)
42352 if (!node.childNodes.length) {
42355 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42356 fn.call(this, node.childNodes[i])
42362 * cleanTableWidths.
42364 * Quite often pasting from word etc.. results in tables with column and widths.
42365 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
42368 cleanTableWidths : function(node)
42373 this.cleanTableWidths(this.doc.body);
42378 if (node.nodeName == "#text" || node.nodeName == "#comment") {
42381 Roo.log(node.tagName);
42382 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
42383 this.iterateChildren(node, this.cleanTableWidths);
42386 if (node.hasAttribute('width')) {
42387 node.removeAttribute('width');
42391 if (node.hasAttribute("style")) {
42394 var styles = node.getAttribute("style").split(";");
42396 Roo.each(styles, function(s) {
42397 if (!s.match(/:/)) {
42400 var kv = s.split(":");
42401 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
42404 // what ever is left... we allow.
42407 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42408 if (!nstyle.length) {
42409 node.removeAttribute('style');
42413 this.iterateChildren(node, this.cleanTableWidths);
42421 domToHTML : function(currentElement, depth, nopadtext) {
42423 depth = depth || 0;
42424 nopadtext = nopadtext || false;
42426 if (!currentElement) {
42427 return this.domToHTML(this.doc.body);
42430 //Roo.log(currentElement);
42432 var allText = false;
42433 var nodeName = currentElement.nodeName;
42434 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42436 if (nodeName == '#text') {
42438 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
42443 if (nodeName != 'BODY') {
42446 // Prints the node tagName, such as <A>, <IMG>, etc
42449 for(i = 0; i < currentElement.attributes.length;i++) {
42451 var aname = currentElement.attributes.item(i).name;
42452 if (!currentElement.attributes.item(i).value.length) {
42455 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42458 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42467 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42470 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42475 // Traverse the tree
42477 var currentElementChild = currentElement.childNodes.item(i);
42478 var allText = true;
42479 var innerHTML = '';
42481 while (currentElementChild) {
42482 // Formatting code (indent the tree so it looks nice on the screen)
42483 var nopad = nopadtext;
42484 if (lastnode == 'SPAN') {
42488 if (currentElementChild.nodeName == '#text') {
42489 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42490 toadd = nopadtext ? toadd : toadd.trim();
42491 if (!nopad && toadd.length > 80) {
42492 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42494 innerHTML += toadd;
42497 currentElementChild = currentElement.childNodes.item(i);
42503 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42505 // Recursively traverse the tree structure of the child node
42506 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42507 lastnode = currentElementChild.nodeName;
42509 currentElementChild=currentElement.childNodes.item(i);
42515 // The remaining code is mostly for formatting the tree
42516 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42521 ret+= "</"+tagName+">";
42527 applyBlacklists : function()
42529 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
42530 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
42534 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
42535 if (b.indexOf(tag) > -1) {
42538 this.white.push(tag);
42542 Roo.each(w, function(tag) {
42543 if (b.indexOf(tag) > -1) {
42546 if (this.white.indexOf(tag) > -1) {
42549 this.white.push(tag);
42554 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
42555 if (w.indexOf(tag) > -1) {
42558 this.black.push(tag);
42562 Roo.each(b, function(tag) {
42563 if (w.indexOf(tag) > -1) {
42566 if (this.black.indexOf(tag) > -1) {
42569 this.black.push(tag);
42574 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
42575 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
42579 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
42580 if (b.indexOf(tag) > -1) {
42583 this.cwhite.push(tag);
42587 Roo.each(w, function(tag) {
42588 if (b.indexOf(tag) > -1) {
42591 if (this.cwhite.indexOf(tag) > -1) {
42594 this.cwhite.push(tag);
42599 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
42600 if (w.indexOf(tag) > -1) {
42603 this.cblack.push(tag);
42607 Roo.each(b, function(tag) {
42608 if (w.indexOf(tag) > -1) {
42611 if (this.cblack.indexOf(tag) > -1) {
42614 this.cblack.push(tag);
42619 setStylesheets : function(stylesheets)
42621 if(typeof(stylesheets) == 'string'){
42622 Roo.get(this.iframe.contentDocument.head).createChild({
42624 rel : 'stylesheet',
42633 Roo.each(stylesheets, function(s) {
42638 Roo.get(_this.iframe.contentDocument.head).createChild({
42640 rel : 'stylesheet',
42649 removeStylesheets : function()
42653 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
42658 // hide stuff that is not compatible
42672 * @event specialkey
42676 * @cfg {String} fieldClass @hide
42679 * @cfg {String} focusClass @hide
42682 * @cfg {String} autoCreate @hide
42685 * @cfg {String} inputType @hide
42688 * @cfg {String} invalidClass @hide
42691 * @cfg {String} invalidText @hide
42694 * @cfg {String} msgFx @hide
42697 * @cfg {String} validateOnBlur @hide
42701 Roo.HtmlEditorCore.white = [
42702 'area', 'br', 'img', 'input', 'hr', 'wbr',
42704 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42705 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42706 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42707 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42708 'table', 'ul', 'xmp',
42710 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42713 'dir', 'menu', 'ol', 'ul', 'dl',
42719 Roo.HtmlEditorCore.black = [
42720 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42722 'base', 'basefont', 'bgsound', 'blink', 'body',
42723 'frame', 'frameset', 'head', 'html', 'ilayer',
42724 'iframe', 'layer', 'link', 'meta', 'object',
42725 'script', 'style' ,'title', 'xml' // clean later..
42727 Roo.HtmlEditorCore.clean = [
42728 'script', 'style', 'title', 'xml'
42730 Roo.HtmlEditorCore.remove = [
42735 Roo.HtmlEditorCore.ablack = [
42739 Roo.HtmlEditorCore.aclean = [
42740 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42744 Roo.HtmlEditorCore.pwhite= [
42745 'http', 'https', 'mailto'
42748 // white listed style attributes.
42749 Roo.HtmlEditorCore.cwhite= [
42750 // 'text-align', /// default is to allow most things..
42756 // black listed style attributes.
42757 Roo.HtmlEditorCore.cblack= [
42758 // 'font-size' -- this can be set by the project
42762 Roo.HtmlEditorCore.swapCodes =[
42773 //<script type="text/javascript">
42776 * Ext JS Library 1.1.1
42777 * Copyright(c) 2006-2007, Ext JS, LLC.
42783 Roo.form.HtmlEditor = function(config){
42787 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42789 if (!this.toolbars) {
42790 this.toolbars = [];
42792 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42798 * @class Roo.form.HtmlEditor
42799 * @extends Roo.form.Field
42800 * Provides a lightweight HTML Editor component.
42802 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42804 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42805 * supported by this editor.</b><br/><br/>
42806 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42807 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42809 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42811 * @cfg {Boolean} clearUp
42815 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42820 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42825 * @cfg {Number} height (in pixels)
42829 * @cfg {Number} width (in pixels)
42834 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42837 stylesheets: false,
42841 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
42846 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
42852 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
42857 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
42865 // private properties
42866 validationEvent : false,
42868 initialized : false,
42871 onFocus : Roo.emptyFn,
42873 hideMode:'offsets',
42875 actionMode : 'container', // defaults to hiding it...
42877 defaultAutoCreate : { // modified by initCompnoent..
42879 style:"width:500px;height:300px;",
42880 autocomplete: "new-password"
42884 initComponent : function(){
42887 * @event initialize
42888 * Fires when the editor is fully initialized (including the iframe)
42889 * @param {HtmlEditor} this
42894 * Fires when the editor is first receives the focus. Any insertion must wait
42895 * until after this event.
42896 * @param {HtmlEditor} this
42900 * @event beforesync
42901 * Fires before the textarea is updated with content from the editor iframe. Return false
42902 * to cancel the sync.
42903 * @param {HtmlEditor} this
42904 * @param {String} html
42908 * @event beforepush
42909 * Fires before the iframe editor is updated with content from the textarea. Return false
42910 * to cancel the push.
42911 * @param {HtmlEditor} this
42912 * @param {String} html
42917 * Fires when the textarea is updated with content from the editor iframe.
42918 * @param {HtmlEditor} this
42919 * @param {String} html
42924 * Fires when the iframe editor is updated with content from the textarea.
42925 * @param {HtmlEditor} this
42926 * @param {String} html
42930 * @event editmodechange
42931 * Fires when the editor switches edit modes
42932 * @param {HtmlEditor} this
42933 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42935 editmodechange: true,
42937 * @event editorevent
42938 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42939 * @param {HtmlEditor} this
42943 * @event firstfocus
42944 * Fires when on first focus - needed by toolbars..
42945 * @param {HtmlEditor} this
42950 * Auto save the htmlEditor value as a file into Events
42951 * @param {HtmlEditor} this
42955 * @event savedpreview
42956 * preview the saved version of htmlEditor
42957 * @param {HtmlEditor} this
42959 savedpreview: true,
42962 * @event stylesheetsclick
42963 * Fires when press the Sytlesheets button
42964 * @param {Roo.HtmlEditorCore} this
42966 stylesheetsclick: true
42968 this.defaultAutoCreate = {
42970 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42971 autocomplete: "new-password"
42976 * Protected method that will not generally be called directly. It
42977 * is called when the editor creates its toolbar. Override this method if you need to
42978 * add custom toolbar buttons.
42979 * @param {HtmlEditor} editor
42981 createToolbar : function(editor){
42982 Roo.log("create toolbars");
42983 if (!editor.toolbars || !editor.toolbars.length) {
42984 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42987 for (var i =0 ; i < editor.toolbars.length;i++) {
42988 editor.toolbars[i] = Roo.factory(
42989 typeof(editor.toolbars[i]) == 'string' ?
42990 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42991 Roo.form.HtmlEditor);
42992 editor.toolbars[i].init(editor);
43000 onRender : function(ct, position)
43003 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
43005 this.wrap = this.el.wrap({
43006 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
43009 this.editorcore.onRender(ct, position);
43011 if (this.resizable) {
43012 this.resizeEl = new Roo.Resizable(this.wrap, {
43016 minHeight : this.height,
43017 height: this.height,
43018 handles : this.resizable,
43021 resize : function(r, w, h) {
43022 _t.onResize(w,h); // -something
43028 this.createToolbar(this);
43032 this.setSize(this.wrap.getSize());
43034 if (this.resizeEl) {
43035 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
43036 // should trigger onReize..
43039 this.keyNav = new Roo.KeyNav(this.el, {
43041 "tab" : function(e){
43042 e.preventDefault();
43044 var value = this.getValue();
43046 var start = this.el.dom.selectionStart;
43047 var end = this.el.dom.selectionEnd;
43051 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
43052 this.el.dom.setSelectionRange(end + 1, end + 1);
43056 var f = value.substring(0, start).split("\t");
43058 if(f.pop().length != 0){
43062 this.setValue(f.join("\t") + value.substring(end));
43063 this.el.dom.setSelectionRange(start - 1, start - 1);
43067 "home" : function(e){
43068 e.preventDefault();
43070 var curr = this.el.dom.selectionStart;
43071 var lines = this.getValue().split("\n");
43078 this.el.dom.setSelectionRange(0, 0);
43084 for (var i = 0; i < lines.length;i++) {
43085 pos += lines[i].length;
43095 pos -= lines[i].length;
43101 this.el.dom.setSelectionRange(pos, pos);
43105 this.el.dom.selectionStart = pos;
43106 this.el.dom.selectionEnd = curr;
43109 "end" : function(e){
43110 e.preventDefault();
43112 var curr = this.el.dom.selectionStart;
43113 var lines = this.getValue().split("\n");
43120 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
43126 for (var i = 0; i < lines.length;i++) {
43128 pos += lines[i].length;
43142 this.el.dom.setSelectionRange(pos, pos);
43146 this.el.dom.selectionStart = curr;
43147 this.el.dom.selectionEnd = pos;
43152 doRelay : function(foo, bar, hname){
43153 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
43159 // if(this.autosave && this.w){
43160 // this.autoSaveFn = setInterval(this.autosave, 1000);
43165 onResize : function(w, h)
43167 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
43172 if(typeof w == 'number'){
43173 var aw = w - this.wrap.getFrameWidth('lr');
43174 this.el.setWidth(this.adjustWidth('textarea', aw));
43177 if(typeof h == 'number'){
43179 for (var i =0; i < this.toolbars.length;i++) {
43180 // fixme - ask toolbars for heights?
43181 tbh += this.toolbars[i].tb.el.getHeight();
43182 if (this.toolbars[i].footer) {
43183 tbh += this.toolbars[i].footer.el.getHeight();
43190 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
43191 ah -= 5; // knock a few pixes off for look..
43193 this.el.setHeight(this.adjustWidth('textarea', ah));
43197 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
43198 this.editorcore.onResize(ew,eh);
43203 * Toggles the editor between standard and source edit mode.
43204 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43206 toggleSourceEdit : function(sourceEditMode)
43208 this.editorcore.toggleSourceEdit(sourceEditMode);
43210 if(this.editorcore.sourceEditMode){
43211 Roo.log('editor - showing textarea');
43214 // Roo.log(this.syncValue());
43215 this.editorcore.syncValue();
43216 this.el.removeClass('x-hidden');
43217 this.el.dom.removeAttribute('tabIndex');
43220 for (var i = 0; i < this.toolbars.length; i++) {
43221 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43222 this.toolbars[i].tb.hide();
43223 this.toolbars[i].footer.hide();
43228 Roo.log('editor - hiding textarea');
43230 // Roo.log(this.pushValue());
43231 this.editorcore.pushValue();
43233 this.el.addClass('x-hidden');
43234 this.el.dom.setAttribute('tabIndex', -1);
43236 for (var i = 0; i < this.toolbars.length; i++) {
43237 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43238 this.toolbars[i].tb.show();
43239 this.toolbars[i].footer.show();
43243 //this.deferFocus();
43246 this.setSize(this.wrap.getSize());
43247 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
43249 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
43252 // private (for BoxComponent)
43253 adjustSize : Roo.BoxComponent.prototype.adjustSize,
43255 // private (for BoxComponent)
43256 getResizeEl : function(){
43260 // private (for BoxComponent)
43261 getPositionEl : function(){
43266 initEvents : function(){
43267 this.originalValue = this.getValue();
43271 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43274 markInvalid : Roo.emptyFn,
43276 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43279 clearInvalid : Roo.emptyFn,
43281 setValue : function(v){
43282 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
43283 this.editorcore.pushValue();
43288 deferFocus : function(){
43289 this.focus.defer(10, this);
43293 focus : function(){
43294 this.editorcore.focus();
43300 onDestroy : function(){
43306 for (var i =0; i < this.toolbars.length;i++) {
43307 // fixme - ask toolbars for heights?
43308 this.toolbars[i].onDestroy();
43311 this.wrap.dom.innerHTML = '';
43312 this.wrap.remove();
43317 onFirstFocus : function(){
43318 //Roo.log("onFirstFocus");
43319 this.editorcore.onFirstFocus();
43320 for (var i =0; i < this.toolbars.length;i++) {
43321 this.toolbars[i].onFirstFocus();
43327 syncValue : function()
43329 this.editorcore.syncValue();
43332 pushValue : function()
43334 this.editorcore.pushValue();
43337 setStylesheets : function(stylesheets)
43339 this.editorcore.setStylesheets(stylesheets);
43342 removeStylesheets : function()
43344 this.editorcore.removeStylesheets();
43348 // hide stuff that is not compatible
43362 * @event specialkey
43366 * @cfg {String} fieldClass @hide
43369 * @cfg {String} focusClass @hide
43372 * @cfg {String} autoCreate @hide
43375 * @cfg {String} inputType @hide
43378 * @cfg {String} invalidClass @hide
43381 * @cfg {String} invalidText @hide
43384 * @cfg {String} msgFx @hide
43387 * @cfg {String} validateOnBlur @hide
43391 // <script type="text/javascript">
43394 * Ext JS Library 1.1.1
43395 * Copyright(c) 2006-2007, Ext JS, LLC.
43401 * @class Roo.form.HtmlEditorToolbar1
43406 new Roo.form.HtmlEditor({
43409 new Roo.form.HtmlEditorToolbar1({
43410 disable : { fonts: 1 , format: 1, ..., ... , ...],
43416 * @cfg {Object} disable List of elements to disable..
43417 * @cfg {Array} btns List of additional buttons.
43421 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
43424 Roo.form.HtmlEditor.ToolbarStandard = function(config)
43427 Roo.apply(this, config);
43429 // default disabled, based on 'good practice'..
43430 this.disable = this.disable || {};
43431 Roo.applyIf(this.disable, {
43434 specialElements : true
43438 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43439 // dont call parent... till later.
43442 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
43449 editorcore : false,
43451 * @cfg {Object} disable List of toolbar elements to disable
43458 * @cfg {String} createLinkText The default text for the create link prompt
43460 createLinkText : 'Please enter the URL for the link:',
43462 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
43464 defaultLinkValue : 'http:/'+'/',
43468 * @cfg {Array} fontFamilies An array of available font families
43486 // "á" , ?? a acute?
43491 "°" // , // degrees
43493 // "é" , // e ecute
43494 // "ú" , // u ecute?
43497 specialElements : [
43499 text: "Insert Table",
43502 ihtml : '<table><tr><td>Cell</td></tr></table>'
43506 text: "Insert Image",
43509 ihtml : '<img src="about:blank"/>'
43518 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
43519 "input:submit", "input:button", "select", "textarea", "label" ],
43522 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
43524 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
43532 * @cfg {String} defaultFont default font to use.
43534 defaultFont: 'tahoma',
43536 fontSelect : false,
43539 formatCombo : false,
43541 init : function(editor)
43543 this.editor = editor;
43544 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43545 var editorcore = this.editorcore;
43549 var fid = editorcore.frameId;
43551 function btn(id, toggle, handler){
43552 var xid = fid + '-'+ id ;
43556 cls : 'x-btn-icon x-edit-'+id,
43557 enableToggle:toggle !== false,
43558 scope: _t, // was editor...
43559 handler:handler||_t.relayBtnCmd,
43560 clickEvent:'mousedown',
43561 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43568 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43570 // stop form submits
43571 tb.el.on('click', function(e){
43572 e.preventDefault(); // what does this do?
43575 if(!this.disable.font) { // && !Roo.isSafari){
43576 /* why no safari for fonts
43577 editor.fontSelect = tb.el.createChild({
43580 cls:'x-font-select',
43581 html: this.createFontOptions()
43584 editor.fontSelect.on('change', function(){
43585 var font = editor.fontSelect.dom.value;
43586 editor.relayCmd('fontname', font);
43587 editor.deferFocus();
43591 editor.fontSelect.dom,
43597 if(!this.disable.formats){
43598 this.formatCombo = new Roo.form.ComboBox({
43599 store: new Roo.data.SimpleStore({
43602 data : this.formats // from states.js
43606 //autoCreate : {tag: "div", size: "20"},
43607 displayField:'tag',
43611 triggerAction: 'all',
43612 emptyText:'Add tag',
43613 selectOnFocus:true,
43616 'select': function(c, r, i) {
43617 editorcore.insertTag(r.get('tag'));
43623 tb.addField(this.formatCombo);
43627 if(!this.disable.format){
43634 if(!this.disable.fontSize){
43639 btn('increasefontsize', false, editorcore.adjustFont),
43640 btn('decreasefontsize', false, editorcore.adjustFont)
43645 if(!this.disable.colors){
43648 id:editorcore.frameId +'-forecolor',
43649 cls:'x-btn-icon x-edit-forecolor',
43650 clickEvent:'mousedown',
43651 tooltip: this.buttonTips['forecolor'] || undefined,
43653 menu : new Roo.menu.ColorMenu({
43654 allowReselect: true,
43655 focus: Roo.emptyFn,
43658 selectHandler: function(cp, color){
43659 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43660 editor.deferFocus();
43663 clickEvent:'mousedown'
43666 id:editorcore.frameId +'backcolor',
43667 cls:'x-btn-icon x-edit-backcolor',
43668 clickEvent:'mousedown',
43669 tooltip: this.buttonTips['backcolor'] || undefined,
43671 menu : new Roo.menu.ColorMenu({
43672 focus: Roo.emptyFn,
43675 allowReselect: true,
43676 selectHandler: function(cp, color){
43678 editorcore.execCmd('useCSS', false);
43679 editorcore.execCmd('hilitecolor', color);
43680 editorcore.execCmd('useCSS', true);
43681 editor.deferFocus();
43683 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43684 Roo.isSafari || Roo.isIE ? '#'+color : color);
43685 editor.deferFocus();
43689 clickEvent:'mousedown'
43694 // now add all the items...
43697 if(!this.disable.alignments){
43700 btn('justifyleft'),
43701 btn('justifycenter'),
43702 btn('justifyright')
43706 //if(!Roo.isSafari){
43707 if(!this.disable.links){
43710 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43714 if(!this.disable.lists){
43717 btn('insertorderedlist'),
43718 btn('insertunorderedlist')
43721 if(!this.disable.sourceEdit){
43724 btn('sourceedit', true, function(btn){
43725 this.toggleSourceEdit(btn.pressed);
43732 // special menu.. - needs to be tidied up..
43733 if (!this.disable.special) {
43736 cls: 'x-edit-none',
43742 for (var i =0; i < this.specialChars.length; i++) {
43743 smenu.menu.items.push({
43745 html: this.specialChars[i],
43746 handler: function(a,b) {
43747 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43748 //editor.insertAtCursor(a.html);
43762 if (!this.disable.cleanStyles) {
43764 cls: 'x-btn-icon x-btn-clear',
43770 for (var i =0; i < this.cleanStyles.length; i++) {
43771 cmenu.menu.items.push({
43772 actiontype : this.cleanStyles[i],
43773 html: 'Remove ' + this.cleanStyles[i],
43774 handler: function(a,b) {
43777 var c = Roo.get(editorcore.doc.body);
43778 c.select('[style]').each(function(s) {
43779 s.dom.style.removeProperty(a.actiontype);
43781 editorcore.syncValue();
43786 cmenu.menu.items.push({
43787 actiontype : 'tablewidths',
43788 html: 'Remove Table Widths',
43789 handler: function(a,b) {
43790 editorcore.cleanTableWidths();
43791 editorcore.syncValue();
43795 cmenu.menu.items.push({
43796 actiontype : 'word',
43797 html: 'Remove MS Word Formating',
43798 handler: function(a,b) {
43799 editorcore.cleanWord();
43800 editorcore.syncValue();
43805 cmenu.menu.items.push({
43806 actiontype : 'all',
43807 html: 'Remove All Styles',
43808 handler: function(a,b) {
43810 var c = Roo.get(editorcore.doc.body);
43811 c.select('[style]').each(function(s) {
43812 s.dom.removeAttribute('style');
43814 editorcore.syncValue();
43819 cmenu.menu.items.push({
43820 actiontype : 'all',
43821 html: 'Remove All CSS Classes',
43822 handler: function(a,b) {
43824 var c = Roo.get(editorcore.doc.body);
43825 c.select('[class]').each(function(s) {
43826 s.dom.className = '';
43828 editorcore.syncValue();
43833 cmenu.menu.items.push({
43834 actiontype : 'tidy',
43835 html: 'Tidy HTML Source',
43836 handler: function(a,b) {
43837 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43838 editorcore.syncValue();
43847 if (!this.disable.specialElements) {
43850 cls: 'x-edit-none',
43855 for (var i =0; i < this.specialElements.length; i++) {
43856 semenu.menu.items.push(
43858 handler: function(a,b) {
43859 editor.insertAtCursor(this.ihtml);
43861 }, this.specialElements[i])
43873 for(var i =0; i< this.btns.length;i++) {
43874 var b = Roo.factory(this.btns[i],Roo.form);
43875 b.cls = 'x-edit-none';
43877 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
43878 b.cls += ' x-init-enable';
43881 b.scope = editorcore;
43889 // disable everything...
43891 this.tb.items.each(function(item){
43894 item.id != editorcore.frameId+ '-sourceedit' &&
43895 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
43901 this.rendered = true;
43903 // the all the btns;
43904 editor.on('editorevent', this.updateToolbar, this);
43905 // other toolbars need to implement this..
43906 //editor.on('editmodechange', this.updateToolbar, this);
43910 relayBtnCmd : function(btn) {
43911 this.editorcore.relayCmd(btn.cmd);
43913 // private used internally
43914 createLink : function(){
43915 Roo.log("create link?");
43916 var url = prompt(this.createLinkText, this.defaultLinkValue);
43917 if(url && url != 'http:/'+'/'){
43918 this.editorcore.relayCmd('createlink', url);
43924 * Protected method that will not generally be called directly. It triggers
43925 * a toolbar update by reading the markup state of the current selection in the editor.
43927 updateToolbar: function(){
43929 if(!this.editorcore.activated){
43930 this.editor.onFirstFocus();
43934 var btns = this.tb.items.map,
43935 doc = this.editorcore.doc,
43936 frameId = this.editorcore.frameId;
43938 if(!this.disable.font && !Roo.isSafari){
43940 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43941 if(name != this.fontSelect.dom.value){
43942 this.fontSelect.dom.value = name;
43946 if(!this.disable.format){
43947 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43948 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43949 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43951 if(!this.disable.alignments){
43952 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43953 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43954 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43956 if(!Roo.isSafari && !this.disable.lists){
43957 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43958 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43961 var ans = this.editorcore.getAllAncestors();
43962 if (this.formatCombo) {
43965 var store = this.formatCombo.store;
43966 this.formatCombo.setValue("");
43967 for (var i =0; i < ans.length;i++) {
43968 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43970 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43978 // hides menus... - so this cant be on a menu...
43979 Roo.menu.MenuMgr.hideAll();
43981 //this.editorsyncValue();
43985 createFontOptions : function(){
43986 var buf = [], fs = this.fontFamilies, ff, lc;
43990 for(var i = 0, len = fs.length; i< len; i++){
43992 lc = ff.toLowerCase();
43994 '<option value="',lc,'" style="font-family:',ff,';"',
43995 (this.defaultFont == lc ? ' selected="true">' : '>'),
44000 return buf.join('');
44003 toggleSourceEdit : function(sourceEditMode){
44005 Roo.log("toolbar toogle");
44006 if(sourceEditMode === undefined){
44007 sourceEditMode = !this.sourceEditMode;
44009 this.sourceEditMode = sourceEditMode === true;
44010 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
44011 // just toggle the button?
44012 if(btn.pressed !== this.sourceEditMode){
44013 btn.toggle(this.sourceEditMode);
44017 if(sourceEditMode){
44018 Roo.log("disabling buttons");
44019 this.tb.items.each(function(item){
44020 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
44026 Roo.log("enabling buttons");
44027 if(this.editorcore.initialized){
44028 this.tb.items.each(function(item){
44034 Roo.log("calling toggole on editor");
44035 // tell the editor that it's been pressed..
44036 this.editor.toggleSourceEdit(sourceEditMode);
44040 * Object collection of toolbar tooltips for the buttons in the editor. The key
44041 * is the command id associated with that button and the value is a valid QuickTips object.
44046 title: 'Bold (Ctrl+B)',
44047 text: 'Make the selected text bold.',
44048 cls: 'x-html-editor-tip'
44051 title: 'Italic (Ctrl+I)',
44052 text: 'Make the selected text italic.',
44053 cls: 'x-html-editor-tip'
44061 title: 'Bold (Ctrl+B)',
44062 text: 'Make the selected text bold.',
44063 cls: 'x-html-editor-tip'
44066 title: 'Italic (Ctrl+I)',
44067 text: 'Make the selected text italic.',
44068 cls: 'x-html-editor-tip'
44071 title: 'Underline (Ctrl+U)',
44072 text: 'Underline the selected text.',
44073 cls: 'x-html-editor-tip'
44075 increasefontsize : {
44076 title: 'Grow Text',
44077 text: 'Increase the font size.',
44078 cls: 'x-html-editor-tip'
44080 decreasefontsize : {
44081 title: 'Shrink Text',
44082 text: 'Decrease the font size.',
44083 cls: 'x-html-editor-tip'
44086 title: 'Text Highlight Color',
44087 text: 'Change the background color of the selected text.',
44088 cls: 'x-html-editor-tip'
44091 title: 'Font Color',
44092 text: 'Change the color of the selected text.',
44093 cls: 'x-html-editor-tip'
44096 title: 'Align Text Left',
44097 text: 'Align text to the left.',
44098 cls: 'x-html-editor-tip'
44101 title: 'Center Text',
44102 text: 'Center text in the editor.',
44103 cls: 'x-html-editor-tip'
44106 title: 'Align Text Right',
44107 text: 'Align text to the right.',
44108 cls: 'x-html-editor-tip'
44110 insertunorderedlist : {
44111 title: 'Bullet List',
44112 text: 'Start a bulleted list.',
44113 cls: 'x-html-editor-tip'
44115 insertorderedlist : {
44116 title: 'Numbered List',
44117 text: 'Start a numbered list.',
44118 cls: 'x-html-editor-tip'
44121 title: 'Hyperlink',
44122 text: 'Make the selected text a hyperlink.',
44123 cls: 'x-html-editor-tip'
44126 title: 'Source Edit',
44127 text: 'Switch to source editing mode.',
44128 cls: 'x-html-editor-tip'
44132 onDestroy : function(){
44135 this.tb.items.each(function(item){
44137 item.menu.removeAll();
44139 item.menu.el.destroy();
44147 onFirstFocus: function() {
44148 this.tb.items.each(function(item){
44157 // <script type="text/javascript">
44160 * Ext JS Library 1.1.1
44161 * Copyright(c) 2006-2007, Ext JS, LLC.
44168 * @class Roo.form.HtmlEditor.ToolbarContext
44173 new Roo.form.HtmlEditor({
44176 { xtype: 'ToolbarStandard', styles : {} }
44177 { xtype: 'ToolbarContext', disable : {} }
44183 * @config : {Object} disable List of elements to disable.. (not done yet.)
44184 * @config : {Object} styles Map of styles available.
44188 Roo.form.HtmlEditor.ToolbarContext = function(config)
44191 Roo.apply(this, config);
44192 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44193 // dont call parent... till later.
44194 this.styles = this.styles || {};
44199 Roo.form.HtmlEditor.ToolbarContext.types = {
44211 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
44277 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
44282 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
44292 style : 'fontFamily',
44293 displayField: 'display',
44294 optname : 'font-family',
44343 // should we really allow this??
44344 // should this just be
44355 style : 'fontFamily',
44356 displayField: 'display',
44357 optname : 'font-family',
44364 style : 'fontFamily',
44365 displayField: 'display',
44366 optname : 'font-family',
44373 style : 'fontFamily',
44374 displayField: 'display',
44375 optname : 'font-family',
44386 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
44387 Roo.form.HtmlEditor.ToolbarContext.stores = false;
44389 Roo.form.HtmlEditor.ToolbarContext.options = {
44391 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
44392 [ 'Courier New', 'Courier New'],
44393 [ 'Tahoma', 'Tahoma'],
44394 [ 'Times New Roman,serif', 'Times'],
44395 [ 'Verdana','Verdana' ]
44399 // fixme - these need to be configurable..
44402 Roo.form.HtmlEditor.ToolbarContext.types
44405 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
44412 editorcore : false,
44414 * @cfg {Object} disable List of toolbar elements to disable
44419 * @cfg {Object} styles List of styles
44420 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
44422 * These must be defined in the page, so they get rendered correctly..
44433 init : function(editor)
44435 this.editor = editor;
44436 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44437 var editorcore = this.editorcore;
44439 var fid = editorcore.frameId;
44441 function btn(id, toggle, handler){
44442 var xid = fid + '-'+ id ;
44446 cls : 'x-btn-icon x-edit-'+id,
44447 enableToggle:toggle !== false,
44448 scope: editorcore, // was editor...
44449 handler:handler||editorcore.relayBtnCmd,
44450 clickEvent:'mousedown',
44451 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44455 // create a new element.
44456 var wdiv = editor.wrap.createChild({
44458 }, editor.wrap.dom.firstChild.nextSibling, true);
44460 // can we do this more than once??
44462 // stop form submits
44465 // disable everything...
44466 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44467 this.toolbars = {};
44469 for (var i in ty) {
44471 this.toolbars[i] = this.buildToolbar(ty[i],i);
44473 this.tb = this.toolbars.BODY;
44475 this.buildFooter();
44476 this.footer.show();
44477 editor.on('hide', function( ) { this.footer.hide() }, this);
44478 editor.on('show', function( ) { this.footer.show() }, this);
44481 this.rendered = true;
44483 // the all the btns;
44484 editor.on('editorevent', this.updateToolbar, this);
44485 // other toolbars need to implement this..
44486 //editor.on('editmodechange', this.updateToolbar, this);
44492 * Protected method that will not generally be called directly. It triggers
44493 * a toolbar update by reading the markup state of the current selection in the editor.
44495 * Note you can force an update by calling on('editorevent', scope, false)
44497 updateToolbar: function(editor,ev,sel){
44500 // capture mouse up - this is handy for selecting images..
44501 // perhaps should go somewhere else...
44502 if(!this.editorcore.activated){
44503 this.editor.onFirstFocus();
44509 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
44510 // selectNode - might want to handle IE?
44512 (ev.type == 'mouseup' || ev.type == 'click' ) &&
44513 ev.target && ev.target.tagName == 'IMG') {
44514 // they have click on an image...
44515 // let's see if we can change the selection...
44518 var nodeRange = sel.ownerDocument.createRange();
44520 nodeRange.selectNode(sel);
44522 nodeRange.selectNodeContents(sel);
44524 //nodeRange.collapse(true);
44525 var s = this.editorcore.win.getSelection();
44526 s.removeAllRanges();
44527 s.addRange(nodeRange);
44531 var updateFooter = sel ? false : true;
44534 var ans = this.editorcore.getAllAncestors();
44537 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44540 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
44541 sel = sel ? sel : this.editorcore.doc.body;
44542 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
44545 // pick a menu that exists..
44546 var tn = sel.tagName.toUpperCase();
44547 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
44549 tn = sel.tagName.toUpperCase();
44551 var lastSel = this.tb.selectedNode
44553 this.tb.selectedNode = sel;
44555 // if current menu does not match..
44557 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
44560 ///console.log("show: " + tn);
44561 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
44564 this.tb.items.first().el.innerHTML = tn + ': ';
44567 // update attributes
44568 if (this.tb.fields) {
44569 this.tb.fields.each(function(e) {
44571 e.setValue(sel.style[e.stylename]);
44574 e.setValue(sel.getAttribute(e.attrname));
44578 var hasStyles = false;
44579 for(var i in this.styles) {
44586 var st = this.tb.fields.item(0);
44588 st.store.removeAll();
44591 var cn = sel.className.split(/\s+/);
44594 if (this.styles['*']) {
44596 Roo.each(this.styles['*'], function(v) {
44597 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44600 if (this.styles[tn]) {
44601 Roo.each(this.styles[tn], function(v) {
44602 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44606 st.store.loadData(avs);
44610 // flag our selected Node.
44611 this.tb.selectedNode = sel;
44614 Roo.menu.MenuMgr.hideAll();
44618 if (!updateFooter) {
44619 //this.footDisp.dom.innerHTML = '';
44622 // update the footer
44626 this.footerEls = ans.reverse();
44627 Roo.each(this.footerEls, function(a,i) {
44628 if (!a) { return; }
44629 html += html.length ? ' > ' : '';
44631 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44636 var sz = this.footDisp.up('td').getSize();
44637 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44638 this.footDisp.dom.style.marginLeft = '5px';
44640 this.footDisp.dom.style.overflow = 'hidden';
44642 this.footDisp.dom.innerHTML = html;
44644 //this.editorsyncValue();
44651 onDestroy : function(){
44654 this.tb.items.each(function(item){
44656 item.menu.removeAll();
44658 item.menu.el.destroy();
44666 onFirstFocus: function() {
44667 // need to do this for all the toolbars..
44668 this.tb.items.each(function(item){
44672 buildToolbar: function(tlist, nm)
44674 var editor = this.editor;
44675 var editorcore = this.editorcore;
44676 // create a new element.
44677 var wdiv = editor.wrap.createChild({
44679 }, editor.wrap.dom.firstChild.nextSibling, true);
44682 var tb = new Roo.Toolbar(wdiv);
44685 tb.add(nm+ ": ");
44688 for(var i in this.styles) {
44693 if (styles && styles.length) {
44695 // this needs a multi-select checkbox...
44696 tb.addField( new Roo.form.ComboBox({
44697 store: new Roo.data.SimpleStore({
44699 fields: ['val', 'selected'],
44702 name : '-roo-edit-className',
44703 attrname : 'className',
44704 displayField: 'val',
44708 triggerAction: 'all',
44709 emptyText:'Select Style',
44710 selectOnFocus:true,
44713 'select': function(c, r, i) {
44714 // initial support only for on class per el..
44715 tb.selectedNode.className = r ? r.get('val') : '';
44716 editorcore.syncValue();
44723 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44724 var tbops = tbc.options;
44726 for (var i in tlist) {
44728 var item = tlist[i];
44729 tb.add(item.title + ": ");
44732 //optname == used so you can configure the options available..
44733 var opts = item.opts ? item.opts : false;
44734 if (item.optname) {
44735 opts = tbops[item.optname];
44740 // opts == pulldown..
44741 tb.addField( new Roo.form.ComboBox({
44742 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44744 fields: ['val', 'display'],
44747 name : '-roo-edit-' + i,
44749 stylename : item.style ? item.style : false,
44750 displayField: item.displayField ? item.displayField : 'val',
44751 valueField : 'val',
44753 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44755 triggerAction: 'all',
44756 emptyText:'Select',
44757 selectOnFocus:true,
44758 width: item.width ? item.width : 130,
44760 'select': function(c, r, i) {
44762 tb.selectedNode.style[c.stylename] = r.get('val');
44765 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44774 tb.addField( new Roo.form.TextField({
44777 //allowBlank:false,
44782 tb.addField( new Roo.form.TextField({
44783 name: '-roo-edit-' + i,
44790 'change' : function(f, nv, ov) {
44791 tb.selectedNode.setAttribute(f.attrname, nv);
44804 text: 'Stylesheets',
44807 click : function ()
44809 _this.editor.fireEvent('stylesheetsclick', _this.editor);
44817 text: 'Remove Tag',
44820 click : function ()
44823 // undo does not work.
44825 var sn = tb.selectedNode;
44827 var pn = sn.parentNode;
44829 var stn = sn.childNodes[0];
44830 var en = sn.childNodes[sn.childNodes.length - 1 ];
44831 while (sn.childNodes.length) {
44832 var node = sn.childNodes[0];
44833 sn.removeChild(node);
44835 pn.insertBefore(node, sn);
44838 pn.removeChild(sn);
44839 var range = editorcore.createRange();
44841 range.setStart(stn,0);
44842 range.setEnd(en,0); //????
44843 //range.selectNode(sel);
44846 var selection = editorcore.getSelection();
44847 selection.removeAllRanges();
44848 selection.addRange(range);
44852 //_this.updateToolbar(null, null, pn);
44853 _this.updateToolbar(null, null, null);
44854 _this.footDisp.dom.innerHTML = '';
44864 tb.el.on('click', function(e){
44865 e.preventDefault(); // what does this do?
44867 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44870 // dont need to disable them... as they will get hidden
44875 buildFooter : function()
44878 var fel = this.editor.wrap.createChild();
44879 this.footer = new Roo.Toolbar(fel);
44880 // toolbar has scrolly on left / right?
44881 var footDisp= new Roo.Toolbar.Fill();
44887 handler : function() {
44888 _t.footDisp.scrollTo('left',0,true)
44892 this.footer.add( footDisp );
44897 handler : function() {
44899 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44903 var fel = Roo.get(footDisp.el);
44904 fel.addClass('x-editor-context');
44905 this.footDispWrap = fel;
44906 this.footDispWrap.overflow = 'hidden';
44908 this.footDisp = fel.createChild();
44909 this.footDispWrap.on('click', this.onContextClick, this)
44913 onContextClick : function (ev,dom)
44915 ev.preventDefault();
44916 var cn = dom.className;
44918 if (!cn.match(/x-ed-loc-/)) {
44921 var n = cn.split('-').pop();
44922 var ans = this.footerEls;
44926 var range = this.editorcore.createRange();
44928 range.selectNodeContents(sel);
44929 //range.selectNode(sel);
44932 var selection = this.editorcore.getSelection();
44933 selection.removeAllRanges();
44934 selection.addRange(range);
44938 this.updateToolbar(null, null, sel);
44955 * Ext JS Library 1.1.1
44956 * Copyright(c) 2006-2007, Ext JS, LLC.
44958 * Originally Released Under LGPL - original licence link has changed is not relivant.
44961 * <script type="text/javascript">
44965 * @class Roo.form.BasicForm
44966 * @extends Roo.util.Observable
44967 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44969 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44970 * @param {Object} config Configuration options
44972 Roo.form.BasicForm = function(el, config){
44973 this.allItems = [];
44974 this.childForms = [];
44975 Roo.apply(this, config);
44977 * The Roo.form.Field items in this form.
44978 * @type MixedCollection
44982 this.items = new Roo.util.MixedCollection(false, function(o){
44983 return o.id || (o.id = Roo.id());
44987 * @event beforeaction
44988 * Fires before any action is performed. Return false to cancel the action.
44989 * @param {Form} this
44990 * @param {Action} action The action to be performed
44992 beforeaction: true,
44994 * @event actionfailed
44995 * Fires when an action fails.
44996 * @param {Form} this
44997 * @param {Action} action The action that failed
44999 actionfailed : true,
45001 * @event actioncomplete
45002 * Fires when an action is completed.
45003 * @param {Form} this
45004 * @param {Action} action The action that completed
45006 actioncomplete : true
45011 Roo.form.BasicForm.superclass.constructor.call(this);
45014 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
45016 * @cfg {String} method
45017 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
45020 * @cfg {DataReader} reader
45021 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
45022 * This is optional as there is built-in support for processing JSON.
45025 * @cfg {DataReader} errorReader
45026 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
45027 * This is completely optional as there is built-in support for processing JSON.
45030 * @cfg {String} url
45031 * The URL to use for form actions if one isn't supplied in the action options.
45034 * @cfg {Boolean} fileUpload
45035 * Set to true if this form is a file upload.
45039 * @cfg {Object} baseParams
45040 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
45045 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
45050 activeAction : null,
45053 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
45054 * or setValues() data instead of when the form was first created.
45056 trackResetOnLoad : false,
45060 * childForms - used for multi-tab forms
45063 childForms : false,
45066 * allItems - full list of fields.
45072 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
45073 * element by passing it or its id or mask the form itself by passing in true.
45076 waitMsgTarget : false,
45079 initEl : function(el){
45080 this.el = Roo.get(el);
45081 this.id = this.el.id || Roo.id();
45082 this.el.on('submit', this.onSubmit, this);
45083 this.el.addClass('x-form');
45087 onSubmit : function(e){
45092 * Returns true if client-side validation on the form is successful.
45095 isValid : function(){
45097 this.items.each(function(f){
45106 * Returns true if any fields in this form have changed since their original load.
45109 isDirty : function(){
45111 this.items.each(function(f){
45121 * Performs a predefined action (submit or load) or custom actions you define on this form.
45122 * @param {String} actionName The name of the action type
45123 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
45124 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
45125 * accept other config options):
45127 Property Type Description
45128 ---------------- --------------- ----------------------------------------------------------------------------------
45129 url String The url for the action (defaults to the form's url)
45130 method String The form method to use (defaults to the form's method, or POST if not defined)
45131 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
45132 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
45133 validate the form on the client (defaults to false)
45135 * @return {BasicForm} this
45137 doAction : function(action, options){
45138 if(typeof action == 'string'){
45139 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
45141 if(this.fireEvent('beforeaction', this, action) !== false){
45142 this.beforeAction(action);
45143 action.run.defer(100, action);
45149 * Shortcut to do a submit action.
45150 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45151 * @return {BasicForm} this
45153 submit : function(options){
45154 this.doAction('submit', options);
45159 * Shortcut to do a load action.
45160 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45161 * @return {BasicForm} this
45163 load : function(options){
45164 this.doAction('load', options);
45169 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
45170 * @param {Record} record The record to edit
45171 * @return {BasicForm} this
45173 updateRecord : function(record){
45174 record.beginEdit();
45175 var fs = record.fields;
45176 fs.each(function(f){
45177 var field = this.findField(f.name);
45179 record.set(f.name, field.getValue());
45187 * Loads an Roo.data.Record into this form.
45188 * @param {Record} record The record to load
45189 * @return {BasicForm} this
45191 loadRecord : function(record){
45192 this.setValues(record.data);
45197 beforeAction : function(action){
45198 var o = action.options;
45201 if(this.waitMsgTarget === true){
45202 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
45203 }else if(this.waitMsgTarget){
45204 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
45205 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
45207 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
45213 afterAction : function(action, success){
45214 this.activeAction = null;
45215 var o = action.options;
45217 if(this.waitMsgTarget === true){
45219 }else if(this.waitMsgTarget){
45220 this.waitMsgTarget.unmask();
45222 Roo.MessageBox.updateProgress(1);
45223 Roo.MessageBox.hide();
45230 Roo.callback(o.success, o.scope, [this, action]);
45231 this.fireEvent('actioncomplete', this, action);
45235 // failure condition..
45236 // we have a scenario where updates need confirming.
45237 // eg. if a locking scenario exists..
45238 // we look for { errors : { needs_confirm : true }} in the response.
45240 (typeof(action.result) != 'undefined') &&
45241 (typeof(action.result.errors) != 'undefined') &&
45242 (typeof(action.result.errors.needs_confirm) != 'undefined')
45245 Roo.MessageBox.confirm(
45246 "Change requires confirmation",
45247 action.result.errorMsg,
45252 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
45262 Roo.callback(o.failure, o.scope, [this, action]);
45263 // show an error message if no failed handler is set..
45264 if (!this.hasListener('actionfailed')) {
45265 Roo.MessageBox.alert("Error",
45266 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
45267 action.result.errorMsg :
45268 "Saving Failed, please check your entries or try again"
45272 this.fireEvent('actionfailed', this, action);
45278 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
45279 * @param {String} id The value to search for
45282 findField : function(id){
45283 var field = this.items.get(id);
45285 this.items.each(function(f){
45286 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
45292 return field || null;
45296 * Add a secondary form to this one,
45297 * Used to provide tabbed forms. One form is primary, with hidden values
45298 * which mirror the elements from the other forms.
45300 * @param {Roo.form.Form} form to add.
45303 addForm : function(form)
45306 if (this.childForms.indexOf(form) > -1) {
45310 this.childForms.push(form);
45312 Roo.each(form.allItems, function (fe) {
45314 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
45315 if (this.findField(n)) { // already added..
45318 var add = new Roo.form.Hidden({
45321 add.render(this.el);
45328 * Mark fields in this form invalid in bulk.
45329 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
45330 * @return {BasicForm} this
45332 markInvalid : function(errors){
45333 if(errors instanceof Array){
45334 for(var i = 0, len = errors.length; i < len; i++){
45335 var fieldError = errors[i];
45336 var f = this.findField(fieldError.id);
45338 f.markInvalid(fieldError.msg);
45344 if(typeof errors[id] != 'function' && (field = this.findField(id))){
45345 field.markInvalid(errors[id]);
45349 Roo.each(this.childForms || [], function (f) {
45350 f.markInvalid(errors);
45357 * Set values for fields in this form in bulk.
45358 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
45359 * @return {BasicForm} this
45361 setValues : function(values){
45362 if(values instanceof Array){ // array of objects
45363 for(var i = 0, len = values.length; i < len; i++){
45365 var f = this.findField(v.id);
45367 f.setValue(v.value);
45368 if(this.trackResetOnLoad){
45369 f.originalValue = f.getValue();
45373 }else{ // object hash
45376 if(typeof values[id] != 'function' && (field = this.findField(id))){
45378 if (field.setFromData &&
45379 field.valueField &&
45380 field.displayField &&
45381 // combos' with local stores can
45382 // be queried via setValue()
45383 // to set their value..
45384 (field.store && !field.store.isLocal)
45388 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
45389 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
45390 field.setFromData(sd);
45393 field.setValue(values[id]);
45397 if(this.trackResetOnLoad){
45398 field.originalValue = field.getValue();
45404 Roo.each(this.childForms || [], function (f) {
45405 f.setValues(values);
45412 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
45413 * they are returned as an array.
45414 * @param {Boolean} asString
45417 getValues : function(asString){
45418 if (this.childForms) {
45419 // copy values from the child forms
45420 Roo.each(this.childForms, function (f) {
45421 this.setValues(f.getValues());
45427 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
45428 if(asString === true){
45431 return Roo.urlDecode(fs);
45435 * Returns the fields in this form as an object with key/value pairs.
45436 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
45439 getFieldValues : function(with_hidden)
45441 if (this.childForms) {
45442 // copy values from the child forms
45443 // should this call getFieldValues - probably not as we do not currently copy
45444 // hidden fields when we generate..
45445 Roo.each(this.childForms, function (f) {
45446 this.setValues(f.getValues());
45451 this.items.each(function(f){
45452 if (!f.getName()) {
45455 var v = f.getValue();
45456 if (f.inputType =='radio') {
45457 if (typeof(ret[f.getName()]) == 'undefined') {
45458 ret[f.getName()] = ''; // empty..
45461 if (!f.el.dom.checked) {
45465 v = f.el.dom.value;
45469 // not sure if this supported any more..
45470 if ((typeof(v) == 'object') && f.getRawValue) {
45471 v = f.getRawValue() ; // dates..
45473 // combo boxes where name != hiddenName...
45474 if (f.name != f.getName()) {
45475 ret[f.name] = f.getRawValue();
45477 ret[f.getName()] = v;
45484 * Clears all invalid messages in this form.
45485 * @return {BasicForm} this
45487 clearInvalid : function(){
45488 this.items.each(function(f){
45492 Roo.each(this.childForms || [], function (f) {
45501 * Resets this form.
45502 * @return {BasicForm} this
45504 reset : function(){
45505 this.items.each(function(f){
45509 Roo.each(this.childForms || [], function (f) {
45518 * Add Roo.form components to this form.
45519 * @param {Field} field1
45520 * @param {Field} field2 (optional)
45521 * @param {Field} etc (optional)
45522 * @return {BasicForm} this
45525 this.items.addAll(Array.prototype.slice.call(arguments, 0));
45531 * Removes a field from the items collection (does NOT remove its markup).
45532 * @param {Field} field
45533 * @return {BasicForm} this
45535 remove : function(field){
45536 this.items.remove(field);
45541 * Looks at the fields in this form, checks them for an id attribute,
45542 * and calls applyTo on the existing dom element with that id.
45543 * @return {BasicForm} this
45545 render : function(){
45546 this.items.each(function(f){
45547 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
45555 * Calls {@link Ext#apply} for all fields in this form with the passed object.
45556 * @param {Object} values
45557 * @return {BasicForm} this
45559 applyToFields : function(o){
45560 this.items.each(function(f){
45567 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
45568 * @param {Object} values
45569 * @return {BasicForm} this
45571 applyIfToFields : function(o){
45572 this.items.each(function(f){
45580 Roo.BasicForm = Roo.form.BasicForm;/*
45582 * Ext JS Library 1.1.1
45583 * Copyright(c) 2006-2007, Ext JS, LLC.
45585 * Originally Released Under LGPL - original licence link has changed is not relivant.
45588 * <script type="text/javascript">
45592 * @class Roo.form.Form
45593 * @extends Roo.form.BasicForm
45594 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
45596 * @param {Object} config Configuration options
45598 Roo.form.Form = function(config){
45600 if (config.items) {
45601 xitems = config.items;
45602 delete config.items;
45606 Roo.form.Form.superclass.constructor.call(this, null, config);
45607 this.url = this.url || this.action;
45609 this.root = new Roo.form.Layout(Roo.applyIf({
45613 this.active = this.root;
45615 * Array of all the buttons that have been added to this form via {@link addButton}
45619 this.allItems = [];
45622 * @event clientvalidation
45623 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45624 * @param {Form} this
45625 * @param {Boolean} valid true if the form has passed client-side validation
45627 clientvalidation: true,
45630 * Fires when the form is rendered
45631 * @param {Roo.form.Form} form
45636 if (this.progressUrl) {
45637 // push a hidden field onto the list of fields..
45641 name : 'UPLOAD_IDENTIFIER'
45646 Roo.each(xitems, this.addxtype, this);
45652 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45654 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45657 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45660 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45662 buttonAlign:'center',
45665 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45670 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45671 * This property cascades to child containers if not set.
45676 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45677 * fires a looping event with that state. This is required to bind buttons to the valid
45678 * state using the config value formBind:true on the button.
45680 monitorValid : false,
45683 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45688 * @cfg {String} progressUrl - Url to return progress data
45691 progressUrl : false,
45694 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45695 * fields are added and the column is closed. If no fields are passed the column remains open
45696 * until end() is called.
45697 * @param {Object} config The config to pass to the column
45698 * @param {Field} field1 (optional)
45699 * @param {Field} field2 (optional)
45700 * @param {Field} etc (optional)
45701 * @return Column The column container object
45703 column : function(c){
45704 var col = new Roo.form.Column(c);
45706 if(arguments.length > 1){ // duplicate code required because of Opera
45707 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45714 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45715 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45716 * until end() is called.
45717 * @param {Object} config The config to pass to the fieldset
45718 * @param {Field} field1 (optional)
45719 * @param {Field} field2 (optional)
45720 * @param {Field} etc (optional)
45721 * @return FieldSet The fieldset container object
45723 fieldset : function(c){
45724 var fs = new Roo.form.FieldSet(c);
45726 if(arguments.length > 1){ // duplicate code required because of Opera
45727 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45734 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45735 * fields are added and the container is closed. If no fields are passed the container remains open
45736 * until end() is called.
45737 * @param {Object} config The config to pass to the Layout
45738 * @param {Field} field1 (optional)
45739 * @param {Field} field2 (optional)
45740 * @param {Field} etc (optional)
45741 * @return Layout The container object
45743 container : function(c){
45744 var l = new Roo.form.Layout(c);
45746 if(arguments.length > 1){ // duplicate code required because of Opera
45747 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45754 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45755 * @param {Object} container A Roo.form.Layout or subclass of Layout
45756 * @return {Form} this
45758 start : function(c){
45759 // cascade label info
45760 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45761 this.active.stack.push(c);
45762 c.ownerCt = this.active;
45768 * Closes the current open container
45769 * @return {Form} this
45772 if(this.active == this.root){
45775 this.active = this.active.ownerCt;
45780 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45781 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45782 * as the label of the field.
45783 * @param {Field} field1
45784 * @param {Field} field2 (optional)
45785 * @param {Field} etc. (optional)
45786 * @return {Form} this
45789 this.active.stack.push.apply(this.active.stack, arguments);
45790 this.allItems.push.apply(this.allItems,arguments);
45792 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45793 if(a[i].isFormField){
45798 Roo.form.Form.superclass.add.apply(this, r);
45808 * Find any element that has been added to a form, using it's ID or name
45809 * This can include framesets, columns etc. along with regular fields..
45810 * @param {String} id - id or name to find.
45812 * @return {Element} e - or false if nothing found.
45814 findbyId : function(id)
45820 Roo.each(this.allItems, function(f){
45821 if (f.id == id || f.name == id ){
45832 * Render this form into the passed container. This should only be called once!
45833 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45834 * @return {Form} this
45836 render : function(ct)
45842 var o = this.autoCreate || {
45844 method : this.method || 'POST',
45845 id : this.id || Roo.id()
45847 this.initEl(ct.createChild(o));
45849 this.root.render(this.el);
45853 this.items.each(function(f){
45854 f.render('x-form-el-'+f.id);
45857 if(this.buttons.length > 0){
45858 // tables are required to maintain order and for correct IE layout
45859 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45860 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45861 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45863 var tr = tb.getElementsByTagName('tr')[0];
45864 for(var i = 0, len = this.buttons.length; i < len; i++) {
45865 var b = this.buttons[i];
45866 var td = document.createElement('td');
45867 td.className = 'x-form-btn-td';
45868 b.render(tr.appendChild(td));
45871 if(this.monitorValid){ // initialize after render
45872 this.startMonitoring();
45874 this.fireEvent('rendered', this);
45879 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45880 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45881 * object or a valid Roo.DomHelper element config
45882 * @param {Function} handler The function called when the button is clicked
45883 * @param {Object} scope (optional) The scope of the handler function
45884 * @return {Roo.Button}
45886 addButton : function(config, handler, scope){
45890 minWidth: this.minButtonWidth,
45893 if(typeof config == "string"){
45896 Roo.apply(bc, config);
45898 var btn = new Roo.Button(null, bc);
45899 this.buttons.push(btn);
45904 * Adds a series of form elements (using the xtype property as the factory method.
45905 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45906 * @param {Object} config
45909 addxtype : function()
45911 var ar = Array.prototype.slice.call(arguments, 0);
45913 for(var i = 0; i < ar.length; i++) {
45915 continue; // skip -- if this happends something invalid got sent, we
45916 // should ignore it, as basically that interface element will not show up
45917 // and that should be pretty obvious!!
45920 if (Roo.form[ar[i].xtype]) {
45922 var fe = Roo.factory(ar[i], Roo.form);
45928 fe.store.form = this;
45933 this.allItems.push(fe);
45934 if (fe.items && fe.addxtype) {
45935 fe.addxtype.apply(fe, fe.items);
45945 // console.log('adding ' + ar[i].xtype);
45947 if (ar[i].xtype == 'Button') {
45948 //console.log('adding button');
45949 //console.log(ar[i]);
45950 this.addButton(ar[i]);
45951 this.allItems.push(fe);
45955 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45956 alert('end is not supported on xtype any more, use items');
45958 // //console.log('adding end');
45966 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45967 * option "monitorValid"
45969 startMonitoring : function(){
45972 Roo.TaskMgr.start({
45973 run : this.bindHandler,
45974 interval : this.monitorPoll || 200,
45981 * Stops monitoring of the valid state of this form
45983 stopMonitoring : function(){
45984 this.bound = false;
45988 bindHandler : function(){
45990 return false; // stops binding
45993 this.items.each(function(f){
45994 if(!f.isValid(true)){
45999 for(var i = 0, len = this.buttons.length; i < len; i++){
46000 var btn = this.buttons[i];
46001 if(btn.formBind === true && btn.disabled === valid){
46002 btn.setDisabled(!valid);
46005 this.fireEvent('clientvalidation', this, valid);
46019 Roo.Form = Roo.form.Form;
46022 * Ext JS Library 1.1.1
46023 * Copyright(c) 2006-2007, Ext JS, LLC.
46025 * Originally Released Under LGPL - original licence link has changed is not relivant.
46028 * <script type="text/javascript">
46031 // as we use this in bootstrap.
46032 Roo.namespace('Roo.form');
46034 * @class Roo.form.Action
46035 * Internal Class used to handle form actions
46037 * @param {Roo.form.BasicForm} el The form element or its id
46038 * @param {Object} config Configuration options
46043 // define the action interface
46044 Roo.form.Action = function(form, options){
46046 this.options = options || {};
46049 * Client Validation Failed
46052 Roo.form.Action.CLIENT_INVALID = 'client';
46054 * Server Validation Failed
46057 Roo.form.Action.SERVER_INVALID = 'server';
46059 * Connect to Server Failed
46062 Roo.form.Action.CONNECT_FAILURE = 'connect';
46064 * Reading Data from Server Failed
46067 Roo.form.Action.LOAD_FAILURE = 'load';
46069 Roo.form.Action.prototype = {
46071 failureType : undefined,
46072 response : undefined,
46073 result : undefined,
46075 // interface method
46076 run : function(options){
46080 // interface method
46081 success : function(response){
46085 // interface method
46086 handleResponse : function(response){
46090 // default connection failure
46091 failure : function(response){
46093 this.response = response;
46094 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46095 this.form.afterAction(this, false);
46098 processResponse : function(response){
46099 this.response = response;
46100 if(!response.responseText){
46103 this.result = this.handleResponse(response);
46104 return this.result;
46107 // utility functions used internally
46108 getUrl : function(appendParams){
46109 var url = this.options.url || this.form.url || this.form.el.dom.action;
46111 var p = this.getParams();
46113 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
46119 getMethod : function(){
46120 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
46123 getParams : function(){
46124 var bp = this.form.baseParams;
46125 var p = this.options.params;
46127 if(typeof p == "object"){
46128 p = Roo.urlEncode(Roo.applyIf(p, bp));
46129 }else if(typeof p == 'string' && bp){
46130 p += '&' + Roo.urlEncode(bp);
46133 p = Roo.urlEncode(bp);
46138 createCallback : function(){
46140 success: this.success,
46141 failure: this.failure,
46143 timeout: (this.form.timeout*1000),
46144 upload: this.form.fileUpload ? this.success : undefined
46149 Roo.form.Action.Submit = function(form, options){
46150 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
46153 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
46156 haveProgress : false,
46157 uploadComplete : false,
46159 // uploadProgress indicator.
46160 uploadProgress : function()
46162 if (!this.form.progressUrl) {
46166 if (!this.haveProgress) {
46167 Roo.MessageBox.progress("Uploading", "Uploading");
46169 if (this.uploadComplete) {
46170 Roo.MessageBox.hide();
46174 this.haveProgress = true;
46176 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
46178 var c = new Roo.data.Connection();
46180 url : this.form.progressUrl,
46185 success : function(req){
46186 //console.log(data);
46190 rdata = Roo.decode(req.responseText)
46192 Roo.log("Invalid data from server..");
46196 if (!rdata || !rdata.success) {
46198 Roo.MessageBox.alert(Roo.encode(rdata));
46201 var data = rdata.data;
46203 if (this.uploadComplete) {
46204 Roo.MessageBox.hide();
46209 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
46210 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
46213 this.uploadProgress.defer(2000,this);
46216 failure: function(data) {
46217 Roo.log('progress url failed ');
46228 // run get Values on the form, so it syncs any secondary forms.
46229 this.form.getValues();
46231 var o = this.options;
46232 var method = this.getMethod();
46233 var isPost = method == 'POST';
46234 if(o.clientValidation === false || this.form.isValid()){
46236 if (this.form.progressUrl) {
46237 this.form.findField('UPLOAD_IDENTIFIER').setValue(
46238 (new Date() * 1) + '' + Math.random());
46243 Roo.Ajax.request(Roo.apply(this.createCallback(), {
46244 form:this.form.el.dom,
46245 url:this.getUrl(!isPost),
46247 params:isPost ? this.getParams() : null,
46248 isUpload: this.form.fileUpload
46251 this.uploadProgress();
46253 }else if (o.clientValidation !== false){ // client validation failed
46254 this.failureType = Roo.form.Action.CLIENT_INVALID;
46255 this.form.afterAction(this, false);
46259 success : function(response)
46261 this.uploadComplete= true;
46262 if (this.haveProgress) {
46263 Roo.MessageBox.hide();
46267 var result = this.processResponse(response);
46268 if(result === true || result.success){
46269 this.form.afterAction(this, true);
46273 this.form.markInvalid(result.errors);
46274 this.failureType = Roo.form.Action.SERVER_INVALID;
46276 this.form.afterAction(this, false);
46278 failure : function(response)
46280 this.uploadComplete= true;
46281 if (this.haveProgress) {
46282 Roo.MessageBox.hide();
46285 this.response = response;
46286 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46287 this.form.afterAction(this, false);
46290 handleResponse : function(response){
46291 if(this.form.errorReader){
46292 var rs = this.form.errorReader.read(response);
46295 for(var i = 0, len = rs.records.length; i < len; i++) {
46296 var r = rs.records[i];
46297 errors[i] = r.data;
46300 if(errors.length < 1){
46304 success : rs.success,
46310 ret = Roo.decode(response.responseText);
46314 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
46324 Roo.form.Action.Load = function(form, options){
46325 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
46326 this.reader = this.form.reader;
46329 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
46334 Roo.Ajax.request(Roo.apply(
46335 this.createCallback(), {
46336 method:this.getMethod(),
46337 url:this.getUrl(false),
46338 params:this.getParams()
46342 success : function(response){
46344 var result = this.processResponse(response);
46345 if(result === true || !result.success || !result.data){
46346 this.failureType = Roo.form.Action.LOAD_FAILURE;
46347 this.form.afterAction(this, false);
46350 this.form.clearInvalid();
46351 this.form.setValues(result.data);
46352 this.form.afterAction(this, true);
46355 handleResponse : function(response){
46356 if(this.form.reader){
46357 var rs = this.form.reader.read(response);
46358 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
46360 success : rs.success,
46364 return Roo.decode(response.responseText);
46368 Roo.form.Action.ACTION_TYPES = {
46369 'load' : Roo.form.Action.Load,
46370 'submit' : Roo.form.Action.Submit
46373 * Ext JS Library 1.1.1
46374 * Copyright(c) 2006-2007, Ext JS, LLC.
46376 * Originally Released Under LGPL - original licence link has changed is not relivant.
46379 * <script type="text/javascript">
46383 * @class Roo.form.Layout
46384 * @extends Roo.Component
46385 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
46387 * @param {Object} config Configuration options
46389 Roo.form.Layout = function(config){
46391 if (config.items) {
46392 xitems = config.items;
46393 delete config.items;
46395 Roo.form.Layout.superclass.constructor.call(this, config);
46397 Roo.each(xitems, this.addxtype, this);
46401 Roo.extend(Roo.form.Layout, Roo.Component, {
46403 * @cfg {String/Object} autoCreate
46404 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
46407 * @cfg {String/Object/Function} style
46408 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
46409 * a function which returns such a specification.
46412 * @cfg {String} labelAlign
46413 * Valid values are "left," "top" and "right" (defaults to "left")
46416 * @cfg {Number} labelWidth
46417 * Fixed width in pixels of all field labels (defaults to undefined)
46420 * @cfg {Boolean} clear
46421 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
46425 * @cfg {String} labelSeparator
46426 * The separator to use after field labels (defaults to ':')
46428 labelSeparator : ':',
46430 * @cfg {Boolean} hideLabels
46431 * True to suppress the display of field labels in this layout (defaults to false)
46433 hideLabels : false,
46436 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
46441 onRender : function(ct, position){
46442 if(this.el){ // from markup
46443 this.el = Roo.get(this.el);
46444 }else { // generate
46445 var cfg = this.getAutoCreate();
46446 this.el = ct.createChild(cfg, position);
46449 this.el.applyStyles(this.style);
46451 if(this.labelAlign){
46452 this.el.addClass('x-form-label-'+this.labelAlign);
46454 if(this.hideLabels){
46455 this.labelStyle = "display:none";
46456 this.elementStyle = "padding-left:0;";
46458 if(typeof this.labelWidth == 'number'){
46459 this.labelStyle = "width:"+this.labelWidth+"px;";
46460 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
46462 if(this.labelAlign == 'top'){
46463 this.labelStyle = "width:auto;";
46464 this.elementStyle = "padding-left:0;";
46467 var stack = this.stack;
46468 var slen = stack.length;
46470 if(!this.fieldTpl){
46471 var t = new Roo.Template(
46472 '<div class="x-form-item {5}">',
46473 '<label for="{0}" style="{2}">{1}{4}</label>',
46474 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46476 '</div><div class="x-form-clear-left"></div>'
46478 t.disableFormats = true;
46480 Roo.form.Layout.prototype.fieldTpl = t;
46482 for(var i = 0; i < slen; i++) {
46483 if(stack[i].isFormField){
46484 this.renderField(stack[i]);
46486 this.renderComponent(stack[i]);
46491 this.el.createChild({cls:'x-form-clear'});
46496 renderField : function(f){
46497 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
46500 f.labelStyle||this.labelStyle||'', //2
46501 this.elementStyle||'', //3
46502 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
46503 f.itemCls||this.itemCls||'' //5
46504 ], true).getPrevSibling());
46508 renderComponent : function(c){
46509 c.render(c.isLayout ? this.el : this.el.createChild());
46512 * Adds a object form elements (using the xtype property as the factory method.)
46513 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
46514 * @param {Object} config
46516 addxtype : function(o)
46518 // create the lement.
46519 o.form = this.form;
46520 var fe = Roo.factory(o, Roo.form);
46521 this.form.allItems.push(fe);
46522 this.stack.push(fe);
46524 if (fe.isFormField) {
46525 this.form.items.add(fe);
46533 * @class Roo.form.Column
46534 * @extends Roo.form.Layout
46535 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
46537 * @param {Object} config Configuration options
46539 Roo.form.Column = function(config){
46540 Roo.form.Column.superclass.constructor.call(this, config);
46543 Roo.extend(Roo.form.Column, Roo.form.Layout, {
46545 * @cfg {Number/String} width
46546 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46549 * @cfg {String/Object} autoCreate
46550 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
46554 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
46557 onRender : function(ct, position){
46558 Roo.form.Column.superclass.onRender.call(this, ct, position);
46560 this.el.setWidth(this.width);
46567 * @class Roo.form.Row
46568 * @extends Roo.form.Layout
46569 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
46571 * @param {Object} config Configuration options
46575 Roo.form.Row = function(config){
46576 Roo.form.Row.superclass.constructor.call(this, config);
46579 Roo.extend(Roo.form.Row, Roo.form.Layout, {
46581 * @cfg {Number/String} width
46582 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46585 * @cfg {Number/String} height
46586 * The fixed height of the column in pixels or CSS value (defaults to "auto")
46588 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
46592 onRender : function(ct, position){
46593 //console.log('row render');
46595 var t = new Roo.Template(
46596 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
46597 '<label for="{0}" style="{2}">{1}{4}</label>',
46598 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46602 t.disableFormats = true;
46604 Roo.form.Layout.prototype.rowTpl = t;
46606 this.fieldTpl = this.rowTpl;
46608 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46609 var labelWidth = 100;
46611 if ((this.labelAlign != 'top')) {
46612 if (typeof this.labelWidth == 'number') {
46613 labelWidth = this.labelWidth
46615 this.padWidth = 20 + labelWidth;
46619 Roo.form.Column.superclass.onRender.call(this, ct, position);
46621 this.el.setWidth(this.width);
46624 this.el.setHeight(this.height);
46629 renderField : function(f){
46630 f.fieldEl = this.fieldTpl.append(this.el, [
46631 f.id, f.fieldLabel,
46632 f.labelStyle||this.labelStyle||'',
46633 this.elementStyle||'',
46634 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46635 f.itemCls||this.itemCls||'',
46636 f.width ? f.width + this.padWidth : 160 + this.padWidth
46643 * @class Roo.form.FieldSet
46644 * @extends Roo.form.Layout
46645 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46647 * @param {Object} config Configuration options
46649 Roo.form.FieldSet = function(config){
46650 Roo.form.FieldSet.superclass.constructor.call(this, config);
46653 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46655 * @cfg {String} legend
46656 * The text to display as the legend for the FieldSet (defaults to '')
46659 * @cfg {String/Object} autoCreate
46660 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46664 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46667 onRender : function(ct, position){
46668 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46670 this.setLegend(this.legend);
46675 setLegend : function(text){
46677 this.el.child('legend').update(text);
46682 * Ext JS Library 1.1.1
46683 * Copyright(c) 2006-2007, Ext JS, LLC.
46685 * Originally Released Under LGPL - original licence link has changed is not relivant.
46688 * <script type="text/javascript">
46691 * @class Roo.form.VTypes
46692 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46695 Roo.form.VTypes = function(){
46696 // closure these in so they are only created once.
46697 var alpha = /^[a-zA-Z_]+$/;
46698 var alphanum = /^[a-zA-Z0-9_]+$/;
46699 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46700 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46702 // All these messages and functions are configurable
46705 * The function used to validate email addresses
46706 * @param {String} value The email address
46708 'email' : function(v){
46709 return email.test(v);
46712 * The error text to display when the email validation function returns false
46715 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46717 * The keystroke filter mask to be applied on email input
46720 'emailMask' : /[a-z0-9_\.\-@]/i,
46723 * The function used to validate URLs
46724 * @param {String} value The URL
46726 'url' : function(v){
46727 return url.test(v);
46730 * The error text to display when the url validation function returns false
46733 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46736 * The function used to validate alpha values
46737 * @param {String} value The value
46739 'alpha' : function(v){
46740 return alpha.test(v);
46743 * The error text to display when the alpha validation function returns false
46746 'alphaText' : 'This field should only contain letters and _',
46748 * The keystroke filter mask to be applied on alpha input
46751 'alphaMask' : /[a-z_]/i,
46754 * The function used to validate alphanumeric values
46755 * @param {String} value The value
46757 'alphanum' : function(v){
46758 return alphanum.test(v);
46761 * The error text to display when the alphanumeric validation function returns false
46764 'alphanumText' : 'This field should only contain letters, numbers and _',
46766 * The keystroke filter mask to be applied on alphanumeric input
46769 'alphanumMask' : /[a-z0-9_]/i
46771 }();//<script type="text/javascript">
46774 * @class Roo.form.FCKeditor
46775 * @extends Roo.form.TextArea
46776 * Wrapper around the FCKEditor http://www.fckeditor.net
46778 * Creates a new FCKeditor
46779 * @param {Object} config Configuration options
46781 Roo.form.FCKeditor = function(config){
46782 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46785 * @event editorinit
46786 * Fired when the editor is initialized - you can add extra handlers here..
46787 * @param {FCKeditor} this
46788 * @param {Object} the FCK object.
46795 Roo.form.FCKeditor.editors = { };
46796 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46798 //defaultAutoCreate : {
46799 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46803 * @cfg {Object} fck options - see fck manual for details.
46808 * @cfg {Object} fck toolbar set (Basic or Default)
46810 toolbarSet : 'Basic',
46812 * @cfg {Object} fck BasePath
46814 basePath : '/fckeditor/',
46822 onRender : function(ct, position)
46825 this.defaultAutoCreate = {
46827 style:"width:300px;height:60px;",
46828 autocomplete: "new-password"
46831 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46834 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46835 if(this.preventScrollbars){
46836 this.el.setStyle("overflow", "hidden");
46838 this.el.setHeight(this.growMin);
46841 //console.log('onrender' + this.getId() );
46842 Roo.form.FCKeditor.editors[this.getId()] = this;
46845 this.replaceTextarea() ;
46849 getEditor : function() {
46850 return this.fckEditor;
46853 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46854 * @param {Mixed} value The value to set
46858 setValue : function(value)
46860 //console.log('setValue: ' + value);
46862 if(typeof(value) == 'undefined') { // not sure why this is happending...
46865 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46867 //if(!this.el || !this.getEditor()) {
46868 // this.value = value;
46869 //this.setValue.defer(100,this,[value]);
46873 if(!this.getEditor()) {
46877 this.getEditor().SetData(value);
46884 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46885 * @return {Mixed} value The field value
46887 getValue : function()
46890 if (this.frame && this.frame.dom.style.display == 'none') {
46891 return Roo.form.FCKeditor.superclass.getValue.call(this);
46894 if(!this.el || !this.getEditor()) {
46896 // this.getValue.defer(100,this);
46901 var value=this.getEditor().GetData();
46902 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46903 return Roo.form.FCKeditor.superclass.getValue.call(this);
46909 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46910 * @return {Mixed} value The field value
46912 getRawValue : function()
46914 if (this.frame && this.frame.dom.style.display == 'none') {
46915 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46918 if(!this.el || !this.getEditor()) {
46919 //this.getRawValue.defer(100,this);
46926 var value=this.getEditor().GetData();
46927 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46928 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46932 setSize : function(w,h) {
46936 //if (this.frame && this.frame.dom.style.display == 'none') {
46937 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46940 //if(!this.el || !this.getEditor()) {
46941 // this.setSize.defer(100,this, [w,h]);
46947 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46949 this.frame.dom.setAttribute('width', w);
46950 this.frame.dom.setAttribute('height', h);
46951 this.frame.setSize(w,h);
46955 toggleSourceEdit : function(value) {
46959 this.el.dom.style.display = value ? '' : 'none';
46960 this.frame.dom.style.display = value ? 'none' : '';
46965 focus: function(tag)
46967 if (this.frame.dom.style.display == 'none') {
46968 return Roo.form.FCKeditor.superclass.focus.call(this);
46970 if(!this.el || !this.getEditor()) {
46971 this.focus.defer(100,this, [tag]);
46978 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46979 this.getEditor().Focus();
46981 if (!this.getEditor().Selection.GetSelection()) {
46982 this.focus.defer(100,this, [tag]);
46987 var r = this.getEditor().EditorDocument.createRange();
46988 r.setStart(tgs[0],0);
46989 r.setEnd(tgs[0],0);
46990 this.getEditor().Selection.GetSelection().removeAllRanges();
46991 this.getEditor().Selection.GetSelection().addRange(r);
46992 this.getEditor().Focus();
46999 replaceTextarea : function()
47001 if ( document.getElementById( this.getId() + '___Frame' ) )
47003 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
47005 // We must check the elements firstly using the Id and then the name.
47006 var oTextarea = document.getElementById( this.getId() );
47008 var colElementsByName = document.getElementsByName( this.getId() ) ;
47010 oTextarea.style.display = 'none' ;
47012 if ( oTextarea.tabIndex ) {
47013 this.TabIndex = oTextarea.tabIndex ;
47016 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
47017 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
47018 this.frame = Roo.get(this.getId() + '___Frame')
47021 _getConfigHtml : function()
47025 for ( var o in this.fckconfig ) {
47026 sConfig += sConfig.length > 0 ? '&' : '';
47027 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
47030 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
47034 _getIFrameHtml : function()
47036 var sFile = 'fckeditor.html' ;
47037 /* no idea what this is about..
47040 if ( (/fcksource=true/i).test( window.top.location.search ) )
47041 sFile = 'fckeditor.original.html' ;
47046 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
47047 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
47050 var html = '<iframe id="' + this.getId() +
47051 '___Frame" src="' + sLink +
47052 '" width="' + this.width +
47053 '" height="' + this.height + '"' +
47054 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
47055 ' frameborder="0" scrolling="no"></iframe>' ;
47060 _insertHtmlBefore : function( html, element )
47062 if ( element.insertAdjacentHTML ) {
47064 element.insertAdjacentHTML( 'beforeBegin', html ) ;
47066 var oRange = document.createRange() ;
47067 oRange.setStartBefore( element ) ;
47068 var oFragment = oRange.createContextualFragment( html );
47069 element.parentNode.insertBefore( oFragment, element ) ;
47082 //Roo.reg('fckeditor', Roo.form.FCKeditor);
47084 function FCKeditor_OnComplete(editorInstance){
47085 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
47086 f.fckEditor = editorInstance;
47087 //console.log("loaded");
47088 f.fireEvent('editorinit', f, editorInstance);
47108 //<script type="text/javascript">
47110 * @class Roo.form.GridField
47111 * @extends Roo.form.Field
47112 * Embed a grid (or editable grid into a form)
47115 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
47117 * xgrid.store = Roo.data.Store
47118 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
47119 * xgrid.store.reader = Roo.data.JsonReader
47123 * Creates a new GridField
47124 * @param {Object} config Configuration options
47126 Roo.form.GridField = function(config){
47127 Roo.form.GridField.superclass.constructor.call(this, config);
47131 Roo.extend(Roo.form.GridField, Roo.form.Field, {
47133 * @cfg {Number} width - used to restrict width of grid..
47137 * @cfg {Number} height - used to restrict height of grid..
47141 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
47147 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47148 * {tag: "input", type: "checkbox", autocomplete: "off"})
47150 // defaultAutoCreate : { tag: 'div' },
47151 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
47153 * @cfg {String} addTitle Text to include for adding a title.
47157 onResize : function(){
47158 Roo.form.Field.superclass.onResize.apply(this, arguments);
47161 initEvents : function(){
47162 // Roo.form.Checkbox.superclass.initEvents.call(this);
47163 // has no events...
47168 getResizeEl : function(){
47172 getPositionEl : function(){
47177 onRender : function(ct, position){
47179 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
47180 var style = this.style;
47183 Roo.form.GridField.superclass.onRender.call(this, ct, position);
47184 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
47185 this.viewEl = this.wrap.createChild({ tag: 'div' });
47187 this.viewEl.applyStyles(style);
47190 this.viewEl.setWidth(this.width);
47193 this.viewEl.setHeight(this.height);
47195 //if(this.inputValue !== undefined){
47196 //this.setValue(this.value);
47199 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
47202 this.grid.render();
47203 this.grid.getDataSource().on('remove', this.refreshValue, this);
47204 this.grid.getDataSource().on('update', this.refreshValue, this);
47205 this.grid.on('afteredit', this.refreshValue, this);
47211 * Sets the value of the item.
47212 * @param {String} either an object or a string..
47214 setValue : function(v){
47216 v = v || []; // empty set..
47217 // this does not seem smart - it really only affects memoryproxy grids..
47218 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
47219 var ds = this.grid.getDataSource();
47220 // assumes a json reader..
47222 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
47223 ds.loadData( data);
47225 // clear selection so it does not get stale.
47226 if (this.grid.sm) {
47227 this.grid.sm.clearSelections();
47230 Roo.form.GridField.superclass.setValue.call(this, v);
47231 this.refreshValue();
47232 // should load data in the grid really....
47236 refreshValue: function() {
47238 this.grid.getDataSource().each(function(r) {
47241 this.el.dom.value = Roo.encode(val);
47249 * Ext JS Library 1.1.1
47250 * Copyright(c) 2006-2007, Ext JS, LLC.
47252 * Originally Released Under LGPL - original licence link has changed is not relivant.
47255 * <script type="text/javascript">
47258 * @class Roo.form.DisplayField
47259 * @extends Roo.form.Field
47260 * A generic Field to display non-editable data.
47262 * Creates a new Display Field item.
47263 * @param {Object} config Configuration options
47265 Roo.form.DisplayField = function(config){
47266 Roo.form.DisplayField.superclass.constructor.call(this, config);
47270 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
47271 inputType: 'hidden',
47277 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47279 focusClass : undefined,
47281 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47283 fieldClass: 'x-form-field',
47286 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
47288 valueRenderer: undefined,
47292 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47293 * {tag: "input", type: "checkbox", autocomplete: "off"})
47296 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
47298 onResize : function(){
47299 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
47303 initEvents : function(){
47304 // Roo.form.Checkbox.superclass.initEvents.call(this);
47305 // has no events...
47310 getResizeEl : function(){
47314 getPositionEl : function(){
47319 onRender : function(ct, position){
47321 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
47322 //if(this.inputValue !== undefined){
47323 this.wrap = this.el.wrap();
47325 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
47327 if (this.bodyStyle) {
47328 this.viewEl.applyStyles(this.bodyStyle);
47330 //this.viewEl.setStyle('padding', '2px');
47332 this.setValue(this.value);
47337 initValue : Roo.emptyFn,
47342 onClick : function(){
47347 * Sets the checked state of the checkbox.
47348 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
47350 setValue : function(v){
47352 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
47353 // this might be called before we have a dom element..
47354 if (!this.viewEl) {
47357 this.viewEl.dom.innerHTML = html;
47358 Roo.form.DisplayField.superclass.setValue.call(this, v);
47368 * @class Roo.form.DayPicker
47369 * @extends Roo.form.Field
47370 * A Day picker show [M] [T] [W] ....
47372 * Creates a new Day Picker
47373 * @param {Object} config Configuration options
47375 Roo.form.DayPicker= function(config){
47376 Roo.form.DayPicker.superclass.constructor.call(this, config);
47380 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
47382 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47384 focusClass : undefined,
47386 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47388 fieldClass: "x-form-field",
47391 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47392 * {tag: "input", type: "checkbox", autocomplete: "off"})
47394 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
47397 actionMode : 'viewEl',
47401 inputType : 'hidden',
47404 inputElement: false, // real input element?
47405 basedOn: false, // ????
47407 isFormField: true, // not sure where this is needed!!!!
47409 onResize : function(){
47410 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
47411 if(!this.boxLabel){
47412 this.el.alignTo(this.wrap, 'c-c');
47416 initEvents : function(){
47417 Roo.form.Checkbox.superclass.initEvents.call(this);
47418 this.el.on("click", this.onClick, this);
47419 this.el.on("change", this.onClick, this);
47423 getResizeEl : function(){
47427 getPositionEl : function(){
47433 onRender : function(ct, position){
47434 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
47436 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
47438 var r1 = '<table><tr>';
47439 var r2 = '<tr class="x-form-daypick-icons">';
47440 for (var i=0; i < 7; i++) {
47441 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
47442 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
47445 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
47446 viewEl.select('img').on('click', this.onClick, this);
47447 this.viewEl = viewEl;
47450 // this will not work on Chrome!!!
47451 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
47452 this.el.on('propertychange', this.setFromHidden, this); //ie
47460 initValue : Roo.emptyFn,
47463 * Returns the checked state of the checkbox.
47464 * @return {Boolean} True if checked, else false
47466 getValue : function(){
47467 return this.el.dom.value;
47472 onClick : function(e){
47473 //this.setChecked(!this.checked);
47474 Roo.get(e.target).toggleClass('x-menu-item-checked');
47475 this.refreshValue();
47476 //if(this.el.dom.checked != this.checked){
47477 // this.setValue(this.el.dom.checked);
47482 refreshValue : function()
47485 this.viewEl.select('img',true).each(function(e,i,n) {
47486 val += e.is(".x-menu-item-checked") ? String(n) : '';
47488 this.setValue(val, true);
47492 * Sets the checked state of the checkbox.
47493 * On is always based on a string comparison between inputValue and the param.
47494 * @param {Boolean/String} value - the value to set
47495 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
47497 setValue : function(v,suppressEvent){
47498 if (!this.el.dom) {
47501 var old = this.el.dom.value ;
47502 this.el.dom.value = v;
47503 if (suppressEvent) {
47507 // update display..
47508 this.viewEl.select('img',true).each(function(e,i,n) {
47510 var on = e.is(".x-menu-item-checked");
47511 var newv = v.indexOf(String(n)) > -1;
47513 e.toggleClass('x-menu-item-checked');
47519 this.fireEvent('change', this, v, old);
47524 // handle setting of hidden value by some other method!!?!?
47525 setFromHidden: function()
47530 //console.log("SET FROM HIDDEN");
47531 //alert('setFrom hidden');
47532 this.setValue(this.el.dom.value);
47535 onDestroy : function()
47538 Roo.get(this.viewEl).remove();
47541 Roo.form.DayPicker.superclass.onDestroy.call(this);
47545 * RooJS Library 1.1.1
47546 * Copyright(c) 2008-2011 Alan Knowles
47553 * @class Roo.form.ComboCheck
47554 * @extends Roo.form.ComboBox
47555 * A combobox for multiple select items.
47557 * FIXME - could do with a reset button..
47560 * Create a new ComboCheck
47561 * @param {Object} config Configuration options
47563 Roo.form.ComboCheck = function(config){
47564 Roo.form.ComboCheck.superclass.constructor.call(this, config);
47565 // should verify some data...
47567 // hiddenName = required..
47568 // displayField = required
47569 // valudField == required
47570 var req= [ 'hiddenName', 'displayField', 'valueField' ];
47572 Roo.each(req, function(e) {
47573 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
47574 throw "Roo.form.ComboCheck : missing value for: " + e;
47581 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
47586 selectedClass: 'x-menu-item-checked',
47589 onRender : function(ct, position){
47595 var cls = 'x-combo-list';
47598 this.tpl = new Roo.Template({
47599 html : '<div class="'+cls+'-item x-menu-check-item">' +
47600 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47601 '<span>{' + this.displayField + '}</span>' +
47608 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47609 this.view.singleSelect = false;
47610 this.view.multiSelect = true;
47611 this.view.toggleSelect = true;
47612 this.pageTb.add(new Roo.Toolbar.Fill(), {
47615 handler: function()
47622 onViewOver : function(e, t){
47628 onViewClick : function(doFocus,index){
47632 select: function () {
47633 //Roo.log("SELECT CALLED");
47636 selectByValue : function(xv, scrollIntoView){
47637 var ar = this.getValueArray();
47640 Roo.each(ar, function(v) {
47641 if(v === undefined || v === null){
47644 var r = this.findRecord(this.valueField, v);
47646 sels.push(this.store.indexOf(r))
47650 this.view.select(sels);
47656 onSelect : function(record, index){
47657 // Roo.log("onselect Called");
47658 // this is only called by the clear button now..
47659 this.view.clearSelections();
47660 this.setValue('[]');
47661 if (this.value != this.valueBefore) {
47662 this.fireEvent('change', this, this.value, this.valueBefore);
47663 this.valueBefore = this.value;
47666 getValueArray : function()
47671 //Roo.log(this.value);
47672 if (typeof(this.value) == 'undefined') {
47675 var ar = Roo.decode(this.value);
47676 return ar instanceof Array ? ar : []; //?? valid?
47679 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47684 expand : function ()
47687 Roo.form.ComboCheck.superclass.expand.call(this);
47688 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47689 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47694 collapse : function(){
47695 Roo.form.ComboCheck.superclass.collapse.call(this);
47696 var sl = this.view.getSelectedIndexes();
47697 var st = this.store;
47701 Roo.each(sl, function(i) {
47703 nv.push(r.get(this.valueField));
47705 this.setValue(Roo.encode(nv));
47706 if (this.value != this.valueBefore) {
47708 this.fireEvent('change', this, this.value, this.valueBefore);
47709 this.valueBefore = this.value;
47714 setValue : function(v){
47718 var vals = this.getValueArray();
47720 Roo.each(vals, function(k) {
47721 var r = this.findRecord(this.valueField, k);
47723 tv.push(r.data[this.displayField]);
47724 }else if(this.valueNotFoundText !== undefined){
47725 tv.push( this.valueNotFoundText );
47730 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47731 this.hiddenField.value = v;
47737 * Ext JS Library 1.1.1
47738 * Copyright(c) 2006-2007, Ext JS, LLC.
47740 * Originally Released Under LGPL - original licence link has changed is not relivant.
47743 * <script type="text/javascript">
47747 * @class Roo.form.Signature
47748 * @extends Roo.form.Field
47752 * @param {Object} config Configuration options
47755 Roo.form.Signature = function(config){
47756 Roo.form.Signature.superclass.constructor.call(this, config);
47758 this.addEvents({// not in used??
47761 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47762 * @param {Roo.form.Signature} combo This combo box
47767 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47768 * @param {Roo.form.ComboBox} combo This combo box
47769 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47775 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47777 * @cfg {Object} labels Label to use when rendering a form.
47781 * confirm : "Confirm"
47786 confirm : "Confirm"
47789 * @cfg {Number} width The signature panel width (defaults to 300)
47793 * @cfg {Number} height The signature panel height (defaults to 100)
47797 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47799 allowBlank : false,
47802 // {Object} signPanel The signature SVG panel element (defaults to {})
47804 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47805 isMouseDown : false,
47806 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47807 isConfirmed : false,
47808 // {String} signatureTmp SVG mapping string (defaults to empty string)
47812 defaultAutoCreate : { // modified by initCompnoent..
47818 onRender : function(ct, position){
47820 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47822 this.wrap = this.el.wrap({
47823 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47826 this.createToolbar(this);
47827 this.signPanel = this.wrap.createChild({
47829 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47833 this.svgID = Roo.id();
47834 this.svgEl = this.signPanel.createChild({
47835 xmlns : 'http://www.w3.org/2000/svg',
47837 id : this.svgID + "-svg",
47839 height: this.height,
47840 viewBox: '0 0 '+this.width+' '+this.height,
47844 id: this.svgID + "-svg-r",
47846 height: this.height,
47851 id: this.svgID + "-svg-l",
47853 y1: (this.height*0.8), // start set the line in 80% of height
47854 x2: this.width, // end
47855 y2: (this.height*0.8), // end set the line in 80% of height
47857 'stroke-width': "1",
47858 'stroke-dasharray': "3",
47859 'shape-rendering': "crispEdges",
47860 'pointer-events': "none"
47864 id: this.svgID + "-svg-p",
47866 'stroke-width': "3",
47868 'pointer-events': 'none'
47873 this.svgBox = this.svgEl.dom.getScreenCTM();
47875 createSVG : function(){
47876 var svg = this.signPanel;
47877 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47880 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47881 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47882 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47883 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47884 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47885 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47886 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47889 isTouchEvent : function(e){
47890 return e.type.match(/^touch/);
47892 getCoords : function (e) {
47893 var pt = this.svgEl.dom.createSVGPoint();
47896 if (this.isTouchEvent(e)) {
47897 pt.x = e.targetTouches[0].clientX
47898 pt.y = e.targetTouches[0].clientY;
47900 var a = this.svgEl.dom.getScreenCTM();
47901 var b = a.inverse();
47902 var mx = pt.matrixTransform(b);
47903 return mx.x + ',' + mx.y;
47905 //mouse event headler
47906 down : function (e) {
47907 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47908 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47910 this.isMouseDown = true;
47912 e.preventDefault();
47914 move : function (e) {
47915 if (this.isMouseDown) {
47916 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47917 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47920 e.preventDefault();
47922 up : function (e) {
47923 this.isMouseDown = false;
47924 var sp = this.signatureTmp.split(' ');
47927 if(!sp[sp.length-2].match(/^L/)){
47931 this.signatureTmp = sp.join(" ");
47934 if(this.getValue() != this.signatureTmp){
47935 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47936 this.isConfirmed = false;
47938 e.preventDefault();
47942 * Protected method that will not generally be called directly. It
47943 * is called when the editor creates its toolbar. Override this method if you need to
47944 * add custom toolbar buttons.
47945 * @param {HtmlEditor} editor
47947 createToolbar : function(editor){
47948 function btn(id, toggle, handler){
47949 var xid = fid + '-'+ id ;
47953 cls : 'x-btn-icon x-edit-'+id,
47954 enableToggle:toggle !== false,
47955 scope: editor, // was editor...
47956 handler:handler||editor.relayBtnCmd,
47957 clickEvent:'mousedown',
47958 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47964 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47968 cls : ' x-signature-btn x-signature-'+id,
47969 scope: editor, // was editor...
47970 handler: this.reset,
47971 clickEvent:'mousedown',
47972 text: this.labels.clear
47979 cls : ' x-signature-btn x-signature-'+id,
47980 scope: editor, // was editor...
47981 handler: this.confirmHandler,
47982 clickEvent:'mousedown',
47983 text: this.labels.confirm
47990 * when user is clicked confirm then show this image.....
47992 * @return {String} Image Data URI
47994 getImageDataURI : function(){
47995 var svg = this.svgEl.dom.parentNode.innerHTML;
47996 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
48001 * @return {Boolean} this.isConfirmed
48003 getConfirmed : function(){
48004 return this.isConfirmed;
48008 * @return {Number} this.width
48010 getWidth : function(){
48015 * @return {Number} this.height
48017 getHeight : function(){
48018 return this.height;
48021 getSignature : function(){
48022 return this.signatureTmp;
48025 reset : function(){
48026 this.signatureTmp = '';
48027 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48028 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
48029 this.isConfirmed = false;
48030 Roo.form.Signature.superclass.reset.call(this);
48032 setSignature : function(s){
48033 this.signatureTmp = s;
48034 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48035 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
48037 this.isConfirmed = false;
48038 Roo.form.Signature.superclass.reset.call(this);
48041 // Roo.log(this.signPanel.dom.contentWindow.up())
48044 setConfirmed : function(){
48048 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
48051 confirmHandler : function(){
48052 if(!this.getSignature()){
48056 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
48057 this.setValue(this.getSignature());
48058 this.isConfirmed = true;
48060 this.fireEvent('confirm', this);
48063 // Subclasses should provide the validation implementation by overriding this
48064 validateValue : function(value){
48065 if(this.allowBlank){
48069 if(this.isConfirmed){
48076 * Ext JS Library 1.1.1
48077 * Copyright(c) 2006-2007, Ext JS, LLC.
48079 * Originally Released Under LGPL - original licence link has changed is not relivant.
48082 * <script type="text/javascript">
48087 * @class Roo.form.ComboBox
48088 * @extends Roo.form.TriggerField
48089 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
48091 * Create a new ComboBox.
48092 * @param {Object} config Configuration options
48094 Roo.form.Select = function(config){
48095 Roo.form.Select.superclass.constructor.call(this, config);
48099 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
48101 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
48104 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
48105 * rendering into an Roo.Editor, defaults to false)
48108 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
48109 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
48112 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
48115 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
48116 * the dropdown list (defaults to undefined, with no header element)
48120 * @cfg {String/Roo.Template} tpl The template to use to render the output
48124 defaultAutoCreate : {tag: "select" },
48126 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
48128 listWidth: undefined,
48130 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
48131 * mode = 'remote' or 'text' if mode = 'local')
48133 displayField: undefined,
48135 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
48136 * mode = 'remote' or 'value' if mode = 'local').
48137 * Note: use of a valueField requires the user make a selection
48138 * in order for a value to be mapped.
48140 valueField: undefined,
48144 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
48145 * field's data value (defaults to the underlying DOM element's name)
48147 hiddenName: undefined,
48149 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
48153 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
48155 selectedClass: 'x-combo-selected',
48157 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
48158 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
48159 * which displays a downward arrow icon).
48161 triggerClass : 'x-form-arrow-trigger',
48163 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
48167 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
48168 * anchor positions (defaults to 'tl-bl')
48170 listAlign: 'tl-bl?',
48172 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
48176 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
48177 * query specified by the allQuery config option (defaults to 'query')
48179 triggerAction: 'query',
48181 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
48182 * (defaults to 4, does not apply if editable = false)
48186 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
48187 * delay (typeAheadDelay) if it matches a known value (defaults to false)
48191 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
48192 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
48196 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
48197 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
48201 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
48202 * when editable = true (defaults to false)
48204 selectOnFocus:false,
48206 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
48208 queryParam: 'query',
48210 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
48211 * when mode = 'remote' (defaults to 'Loading...')
48213 loadingText: 'Loading...',
48215 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
48219 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
48223 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
48224 * traditional select (defaults to true)
48228 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
48232 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
48236 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
48237 * listWidth has a higher value)
48241 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
48242 * allow the user to set arbitrary text into the field (defaults to false)
48244 forceSelection:false,
48246 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
48247 * if typeAhead = true (defaults to 250)
48249 typeAheadDelay : 250,
48251 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
48252 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
48254 valueNotFoundText : undefined,
48257 * @cfg {String} defaultValue The value displayed after loading the store.
48262 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
48264 blockFocus : false,
48267 * @cfg {Boolean} disableClear Disable showing of clear button.
48269 disableClear : false,
48271 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
48273 alwaysQuery : false,
48279 // element that contains real text value.. (when hidden is used..)
48282 onRender : function(ct, position){
48283 Roo.form.Field.prototype.onRender.call(this, ct, position);
48286 this.store.on('beforeload', this.onBeforeLoad, this);
48287 this.store.on('load', this.onLoad, this);
48288 this.store.on('loadexception', this.onLoadException, this);
48289 this.store.load({});
48297 initEvents : function(){
48298 //Roo.form.ComboBox.superclass.initEvents.call(this);
48302 onDestroy : function(){
48305 this.store.un('beforeload', this.onBeforeLoad, this);
48306 this.store.un('load', this.onLoad, this);
48307 this.store.un('loadexception', this.onLoadException, this);
48309 //Roo.form.ComboBox.superclass.onDestroy.call(this);
48313 fireKey : function(e){
48314 if(e.isNavKeyPress() && !this.list.isVisible()){
48315 this.fireEvent("specialkey", this, e);
48320 onResize: function(w, h){
48328 * Allow or prevent the user from directly editing the field text. If false is passed,
48329 * the user will only be able to select from the items defined in the dropdown list. This method
48330 * is the runtime equivalent of setting the 'editable' config option at config time.
48331 * @param {Boolean} value True to allow the user to directly edit the field text
48333 setEditable : function(value){
48338 onBeforeLoad : function(){
48340 Roo.log("Select before load");
48343 this.innerList.update(this.loadingText ?
48344 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
48345 //this.restrictHeight();
48346 this.selectedIndex = -1;
48350 onLoad : function(){
48353 var dom = this.el.dom;
48354 dom.innerHTML = '';
48355 var od = dom.ownerDocument;
48357 if (this.emptyText) {
48358 var op = od.createElement('option');
48359 op.setAttribute('value', '');
48360 op.innerHTML = String.format('{0}', this.emptyText);
48361 dom.appendChild(op);
48363 if(this.store.getCount() > 0){
48365 var vf = this.valueField;
48366 var df = this.displayField;
48367 this.store.data.each(function(r) {
48368 // which colmsn to use... testing - cdoe / title..
48369 var op = od.createElement('option');
48370 op.setAttribute('value', r.data[vf]);
48371 op.innerHTML = String.format('{0}', r.data[df]);
48372 dom.appendChild(op);
48374 if (typeof(this.defaultValue != 'undefined')) {
48375 this.setValue(this.defaultValue);
48380 //this.onEmptyResults();
48385 onLoadException : function()
48387 dom.innerHTML = '';
48389 Roo.log("Select on load exception");
48393 Roo.log(this.store.reader.jsonData);
48394 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
48395 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
48401 onTypeAhead : function(){
48406 onSelect : function(record, index){
48407 Roo.log('on select?');
48409 if(this.fireEvent('beforeselect', this, record, index) !== false){
48410 this.setFromData(index > -1 ? record.data : false);
48412 this.fireEvent('select', this, record, index);
48417 * Returns the currently selected field value or empty string if no value is set.
48418 * @return {String} value The selected value
48420 getValue : function(){
48421 var dom = this.el.dom;
48422 this.value = dom.options[dom.selectedIndex].value;
48428 * Clears any text/value currently set in the field
48430 clearValue : function(){
48432 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
48437 * Sets the specified value into the field. If the value finds a match, the corresponding record text
48438 * will be displayed in the field. If the value does not match the data value of an existing item,
48439 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
48440 * Otherwise the field will be blank (although the value will still be set).
48441 * @param {String} value The value to match
48443 setValue : function(v){
48444 var d = this.el.dom;
48445 for (var i =0; i < d.options.length;i++) {
48446 if (v == d.options[i].value) {
48447 d.selectedIndex = i;
48455 * @property {Object} the last set data for the element
48460 * Sets the value of the field based on a object which is related to the record format for the store.
48461 * @param {Object} value the value to set as. or false on reset?
48463 setFromData : function(o){
48464 Roo.log('setfrom data?');
48470 reset : function(){
48474 findRecord : function(prop, value){
48479 if(this.store.getCount() > 0){
48480 this.store.each(function(r){
48481 if(r.data[prop] == value){
48491 getName: function()
48493 // returns hidden if it's set..
48494 if (!this.rendered) {return ''};
48495 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
48503 onEmptyResults : function(){
48504 Roo.log('empty results');
48509 * Returns true if the dropdown list is expanded, else false.
48511 isExpanded : function(){
48516 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
48517 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48518 * @param {String} value The data value of the item to select
48519 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48520 * selected item if it is not currently in view (defaults to true)
48521 * @return {Boolean} True if the value matched an item in the list, else false
48523 selectByValue : function(v, scrollIntoView){
48524 Roo.log('select By Value');
48527 if(v !== undefined && v !== null){
48528 var r = this.findRecord(this.valueField || this.displayField, v);
48530 this.select(this.store.indexOf(r), scrollIntoView);
48538 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
48539 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48540 * @param {Number} index The zero-based index of the list item to select
48541 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48542 * selected item if it is not currently in view (defaults to true)
48544 select : function(index, scrollIntoView){
48545 Roo.log('select ');
48548 this.selectedIndex = index;
48549 this.view.select(index);
48550 if(scrollIntoView !== false){
48551 var el = this.view.getNode(index);
48553 this.innerList.scrollChildIntoView(el, false);
48561 validateBlur : function(){
48568 initQuery : function(){
48569 this.doQuery(this.getRawValue());
48573 doForce : function(){
48574 if(this.el.dom.value.length > 0){
48575 this.el.dom.value =
48576 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
48582 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
48583 * query allowing the query action to be canceled if needed.
48584 * @param {String} query The SQL query to execute
48585 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
48586 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
48587 * saved in the current store (defaults to false)
48589 doQuery : function(q, forceAll){
48591 Roo.log('doQuery?');
48592 if(q === undefined || q === null){
48597 forceAll: forceAll,
48601 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48605 forceAll = qe.forceAll;
48606 if(forceAll === true || (q.length >= this.minChars)){
48607 if(this.lastQuery != q || this.alwaysQuery){
48608 this.lastQuery = q;
48609 if(this.mode == 'local'){
48610 this.selectedIndex = -1;
48612 this.store.clearFilter();
48614 this.store.filter(this.displayField, q);
48618 this.store.baseParams[this.queryParam] = q;
48620 params: this.getParams(q)
48625 this.selectedIndex = -1;
48632 getParams : function(q){
48634 //p[this.queryParam] = q;
48637 p.limit = this.pageSize;
48643 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48645 collapse : function(){
48650 collapseIf : function(e){
48655 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48657 expand : function(){
48665 * @cfg {Boolean} grow
48669 * @cfg {Number} growMin
48673 * @cfg {Number} growMax
48681 setWidth : function()
48685 getResizeEl : function(){
48688 });//<script type="text/javasscript">
48692 * @class Roo.DDView
48693 * A DnD enabled version of Roo.View.
48694 * @param {Element/String} container The Element in which to create the View.
48695 * @param {String} tpl The template string used to create the markup for each element of the View
48696 * @param {Object} config The configuration properties. These include all the config options of
48697 * {@link Roo.View} plus some specific to this class.<br>
48699 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48700 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48702 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48703 .x-view-drag-insert-above {
48704 border-top:1px dotted #3366cc;
48706 .x-view-drag-insert-below {
48707 border-bottom:1px dotted #3366cc;
48713 Roo.DDView = function(container, tpl, config) {
48714 Roo.DDView.superclass.constructor.apply(this, arguments);
48715 this.getEl().setStyle("outline", "0px none");
48716 this.getEl().unselectable();
48717 if (this.dragGroup) {
48718 this.setDraggable(this.dragGroup.split(","));
48720 if (this.dropGroup) {
48721 this.setDroppable(this.dropGroup.split(","));
48723 if (this.deletable) {
48724 this.setDeletable();
48726 this.isDirtyFlag = false;
48732 Roo.extend(Roo.DDView, Roo.View, {
48733 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48734 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48735 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48736 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48740 reset: Roo.emptyFn,
48742 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48744 validate: function() {
48748 destroy: function() {
48749 this.purgeListeners();
48750 this.getEl.removeAllListeners();
48751 this.getEl().remove();
48752 if (this.dragZone) {
48753 if (this.dragZone.destroy) {
48754 this.dragZone.destroy();
48757 if (this.dropZone) {
48758 if (this.dropZone.destroy) {
48759 this.dropZone.destroy();
48764 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48765 getName: function() {
48769 /** Loads the View from a JSON string representing the Records to put into the Store. */
48770 setValue: function(v) {
48772 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48775 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48776 this.store.proxy = new Roo.data.MemoryProxy(data);
48780 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48781 getValue: function() {
48783 this.store.each(function(rec) {
48784 result += rec.id + ',';
48786 return result.substr(0, result.length - 1) + ')';
48789 getIds: function() {
48790 var i = 0, result = new Array(this.store.getCount());
48791 this.store.each(function(rec) {
48792 result[i++] = rec.id;
48797 isDirty: function() {
48798 return this.isDirtyFlag;
48802 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48803 * whole Element becomes the target, and this causes the drop gesture to append.
48805 getTargetFromEvent : function(e) {
48806 var target = e.getTarget();
48807 while ((target !== null) && (target.parentNode != this.el.dom)) {
48808 target = target.parentNode;
48811 target = this.el.dom.lastChild || this.el.dom;
48817 * Create the drag data which consists of an object which has the property "ddel" as
48818 * the drag proxy element.
48820 getDragData : function(e) {
48821 var target = this.findItemFromChild(e.getTarget());
48823 this.handleSelection(e);
48824 var selNodes = this.getSelectedNodes();
48827 copy: this.copy || (this.allowCopy && e.ctrlKey),
48831 var selectedIndices = this.getSelectedIndexes();
48832 for (var i = 0; i < selectedIndices.length; i++) {
48833 dragData.records.push(this.store.getAt(selectedIndices[i]));
48835 if (selNodes.length == 1) {
48836 dragData.ddel = target.cloneNode(true); // the div element
48838 var div = document.createElement('div'); // create the multi element drag "ghost"
48839 div.className = 'multi-proxy';
48840 for (var i = 0, len = selNodes.length; i < len; i++) {
48841 div.appendChild(selNodes[i].cloneNode(true));
48843 dragData.ddel = div;
48845 //console.log(dragData)
48846 //console.log(dragData.ddel.innerHTML)
48849 //console.log('nodragData')
48853 /** Specify to which ddGroup items in this DDView may be dragged. */
48854 setDraggable: function(ddGroup) {
48855 if (ddGroup instanceof Array) {
48856 Roo.each(ddGroup, this.setDraggable, this);
48859 if (this.dragZone) {
48860 this.dragZone.addToGroup(ddGroup);
48862 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48863 containerScroll: true,
48867 // Draggability implies selection. DragZone's mousedown selects the element.
48868 if (!this.multiSelect) { this.singleSelect = true; }
48870 // Wire the DragZone's handlers up to methods in *this*
48871 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48875 /** Specify from which ddGroup this DDView accepts drops. */
48876 setDroppable: function(ddGroup) {
48877 if (ddGroup instanceof Array) {
48878 Roo.each(ddGroup, this.setDroppable, this);
48881 if (this.dropZone) {
48882 this.dropZone.addToGroup(ddGroup);
48884 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48885 containerScroll: true,
48889 // Wire the DropZone's handlers up to methods in *this*
48890 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48891 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48892 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48893 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48894 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48898 /** Decide whether to drop above or below a View node. */
48899 getDropPoint : function(e, n, dd){
48900 if (n == this.el.dom) { return "above"; }
48901 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48902 var c = t + (b - t) / 2;
48903 var y = Roo.lib.Event.getPageY(e);
48911 onNodeEnter : function(n, dd, e, data){
48915 onNodeOver : function(n, dd, e, data){
48916 var pt = this.getDropPoint(e, n, dd);
48917 // set the insert point style on the target node
48918 var dragElClass = this.dropNotAllowed;
48921 if (pt == "above"){
48922 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48923 targetElClass = "x-view-drag-insert-above";
48925 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48926 targetElClass = "x-view-drag-insert-below";
48928 if (this.lastInsertClass != targetElClass){
48929 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48930 this.lastInsertClass = targetElClass;
48933 return dragElClass;
48936 onNodeOut : function(n, dd, e, data){
48937 this.removeDropIndicators(n);
48940 onNodeDrop : function(n, dd, e, data){
48941 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48944 var pt = this.getDropPoint(e, n, dd);
48945 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48946 if (pt == "below") { insertAt++; }
48947 for (var i = 0; i < data.records.length; i++) {
48948 var r = data.records[i];
48949 var dup = this.store.getById(r.id);
48950 if (dup && (dd != this.dragZone)) {
48951 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48954 this.store.insert(insertAt++, r.copy());
48956 data.source.isDirtyFlag = true;
48958 this.store.insert(insertAt++, r);
48960 this.isDirtyFlag = true;
48963 this.dragZone.cachedTarget = null;
48967 removeDropIndicators : function(n){
48969 Roo.fly(n).removeClass([
48970 "x-view-drag-insert-above",
48971 "x-view-drag-insert-below"]);
48972 this.lastInsertClass = "_noclass";
48977 * Utility method. Add a delete option to the DDView's context menu.
48978 * @param {String} imageUrl The URL of the "delete" icon image.
48980 setDeletable: function(imageUrl) {
48981 if (!this.singleSelect && !this.multiSelect) {
48982 this.singleSelect = true;
48984 var c = this.getContextMenu();
48985 this.contextMenu.on("itemclick", function(item) {
48988 this.remove(this.getSelectedIndexes());
48992 this.contextMenu.add({
48999 /** Return the context menu for this DDView. */
49000 getContextMenu: function() {
49001 if (!this.contextMenu) {
49002 // Create the View's context menu
49003 this.contextMenu = new Roo.menu.Menu({
49004 id: this.id + "-contextmenu"
49006 this.el.on("contextmenu", this.showContextMenu, this);
49008 return this.contextMenu;
49011 disableContextMenu: function() {
49012 if (this.contextMenu) {
49013 this.el.un("contextmenu", this.showContextMenu, this);
49017 showContextMenu: function(e, item) {
49018 item = this.findItemFromChild(e.getTarget());
49021 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
49022 this.contextMenu.showAt(e.getXY());
49027 * Remove {@link Roo.data.Record}s at the specified indices.
49028 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
49030 remove: function(selectedIndices) {
49031 selectedIndices = [].concat(selectedIndices);
49032 for (var i = 0; i < selectedIndices.length; i++) {
49033 var rec = this.store.getAt(selectedIndices[i]);
49034 this.store.remove(rec);
49039 * Double click fires the event, but also, if this is draggable, and there is only one other
49040 * related DropZone, it transfers the selected node.
49042 onDblClick : function(e){
49043 var item = this.findItemFromChild(e.getTarget());
49045 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
49048 if (this.dragGroup) {
49049 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
49050 while (targets.indexOf(this.dropZone) > -1) {
49051 targets.remove(this.dropZone);
49053 if (targets.length == 1) {
49054 this.dragZone.cachedTarget = null;
49055 var el = Roo.get(targets[0].getEl());
49056 var box = el.getBox(true);
49057 targets[0].onNodeDrop(el.dom, {
49059 xy: [box.x, box.y + box.height - 1]
49060 }, null, this.getDragData(e));
49066 handleSelection: function(e) {
49067 this.dragZone.cachedTarget = null;
49068 var item = this.findItemFromChild(e.getTarget());
49070 this.clearSelections(true);
49073 if (item && (this.multiSelect || this.singleSelect)){
49074 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
49075 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
49076 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
49077 this.unselect(item);
49079 this.select(item, this.multiSelect && e.ctrlKey);
49080 this.lastSelection = item;
49085 onItemClick : function(item, index, e){
49086 if(this.fireEvent("beforeclick", this, index, item, e) === false){
49092 unselect : function(nodeInfo, suppressEvent){
49093 var node = this.getNode(nodeInfo);
49094 if(node && this.isSelected(node)){
49095 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
49096 Roo.fly(node).removeClass(this.selectedClass);
49097 this.selections.remove(node);
49098 if(!suppressEvent){
49099 this.fireEvent("selectionchange", this, this.selections);
49107 * Ext JS Library 1.1.1
49108 * Copyright(c) 2006-2007, Ext JS, LLC.
49110 * Originally Released Under LGPL - original licence link has changed is not relivant.
49113 * <script type="text/javascript">
49117 * @class Roo.LayoutManager
49118 * @extends Roo.util.Observable
49119 * Base class for layout managers.
49121 Roo.LayoutManager = function(container, config){
49122 Roo.LayoutManager.superclass.constructor.call(this);
49123 this.el = Roo.get(container);
49124 // ie scrollbar fix
49125 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
49126 document.body.scroll = "no";
49127 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
49128 this.el.position('relative');
49130 this.id = this.el.id;
49131 this.el.addClass("x-layout-container");
49132 /** false to disable window resize monitoring @type Boolean */
49133 this.monitorWindowResize = true;
49138 * Fires when a layout is performed.
49139 * @param {Roo.LayoutManager} this
49143 * @event regionresized
49144 * Fires when the user resizes a region.
49145 * @param {Roo.LayoutRegion} region The resized region
49146 * @param {Number} newSize The new size (width for east/west, height for north/south)
49148 "regionresized" : true,
49150 * @event regioncollapsed
49151 * Fires when a region is collapsed.
49152 * @param {Roo.LayoutRegion} region The collapsed region
49154 "regioncollapsed" : true,
49156 * @event regionexpanded
49157 * Fires when a region is expanded.
49158 * @param {Roo.LayoutRegion} region The expanded region
49160 "regionexpanded" : true
49162 this.updating = false;
49163 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
49166 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
49168 * Returns true if this layout is currently being updated
49169 * @return {Boolean}
49171 isUpdating : function(){
49172 return this.updating;
49176 * Suspend the LayoutManager from doing auto-layouts while
49177 * making multiple add or remove calls
49179 beginUpdate : function(){
49180 this.updating = true;
49184 * Restore auto-layouts and optionally disable the manager from performing a layout
49185 * @param {Boolean} noLayout true to disable a layout update
49187 endUpdate : function(noLayout){
49188 this.updating = false;
49194 layout: function(){
49198 onRegionResized : function(region, newSize){
49199 this.fireEvent("regionresized", region, newSize);
49203 onRegionCollapsed : function(region){
49204 this.fireEvent("regioncollapsed", region);
49207 onRegionExpanded : function(region){
49208 this.fireEvent("regionexpanded", region);
49212 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
49213 * performs box-model adjustments.
49214 * @return {Object} The size as an object {width: (the width), height: (the height)}
49216 getViewSize : function(){
49218 if(this.el.dom != document.body){
49219 size = this.el.getSize();
49221 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
49223 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
49224 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
49229 * Returns the Element this layout is bound to.
49230 * @return {Roo.Element}
49232 getEl : function(){
49237 * Returns the specified region.
49238 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
49239 * @return {Roo.LayoutRegion}
49241 getRegion : function(target){
49242 return this.regions[target.toLowerCase()];
49245 onWindowResize : function(){
49246 if(this.monitorWindowResize){
49252 * Ext JS Library 1.1.1
49253 * Copyright(c) 2006-2007, Ext JS, LLC.
49255 * Originally Released Under LGPL - original licence link has changed is not relivant.
49258 * <script type="text/javascript">
49261 * @class Roo.BorderLayout
49262 * @extends Roo.LayoutManager
49263 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
49264 * please see: <br><br>
49265 * <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>
49266 * <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>
49269 var layout = new Roo.BorderLayout(document.body, {
49303 preferredTabWidth: 150
49308 var CP = Roo.ContentPanel;
49310 layout.beginUpdate();
49311 layout.add("north", new CP("north", "North"));
49312 layout.add("south", new CP("south", {title: "South", closable: true}));
49313 layout.add("west", new CP("west", {title: "West"}));
49314 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
49315 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
49316 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
49317 layout.getRegion("center").showPanel("center1");
49318 layout.endUpdate();
49321 <b>The container the layout is rendered into can be either the body element or any other element.
49322 If it is not the body element, the container needs to either be an absolute positioned element,
49323 or you will need to add "position:relative" to the css of the container. You will also need to specify
49324 the container size if it is not the body element.</b>
49327 * Create a new BorderLayout
49328 * @param {String/HTMLElement/Element} container The container this layout is bound to
49329 * @param {Object} config Configuration options
49331 Roo.BorderLayout = function(container, config){
49332 config = config || {};
49333 Roo.BorderLayout.superclass.constructor.call(this, container, config);
49334 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
49335 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
49336 var target = this.factory.validRegions[i];
49337 if(config[target]){
49338 this.addRegion(target, config[target]);
49343 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
49345 * Creates and adds a new region if it doesn't already exist.
49346 * @param {String} target The target region key (north, south, east, west or center).
49347 * @param {Object} config The regions config object
49348 * @return {BorderLayoutRegion} The new region
49350 addRegion : function(target, config){
49351 if(!this.regions[target]){
49352 var r = this.factory.create(target, this, config);
49353 this.bindRegion(target, r);
49355 return this.regions[target];
49359 bindRegion : function(name, r){
49360 this.regions[name] = r;
49361 r.on("visibilitychange", this.layout, this);
49362 r.on("paneladded", this.layout, this);
49363 r.on("panelremoved", this.layout, this);
49364 r.on("invalidated", this.layout, this);
49365 r.on("resized", this.onRegionResized, this);
49366 r.on("collapsed", this.onRegionCollapsed, this);
49367 r.on("expanded", this.onRegionExpanded, this);
49371 * Performs a layout update.
49373 layout : function(){
49374 if(this.updating) return;
49375 var size = this.getViewSize();
49376 var w = size.width;
49377 var h = size.height;
49382 //var x = 0, y = 0;
49384 var rs = this.regions;
49385 var north = rs["north"];
49386 var south = rs["south"];
49387 var west = rs["west"];
49388 var east = rs["east"];
49389 var center = rs["center"];
49390 //if(this.hideOnLayout){ // not supported anymore
49391 //c.el.setStyle("display", "none");
49393 if(north && north.isVisible()){
49394 var b = north.getBox();
49395 var m = north.getMargins();
49396 b.width = w - (m.left+m.right);
49399 centerY = b.height + b.y + m.bottom;
49400 centerH -= centerY;
49401 north.updateBox(this.safeBox(b));
49403 if(south && south.isVisible()){
49404 var b = south.getBox();
49405 var m = south.getMargins();
49406 b.width = w - (m.left+m.right);
49408 var totalHeight = (b.height + m.top + m.bottom);
49409 b.y = h - totalHeight + m.top;
49410 centerH -= totalHeight;
49411 south.updateBox(this.safeBox(b));
49413 if(west && west.isVisible()){
49414 var b = west.getBox();
49415 var m = west.getMargins();
49416 b.height = centerH - (m.top+m.bottom);
49418 b.y = centerY + m.top;
49419 var totalWidth = (b.width + m.left + m.right);
49420 centerX += totalWidth;
49421 centerW -= totalWidth;
49422 west.updateBox(this.safeBox(b));
49424 if(east && east.isVisible()){
49425 var b = east.getBox();
49426 var m = east.getMargins();
49427 b.height = centerH - (m.top+m.bottom);
49428 var totalWidth = (b.width + m.left + m.right);
49429 b.x = w - totalWidth + m.left;
49430 b.y = centerY + m.top;
49431 centerW -= totalWidth;
49432 east.updateBox(this.safeBox(b));
49435 var m = center.getMargins();
49437 x: centerX + m.left,
49438 y: centerY + m.top,
49439 width: centerW - (m.left+m.right),
49440 height: centerH - (m.top+m.bottom)
49442 //if(this.hideOnLayout){
49443 //center.el.setStyle("display", "block");
49445 center.updateBox(this.safeBox(centerBox));
49448 this.fireEvent("layout", this);
49452 safeBox : function(box){
49453 box.width = Math.max(0, box.width);
49454 box.height = Math.max(0, box.height);
49459 * Adds a ContentPanel (or subclass) to this layout.
49460 * @param {String} target The target region key (north, south, east, west or center).
49461 * @param {Roo.ContentPanel} panel The panel to add
49462 * @return {Roo.ContentPanel} The added panel
49464 add : function(target, panel){
49466 target = target.toLowerCase();
49467 return this.regions[target].add(panel);
49471 * Remove a ContentPanel (or subclass) to this layout.
49472 * @param {String} target The target region key (north, south, east, west or center).
49473 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
49474 * @return {Roo.ContentPanel} The removed panel
49476 remove : function(target, panel){
49477 target = target.toLowerCase();
49478 return this.regions[target].remove(panel);
49482 * Searches all regions for a panel with the specified id
49483 * @param {String} panelId
49484 * @return {Roo.ContentPanel} The panel or null if it wasn't found
49486 findPanel : function(panelId){
49487 var rs = this.regions;
49488 for(var target in rs){
49489 if(typeof rs[target] != "function"){
49490 var p = rs[target].getPanel(panelId);
49500 * Searches all regions for a panel with the specified id and activates (shows) it.
49501 * @param {String/ContentPanel} panelId The panels id or the panel itself
49502 * @return {Roo.ContentPanel} The shown panel or null
49504 showPanel : function(panelId) {
49505 var rs = this.regions;
49506 for(var target in rs){
49507 var r = rs[target];
49508 if(typeof r != "function"){
49509 if(r.hasPanel(panelId)){
49510 return r.showPanel(panelId);
49518 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
49519 * @param {Roo.state.Provider} provider (optional) An alternate state provider
49521 restoreState : function(provider){
49523 provider = Roo.state.Manager;
49525 var sm = new Roo.LayoutStateManager();
49526 sm.init(this, provider);
49530 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
49531 * object should contain properties for each region to add ContentPanels to, and each property's value should be
49532 * a valid ContentPanel config object. Example:
49534 // Create the main layout
49535 var layout = new Roo.BorderLayout('main-ct', {
49546 // Create and add multiple ContentPanels at once via configs
49549 id: 'source-files',
49551 title:'Ext Source Files',
49564 * @param {Object} regions An object containing ContentPanel configs by region name
49566 batchAdd : function(regions){
49567 this.beginUpdate();
49568 for(var rname in regions){
49569 var lr = this.regions[rname];
49571 this.addTypedPanels(lr, regions[rname]);
49578 addTypedPanels : function(lr, ps){
49579 if(typeof ps == 'string'){
49580 lr.add(new Roo.ContentPanel(ps));
49582 else if(ps instanceof Array){
49583 for(var i =0, len = ps.length; i < len; i++){
49584 this.addTypedPanels(lr, ps[i]);
49587 else if(!ps.events){ // raw config?
49589 delete ps.el; // prevent conflict
49590 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
49592 else { // panel object assumed!
49597 * Adds a xtype elements to the layout.
49601 xtype : 'ContentPanel',
49608 xtype : 'NestedLayoutPanel',
49614 items : [ ... list of content panels or nested layout panels.. ]
49618 * @param {Object} cfg Xtype definition of item to add.
49620 addxtype : function(cfg)
49622 // basically accepts a pannel...
49623 // can accept a layout region..!?!?
49624 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49626 if (!cfg.xtype.match(/Panel$/)) {
49631 if (typeof(cfg.region) == 'undefined') {
49632 Roo.log("Failed to add Panel, region was not set");
49636 var region = cfg.region;
49642 xitems = cfg.items;
49649 case 'ContentPanel': // ContentPanel (el, cfg)
49650 case 'ScrollPanel': // ContentPanel (el, cfg)
49652 if(cfg.autoCreate) {
49653 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49655 var el = this.el.createChild();
49656 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49659 this.add(region, ret);
49663 case 'TreePanel': // our new panel!
49664 cfg.el = this.el.createChild();
49665 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49666 this.add(region, ret);
49669 case 'NestedLayoutPanel':
49670 // create a new Layout (which is a Border Layout...
49671 var el = this.el.createChild();
49672 var clayout = cfg.layout;
49674 clayout.items = clayout.items || [];
49675 // replace this exitems with the clayout ones..
49676 xitems = clayout.items;
49679 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49680 cfg.background = false;
49682 var layout = new Roo.BorderLayout(el, clayout);
49684 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49685 //console.log('adding nested layout panel ' + cfg.toSource());
49686 this.add(region, ret);
49687 nb = {}; /// find first...
49692 // needs grid and region
49694 //var el = this.getRegion(region).el.createChild();
49695 var el = this.el.createChild();
49696 // create the grid first...
49698 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49700 if (region == 'center' && this.active ) {
49701 cfg.background = false;
49703 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49705 this.add(region, ret);
49706 if (cfg.background) {
49707 ret.on('activate', function(gp) {
49708 if (!gp.grid.rendered) {
49723 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49725 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49726 this.add(region, ret);
49729 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49733 // GridPanel (grid, cfg)
49736 this.beginUpdate();
49740 Roo.each(xitems, function(i) {
49741 region = nb && i.region ? i.region : false;
49743 var add = ret.addxtype(i);
49746 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49747 if (!i.background) {
49748 abn[region] = nb[region] ;
49755 // make the last non-background panel active..
49756 //if (nb) { Roo.log(abn); }
49759 for(var r in abn) {
49760 region = this.getRegion(r);
49762 // tried using nb[r], but it does not work..
49764 region.showPanel(abn[r]);
49775 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49776 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49777 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49778 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49781 var CP = Roo.ContentPanel;
49783 var layout = Roo.BorderLayout.create({
49787 panels: [new CP("north", "North")]
49796 panels: [new CP("west", {title: "West"})]
49805 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49814 panels: [new CP("south", {title: "South", closable: true})]
49821 preferredTabWidth: 150,
49823 new CP("center1", {title: "Close Me", closable: true}),
49824 new CP("center2", {title: "Center Panel", closable: false})
49829 layout.getRegion("center").showPanel("center1");
49834 Roo.BorderLayout.create = function(config, targetEl){
49835 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49836 layout.beginUpdate();
49837 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49838 for(var j = 0, jlen = regions.length; j < jlen; j++){
49839 var lr = regions[j];
49840 if(layout.regions[lr] && config[lr].panels){
49841 var r = layout.regions[lr];
49842 var ps = config[lr].panels;
49843 layout.addTypedPanels(r, ps);
49846 layout.endUpdate();
49851 Roo.BorderLayout.RegionFactory = {
49853 validRegions : ["north","south","east","west","center"],
49856 create : function(target, mgr, config){
49857 target = target.toLowerCase();
49858 if(config.lightweight || config.basic){
49859 return new Roo.BasicLayoutRegion(mgr, config, target);
49863 return new Roo.NorthLayoutRegion(mgr, config);
49865 return new Roo.SouthLayoutRegion(mgr, config);
49867 return new Roo.EastLayoutRegion(mgr, config);
49869 return new Roo.WestLayoutRegion(mgr, config);
49871 return new Roo.CenterLayoutRegion(mgr, config);
49873 throw 'Layout region "'+target+'" not supported.';
49877 * Ext JS Library 1.1.1
49878 * Copyright(c) 2006-2007, Ext JS, LLC.
49880 * Originally Released Under LGPL - original licence link has changed is not relivant.
49883 * <script type="text/javascript">
49887 * @class Roo.BasicLayoutRegion
49888 * @extends Roo.util.Observable
49889 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49890 * and does not have a titlebar, tabs or any other features. All it does is size and position
49891 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49893 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49895 this.position = pos;
49898 * @scope Roo.BasicLayoutRegion
49902 * @event beforeremove
49903 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49904 * @param {Roo.LayoutRegion} this
49905 * @param {Roo.ContentPanel} panel The panel
49906 * @param {Object} e The cancel event object
49908 "beforeremove" : true,
49910 * @event invalidated
49911 * Fires when the layout for this region is changed.
49912 * @param {Roo.LayoutRegion} this
49914 "invalidated" : true,
49916 * @event visibilitychange
49917 * Fires when this region is shown or hidden
49918 * @param {Roo.LayoutRegion} this
49919 * @param {Boolean} visibility true or false
49921 "visibilitychange" : true,
49923 * @event paneladded
49924 * Fires when a panel is added.
49925 * @param {Roo.LayoutRegion} this
49926 * @param {Roo.ContentPanel} panel The panel
49928 "paneladded" : true,
49930 * @event panelremoved
49931 * Fires when a panel is removed.
49932 * @param {Roo.LayoutRegion} this
49933 * @param {Roo.ContentPanel} panel The panel
49935 "panelremoved" : true,
49938 * Fires when this region is collapsed.
49939 * @param {Roo.LayoutRegion} this
49941 "collapsed" : true,
49944 * Fires when this region is expanded.
49945 * @param {Roo.LayoutRegion} this
49950 * Fires when this region is slid into view.
49951 * @param {Roo.LayoutRegion} this
49953 "slideshow" : true,
49956 * Fires when this region slides out of view.
49957 * @param {Roo.LayoutRegion} this
49959 "slidehide" : true,
49961 * @event panelactivated
49962 * Fires when a panel is activated.
49963 * @param {Roo.LayoutRegion} this
49964 * @param {Roo.ContentPanel} panel The activated panel
49966 "panelactivated" : true,
49969 * Fires when the user resizes this region.
49970 * @param {Roo.LayoutRegion} this
49971 * @param {Number} newSize The new size (width for east/west, height for north/south)
49975 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49976 this.panels = new Roo.util.MixedCollection();
49977 this.panels.getKey = this.getPanelId.createDelegate(this);
49979 this.activePanel = null;
49980 // ensure listeners are added...
49982 if (config.listeners || config.events) {
49983 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49984 listeners : config.listeners || {},
49985 events : config.events || {}
49989 if(skipConfig !== true){
49990 this.applyConfig(config);
49994 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49995 getPanelId : function(p){
49999 applyConfig : function(config){
50000 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50001 this.config = config;
50006 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
50007 * the width, for horizontal (north, south) the height.
50008 * @param {Number} newSize The new width or height
50010 resizeTo : function(newSize){
50011 var el = this.el ? this.el :
50012 (this.activePanel ? this.activePanel.getEl() : null);
50014 switch(this.position){
50017 el.setWidth(newSize);
50018 this.fireEvent("resized", this, newSize);
50022 el.setHeight(newSize);
50023 this.fireEvent("resized", this, newSize);
50029 getBox : function(){
50030 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
50033 getMargins : function(){
50034 return this.margins;
50037 updateBox : function(box){
50039 var el = this.activePanel.getEl();
50040 el.dom.style.left = box.x + "px";
50041 el.dom.style.top = box.y + "px";
50042 this.activePanel.setSize(box.width, box.height);
50046 * Returns the container element for this region.
50047 * @return {Roo.Element}
50049 getEl : function(){
50050 return this.activePanel;
50054 * Returns true if this region is currently visible.
50055 * @return {Boolean}
50057 isVisible : function(){
50058 return this.activePanel ? true : false;
50061 setActivePanel : function(panel){
50062 panel = this.getPanel(panel);
50063 if(this.activePanel && this.activePanel != panel){
50064 this.activePanel.setActiveState(false);
50065 this.activePanel.getEl().setLeftTop(-10000,-10000);
50067 this.activePanel = panel;
50068 panel.setActiveState(true);
50070 panel.setSize(this.box.width, this.box.height);
50072 this.fireEvent("panelactivated", this, panel);
50073 this.fireEvent("invalidated");
50077 * Show the specified panel.
50078 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
50079 * @return {Roo.ContentPanel} The shown panel or null
50081 showPanel : function(panel){
50082 if(panel = this.getPanel(panel)){
50083 this.setActivePanel(panel);
50089 * Get the active panel for this region.
50090 * @return {Roo.ContentPanel} The active panel or null
50092 getActivePanel : function(){
50093 return this.activePanel;
50097 * Add the passed ContentPanel(s)
50098 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50099 * @return {Roo.ContentPanel} The panel added (if only one was added)
50101 add : function(panel){
50102 if(arguments.length > 1){
50103 for(var i = 0, len = arguments.length; i < len; i++) {
50104 this.add(arguments[i]);
50108 if(this.hasPanel(panel)){
50109 this.showPanel(panel);
50112 var el = panel.getEl();
50113 if(el.dom.parentNode != this.mgr.el.dom){
50114 this.mgr.el.dom.appendChild(el.dom);
50116 if(panel.setRegion){
50117 panel.setRegion(this);
50119 this.panels.add(panel);
50120 el.setStyle("position", "absolute");
50121 if(!panel.background){
50122 this.setActivePanel(panel);
50123 if(this.config.initialSize && this.panels.getCount()==1){
50124 this.resizeTo(this.config.initialSize);
50127 this.fireEvent("paneladded", this, panel);
50132 * Returns true if the panel is in this region.
50133 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50134 * @return {Boolean}
50136 hasPanel : function(panel){
50137 if(typeof panel == "object"){ // must be panel obj
50138 panel = panel.getId();
50140 return this.getPanel(panel) ? true : false;
50144 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50145 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50146 * @param {Boolean} preservePanel Overrides the config preservePanel option
50147 * @return {Roo.ContentPanel} The panel that was removed
50149 remove : function(panel, preservePanel){
50150 panel = this.getPanel(panel);
50155 this.fireEvent("beforeremove", this, panel, e);
50156 if(e.cancel === true){
50159 var panelId = panel.getId();
50160 this.panels.removeKey(panelId);
50165 * Returns the panel specified or null if it's not in this region.
50166 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50167 * @return {Roo.ContentPanel}
50169 getPanel : function(id){
50170 if(typeof id == "object"){ // must be panel obj
50173 return this.panels.get(id);
50177 * Returns this regions position (north/south/east/west/center).
50180 getPosition: function(){
50181 return this.position;
50185 * Ext JS Library 1.1.1
50186 * Copyright(c) 2006-2007, Ext JS, LLC.
50188 * Originally Released Under LGPL - original licence link has changed is not relivant.
50191 * <script type="text/javascript">
50195 * @class Roo.LayoutRegion
50196 * @extends Roo.BasicLayoutRegion
50197 * This class represents a region in a layout manager.
50198 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
50199 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
50200 * @cfg {Boolean} floatable False to disable floating (defaults to true)
50201 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
50202 * @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})
50203 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
50204 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
50205 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
50206 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
50207 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
50208 * @cfg {String} title The title for the region (overrides panel titles)
50209 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
50210 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
50211 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
50212 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
50213 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
50214 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
50215 * the space available, similar to FireFox 1.5 tabs (defaults to false)
50216 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
50217 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
50218 * @cfg {Boolean} showPin True to show a pin button
50219 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
50220 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
50221 * @cfg {Boolean} disableTabTips True to disable tab tooltips
50222 * @cfg {Number} width For East/West panels
50223 * @cfg {Number} height For North/South panels
50224 * @cfg {Boolean} split To show the splitter
50225 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
50227 Roo.LayoutRegion = function(mgr, config, pos){
50228 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
50229 var dh = Roo.DomHelper;
50230 /** This region's container element
50231 * @type Roo.Element */
50232 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
50233 /** This region's title element
50234 * @type Roo.Element */
50236 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
50237 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
50238 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
50240 this.titleEl.enableDisplayMode();
50241 /** This region's title text element
50242 * @type HTMLElement */
50243 this.titleTextEl = this.titleEl.dom.firstChild;
50244 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
50245 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
50246 this.closeBtn.enableDisplayMode();
50247 this.closeBtn.on("click", this.closeClicked, this);
50248 this.closeBtn.hide();
50250 this.createBody(config);
50251 this.visible = true;
50252 this.collapsed = false;
50254 if(config.hideWhenEmpty){
50256 this.on("paneladded", this.validateVisibility, this);
50257 this.on("panelremoved", this.validateVisibility, this);
50259 this.applyConfig(config);
50262 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
50264 createBody : function(){
50265 /** This region's body element
50266 * @type Roo.Element */
50267 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
50270 applyConfig : function(c){
50271 if(c.collapsible && this.position != "center" && !this.collapsedEl){
50272 var dh = Roo.DomHelper;
50273 if(c.titlebar !== false){
50274 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
50275 this.collapseBtn.on("click", this.collapse, this);
50276 this.collapseBtn.enableDisplayMode();
50278 if(c.showPin === true || this.showPin){
50279 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
50280 this.stickBtn.enableDisplayMode();
50281 this.stickBtn.on("click", this.expand, this);
50282 this.stickBtn.hide();
50285 /** This region's collapsed element
50286 * @type Roo.Element */
50287 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
50288 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
50290 if(c.floatable !== false){
50291 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
50292 this.collapsedEl.on("click", this.collapseClick, this);
50295 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
50296 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
50297 id: "message", unselectable: "on", style:{"float":"left"}});
50298 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
50300 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
50301 this.expandBtn.on("click", this.expand, this);
50303 if(this.collapseBtn){
50304 this.collapseBtn.setVisible(c.collapsible == true);
50306 this.cmargins = c.cmargins || this.cmargins ||
50307 (this.position == "west" || this.position == "east" ?
50308 {top: 0, left: 2, right:2, bottom: 0} :
50309 {top: 2, left: 0, right:0, bottom: 2});
50310 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50311 this.bottomTabs = c.tabPosition != "top";
50312 this.autoScroll = c.autoScroll || false;
50313 if(this.autoScroll){
50314 this.bodyEl.setStyle("overflow", "auto");
50316 this.bodyEl.setStyle("overflow", "hidden");
50318 //if(c.titlebar !== false){
50319 if((!c.titlebar && !c.title) || c.titlebar === false){
50320 this.titleEl.hide();
50322 this.titleEl.show();
50324 this.titleTextEl.innerHTML = c.title;
50328 this.duration = c.duration || .30;
50329 this.slideDuration = c.slideDuration || .45;
50332 this.collapse(true);
50339 * Returns true if this region is currently visible.
50340 * @return {Boolean}
50342 isVisible : function(){
50343 return this.visible;
50347 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
50348 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
50350 setCollapsedTitle : function(title){
50351 title = title || " ";
50352 if(this.collapsedTitleTextEl){
50353 this.collapsedTitleTextEl.innerHTML = title;
50357 getBox : function(){
50359 if(!this.collapsed){
50360 b = this.el.getBox(false, true);
50362 b = this.collapsedEl.getBox(false, true);
50367 getMargins : function(){
50368 return this.collapsed ? this.cmargins : this.margins;
50371 highlight : function(){
50372 this.el.addClass("x-layout-panel-dragover");
50375 unhighlight : function(){
50376 this.el.removeClass("x-layout-panel-dragover");
50379 updateBox : function(box){
50381 if(!this.collapsed){
50382 this.el.dom.style.left = box.x + "px";
50383 this.el.dom.style.top = box.y + "px";
50384 this.updateBody(box.width, box.height);
50386 this.collapsedEl.dom.style.left = box.x + "px";
50387 this.collapsedEl.dom.style.top = box.y + "px";
50388 this.collapsedEl.setSize(box.width, box.height);
50391 this.tabs.autoSizeTabs();
50395 updateBody : function(w, h){
50397 this.el.setWidth(w);
50398 w -= this.el.getBorderWidth("rl");
50399 if(this.config.adjustments){
50400 w += this.config.adjustments[0];
50404 this.el.setHeight(h);
50405 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
50406 h -= this.el.getBorderWidth("tb");
50407 if(this.config.adjustments){
50408 h += this.config.adjustments[1];
50410 this.bodyEl.setHeight(h);
50412 h = this.tabs.syncHeight(h);
50415 if(this.panelSize){
50416 w = w !== null ? w : this.panelSize.width;
50417 h = h !== null ? h : this.panelSize.height;
50419 if(this.activePanel){
50420 var el = this.activePanel.getEl();
50421 w = w !== null ? w : el.getWidth();
50422 h = h !== null ? h : el.getHeight();
50423 this.panelSize = {width: w, height: h};
50424 this.activePanel.setSize(w, h);
50426 if(Roo.isIE && this.tabs){
50427 this.tabs.el.repaint();
50432 * Returns the container element for this region.
50433 * @return {Roo.Element}
50435 getEl : function(){
50440 * Hides this region.
50443 if(!this.collapsed){
50444 this.el.dom.style.left = "-2000px";
50447 this.collapsedEl.dom.style.left = "-2000px";
50448 this.collapsedEl.hide();
50450 this.visible = false;
50451 this.fireEvent("visibilitychange", this, false);
50455 * Shows this region if it was previously hidden.
50458 if(!this.collapsed){
50461 this.collapsedEl.show();
50463 this.visible = true;
50464 this.fireEvent("visibilitychange", this, true);
50467 closeClicked : function(){
50468 if(this.activePanel){
50469 this.remove(this.activePanel);
50473 collapseClick : function(e){
50475 e.stopPropagation();
50478 e.stopPropagation();
50484 * Collapses this region.
50485 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
50487 collapse : function(skipAnim){
50488 if(this.collapsed) return;
50489 this.collapsed = true;
50491 this.split.el.hide();
50493 if(this.config.animate && skipAnim !== true){
50494 this.fireEvent("invalidated", this);
50495 this.animateCollapse();
50497 this.el.setLocation(-20000,-20000);
50499 this.collapsedEl.show();
50500 this.fireEvent("collapsed", this);
50501 this.fireEvent("invalidated", this);
50505 animateCollapse : function(){
50510 * Expands this region if it was previously collapsed.
50511 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
50512 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
50514 expand : function(e, skipAnim){
50515 if(e) e.stopPropagation();
50516 if(!this.collapsed || this.el.hasActiveFx()) return;
50518 this.afterSlideIn();
50521 this.collapsed = false;
50522 if(this.config.animate && skipAnim !== true){
50523 this.animateExpand();
50527 this.split.el.show();
50529 this.collapsedEl.setLocation(-2000,-2000);
50530 this.collapsedEl.hide();
50531 this.fireEvent("invalidated", this);
50532 this.fireEvent("expanded", this);
50536 animateExpand : function(){
50540 initTabs : function()
50542 this.bodyEl.setStyle("overflow", "hidden");
50543 var ts = new Roo.TabPanel(
50546 tabPosition: this.bottomTabs ? 'bottom' : 'top',
50547 disableTooltips: this.config.disableTabTips,
50548 toolbar : this.config.toolbar
50551 if(this.config.hideTabs){
50552 ts.stripWrap.setDisplayed(false);
50555 ts.resizeTabs = this.config.resizeTabs === true;
50556 ts.minTabWidth = this.config.minTabWidth || 40;
50557 ts.maxTabWidth = this.config.maxTabWidth || 250;
50558 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
50559 ts.monitorResize = false;
50560 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50561 ts.bodyEl.addClass('x-layout-tabs-body');
50562 this.panels.each(this.initPanelAsTab, this);
50565 initPanelAsTab : function(panel){
50566 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
50567 this.config.closeOnTab && panel.isClosable());
50568 if(panel.tabTip !== undefined){
50569 ti.setTooltip(panel.tabTip);
50571 ti.on("activate", function(){
50572 this.setActivePanel(panel);
50574 if(this.config.closeOnTab){
50575 ti.on("beforeclose", function(t, e){
50577 this.remove(panel);
50583 updatePanelTitle : function(panel, title){
50584 if(this.activePanel == panel){
50585 this.updateTitle(title);
50588 var ti = this.tabs.getTab(panel.getEl().id);
50590 if(panel.tabTip !== undefined){
50591 ti.setTooltip(panel.tabTip);
50596 updateTitle : function(title){
50597 if(this.titleTextEl && !this.config.title){
50598 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50602 setActivePanel : function(panel){
50603 panel = this.getPanel(panel);
50604 if(this.activePanel && this.activePanel != panel){
50605 this.activePanel.setActiveState(false);
50607 this.activePanel = panel;
50608 panel.setActiveState(true);
50609 if(this.panelSize){
50610 panel.setSize(this.panelSize.width, this.panelSize.height);
50613 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50615 this.updateTitle(panel.getTitle());
50617 this.fireEvent("invalidated", this);
50619 this.fireEvent("panelactivated", this, panel);
50623 * Shows the specified panel.
50624 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50625 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50627 showPanel : function(panel)
50629 panel = this.getPanel(panel);
50632 var tab = this.tabs.getTab(panel.getEl().id);
50633 if(tab.isHidden()){
50634 this.tabs.unhideTab(tab.id);
50638 this.setActivePanel(panel);
50645 * Get the active panel for this region.
50646 * @return {Roo.ContentPanel} The active panel or null
50648 getActivePanel : function(){
50649 return this.activePanel;
50652 validateVisibility : function(){
50653 if(this.panels.getCount() < 1){
50654 this.updateTitle(" ");
50655 this.closeBtn.hide();
50658 if(!this.isVisible()){
50665 * Adds the passed ContentPanel(s) to this region.
50666 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50667 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50669 add : function(panel){
50670 if(arguments.length > 1){
50671 for(var i = 0, len = arguments.length; i < len; i++) {
50672 this.add(arguments[i]);
50676 if(this.hasPanel(panel)){
50677 this.showPanel(panel);
50680 panel.setRegion(this);
50681 this.panels.add(panel);
50682 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50683 this.bodyEl.dom.appendChild(panel.getEl().dom);
50684 if(panel.background !== true){
50685 this.setActivePanel(panel);
50687 this.fireEvent("paneladded", this, panel);
50693 this.initPanelAsTab(panel);
50695 if(panel.background !== true){
50696 this.tabs.activate(panel.getEl().id);
50698 this.fireEvent("paneladded", this, panel);
50703 * Hides the tab for the specified panel.
50704 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50706 hidePanel : function(panel){
50707 if(this.tabs && (panel = this.getPanel(panel))){
50708 this.tabs.hideTab(panel.getEl().id);
50713 * Unhides the tab for a previously hidden panel.
50714 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50716 unhidePanel : function(panel){
50717 if(this.tabs && (panel = this.getPanel(panel))){
50718 this.tabs.unhideTab(panel.getEl().id);
50722 clearPanels : function(){
50723 while(this.panels.getCount() > 0){
50724 this.remove(this.panels.first());
50729 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50730 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50731 * @param {Boolean} preservePanel Overrides the config preservePanel option
50732 * @return {Roo.ContentPanel} The panel that was removed
50734 remove : function(panel, preservePanel){
50735 panel = this.getPanel(panel);
50740 this.fireEvent("beforeremove", this, panel, e);
50741 if(e.cancel === true){
50744 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50745 var panelId = panel.getId();
50746 this.panels.removeKey(panelId);
50748 document.body.appendChild(panel.getEl().dom);
50751 this.tabs.removeTab(panel.getEl().id);
50752 }else if (!preservePanel){
50753 this.bodyEl.dom.removeChild(panel.getEl().dom);
50755 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50756 var p = this.panels.first();
50757 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50758 tempEl.appendChild(p.getEl().dom);
50759 this.bodyEl.update("");
50760 this.bodyEl.dom.appendChild(p.getEl().dom);
50762 this.updateTitle(p.getTitle());
50764 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50765 this.setActivePanel(p);
50767 panel.setRegion(null);
50768 if(this.activePanel == panel){
50769 this.activePanel = null;
50771 if(this.config.autoDestroy !== false && preservePanel !== true){
50772 try{panel.destroy();}catch(e){}
50774 this.fireEvent("panelremoved", this, panel);
50779 * Returns the TabPanel component used by this region
50780 * @return {Roo.TabPanel}
50782 getTabs : function(){
50786 createTool : function(parentEl, className){
50787 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50788 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50789 btn.addClassOnOver("x-layout-tools-button-over");
50794 * Ext JS Library 1.1.1
50795 * Copyright(c) 2006-2007, Ext JS, LLC.
50797 * Originally Released Under LGPL - original licence link has changed is not relivant.
50800 * <script type="text/javascript">
50806 * @class Roo.SplitLayoutRegion
50807 * @extends Roo.LayoutRegion
50808 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50810 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50811 this.cursor = cursor;
50812 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50815 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50816 splitTip : "Drag to resize.",
50817 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50818 useSplitTips : false,
50820 applyConfig : function(config){
50821 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50824 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50825 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50826 /** The SplitBar for this region
50827 * @type Roo.SplitBar */
50828 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50829 this.split.on("moved", this.onSplitMove, this);
50830 this.split.useShim = config.useShim === true;
50831 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50832 if(this.useSplitTips){
50833 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50835 if(config.collapsible){
50836 this.split.el.on("dblclick", this.collapse, this);
50839 if(typeof config.minSize != "undefined"){
50840 this.split.minSize = config.minSize;
50842 if(typeof config.maxSize != "undefined"){
50843 this.split.maxSize = config.maxSize;
50845 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50846 this.hideSplitter();
50851 getHMaxSize : function(){
50852 var cmax = this.config.maxSize || 10000;
50853 var center = this.mgr.getRegion("center");
50854 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50857 getVMaxSize : function(){
50858 var cmax = this.config.maxSize || 10000;
50859 var center = this.mgr.getRegion("center");
50860 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50863 onSplitMove : function(split, newSize){
50864 this.fireEvent("resized", this, newSize);
50868 * Returns the {@link Roo.SplitBar} for this region.
50869 * @return {Roo.SplitBar}
50871 getSplitBar : function(){
50876 this.hideSplitter();
50877 Roo.SplitLayoutRegion.superclass.hide.call(this);
50880 hideSplitter : function(){
50882 this.split.el.setLocation(-2000,-2000);
50883 this.split.el.hide();
50889 this.split.el.show();
50891 Roo.SplitLayoutRegion.superclass.show.call(this);
50894 beforeSlide: function(){
50895 if(Roo.isGecko){// firefox overflow auto bug workaround
50896 this.bodyEl.clip();
50897 if(this.tabs) this.tabs.bodyEl.clip();
50898 if(this.activePanel){
50899 this.activePanel.getEl().clip();
50901 if(this.activePanel.beforeSlide){
50902 this.activePanel.beforeSlide();
50908 afterSlide : function(){
50909 if(Roo.isGecko){// firefox overflow auto bug workaround
50910 this.bodyEl.unclip();
50911 if(this.tabs) this.tabs.bodyEl.unclip();
50912 if(this.activePanel){
50913 this.activePanel.getEl().unclip();
50914 if(this.activePanel.afterSlide){
50915 this.activePanel.afterSlide();
50921 initAutoHide : function(){
50922 if(this.autoHide !== false){
50923 if(!this.autoHideHd){
50924 var st = new Roo.util.DelayedTask(this.slideIn, this);
50925 this.autoHideHd = {
50926 "mouseout": function(e){
50927 if(!e.within(this.el, true)){
50931 "mouseover" : function(e){
50937 this.el.on(this.autoHideHd);
50941 clearAutoHide : function(){
50942 if(this.autoHide !== false){
50943 this.el.un("mouseout", this.autoHideHd.mouseout);
50944 this.el.un("mouseover", this.autoHideHd.mouseover);
50948 clearMonitor : function(){
50949 Roo.get(document).un("click", this.slideInIf, this);
50952 // these names are backwards but not changed for compat
50953 slideOut : function(){
50954 if(this.isSlid || this.el.hasActiveFx()){
50957 this.isSlid = true;
50958 if(this.collapseBtn){
50959 this.collapseBtn.hide();
50961 this.closeBtnState = this.closeBtn.getStyle('display');
50962 this.closeBtn.hide();
50964 this.stickBtn.show();
50967 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50968 this.beforeSlide();
50969 this.el.setStyle("z-index", 10001);
50970 this.el.slideIn(this.getSlideAnchor(), {
50971 callback: function(){
50973 this.initAutoHide();
50974 Roo.get(document).on("click", this.slideInIf, this);
50975 this.fireEvent("slideshow", this);
50982 afterSlideIn : function(){
50983 this.clearAutoHide();
50984 this.isSlid = false;
50985 this.clearMonitor();
50986 this.el.setStyle("z-index", "");
50987 if(this.collapseBtn){
50988 this.collapseBtn.show();
50990 this.closeBtn.setStyle('display', this.closeBtnState);
50992 this.stickBtn.hide();
50994 this.fireEvent("slidehide", this);
50997 slideIn : function(cb){
50998 if(!this.isSlid || this.el.hasActiveFx()){
51002 this.isSlid = false;
51003 this.beforeSlide();
51004 this.el.slideOut(this.getSlideAnchor(), {
51005 callback: function(){
51006 this.el.setLeftTop(-10000, -10000);
51008 this.afterSlideIn();
51016 slideInIf : function(e){
51017 if(!e.within(this.el)){
51022 animateCollapse : function(){
51023 this.beforeSlide();
51024 this.el.setStyle("z-index", 20000);
51025 var anchor = this.getSlideAnchor();
51026 this.el.slideOut(anchor, {
51027 callback : function(){
51028 this.el.setStyle("z-index", "");
51029 this.collapsedEl.slideIn(anchor, {duration:.3});
51031 this.el.setLocation(-10000,-10000);
51033 this.fireEvent("collapsed", this);
51040 animateExpand : function(){
51041 this.beforeSlide();
51042 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
51043 this.el.setStyle("z-index", 20000);
51044 this.collapsedEl.hide({
51047 this.el.slideIn(this.getSlideAnchor(), {
51048 callback : function(){
51049 this.el.setStyle("z-index", "");
51052 this.split.el.show();
51054 this.fireEvent("invalidated", this);
51055 this.fireEvent("expanded", this);
51083 getAnchor : function(){
51084 return this.anchors[this.position];
51087 getCollapseAnchor : function(){
51088 return this.canchors[this.position];
51091 getSlideAnchor : function(){
51092 return this.sanchors[this.position];
51095 getAlignAdj : function(){
51096 var cm = this.cmargins;
51097 switch(this.position){
51113 getExpandAdj : function(){
51114 var c = this.collapsedEl, cm = this.cmargins;
51115 switch(this.position){
51117 return [-(cm.right+c.getWidth()+cm.left), 0];
51120 return [cm.right+c.getWidth()+cm.left, 0];
51123 return [0, -(cm.top+cm.bottom+c.getHeight())];
51126 return [0, cm.top+cm.bottom+c.getHeight()];
51132 * Ext JS Library 1.1.1
51133 * Copyright(c) 2006-2007, Ext JS, LLC.
51135 * Originally Released Under LGPL - original licence link has changed is not relivant.
51138 * <script type="text/javascript">
51141 * These classes are private internal classes
51143 Roo.CenterLayoutRegion = function(mgr, config){
51144 Roo.LayoutRegion.call(this, mgr, config, "center");
51145 this.visible = true;
51146 this.minWidth = config.minWidth || 20;
51147 this.minHeight = config.minHeight || 20;
51150 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
51152 // center panel can't be hidden
51156 // center panel can't be hidden
51159 getMinWidth: function(){
51160 return this.minWidth;
51163 getMinHeight: function(){
51164 return this.minHeight;
51169 Roo.NorthLayoutRegion = function(mgr, config){
51170 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
51172 this.split.placement = Roo.SplitBar.TOP;
51173 this.split.orientation = Roo.SplitBar.VERTICAL;
51174 this.split.el.addClass("x-layout-split-v");
51176 var size = config.initialSize || config.height;
51177 if(typeof size != "undefined"){
51178 this.el.setHeight(size);
51181 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
51182 orientation: Roo.SplitBar.VERTICAL,
51183 getBox : function(){
51184 if(this.collapsed){
51185 return this.collapsedEl.getBox();
51187 var box = this.el.getBox();
51189 box.height += this.split.el.getHeight();
51194 updateBox : function(box){
51195 if(this.split && !this.collapsed){
51196 box.height -= this.split.el.getHeight();
51197 this.split.el.setLeft(box.x);
51198 this.split.el.setTop(box.y+box.height);
51199 this.split.el.setWidth(box.width);
51201 if(this.collapsed){
51202 this.updateBody(box.width, null);
51204 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51208 Roo.SouthLayoutRegion = function(mgr, config){
51209 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
51211 this.split.placement = Roo.SplitBar.BOTTOM;
51212 this.split.orientation = Roo.SplitBar.VERTICAL;
51213 this.split.el.addClass("x-layout-split-v");
51215 var size = config.initialSize || config.height;
51216 if(typeof size != "undefined"){
51217 this.el.setHeight(size);
51220 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
51221 orientation: Roo.SplitBar.VERTICAL,
51222 getBox : function(){
51223 if(this.collapsed){
51224 return this.collapsedEl.getBox();
51226 var box = this.el.getBox();
51228 var sh = this.split.el.getHeight();
51235 updateBox : function(box){
51236 if(this.split && !this.collapsed){
51237 var sh = this.split.el.getHeight();
51240 this.split.el.setLeft(box.x);
51241 this.split.el.setTop(box.y-sh);
51242 this.split.el.setWidth(box.width);
51244 if(this.collapsed){
51245 this.updateBody(box.width, null);
51247 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51251 Roo.EastLayoutRegion = function(mgr, config){
51252 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
51254 this.split.placement = Roo.SplitBar.RIGHT;
51255 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51256 this.split.el.addClass("x-layout-split-h");
51258 var size = config.initialSize || config.width;
51259 if(typeof size != "undefined"){
51260 this.el.setWidth(size);
51263 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
51264 orientation: Roo.SplitBar.HORIZONTAL,
51265 getBox : function(){
51266 if(this.collapsed){
51267 return this.collapsedEl.getBox();
51269 var box = this.el.getBox();
51271 var sw = this.split.el.getWidth();
51278 updateBox : function(box){
51279 if(this.split && !this.collapsed){
51280 var sw = this.split.el.getWidth();
51282 this.split.el.setLeft(box.x);
51283 this.split.el.setTop(box.y);
51284 this.split.el.setHeight(box.height);
51287 if(this.collapsed){
51288 this.updateBody(null, box.height);
51290 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51294 Roo.WestLayoutRegion = function(mgr, config){
51295 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
51297 this.split.placement = Roo.SplitBar.LEFT;
51298 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51299 this.split.el.addClass("x-layout-split-h");
51301 var size = config.initialSize || config.width;
51302 if(typeof size != "undefined"){
51303 this.el.setWidth(size);
51306 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
51307 orientation: Roo.SplitBar.HORIZONTAL,
51308 getBox : function(){
51309 if(this.collapsed){
51310 return this.collapsedEl.getBox();
51312 var box = this.el.getBox();
51314 box.width += this.split.el.getWidth();
51319 updateBox : function(box){
51320 if(this.split && !this.collapsed){
51321 var sw = this.split.el.getWidth();
51323 this.split.el.setLeft(box.x+box.width);
51324 this.split.el.setTop(box.y);
51325 this.split.el.setHeight(box.height);
51327 if(this.collapsed){
51328 this.updateBody(null, box.height);
51330 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51335 * Ext JS Library 1.1.1
51336 * Copyright(c) 2006-2007, Ext JS, LLC.
51338 * Originally Released Under LGPL - original licence link has changed is not relivant.
51341 * <script type="text/javascript">
51346 * Private internal class for reading and applying state
51348 Roo.LayoutStateManager = function(layout){
51349 // default empty state
51358 Roo.LayoutStateManager.prototype = {
51359 init : function(layout, provider){
51360 this.provider = provider;
51361 var state = provider.get(layout.id+"-layout-state");
51363 var wasUpdating = layout.isUpdating();
51365 layout.beginUpdate();
51367 for(var key in state){
51368 if(typeof state[key] != "function"){
51369 var rstate = state[key];
51370 var r = layout.getRegion(key);
51373 r.resizeTo(rstate.size);
51375 if(rstate.collapsed == true){
51378 r.expand(null, true);
51384 layout.endUpdate();
51386 this.state = state;
51388 this.layout = layout;
51389 layout.on("regionresized", this.onRegionResized, this);
51390 layout.on("regioncollapsed", this.onRegionCollapsed, this);
51391 layout.on("regionexpanded", this.onRegionExpanded, this);
51394 storeState : function(){
51395 this.provider.set(this.layout.id+"-layout-state", this.state);
51398 onRegionResized : function(region, newSize){
51399 this.state[region.getPosition()].size = newSize;
51403 onRegionCollapsed : function(region){
51404 this.state[region.getPosition()].collapsed = true;
51408 onRegionExpanded : function(region){
51409 this.state[region.getPosition()].collapsed = false;
51414 * Ext JS Library 1.1.1
51415 * Copyright(c) 2006-2007, Ext JS, LLC.
51417 * Originally Released Under LGPL - original licence link has changed is not relivant.
51420 * <script type="text/javascript">
51423 * @class Roo.ContentPanel
51424 * @extends Roo.util.Observable
51425 * A basic ContentPanel element.
51426 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
51427 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
51428 * @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
51429 * @cfg {Boolean} closable True if the panel can be closed/removed
51430 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
51431 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
51432 * @cfg {Toolbar} toolbar A toolbar for this panel
51433 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
51434 * @cfg {String} title The title for this panel
51435 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
51436 * @cfg {String} url Calls {@link #setUrl} with this value
51437 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
51438 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
51439 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
51440 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
51443 * Create a new ContentPanel.
51444 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
51445 * @param {String/Object} config A string to set only the title or a config object
51446 * @param {String} content (optional) Set the HTML content for this panel
51447 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
51449 Roo.ContentPanel = function(el, config, content){
51453 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
51457 if (config && config.parentLayout) {
51458 el = config.parentLayout.el.createChild();
51461 if(el.autoCreate){ // xtype is available if this is called from factory
51465 this.el = Roo.get(el);
51466 if(!this.el && config && config.autoCreate){
51467 if(typeof config.autoCreate == "object"){
51468 if(!config.autoCreate.id){
51469 config.autoCreate.id = config.id||el;
51471 this.el = Roo.DomHelper.append(document.body,
51472 config.autoCreate, true);
51474 this.el = Roo.DomHelper.append(document.body,
51475 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
51478 this.closable = false;
51479 this.loaded = false;
51480 this.active = false;
51481 if(typeof config == "string"){
51482 this.title = config;
51484 Roo.apply(this, config);
51487 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
51488 this.wrapEl = this.el.wrap();
51489 this.toolbar.container = this.el.insertSibling(false, 'before');
51490 this.toolbar = new Roo.Toolbar(this.toolbar);
51493 // xtype created footer. - not sure if will work as we normally have to render first..
51494 if (this.footer && !this.footer.el && this.footer.xtype) {
51495 if (!this.wrapEl) {
51496 this.wrapEl = this.el.wrap();
51499 this.footer.container = this.wrapEl.createChild();
51501 this.footer = Roo.factory(this.footer, Roo);
51506 this.resizeEl = Roo.get(this.resizeEl, true);
51508 this.resizeEl = this.el;
51510 // handle view.xtype
51518 * Fires when this panel is activated.
51519 * @param {Roo.ContentPanel} this
51523 * @event deactivate
51524 * Fires when this panel is activated.
51525 * @param {Roo.ContentPanel} this
51527 "deactivate" : true,
51531 * Fires when this panel is resized if fitToFrame is true.
51532 * @param {Roo.ContentPanel} this
51533 * @param {Number} width The width after any component adjustments
51534 * @param {Number} height The height after any component adjustments
51540 * Fires when this tab is created
51541 * @param {Roo.ContentPanel} this
51552 if(this.autoScroll){
51553 this.resizeEl.setStyle("overflow", "auto");
51555 // fix randome scrolling
51556 this.el.on('scroll', function() {
51557 Roo.log('fix random scolling');
51558 this.scrollTo('top',0);
51561 content = content || this.content;
51563 this.setContent(content);
51565 if(config && config.url){
51566 this.setUrl(this.url, this.params, this.loadOnce);
51571 Roo.ContentPanel.superclass.constructor.call(this);
51573 if (this.view && typeof(this.view.xtype) != 'undefined') {
51574 this.view.el = this.el.appendChild(document.createElement("div"));
51575 this.view = Roo.factory(this.view);
51576 this.view.render && this.view.render(false, '');
51580 this.fireEvent('render', this);
51583 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
51585 setRegion : function(region){
51586 this.region = region;
51588 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
51590 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
51595 * Returns the toolbar for this Panel if one was configured.
51596 * @return {Roo.Toolbar}
51598 getToolbar : function(){
51599 return this.toolbar;
51602 setActiveState : function(active){
51603 this.active = active;
51605 this.fireEvent("deactivate", this);
51607 this.fireEvent("activate", this);
51611 * Updates this panel's element
51612 * @param {String} content The new content
51613 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51615 setContent : function(content, loadScripts){
51616 this.el.update(content, loadScripts);
51619 ignoreResize : function(w, h){
51620 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51623 this.lastSize = {width: w, height: h};
51628 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51629 * @return {Roo.UpdateManager} The UpdateManager
51631 getUpdateManager : function(){
51632 return this.el.getUpdateManager();
51635 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51636 * @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:
51639 url: "your-url.php",
51640 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51641 callback: yourFunction,
51642 scope: yourObject, //(optional scope)
51645 text: "Loading...",
51650 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51651 * 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.
51652 * @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}
51653 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51654 * @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.
51655 * @return {Roo.ContentPanel} this
51658 var um = this.el.getUpdateManager();
51659 um.update.apply(um, arguments);
51665 * 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.
51666 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51667 * @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)
51668 * @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)
51669 * @return {Roo.UpdateManager} The UpdateManager
51671 setUrl : function(url, params, loadOnce){
51672 if(this.refreshDelegate){
51673 this.removeListener("activate", this.refreshDelegate);
51675 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51676 this.on("activate", this.refreshDelegate);
51677 return this.el.getUpdateManager();
51680 _handleRefresh : function(url, params, loadOnce){
51681 if(!loadOnce || !this.loaded){
51682 var updater = this.el.getUpdateManager();
51683 updater.update(url, params, this._setLoaded.createDelegate(this));
51687 _setLoaded : function(){
51688 this.loaded = true;
51692 * Returns this panel's id
51695 getId : function(){
51700 * Returns this panel's element - used by regiosn to add.
51701 * @return {Roo.Element}
51703 getEl : function(){
51704 return this.wrapEl || this.el;
51707 adjustForComponents : function(width, height)
51709 //Roo.log('adjustForComponents ');
51710 if(this.resizeEl != this.el){
51711 width -= this.el.getFrameWidth('lr');
51712 height -= this.el.getFrameWidth('tb');
51715 var te = this.toolbar.getEl();
51716 height -= te.getHeight();
51717 te.setWidth(width);
51720 var te = this.footer.getEl();
51721 Roo.log("footer:" + te.getHeight());
51723 height -= te.getHeight();
51724 te.setWidth(width);
51728 if(this.adjustments){
51729 width += this.adjustments[0];
51730 height += this.adjustments[1];
51732 return {"width": width, "height": height};
51735 setSize : function(width, height){
51736 if(this.fitToFrame && !this.ignoreResize(width, height)){
51737 if(this.fitContainer && this.resizeEl != this.el){
51738 this.el.setSize(width, height);
51740 var size = this.adjustForComponents(width, height);
51741 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51742 this.fireEvent('resize', this, size.width, size.height);
51747 * Returns this panel's title
51750 getTitle : function(){
51755 * Set this panel's title
51756 * @param {String} title
51758 setTitle : function(title){
51759 this.title = title;
51761 this.region.updatePanelTitle(this, title);
51766 * Returns true is this panel was configured to be closable
51767 * @return {Boolean}
51769 isClosable : function(){
51770 return this.closable;
51773 beforeSlide : function(){
51775 this.resizeEl.clip();
51778 afterSlide : function(){
51780 this.resizeEl.unclip();
51784 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51785 * Will fail silently if the {@link #setUrl} method has not been called.
51786 * This does not activate the panel, just updates its content.
51788 refresh : function(){
51789 if(this.refreshDelegate){
51790 this.loaded = false;
51791 this.refreshDelegate();
51796 * Destroys this panel
51798 destroy : function(){
51799 this.el.removeAllListeners();
51800 var tempEl = document.createElement("span");
51801 tempEl.appendChild(this.el.dom);
51802 tempEl.innerHTML = "";
51808 * form - if the content panel contains a form - this is a reference to it.
51809 * @type {Roo.form.Form}
51813 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51814 * This contains a reference to it.
51820 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51830 * @param {Object} cfg Xtype definition of item to add.
51833 addxtype : function(cfg) {
51835 if (cfg.xtype.match(/^Form$/)) {
51838 //if (this.footer) {
51839 // el = this.footer.container.insertSibling(false, 'before');
51841 el = this.el.createChild();
51844 this.form = new Roo.form.Form(cfg);
51847 if ( this.form.allItems.length) this.form.render(el.dom);
51850 // should only have one of theses..
51851 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51852 // views.. should not be just added - used named prop 'view''
51854 cfg.el = this.el.appendChild(document.createElement("div"));
51857 var ret = new Roo.factory(cfg);
51859 ret.render && ret.render(false, ''); // render blank..
51868 * @class Roo.GridPanel
51869 * @extends Roo.ContentPanel
51871 * Create a new GridPanel.
51872 * @param {Roo.grid.Grid} grid The grid for this panel
51873 * @param {String/Object} config A string to set only the panel's title, or a config object
51875 Roo.GridPanel = function(grid, config){
51878 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51879 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51881 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51883 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51886 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51888 // xtype created footer. - not sure if will work as we normally have to render first..
51889 if (this.footer && !this.footer.el && this.footer.xtype) {
51891 this.footer.container = this.grid.getView().getFooterPanel(true);
51892 this.footer.dataSource = this.grid.dataSource;
51893 this.footer = Roo.factory(this.footer, Roo);
51897 grid.monitorWindowResize = false; // turn off autosizing
51898 grid.autoHeight = false;
51899 grid.autoWidth = false;
51901 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51904 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51905 getId : function(){
51906 return this.grid.id;
51910 * Returns the grid for this panel
51911 * @return {Roo.grid.Grid}
51913 getGrid : function(){
51917 setSize : function(width, height){
51918 if(!this.ignoreResize(width, height)){
51919 var grid = this.grid;
51920 var size = this.adjustForComponents(width, height);
51921 grid.getGridEl().setSize(size.width, size.height);
51926 beforeSlide : function(){
51927 this.grid.getView().scroller.clip();
51930 afterSlide : function(){
51931 this.grid.getView().scroller.unclip();
51934 destroy : function(){
51935 this.grid.destroy();
51937 Roo.GridPanel.superclass.destroy.call(this);
51943 * @class Roo.NestedLayoutPanel
51944 * @extends Roo.ContentPanel
51946 * Create a new NestedLayoutPanel.
51949 * @param {Roo.BorderLayout} layout The layout for this panel
51950 * @param {String/Object} config A string to set only the title or a config object
51952 Roo.NestedLayoutPanel = function(layout, config)
51954 // construct with only one argument..
51955 /* FIXME - implement nicer consturctors
51956 if (layout.layout) {
51958 layout = config.layout;
51959 delete config.layout;
51961 if (layout.xtype && !layout.getEl) {
51962 // then layout needs constructing..
51963 layout = Roo.factory(layout, Roo);
51968 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51970 layout.monitorWindowResize = false; // turn off autosizing
51971 this.layout = layout;
51972 this.layout.getEl().addClass("x-layout-nested-layout");
51979 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51981 setSize : function(width, height){
51982 if(!this.ignoreResize(width, height)){
51983 var size = this.adjustForComponents(width, height);
51984 var el = this.layout.getEl();
51985 el.setSize(size.width, size.height);
51986 var touch = el.dom.offsetWidth;
51987 this.layout.layout();
51988 // ie requires a double layout on the first pass
51989 if(Roo.isIE && !this.initialized){
51990 this.initialized = true;
51991 this.layout.layout();
51996 // activate all subpanels if not currently active..
51998 setActiveState : function(active){
51999 this.active = active;
52001 this.fireEvent("deactivate", this);
52005 this.fireEvent("activate", this);
52006 // not sure if this should happen before or after..
52007 if (!this.layout) {
52008 return; // should not happen..
52011 for (var r in this.layout.regions) {
52012 reg = this.layout.getRegion(r);
52013 if (reg.getActivePanel()) {
52014 //reg.showPanel(reg.getActivePanel()); // force it to activate..
52015 reg.setActivePanel(reg.getActivePanel());
52018 if (!reg.panels.length) {
52021 reg.showPanel(reg.getPanel(0));
52030 * Returns the nested BorderLayout for this panel
52031 * @return {Roo.BorderLayout}
52033 getLayout : function(){
52034 return this.layout;
52038 * Adds a xtype elements to the layout of the nested panel
52042 xtype : 'ContentPanel',
52049 xtype : 'NestedLayoutPanel',
52055 items : [ ... list of content panels or nested layout panels.. ]
52059 * @param {Object} cfg Xtype definition of item to add.
52061 addxtype : function(cfg) {
52062 return this.layout.addxtype(cfg);
52067 Roo.ScrollPanel = function(el, config, content){
52068 config = config || {};
52069 config.fitToFrame = true;
52070 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
52072 this.el.dom.style.overflow = "hidden";
52073 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
52074 this.el.removeClass("x-layout-inactive-content");
52075 this.el.on("mousewheel", this.onWheel, this);
52077 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
52078 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
52079 up.unselectable(); down.unselectable();
52080 up.on("click", this.scrollUp, this);
52081 down.on("click", this.scrollDown, this);
52082 up.addClassOnOver("x-scroller-btn-over");
52083 down.addClassOnOver("x-scroller-btn-over");
52084 up.addClassOnClick("x-scroller-btn-click");
52085 down.addClassOnClick("x-scroller-btn-click");
52086 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
52088 this.resizeEl = this.el;
52089 this.el = wrap; this.up = up; this.down = down;
52092 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
52094 wheelIncrement : 5,
52095 scrollUp : function(){
52096 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
52099 scrollDown : function(){
52100 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
52103 afterScroll : function(){
52104 var el = this.resizeEl;
52105 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
52106 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52107 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52110 setSize : function(){
52111 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
52112 this.afterScroll();
52115 onWheel : function(e){
52116 var d = e.getWheelDelta();
52117 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
52118 this.afterScroll();
52122 setContent : function(content, loadScripts){
52123 this.resizeEl.update(content, loadScripts);
52137 * @class Roo.TreePanel
52138 * @extends Roo.ContentPanel
52140 * Create a new TreePanel. - defaults to fit/scoll contents.
52141 * @param {String/Object} config A string to set only the panel's title, or a config object
52142 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
52144 Roo.TreePanel = function(config){
52145 var el = config.el;
52146 var tree = config.tree;
52147 delete config.tree;
52148 delete config.el; // hopefull!
52150 // wrapper for IE7 strict & safari scroll issue
52152 var treeEl = el.createChild();
52153 config.resizeEl = treeEl;
52157 Roo.TreePanel.superclass.constructor.call(this, el, config);
52160 this.tree = new Roo.tree.TreePanel(treeEl , tree);
52161 //console.log(tree);
52162 this.on('activate', function()
52164 if (this.tree.rendered) {
52167 //console.log('render tree');
52168 this.tree.render();
52170 // this should not be needed.. - it's actually the 'el' that resizes?
52171 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
52173 //this.on('resize', function (cp, w, h) {
52174 // this.tree.innerCt.setWidth(w);
52175 // this.tree.innerCt.setHeight(h);
52176 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
52183 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
52200 * Ext JS Library 1.1.1
52201 * Copyright(c) 2006-2007, Ext JS, LLC.
52203 * Originally Released Under LGPL - original licence link has changed is not relivant.
52206 * <script type="text/javascript">
52211 * @class Roo.ReaderLayout
52212 * @extends Roo.BorderLayout
52213 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
52214 * center region containing two nested regions (a top one for a list view and one for item preview below),
52215 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
52216 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
52217 * expedites the setup of the overall layout and regions for this common application style.
52220 var reader = new Roo.ReaderLayout();
52221 var CP = Roo.ContentPanel; // shortcut for adding
52223 reader.beginUpdate();
52224 reader.add("north", new CP("north", "North"));
52225 reader.add("west", new CP("west", {title: "West"}));
52226 reader.add("east", new CP("east", {title: "East"}));
52228 reader.regions.listView.add(new CP("listView", "List"));
52229 reader.regions.preview.add(new CP("preview", "Preview"));
52230 reader.endUpdate();
52233 * Create a new ReaderLayout
52234 * @param {Object} config Configuration options
52235 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
52236 * document.body if omitted)
52238 Roo.ReaderLayout = function(config, renderTo){
52239 var c = config || {size:{}};
52240 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
52241 north: c.north !== false ? Roo.apply({
52245 }, c.north) : false,
52246 west: c.west !== false ? Roo.apply({
52254 margins:{left:5,right:0,bottom:5,top:5},
52255 cmargins:{left:5,right:5,bottom:5,top:5}
52256 }, c.west) : false,
52257 east: c.east !== false ? Roo.apply({
52265 margins:{left:0,right:5,bottom:5,top:5},
52266 cmargins:{left:5,right:5,bottom:5,top:5}
52267 }, c.east) : false,
52268 center: Roo.apply({
52269 tabPosition: 'top',
52273 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
52277 this.el.addClass('x-reader');
52279 this.beginUpdate();
52281 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
52282 south: c.preview !== false ? Roo.apply({
52289 cmargins:{top:5,left:0, right:0, bottom:0}
52290 }, c.preview) : false,
52291 center: Roo.apply({
52297 this.add('center', new Roo.NestedLayoutPanel(inner,
52298 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
52302 this.regions.preview = inner.getRegion('south');
52303 this.regions.listView = inner.getRegion('center');
52306 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
52308 * Ext JS Library 1.1.1
52309 * Copyright(c) 2006-2007, Ext JS, LLC.
52311 * Originally Released Under LGPL - original licence link has changed is not relivant.
52314 * <script type="text/javascript">
52318 * @class Roo.grid.Grid
52319 * @extends Roo.util.Observable
52320 * This class represents the primary interface of a component based grid control.
52321 * <br><br>Usage:<pre><code>
52322 var grid = new Roo.grid.Grid("my-container-id", {
52325 selModel: mySelectionModel,
52326 autoSizeColumns: true,
52327 monitorWindowResize: false,
52328 trackMouseOver: true
52333 * <b>Common Problems:</b><br/>
52334 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
52335 * element will correct this<br/>
52336 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
52337 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
52338 * are unpredictable.<br/>
52339 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
52340 * grid to calculate dimensions/offsets.<br/>
52342 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
52343 * The container MUST have some type of size defined for the grid to fill. The container will be
52344 * automatically set to position relative if it isn't already.
52345 * @param {Object} config A config object that sets properties on this grid.
52347 Roo.grid.Grid = function(container, config){
52348 // initialize the container
52349 this.container = Roo.get(container);
52350 this.container.update("");
52351 this.container.setStyle("overflow", "hidden");
52352 this.container.addClass('x-grid-container');
52354 this.id = this.container.id;
52356 Roo.apply(this, config);
52357 // check and correct shorthanded configs
52359 this.dataSource = this.ds;
52363 this.colModel = this.cm;
52367 this.selModel = this.sm;
52371 if (this.selModel) {
52372 this.selModel = Roo.factory(this.selModel, Roo.grid);
52373 this.sm = this.selModel;
52374 this.sm.xmodule = this.xmodule || false;
52376 if (typeof(this.colModel.config) == 'undefined') {
52377 this.colModel = new Roo.grid.ColumnModel(this.colModel);
52378 this.cm = this.colModel;
52379 this.cm.xmodule = this.xmodule || false;
52381 if (this.dataSource) {
52382 this.dataSource= Roo.factory(this.dataSource, Roo.data);
52383 this.ds = this.dataSource;
52384 this.ds.xmodule = this.xmodule || false;
52391 this.container.setWidth(this.width);
52395 this.container.setHeight(this.height);
52402 * The raw click event for the entire grid.
52403 * @param {Roo.EventObject} e
52408 * The raw dblclick event for the entire grid.
52409 * @param {Roo.EventObject} e
52413 * @event contextmenu
52414 * The raw contextmenu event for the entire grid.
52415 * @param {Roo.EventObject} e
52417 "contextmenu" : true,
52420 * The raw mousedown event for the entire grid.
52421 * @param {Roo.EventObject} e
52423 "mousedown" : true,
52426 * The raw mouseup event for the entire grid.
52427 * @param {Roo.EventObject} e
52432 * The raw mouseover event for the entire grid.
52433 * @param {Roo.EventObject} e
52435 "mouseover" : true,
52438 * The raw mouseout event for the entire grid.
52439 * @param {Roo.EventObject} e
52444 * The raw keypress event for the entire grid.
52445 * @param {Roo.EventObject} e
52450 * The raw keydown event for the entire grid.
52451 * @param {Roo.EventObject} e
52459 * Fires when a cell is clicked
52460 * @param {Grid} this
52461 * @param {Number} rowIndex
52462 * @param {Number} columnIndex
52463 * @param {Roo.EventObject} e
52465 "cellclick" : true,
52467 * @event celldblclick
52468 * Fires when a cell is double clicked
52469 * @param {Grid} this
52470 * @param {Number} rowIndex
52471 * @param {Number} columnIndex
52472 * @param {Roo.EventObject} e
52474 "celldblclick" : true,
52477 * Fires when a row is clicked
52478 * @param {Grid} this
52479 * @param {Number} rowIndex
52480 * @param {Roo.EventObject} e
52484 * @event rowdblclick
52485 * Fires when a row is double clicked
52486 * @param {Grid} this
52487 * @param {Number} rowIndex
52488 * @param {Roo.EventObject} e
52490 "rowdblclick" : true,
52492 * @event headerclick
52493 * Fires when a header is clicked
52494 * @param {Grid} this
52495 * @param {Number} columnIndex
52496 * @param {Roo.EventObject} e
52498 "headerclick" : true,
52500 * @event headerdblclick
52501 * Fires when a header cell is double clicked
52502 * @param {Grid} this
52503 * @param {Number} columnIndex
52504 * @param {Roo.EventObject} e
52506 "headerdblclick" : true,
52508 * @event rowcontextmenu
52509 * Fires when a row is right clicked
52510 * @param {Grid} this
52511 * @param {Number} rowIndex
52512 * @param {Roo.EventObject} e
52514 "rowcontextmenu" : true,
52516 * @event cellcontextmenu
52517 * Fires when a cell is right clicked
52518 * @param {Grid} this
52519 * @param {Number} rowIndex
52520 * @param {Number} cellIndex
52521 * @param {Roo.EventObject} e
52523 "cellcontextmenu" : true,
52525 * @event headercontextmenu
52526 * Fires when a header is right clicked
52527 * @param {Grid} this
52528 * @param {Number} columnIndex
52529 * @param {Roo.EventObject} e
52531 "headercontextmenu" : true,
52533 * @event bodyscroll
52534 * Fires when the body element is scrolled
52535 * @param {Number} scrollLeft
52536 * @param {Number} scrollTop
52538 "bodyscroll" : true,
52540 * @event columnresize
52541 * Fires when the user resizes a column
52542 * @param {Number} columnIndex
52543 * @param {Number} newSize
52545 "columnresize" : true,
52547 * @event columnmove
52548 * Fires when the user moves a column
52549 * @param {Number} oldIndex
52550 * @param {Number} newIndex
52552 "columnmove" : true,
52555 * Fires when row(s) start being dragged
52556 * @param {Grid} this
52557 * @param {Roo.GridDD} dd The drag drop object
52558 * @param {event} e The raw browser event
52560 "startdrag" : true,
52563 * Fires when a drag operation is complete
52564 * @param {Grid} this
52565 * @param {Roo.GridDD} dd The drag drop object
52566 * @param {event} e The raw browser event
52571 * Fires when dragged row(s) are dropped on a valid DD target
52572 * @param {Grid} this
52573 * @param {Roo.GridDD} dd The drag drop object
52574 * @param {String} targetId The target drag drop object
52575 * @param {event} e The raw browser event
52580 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
52581 * @param {Grid} this
52582 * @param {Roo.GridDD} dd The drag drop object
52583 * @param {String} targetId The target drag drop object
52584 * @param {event} e The raw browser event
52589 * Fires when the dragged row(s) first cross another DD target while being dragged
52590 * @param {Grid} this
52591 * @param {Roo.GridDD} dd The drag drop object
52592 * @param {String} targetId The target drag drop object
52593 * @param {event} e The raw browser event
52595 "dragenter" : true,
52598 * Fires when the dragged row(s) leave another DD target while being dragged
52599 * @param {Grid} this
52600 * @param {Roo.GridDD} dd The drag drop object
52601 * @param {String} targetId The target drag drop object
52602 * @param {event} e The raw browser event
52607 * Fires when a row is rendered, so you can change add a style to it.
52608 * @param {GridView} gridview The grid view
52609 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52615 * Fires when the grid is rendered
52616 * @param {Grid} grid
52621 Roo.grid.Grid.superclass.constructor.call(this);
52623 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52626 * @cfg {String} ddGroup - drag drop group.
52630 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52632 minColumnWidth : 25,
52635 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52636 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52637 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52639 autoSizeColumns : false,
52642 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52644 autoSizeHeaders : true,
52647 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52649 monitorWindowResize : true,
52652 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52653 * rows measured to get a columns size. Default is 0 (all rows).
52655 maxRowsToMeasure : 0,
52658 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52660 trackMouseOver : true,
52663 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52667 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52669 enableDragDrop : false,
52672 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52674 enableColumnMove : true,
52677 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52679 enableColumnHide : true,
52682 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52684 enableRowHeightSync : false,
52687 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52692 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52694 autoHeight : false,
52697 * @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.
52699 autoExpandColumn : false,
52702 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52705 autoExpandMin : 50,
52708 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52710 autoExpandMax : 1000,
52713 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52718 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52722 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52732 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52733 * of a fixed width. Default is false.
52736 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52739 * Called once after all setup has been completed and the grid is ready to be rendered.
52740 * @return {Roo.grid.Grid} this
52742 render : function()
52744 var c = this.container;
52745 // try to detect autoHeight/width mode
52746 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52747 this.autoHeight = true;
52749 var view = this.getView();
52752 c.on("click", this.onClick, this);
52753 c.on("dblclick", this.onDblClick, this);
52754 c.on("contextmenu", this.onContextMenu, this);
52755 c.on("keydown", this.onKeyDown, this);
52757 c.on("touchstart", this.onTouchStart, this);
52760 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52762 this.getSelectionModel().init(this);
52767 this.loadMask = new Roo.LoadMask(this.container,
52768 Roo.apply({store:this.dataSource}, this.loadMask));
52772 if (this.toolbar && this.toolbar.xtype) {
52773 this.toolbar.container = this.getView().getHeaderPanel(true);
52774 this.toolbar = new Roo.Toolbar(this.toolbar);
52776 if (this.footer && this.footer.xtype) {
52777 this.footer.dataSource = this.getDataSource();
52778 this.footer.container = this.getView().getFooterPanel(true);
52779 this.footer = Roo.factory(this.footer, Roo);
52781 if (this.dropTarget && this.dropTarget.xtype) {
52782 delete this.dropTarget.xtype;
52783 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52787 this.rendered = true;
52788 this.fireEvent('render', this);
52793 * Reconfigures the grid to use a different Store and Column Model.
52794 * The View will be bound to the new objects and refreshed.
52795 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52796 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52798 reconfigure : function(dataSource, colModel){
52800 this.loadMask.destroy();
52801 this.loadMask = new Roo.LoadMask(this.container,
52802 Roo.apply({store:dataSource}, this.loadMask));
52804 this.view.bind(dataSource, colModel);
52805 this.dataSource = dataSource;
52806 this.colModel = colModel;
52807 this.view.refresh(true);
52811 onKeyDown : function(e){
52812 this.fireEvent("keydown", e);
52816 * Destroy this grid.
52817 * @param {Boolean} removeEl True to remove the element
52819 destroy : function(removeEl, keepListeners){
52821 this.loadMask.destroy();
52823 var c = this.container;
52824 c.removeAllListeners();
52825 this.view.destroy();
52826 this.colModel.purgeListeners();
52827 if(!keepListeners){
52828 this.purgeListeners();
52831 if(removeEl === true){
52837 processEvent : function(name, e){
52838 // does this fire select???
52839 //Roo.log('grid:processEvent ' + name);
52841 if (name != 'touchstart' ) {
52842 this.fireEvent(name, e);
52845 var t = e.getTarget();
52847 var header = v.findHeaderIndex(t);
52848 if(header !== false){
52849 var ename = name == 'touchstart' ? 'click' : name;
52851 this.fireEvent("header" + ename, this, header, e);
52853 var row = v.findRowIndex(t);
52854 var cell = v.findCellIndex(t);
52855 if (name == 'touchstart') {
52856 // first touch is always a click.
52857 // hopefull this happens after selection is updated.?
52860 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52861 var cs = this.selModel.getSelectedCell();
52862 if (row == cs[0] && cell == cs[1]){
52866 if (typeof(this.selModel.getSelections) != 'undefined') {
52867 var cs = this.selModel.getSelections();
52868 var ds = this.dataSource;
52869 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52880 this.fireEvent("row" + name, this, row, e);
52881 if(cell !== false){
52882 this.fireEvent("cell" + name, this, row, cell, e);
52889 onClick : function(e){
52890 this.processEvent("click", e);
52893 onTouchStart : function(e){
52894 this.processEvent("touchstart", e);
52898 onContextMenu : function(e, t){
52899 this.processEvent("contextmenu", e);
52903 onDblClick : function(e){
52904 this.processEvent("dblclick", e);
52908 walkCells : function(row, col, step, fn, scope){
52909 var cm = this.colModel, clen = cm.getColumnCount();
52910 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52922 if(fn.call(scope || this, row, col, cm) === true){
52940 if(fn.call(scope || this, row, col, cm) === true){
52952 getSelections : function(){
52953 return this.selModel.getSelections();
52957 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52958 * but if manual update is required this method will initiate it.
52960 autoSize : function(){
52962 this.view.layout();
52963 if(this.view.adjustForScroll){
52964 this.view.adjustForScroll();
52970 * Returns the grid's underlying element.
52971 * @return {Element} The element
52973 getGridEl : function(){
52974 return this.container;
52977 // private for compatibility, overridden by editor grid
52978 stopEditing : function(){},
52981 * Returns the grid's SelectionModel.
52982 * @return {SelectionModel}
52984 getSelectionModel : function(){
52985 if(!this.selModel){
52986 this.selModel = new Roo.grid.RowSelectionModel();
52988 return this.selModel;
52992 * Returns the grid's DataSource.
52993 * @return {DataSource}
52995 getDataSource : function(){
52996 return this.dataSource;
53000 * Returns the grid's ColumnModel.
53001 * @return {ColumnModel}
53003 getColumnModel : function(){
53004 return this.colModel;
53008 * Returns the grid's GridView object.
53009 * @return {GridView}
53011 getView : function(){
53013 this.view = new Roo.grid.GridView(this.viewConfig);
53018 * Called to get grid's drag proxy text, by default returns this.ddText.
53021 getDragDropText : function(){
53022 var count = this.selModel.getCount();
53023 return String.format(this.ddText, count, count == 1 ? '' : 's');
53027 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
53028 * %0 is replaced with the number of selected rows.
53031 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
53033 * Ext JS Library 1.1.1
53034 * Copyright(c) 2006-2007, Ext JS, LLC.
53036 * Originally Released Under LGPL - original licence link has changed is not relivant.
53039 * <script type="text/javascript">
53042 Roo.grid.AbstractGridView = function(){
53046 "beforerowremoved" : true,
53047 "beforerowsinserted" : true,
53048 "beforerefresh" : true,
53049 "rowremoved" : true,
53050 "rowsinserted" : true,
53051 "rowupdated" : true,
53054 Roo.grid.AbstractGridView.superclass.constructor.call(this);
53057 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
53058 rowClass : "x-grid-row",
53059 cellClass : "x-grid-cell",
53060 tdClass : "x-grid-td",
53061 hdClass : "x-grid-hd",
53062 splitClass : "x-grid-hd-split",
53064 init: function(grid){
53066 var cid = this.grid.getGridEl().id;
53067 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
53068 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
53069 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
53070 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
53073 getColumnRenderers : function(){
53074 var renderers = [];
53075 var cm = this.grid.colModel;
53076 var colCount = cm.getColumnCount();
53077 for(var i = 0; i < colCount; i++){
53078 renderers[i] = cm.getRenderer(i);
53083 getColumnIds : function(){
53085 var cm = this.grid.colModel;
53086 var colCount = cm.getColumnCount();
53087 for(var i = 0; i < colCount; i++){
53088 ids[i] = cm.getColumnId(i);
53093 getDataIndexes : function(){
53094 if(!this.indexMap){
53095 this.indexMap = this.buildIndexMap();
53097 return this.indexMap.colToData;
53100 getColumnIndexByDataIndex : function(dataIndex){
53101 if(!this.indexMap){
53102 this.indexMap = this.buildIndexMap();
53104 return this.indexMap.dataToCol[dataIndex];
53108 * Set a css style for a column dynamically.
53109 * @param {Number} colIndex The index of the column
53110 * @param {String} name The css property name
53111 * @param {String} value The css value
53113 setCSSStyle : function(colIndex, name, value){
53114 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
53115 Roo.util.CSS.updateRule(selector, name, value);
53118 generateRules : function(cm){
53119 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
53120 Roo.util.CSS.removeStyleSheet(rulesId);
53121 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53122 var cid = cm.getColumnId(i);
53123 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
53124 this.tdSelector, cid, " {\n}\n",
53125 this.hdSelector, cid, " {\n}\n",
53126 this.splitSelector, cid, " {\n}\n");
53128 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53132 * Ext JS Library 1.1.1
53133 * Copyright(c) 2006-2007, Ext JS, LLC.
53135 * Originally Released Under LGPL - original licence link has changed is not relivant.
53138 * <script type="text/javascript">
53142 // This is a support class used internally by the Grid components
53143 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
53145 this.view = grid.getView();
53146 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53147 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
53149 this.setHandleElId(Roo.id(hd));
53150 this.setOuterHandleElId(Roo.id(hd2));
53152 this.scroll = false;
53154 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
53156 getDragData : function(e){
53157 var t = Roo.lib.Event.getTarget(e);
53158 var h = this.view.findHeaderCell(t);
53160 return {ddel: h.firstChild, header:h};
53165 onInitDrag : function(e){
53166 this.view.headersDisabled = true;
53167 var clone = this.dragData.ddel.cloneNode(true);
53168 clone.id = Roo.id();
53169 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
53170 this.proxy.update(clone);
53174 afterValidDrop : function(){
53176 setTimeout(function(){
53177 v.headersDisabled = false;
53181 afterInvalidDrop : function(){
53183 setTimeout(function(){
53184 v.headersDisabled = false;
53190 * Ext JS Library 1.1.1
53191 * Copyright(c) 2006-2007, Ext JS, LLC.
53193 * Originally Released Under LGPL - original licence link has changed is not relivant.
53196 * <script type="text/javascript">
53199 // This is a support class used internally by the Grid components
53200 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
53202 this.view = grid.getView();
53203 // split the proxies so they don't interfere with mouse events
53204 this.proxyTop = Roo.DomHelper.append(document.body, {
53205 cls:"col-move-top", html:" "
53207 this.proxyBottom = Roo.DomHelper.append(document.body, {
53208 cls:"col-move-bottom", html:" "
53210 this.proxyTop.hide = this.proxyBottom.hide = function(){
53211 this.setLeftTop(-100,-100);
53212 this.setStyle("visibility", "hidden");
53214 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53215 // temporarily disabled
53216 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
53217 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
53219 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
53220 proxyOffsets : [-4, -9],
53221 fly: Roo.Element.fly,
53223 getTargetFromEvent : function(e){
53224 var t = Roo.lib.Event.getTarget(e);
53225 var cindex = this.view.findCellIndex(t);
53226 if(cindex !== false){
53227 return this.view.getHeaderCell(cindex);
53232 nextVisible : function(h){
53233 var v = this.view, cm = this.grid.colModel;
53236 if(!cm.isHidden(v.getCellIndex(h))){
53244 prevVisible : function(h){
53245 var v = this.view, cm = this.grid.colModel;
53248 if(!cm.isHidden(v.getCellIndex(h))){
53256 positionIndicator : function(h, n, e){
53257 var x = Roo.lib.Event.getPageX(e);
53258 var r = Roo.lib.Dom.getRegion(n.firstChild);
53259 var px, pt, py = r.top + this.proxyOffsets[1];
53260 if((r.right - x) <= (r.right-r.left)/2){
53261 px = r.right+this.view.borderWidth;
53267 var oldIndex = this.view.getCellIndex(h);
53268 var newIndex = this.view.getCellIndex(n);
53270 if(this.grid.colModel.isFixed(newIndex)){
53274 var locked = this.grid.colModel.isLocked(newIndex);
53279 if(oldIndex < newIndex){
53282 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
53285 px += this.proxyOffsets[0];
53286 this.proxyTop.setLeftTop(px, py);
53287 this.proxyTop.show();
53288 if(!this.bottomOffset){
53289 this.bottomOffset = this.view.mainHd.getHeight();
53291 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
53292 this.proxyBottom.show();
53296 onNodeEnter : function(n, dd, e, data){
53297 if(data.header != n){
53298 this.positionIndicator(data.header, n, e);
53302 onNodeOver : function(n, dd, e, data){
53303 var result = false;
53304 if(data.header != n){
53305 result = this.positionIndicator(data.header, n, e);
53308 this.proxyTop.hide();
53309 this.proxyBottom.hide();
53311 return result ? this.dropAllowed : this.dropNotAllowed;
53314 onNodeOut : function(n, dd, e, data){
53315 this.proxyTop.hide();
53316 this.proxyBottom.hide();
53319 onNodeDrop : function(n, dd, e, data){
53320 var h = data.header;
53322 var cm = this.grid.colModel;
53323 var x = Roo.lib.Event.getPageX(e);
53324 var r = Roo.lib.Dom.getRegion(n.firstChild);
53325 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
53326 var oldIndex = this.view.getCellIndex(h);
53327 var newIndex = this.view.getCellIndex(n);
53328 var locked = cm.isLocked(newIndex);
53332 if(oldIndex < newIndex){
53335 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
53338 cm.setLocked(oldIndex, locked, true);
53339 cm.moveColumn(oldIndex, newIndex);
53340 this.grid.fireEvent("columnmove", oldIndex, newIndex);
53348 * Ext JS Library 1.1.1
53349 * Copyright(c) 2006-2007, Ext JS, LLC.
53351 * Originally Released Under LGPL - original licence link has changed is not relivant.
53354 * <script type="text/javascript">
53358 * @class Roo.grid.GridView
53359 * @extends Roo.util.Observable
53362 * @param {Object} config
53364 Roo.grid.GridView = function(config){
53365 Roo.grid.GridView.superclass.constructor.call(this);
53368 Roo.apply(this, config);
53371 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
53373 unselectable : 'unselectable="on"',
53374 unselectableCls : 'x-unselectable',
53377 rowClass : "x-grid-row",
53379 cellClass : "x-grid-col",
53381 tdClass : "x-grid-td",
53383 hdClass : "x-grid-hd",
53385 splitClass : "x-grid-split",
53387 sortClasses : ["sort-asc", "sort-desc"],
53389 enableMoveAnim : false,
53393 dh : Roo.DomHelper,
53395 fly : Roo.Element.fly,
53397 css : Roo.util.CSS,
53403 scrollIncrement : 22,
53405 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
53407 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
53409 bind : function(ds, cm){
53411 this.ds.un("load", this.onLoad, this);
53412 this.ds.un("datachanged", this.onDataChange, this);
53413 this.ds.un("add", this.onAdd, this);
53414 this.ds.un("remove", this.onRemove, this);
53415 this.ds.un("update", this.onUpdate, this);
53416 this.ds.un("clear", this.onClear, this);
53419 ds.on("load", this.onLoad, this);
53420 ds.on("datachanged", this.onDataChange, this);
53421 ds.on("add", this.onAdd, this);
53422 ds.on("remove", this.onRemove, this);
53423 ds.on("update", this.onUpdate, this);
53424 ds.on("clear", this.onClear, this);
53429 this.cm.un("widthchange", this.onColWidthChange, this);
53430 this.cm.un("headerchange", this.onHeaderChange, this);
53431 this.cm.un("hiddenchange", this.onHiddenChange, this);
53432 this.cm.un("columnmoved", this.onColumnMove, this);
53433 this.cm.un("columnlockchange", this.onColumnLock, this);
53436 this.generateRules(cm);
53437 cm.on("widthchange", this.onColWidthChange, this);
53438 cm.on("headerchange", this.onHeaderChange, this);
53439 cm.on("hiddenchange", this.onHiddenChange, this);
53440 cm.on("columnmoved", this.onColumnMove, this);
53441 cm.on("columnlockchange", this.onColumnLock, this);
53446 init: function(grid){
53447 Roo.grid.GridView.superclass.init.call(this, grid);
53449 this.bind(grid.dataSource, grid.colModel);
53451 grid.on("headerclick", this.handleHeaderClick, this);
53453 if(grid.trackMouseOver){
53454 grid.on("mouseover", this.onRowOver, this);
53455 grid.on("mouseout", this.onRowOut, this);
53457 grid.cancelTextSelection = function(){};
53458 this.gridId = grid.id;
53460 var tpls = this.templates || {};
53463 tpls.master = new Roo.Template(
53464 '<div class="x-grid" hidefocus="true">',
53465 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
53466 '<div class="x-grid-topbar"></div>',
53467 '<div class="x-grid-scroller"><div></div></div>',
53468 '<div class="x-grid-locked">',
53469 '<div class="x-grid-header">{lockedHeader}</div>',
53470 '<div class="x-grid-body">{lockedBody}</div>',
53472 '<div class="x-grid-viewport">',
53473 '<div class="x-grid-header">{header}</div>',
53474 '<div class="x-grid-body">{body}</div>',
53476 '<div class="x-grid-bottombar"></div>',
53478 '<div class="x-grid-resize-proxy"> </div>',
53481 tpls.master.disableformats = true;
53485 tpls.header = new Roo.Template(
53486 '<table border="0" cellspacing="0" cellpadding="0">',
53487 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
53490 tpls.header.disableformats = true;
53492 tpls.header.compile();
53495 tpls.hcell = new Roo.Template(
53496 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
53497 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
53500 tpls.hcell.disableFormats = true;
53502 tpls.hcell.compile();
53505 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
53506 this.unselectableCls + '" ' + this.unselectable +'> </div>');
53507 tpls.hsplit.disableFormats = true;
53509 tpls.hsplit.compile();
53512 tpls.body = new Roo.Template(
53513 '<table border="0" cellspacing="0" cellpadding="0">',
53514 "<tbody>{rows}</tbody>",
53517 tpls.body.disableFormats = true;
53519 tpls.body.compile();
53522 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
53523 tpls.row.disableFormats = true;
53525 tpls.row.compile();
53528 tpls.cell = new Roo.Template(
53529 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
53530 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
53531 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
53534 tpls.cell.disableFormats = true;
53536 tpls.cell.compile();
53538 this.templates = tpls;
53541 // remap these for backwards compat
53542 onColWidthChange : function(){
53543 this.updateColumns.apply(this, arguments);
53545 onHeaderChange : function(){
53546 this.updateHeaders.apply(this, arguments);
53548 onHiddenChange : function(){
53549 this.handleHiddenChange.apply(this, arguments);
53551 onColumnMove : function(){
53552 this.handleColumnMove.apply(this, arguments);
53554 onColumnLock : function(){
53555 this.handleLockChange.apply(this, arguments);
53558 onDataChange : function(){
53560 this.updateHeaderSortState();
53563 onClear : function(){
53567 onUpdate : function(ds, record){
53568 this.refreshRow(record);
53571 refreshRow : function(record){
53572 var ds = this.ds, index;
53573 if(typeof record == 'number'){
53575 record = ds.getAt(index);
53577 index = ds.indexOf(record);
53579 this.insertRows(ds, index, index, true);
53580 this.onRemove(ds, record, index+1, true);
53581 this.syncRowHeights(index, index);
53583 this.fireEvent("rowupdated", this, index, record);
53586 onAdd : function(ds, records, index){
53587 this.insertRows(ds, index, index + (records.length-1));
53590 onRemove : function(ds, record, index, isUpdate){
53591 if(isUpdate !== true){
53592 this.fireEvent("beforerowremoved", this, index, record);
53594 var bt = this.getBodyTable(), lt = this.getLockedTable();
53595 if(bt.rows[index]){
53596 bt.firstChild.removeChild(bt.rows[index]);
53598 if(lt.rows[index]){
53599 lt.firstChild.removeChild(lt.rows[index]);
53601 if(isUpdate !== true){
53602 this.stripeRows(index);
53603 this.syncRowHeights(index, index);
53605 this.fireEvent("rowremoved", this, index, record);
53609 onLoad : function(){
53610 this.scrollToTop();
53614 * Scrolls the grid to the top
53616 scrollToTop : function(){
53618 this.scroller.dom.scrollTop = 0;
53624 * Gets a panel in the header of the grid that can be used for toolbars etc.
53625 * After modifying the contents of this panel a call to grid.autoSize() may be
53626 * required to register any changes in size.
53627 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
53628 * @return Roo.Element
53630 getHeaderPanel : function(doShow){
53632 this.headerPanel.show();
53634 return this.headerPanel;
53638 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53639 * After modifying the contents of this panel a call to grid.autoSize() may be
53640 * required to register any changes in size.
53641 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53642 * @return Roo.Element
53644 getFooterPanel : function(doShow){
53646 this.footerPanel.show();
53648 return this.footerPanel;
53651 initElements : function(){
53652 var E = Roo.Element;
53653 var el = this.grid.getGridEl().dom.firstChild;
53654 var cs = el.childNodes;
53656 this.el = new E(el);
53658 this.focusEl = new E(el.firstChild);
53659 this.focusEl.swallowEvent("click", true);
53661 this.headerPanel = new E(cs[1]);
53662 this.headerPanel.enableDisplayMode("block");
53664 this.scroller = new E(cs[2]);
53665 this.scrollSizer = new E(this.scroller.dom.firstChild);
53667 this.lockedWrap = new E(cs[3]);
53668 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53669 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53671 this.mainWrap = new E(cs[4]);
53672 this.mainHd = new E(this.mainWrap.dom.firstChild);
53673 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53675 this.footerPanel = new E(cs[5]);
53676 this.footerPanel.enableDisplayMode("block");
53678 this.resizeProxy = new E(cs[6]);
53680 this.headerSelector = String.format(
53681 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53682 this.lockedHd.id, this.mainHd.id
53685 this.splitterSelector = String.format(
53686 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53687 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53690 idToCssName : function(s)
53692 return s.replace(/[^a-z0-9]+/ig, '-');
53695 getHeaderCell : function(index){
53696 return Roo.DomQuery.select(this.headerSelector)[index];
53699 getHeaderCellMeasure : function(index){
53700 return this.getHeaderCell(index).firstChild;
53703 getHeaderCellText : function(index){
53704 return this.getHeaderCell(index).firstChild.firstChild;
53707 getLockedTable : function(){
53708 return this.lockedBody.dom.firstChild;
53711 getBodyTable : function(){
53712 return this.mainBody.dom.firstChild;
53715 getLockedRow : function(index){
53716 return this.getLockedTable().rows[index];
53719 getRow : function(index){
53720 return this.getBodyTable().rows[index];
53723 getRowComposite : function(index){
53725 this.rowEl = new Roo.CompositeElementLite();
53727 var els = [], lrow, mrow;
53728 if(lrow = this.getLockedRow(index)){
53731 if(mrow = this.getRow(index)){
53734 this.rowEl.elements = els;
53738 * Gets the 'td' of the cell
53740 * @param {Integer} rowIndex row to select
53741 * @param {Integer} colIndex column to select
53745 getCell : function(rowIndex, colIndex){
53746 var locked = this.cm.getLockedCount();
53748 if(colIndex < locked){
53749 source = this.lockedBody.dom.firstChild;
53751 source = this.mainBody.dom.firstChild;
53752 colIndex -= locked;
53754 return source.rows[rowIndex].childNodes[colIndex];
53757 getCellText : function(rowIndex, colIndex){
53758 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53761 getCellBox : function(cell){
53762 var b = this.fly(cell).getBox();
53763 if(Roo.isOpera){ // opera fails to report the Y
53764 b.y = cell.offsetTop + this.mainBody.getY();
53769 getCellIndex : function(cell){
53770 var id = String(cell.className).match(this.cellRE);
53772 return parseInt(id[1], 10);
53777 findHeaderIndex : function(n){
53778 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53779 return r ? this.getCellIndex(r) : false;
53782 findHeaderCell : function(n){
53783 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53784 return r ? r : false;
53787 findRowIndex : function(n){
53791 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53792 return r ? r.rowIndex : false;
53795 findCellIndex : function(node){
53796 var stop = this.el.dom;
53797 while(node && node != stop){
53798 if(this.findRE.test(node.className)){
53799 return this.getCellIndex(node);
53801 node = node.parentNode;
53806 getColumnId : function(index){
53807 return this.cm.getColumnId(index);
53810 getSplitters : function()
53812 if(this.splitterSelector){
53813 return Roo.DomQuery.select(this.splitterSelector);
53819 getSplitter : function(index){
53820 return this.getSplitters()[index];
53823 onRowOver : function(e, t){
53825 if((row = this.findRowIndex(t)) !== false){
53826 this.getRowComposite(row).addClass("x-grid-row-over");
53830 onRowOut : function(e, t){
53832 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53833 this.getRowComposite(row).removeClass("x-grid-row-over");
53837 renderHeaders : function(){
53839 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53840 var cb = [], lb = [], sb = [], lsb = [], p = {};
53841 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53842 p.cellId = "x-grid-hd-0-" + i;
53843 p.splitId = "x-grid-csplit-0-" + i;
53844 p.id = cm.getColumnId(i);
53845 p.title = cm.getColumnTooltip(i) || "";
53846 p.value = cm.getColumnHeader(i) || "";
53847 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53848 if(!cm.isLocked(i)){
53849 cb[cb.length] = ct.apply(p);
53850 sb[sb.length] = st.apply(p);
53852 lb[lb.length] = ct.apply(p);
53853 lsb[lsb.length] = st.apply(p);
53856 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53857 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53860 updateHeaders : function(){
53861 var html = this.renderHeaders();
53862 this.lockedHd.update(html[0]);
53863 this.mainHd.update(html[1]);
53867 * Focuses the specified row.
53868 * @param {Number} row The row index
53870 focusRow : function(row)
53872 //Roo.log('GridView.focusRow');
53873 var x = this.scroller.dom.scrollLeft;
53874 this.focusCell(row, 0, false);
53875 this.scroller.dom.scrollLeft = x;
53879 * Focuses the specified cell.
53880 * @param {Number} row The row index
53881 * @param {Number} col The column index
53882 * @param {Boolean} hscroll false to disable horizontal scrolling
53884 focusCell : function(row, col, hscroll)
53886 //Roo.log('GridView.focusCell');
53887 var el = this.ensureVisible(row, col, hscroll);
53888 this.focusEl.alignTo(el, "tl-tl");
53890 this.focusEl.focus();
53892 this.focusEl.focus.defer(1, this.focusEl);
53897 * Scrolls the specified cell into view
53898 * @param {Number} row The row index
53899 * @param {Number} col The column index
53900 * @param {Boolean} hscroll false to disable horizontal scrolling
53902 ensureVisible : function(row, col, hscroll)
53904 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53905 //return null; //disable for testing.
53906 if(typeof row != "number"){
53907 row = row.rowIndex;
53909 if(row < 0 && row >= this.ds.getCount()){
53912 col = (col !== undefined ? col : 0);
53913 var cm = this.grid.colModel;
53914 while(cm.isHidden(col)){
53918 var el = this.getCell(row, col);
53922 var c = this.scroller.dom;
53924 var ctop = parseInt(el.offsetTop, 10);
53925 var cleft = parseInt(el.offsetLeft, 10);
53926 var cbot = ctop + el.offsetHeight;
53927 var cright = cleft + el.offsetWidth;
53929 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53930 var stop = parseInt(c.scrollTop, 10);
53931 var sleft = parseInt(c.scrollLeft, 10);
53932 var sbot = stop + ch;
53933 var sright = sleft + c.clientWidth;
53935 Roo.log('GridView.ensureVisible:' +
53937 ' c.clientHeight:' + c.clientHeight +
53938 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53946 c.scrollTop = ctop;
53947 //Roo.log("set scrolltop to ctop DISABLE?");
53948 }else if(cbot > sbot){
53949 //Roo.log("set scrolltop to cbot-ch");
53950 c.scrollTop = cbot-ch;
53953 if(hscroll !== false){
53955 c.scrollLeft = cleft;
53956 }else if(cright > sright){
53957 c.scrollLeft = cright-c.clientWidth;
53964 updateColumns : function(){
53965 this.grid.stopEditing();
53966 var cm = this.grid.colModel, colIds = this.getColumnIds();
53967 //var totalWidth = cm.getTotalWidth();
53969 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53970 //if(cm.isHidden(i)) continue;
53971 var w = cm.getColumnWidth(i);
53972 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53973 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53975 this.updateSplitters();
53978 generateRules : function(cm){
53979 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53980 Roo.util.CSS.removeStyleSheet(rulesId);
53981 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53982 var cid = cm.getColumnId(i);
53984 if(cm.config[i].align){
53985 align = 'text-align:'+cm.config[i].align+';';
53988 if(cm.isHidden(i)){
53989 hidden = 'display:none;';
53991 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53993 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53994 this.hdSelector, cid, " {\n", align, width, "}\n",
53995 this.tdSelector, cid, " {\n",hidden,"\n}\n",
53996 this.splitSelector, cid, " {\n", hidden , "\n}\n");
53998 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54001 updateSplitters : function(){
54002 var cm = this.cm, s = this.getSplitters();
54003 if(s){ // splitters not created yet
54004 var pos = 0, locked = true;
54005 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54006 if(cm.isHidden(i)) continue;
54007 var w = cm.getColumnWidth(i); // make sure it's a number
54008 if(!cm.isLocked(i) && locked){
54013 s[i].style.left = (pos-this.splitOffset) + "px";
54018 handleHiddenChange : function(colModel, colIndex, hidden){
54020 this.hideColumn(colIndex);
54022 this.unhideColumn(colIndex);
54026 hideColumn : function(colIndex){
54027 var cid = this.getColumnId(colIndex);
54028 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
54029 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
54031 this.updateHeaders();
54033 this.updateSplitters();
54037 unhideColumn : function(colIndex){
54038 var cid = this.getColumnId(colIndex);
54039 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
54040 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
54043 this.updateHeaders();
54045 this.updateSplitters();
54049 insertRows : function(dm, firstRow, lastRow, isUpdate){
54050 if(firstRow == 0 && lastRow == dm.getCount()-1){
54054 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
54056 var s = this.getScrollState();
54057 var markup = this.renderRows(firstRow, lastRow);
54058 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
54059 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
54060 this.restoreScroll(s);
54062 this.fireEvent("rowsinserted", this, firstRow, lastRow);
54063 this.syncRowHeights(firstRow, lastRow);
54064 this.stripeRows(firstRow);
54070 bufferRows : function(markup, target, index){
54071 var before = null, trows = target.rows, tbody = target.tBodies[0];
54072 if(index < trows.length){
54073 before = trows[index];
54075 var b = document.createElement("div");
54076 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
54077 var rows = b.firstChild.rows;
54078 for(var i = 0, len = rows.length; i < len; i++){
54080 tbody.insertBefore(rows[0], before);
54082 tbody.appendChild(rows[0]);
54089 deleteRows : function(dm, firstRow, lastRow){
54090 if(dm.getRowCount()<1){
54091 this.fireEvent("beforerefresh", this);
54092 this.mainBody.update("");
54093 this.lockedBody.update("");
54094 this.fireEvent("refresh", this);
54096 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
54097 var bt = this.getBodyTable();
54098 var tbody = bt.firstChild;
54099 var rows = bt.rows;
54100 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
54101 tbody.removeChild(rows[firstRow]);
54103 this.stripeRows(firstRow);
54104 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
54108 updateRows : function(dataSource, firstRow, lastRow){
54109 var s = this.getScrollState();
54111 this.restoreScroll(s);
54114 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
54118 this.updateHeaderSortState();
54121 getScrollState : function(){
54123 var sb = this.scroller.dom;
54124 return {left: sb.scrollLeft, top: sb.scrollTop};
54127 stripeRows : function(startRow){
54128 if(!this.grid.stripeRows || this.ds.getCount() < 1){
54131 startRow = startRow || 0;
54132 var rows = this.getBodyTable().rows;
54133 var lrows = this.getLockedTable().rows;
54134 var cls = ' x-grid-row-alt ';
54135 for(var i = startRow, len = rows.length; i < len; i++){
54136 var row = rows[i], lrow = lrows[i];
54137 var isAlt = ((i+1) % 2 == 0);
54138 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
54139 if(isAlt == hasAlt){
54143 row.className += " x-grid-row-alt";
54145 row.className = row.className.replace("x-grid-row-alt", "");
54148 lrow.className = row.className;
54153 restoreScroll : function(state){
54154 //Roo.log('GridView.restoreScroll');
54155 var sb = this.scroller.dom;
54156 sb.scrollLeft = state.left;
54157 sb.scrollTop = state.top;
54161 syncScroll : function(){
54162 //Roo.log('GridView.syncScroll');
54163 var sb = this.scroller.dom;
54164 var sh = this.mainHd.dom;
54165 var bs = this.mainBody.dom;
54166 var lv = this.lockedBody.dom;
54167 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
54168 lv.scrollTop = bs.scrollTop = sb.scrollTop;
54171 handleScroll : function(e){
54173 var sb = this.scroller.dom;
54174 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
54178 handleWheel : function(e){
54179 var d = e.getWheelDelta();
54180 this.scroller.dom.scrollTop -= d*22;
54181 // set this here to prevent jumpy scrolling on large tables
54182 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
54186 renderRows : function(startRow, endRow){
54187 // pull in all the crap needed to render rows
54188 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
54189 var colCount = cm.getColumnCount();
54191 if(ds.getCount() < 1){
54195 // build a map for all the columns
54197 for(var i = 0; i < colCount; i++){
54198 var name = cm.getDataIndex(i);
54200 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
54201 renderer : cm.getRenderer(i),
54202 id : cm.getColumnId(i),
54203 locked : cm.isLocked(i)
54207 startRow = startRow || 0;
54208 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
54210 // records to render
54211 var rs = ds.getRange(startRow, endRow);
54213 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
54216 // As much as I hate to duplicate code, this was branched because FireFox really hates
54217 // [].join("") on strings. The performance difference was substantial enough to
54218 // branch this function
54219 doRender : Roo.isGecko ?
54220 function(cs, rs, ds, startRow, colCount, stripe){
54221 var ts = this.templates, ct = ts.cell, rt = ts.row;
54223 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54225 var hasListener = this.grid.hasListener('rowclass');
54227 for(var j = 0, len = rs.length; j < len; j++){
54228 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
54229 for(var i = 0; i < colCount; i++){
54231 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54233 p.css = p.attr = "";
54234 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54235 if(p.value == undefined || p.value === "") p.value = " ";
54236 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54237 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54239 var markup = ct.apply(p);
54247 if(stripe && ((rowIndex+1) % 2 == 0)){
54248 alt.push("x-grid-row-alt")
54251 alt.push( " x-grid-dirty-row");
54254 if(this.getRowClass){
54255 alt.push(this.getRowClass(r, rowIndex));
54261 rowIndex : rowIndex,
54264 this.grid.fireEvent('rowclass', this, rowcfg);
54265 alt.push(rowcfg.rowClass);
54267 rp.alt = alt.join(" ");
54268 lbuf+= rt.apply(rp);
54270 buf+= rt.apply(rp);
54272 return [lbuf, buf];
54274 function(cs, rs, ds, startRow, colCount, stripe){
54275 var ts = this.templates, ct = ts.cell, rt = ts.row;
54277 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54278 var hasListener = this.grid.hasListener('rowclass');
54281 for(var j = 0, len = rs.length; j < len; j++){
54282 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
54283 for(var i = 0; i < colCount; i++){
54285 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54287 p.css = p.attr = "";
54288 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54289 if(p.value == undefined || p.value === "") p.value = " ";
54290 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54291 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54294 var markup = ct.apply(p);
54296 cb[cb.length] = markup;
54298 lcb[lcb.length] = markup;
54302 if(stripe && ((rowIndex+1) % 2 == 0)){
54303 alt.push( "x-grid-row-alt");
54306 alt.push(" x-grid-dirty-row");
54309 if(this.getRowClass){
54310 alt.push( this.getRowClass(r, rowIndex));
54316 rowIndex : rowIndex,
54319 this.grid.fireEvent('rowclass', this, rowcfg);
54320 alt.push(rowcfg.rowClass);
54322 rp.alt = alt.join(" ");
54323 rp.cells = lcb.join("");
54324 lbuf[lbuf.length] = rt.apply(rp);
54325 rp.cells = cb.join("");
54326 buf[buf.length] = rt.apply(rp);
54328 return [lbuf.join(""), buf.join("")];
54331 renderBody : function(){
54332 var markup = this.renderRows();
54333 var bt = this.templates.body;
54334 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
54338 * Refreshes the grid
54339 * @param {Boolean} headersToo
54341 refresh : function(headersToo){
54342 this.fireEvent("beforerefresh", this);
54343 this.grid.stopEditing();
54344 var result = this.renderBody();
54345 this.lockedBody.update(result[0]);
54346 this.mainBody.update(result[1]);
54347 if(headersToo === true){
54348 this.updateHeaders();
54349 this.updateColumns();
54350 this.updateSplitters();
54351 this.updateHeaderSortState();
54353 this.syncRowHeights();
54355 this.fireEvent("refresh", this);
54358 handleColumnMove : function(cm, oldIndex, newIndex){
54359 this.indexMap = null;
54360 var s = this.getScrollState();
54361 this.refresh(true);
54362 this.restoreScroll(s);
54363 this.afterMove(newIndex);
54366 afterMove : function(colIndex){
54367 if(this.enableMoveAnim && Roo.enableFx){
54368 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
54370 // if multisort - fix sortOrder, and reload..
54371 if (this.grid.dataSource.multiSort) {
54372 // the we can call sort again..
54373 var dm = this.grid.dataSource;
54374 var cm = this.grid.colModel;
54376 for(var i = 0; i < cm.config.length; i++ ) {
54378 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
54379 continue; // dont' bother, it's not in sort list or being set.
54382 so.push(cm.config[i].dataIndex);
54385 dm.load(dm.lastOptions);
54392 updateCell : function(dm, rowIndex, dataIndex){
54393 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
54394 if(typeof colIndex == "undefined"){ // not present in grid
54397 var cm = this.grid.colModel;
54398 var cell = this.getCell(rowIndex, colIndex);
54399 var cellText = this.getCellText(rowIndex, colIndex);
54402 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
54403 id : cm.getColumnId(colIndex),
54404 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
54406 var renderer = cm.getRenderer(colIndex);
54407 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
54408 if(typeof val == "undefined" || val === "") val = " ";
54409 cellText.innerHTML = val;
54410 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
54411 this.syncRowHeights(rowIndex, rowIndex);
54414 calcColumnWidth : function(colIndex, maxRowsToMeasure){
54416 if(this.grid.autoSizeHeaders){
54417 var h = this.getHeaderCellMeasure(colIndex);
54418 maxWidth = Math.max(maxWidth, h.scrollWidth);
54421 if(this.cm.isLocked(colIndex)){
54422 tb = this.getLockedTable();
54425 tb = this.getBodyTable();
54426 index = colIndex - this.cm.getLockedCount();
54429 var rows = tb.rows;
54430 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
54431 for(var i = 0; i < stopIndex; i++){
54432 var cell = rows[i].childNodes[index].firstChild;
54433 maxWidth = Math.max(maxWidth, cell.scrollWidth);
54436 return maxWidth + /*margin for error in IE*/ 5;
54439 * Autofit a column to its content.
54440 * @param {Number} colIndex
54441 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
54443 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
54444 if(this.cm.isHidden(colIndex)){
54445 return; // can't calc a hidden column
54448 var cid = this.cm.getColumnId(colIndex);
54449 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
54450 if(this.grid.autoSizeHeaders){
54451 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
54454 var newWidth = this.calcColumnWidth(colIndex);
54455 this.cm.setColumnWidth(colIndex,
54456 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
54457 if(!suppressEvent){
54458 this.grid.fireEvent("columnresize", colIndex, newWidth);
54463 * Autofits all columns to their content and then expands to fit any extra space in the grid
54465 autoSizeColumns : function(){
54466 var cm = this.grid.colModel;
54467 var colCount = cm.getColumnCount();
54468 for(var i = 0; i < colCount; i++){
54469 this.autoSizeColumn(i, true, true);
54471 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
54474 this.updateColumns();
54480 * Autofits all columns to the grid's width proportionate with their current size
54481 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
54483 fitColumns : function(reserveScrollSpace){
54484 var cm = this.grid.colModel;
54485 var colCount = cm.getColumnCount();
54489 for (i = 0; i < colCount; i++){
54490 if(!cm.isHidden(i) && !cm.isFixed(i)){
54491 w = cm.getColumnWidth(i);
54497 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
54498 if(reserveScrollSpace){
54501 var frac = (avail - cm.getTotalWidth())/width;
54502 while (cols.length){
54505 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
54507 this.updateColumns();
54511 onRowSelect : function(rowIndex){
54512 var row = this.getRowComposite(rowIndex);
54513 row.addClass("x-grid-row-selected");
54516 onRowDeselect : function(rowIndex){
54517 var row = this.getRowComposite(rowIndex);
54518 row.removeClass("x-grid-row-selected");
54521 onCellSelect : function(row, col){
54522 var cell = this.getCell(row, col);
54524 Roo.fly(cell).addClass("x-grid-cell-selected");
54528 onCellDeselect : function(row, col){
54529 var cell = this.getCell(row, col);
54531 Roo.fly(cell).removeClass("x-grid-cell-selected");
54535 updateHeaderSortState : function(){
54537 // sort state can be single { field: xxx, direction : yyy}
54538 // or { xxx=>ASC , yyy : DESC ..... }
54541 if (!this.ds.multiSort) {
54542 var state = this.ds.getSortState();
54546 mstate[state.field] = state.direction;
54547 // FIXME... - this is not used here.. but might be elsewhere..
54548 this.sortState = state;
54551 mstate = this.ds.sortToggle;
54553 //remove existing sort classes..
54555 var sc = this.sortClasses;
54556 var hds = this.el.select(this.headerSelector).removeClass(sc);
54558 for(var f in mstate) {
54560 var sortColumn = this.cm.findColumnIndex(f);
54562 if(sortColumn != -1){
54563 var sortDir = mstate[f];
54564 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
54573 handleHeaderClick : function(g, index,e){
54575 Roo.log("header click");
54578 // touch events on header are handled by context
54579 this.handleHdCtx(g,index,e);
54584 if(this.headersDisabled){
54587 var dm = g.dataSource, cm = g.colModel;
54588 if(!cm.isSortable(index)){
54593 if (dm.multiSort) {
54594 // update the sortOrder
54596 for(var i = 0; i < cm.config.length; i++ ) {
54598 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
54599 continue; // dont' bother, it's not in sort list or being set.
54602 so.push(cm.config[i].dataIndex);
54608 dm.sort(cm.getDataIndex(index));
54612 destroy : function(){
54614 this.colMenu.removeAll();
54615 Roo.menu.MenuMgr.unregister(this.colMenu);
54616 this.colMenu.getEl().remove();
54617 delete this.colMenu;
54620 this.hmenu.removeAll();
54621 Roo.menu.MenuMgr.unregister(this.hmenu);
54622 this.hmenu.getEl().remove();
54625 if(this.grid.enableColumnMove){
54626 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54628 for(var dd in dds){
54629 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54630 var elid = dds[dd].dragElId;
54632 Roo.get(elid).remove();
54633 } else if(dds[dd].config.isTarget){
54634 dds[dd].proxyTop.remove();
54635 dds[dd].proxyBottom.remove();
54638 if(Roo.dd.DDM.locationCache[dd]){
54639 delete Roo.dd.DDM.locationCache[dd];
54642 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54645 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54646 this.bind(null, null);
54647 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54650 handleLockChange : function(){
54651 this.refresh(true);
54654 onDenyColumnLock : function(){
54658 onDenyColumnHide : function(){
54662 handleHdMenuClick : function(item){
54663 var index = this.hdCtxIndex;
54664 var cm = this.cm, ds = this.ds;
54667 ds.sort(cm.getDataIndex(index), "ASC");
54670 ds.sort(cm.getDataIndex(index), "DESC");
54673 var lc = cm.getLockedCount();
54674 if(cm.getColumnCount(true) <= lc+1){
54675 this.onDenyColumnLock();
54679 cm.setLocked(index, true, true);
54680 cm.moveColumn(index, lc);
54681 this.grid.fireEvent("columnmove", index, lc);
54683 cm.setLocked(index, true);
54687 var lc = cm.getLockedCount();
54688 if((lc-1) != index){
54689 cm.setLocked(index, false, true);
54690 cm.moveColumn(index, lc-1);
54691 this.grid.fireEvent("columnmove", index, lc-1);
54693 cm.setLocked(index, false);
54696 case 'wider': // used to expand cols on touch..
54698 var cw = cm.getColumnWidth(index);
54699 cw += (item.id == 'wider' ? 1 : -1) * 50;
54700 cw = Math.max(0, cw);
54701 cw = Math.min(cw,4000);
54702 cm.setColumnWidth(index, cw);
54706 index = cm.getIndexById(item.id.substr(4));
54708 if(item.checked && cm.getColumnCount(true) <= 1){
54709 this.onDenyColumnHide();
54712 cm.setHidden(index, item.checked);
54718 beforeColMenuShow : function(){
54719 var cm = this.cm, colCount = cm.getColumnCount();
54720 this.colMenu.removeAll();
54721 for(var i = 0; i < colCount; i++){
54722 this.colMenu.add(new Roo.menu.CheckItem({
54723 id: "col-"+cm.getColumnId(i),
54724 text: cm.getColumnHeader(i),
54725 checked: !cm.isHidden(i),
54731 handleHdCtx : function(g, index, e){
54733 var hd = this.getHeaderCell(index);
54734 this.hdCtxIndex = index;
54735 var ms = this.hmenu.items, cm = this.cm;
54736 ms.get("asc").setDisabled(!cm.isSortable(index));
54737 ms.get("desc").setDisabled(!cm.isSortable(index));
54738 if(this.grid.enableColLock !== false){
54739 ms.get("lock").setDisabled(cm.isLocked(index));
54740 ms.get("unlock").setDisabled(!cm.isLocked(index));
54742 this.hmenu.show(hd, "tl-bl");
54745 handleHdOver : function(e){
54746 var hd = this.findHeaderCell(e.getTarget());
54747 if(hd && !this.headersDisabled){
54748 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54749 this.fly(hd).addClass("x-grid-hd-over");
54754 handleHdOut : function(e){
54755 var hd = this.findHeaderCell(e.getTarget());
54757 this.fly(hd).removeClass("x-grid-hd-over");
54761 handleSplitDblClick : function(e, t){
54762 var i = this.getCellIndex(t);
54763 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54764 this.autoSizeColumn(i, true);
54769 render : function(){
54772 var colCount = cm.getColumnCount();
54774 if(this.grid.monitorWindowResize === true){
54775 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54777 var header = this.renderHeaders();
54778 var body = this.templates.body.apply({rows:""});
54779 var html = this.templates.master.apply({
54782 lockedHeader: header[0],
54786 //this.updateColumns();
54788 this.grid.getGridEl().dom.innerHTML = html;
54790 this.initElements();
54792 // a kludge to fix the random scolling effect in webkit
54793 this.el.on("scroll", function() {
54794 this.el.dom.scrollTop=0; // hopefully not recursive..
54797 this.scroller.on("scroll", this.handleScroll, this);
54798 this.lockedBody.on("mousewheel", this.handleWheel, this);
54799 this.mainBody.on("mousewheel", this.handleWheel, this);
54801 this.mainHd.on("mouseover", this.handleHdOver, this);
54802 this.mainHd.on("mouseout", this.handleHdOut, this);
54803 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54804 {delegate: "."+this.splitClass});
54806 this.lockedHd.on("mouseover", this.handleHdOver, this);
54807 this.lockedHd.on("mouseout", this.handleHdOut, this);
54808 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54809 {delegate: "."+this.splitClass});
54811 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54812 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54815 this.updateSplitters();
54817 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54818 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54819 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54822 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54823 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54825 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54826 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54828 if(this.grid.enableColLock !== false){
54829 this.hmenu.add('-',
54830 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54831 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54835 this.hmenu.add('-',
54836 {id:"wider", text: this.columnsWiderText},
54837 {id:"narrow", text: this.columnsNarrowText }
54843 if(this.grid.enableColumnHide !== false){
54845 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54846 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54847 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54849 this.hmenu.add('-',
54850 {id:"columns", text: this.columnsText, menu: this.colMenu}
54853 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54855 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54858 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54859 this.dd = new Roo.grid.GridDragZone(this.grid, {
54860 ddGroup : this.grid.ddGroup || 'GridDD'
54866 for(var i = 0; i < colCount; i++){
54867 if(cm.isHidden(i)){
54868 this.hideColumn(i);
54870 if(cm.config[i].align){
54871 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54872 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54876 this.updateHeaderSortState();
54878 this.beforeInitialResize();
54881 // two part rendering gives faster view to the user
54882 this.renderPhase2.defer(1, this);
54885 renderPhase2 : function(){
54886 // render the rows now
54888 if(this.grid.autoSizeColumns){
54889 this.autoSizeColumns();
54893 beforeInitialResize : function(){
54897 onColumnSplitterMoved : function(i, w){
54898 this.userResized = true;
54899 var cm = this.grid.colModel;
54900 cm.setColumnWidth(i, w, true);
54901 var cid = cm.getColumnId(i);
54902 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54903 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54904 this.updateSplitters();
54906 this.grid.fireEvent("columnresize", i, w);
54909 syncRowHeights : function(startIndex, endIndex){
54910 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54911 startIndex = startIndex || 0;
54912 var mrows = this.getBodyTable().rows;
54913 var lrows = this.getLockedTable().rows;
54914 var len = mrows.length-1;
54915 endIndex = Math.min(endIndex || len, len);
54916 for(var i = startIndex; i <= endIndex; i++){
54917 var m = mrows[i], l = lrows[i];
54918 var h = Math.max(m.offsetHeight, l.offsetHeight);
54919 m.style.height = l.style.height = h + "px";
54924 layout : function(initialRender, is2ndPass){
54926 var auto = g.autoHeight;
54927 var scrollOffset = 16;
54928 var c = g.getGridEl(), cm = this.cm,
54929 expandCol = g.autoExpandColumn,
54931 //c.beginMeasure();
54933 if(!c.dom.offsetWidth){ // display:none?
54935 this.lockedWrap.show();
54936 this.mainWrap.show();
54941 var hasLock = this.cm.isLocked(0);
54943 var tbh = this.headerPanel.getHeight();
54944 var bbh = this.footerPanel.getHeight();
54947 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54948 var newHeight = ch + c.getBorderWidth("tb");
54950 newHeight = Math.min(g.maxHeight, newHeight);
54952 c.setHeight(newHeight);
54956 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54959 var s = this.scroller;
54961 var csize = c.getSize(true);
54963 this.el.setSize(csize.width, csize.height);
54965 this.headerPanel.setWidth(csize.width);
54966 this.footerPanel.setWidth(csize.width);
54968 var hdHeight = this.mainHd.getHeight();
54969 var vw = csize.width;
54970 var vh = csize.height - (tbh + bbh);
54974 var bt = this.getBodyTable();
54975 var ltWidth = hasLock ?
54976 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54978 var scrollHeight = bt.offsetHeight;
54979 var scrollWidth = ltWidth + bt.offsetWidth;
54980 var vscroll = false, hscroll = false;
54982 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54984 var lw = this.lockedWrap, mw = this.mainWrap;
54985 var lb = this.lockedBody, mb = this.mainBody;
54987 setTimeout(function(){
54988 var t = s.dom.offsetTop;
54989 var w = s.dom.clientWidth,
54990 h = s.dom.clientHeight;
54993 lw.setSize(ltWidth, h);
54995 mw.setLeftTop(ltWidth, t);
54996 mw.setSize(w-ltWidth, h);
54998 lb.setHeight(h-hdHeight);
54999 mb.setHeight(h-hdHeight);
55001 if(is2ndPass !== true && !gv.userResized && expandCol){
55002 // high speed resize without full column calculation
55004 var ci = cm.getIndexById(expandCol);
55006 ci = cm.findColumnIndex(expandCol);
55008 ci = Math.max(0, ci); // make sure it's got at least the first col.
55009 var expandId = cm.getColumnId(ci);
55010 var tw = cm.getTotalWidth(false);
55011 var currentWidth = cm.getColumnWidth(ci);
55012 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
55013 if(currentWidth != cw){
55014 cm.setColumnWidth(ci, cw, true);
55015 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
55016 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
55017 gv.updateSplitters();
55018 gv.layout(false, true);
55030 onWindowResize : function(){
55031 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
55037 appendFooter : function(parentEl){
55041 sortAscText : "Sort Ascending",
55042 sortDescText : "Sort Descending",
55043 lockText : "Lock Column",
55044 unlockText : "Unlock Column",
55045 columnsText : "Columns",
55047 columnsWiderText : "Wider",
55048 columnsNarrowText : "Thinner"
55052 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
55053 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
55054 this.proxy.el.addClass('x-grid3-col-dd');
55057 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
55058 handleMouseDown : function(e){
55062 callHandleMouseDown : function(e){
55063 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
55068 * Ext JS Library 1.1.1
55069 * Copyright(c) 2006-2007, Ext JS, LLC.
55071 * Originally Released Under LGPL - original licence link has changed is not relivant.
55074 * <script type="text/javascript">
55078 // This is a support class used internally by the Grid components
55079 Roo.grid.SplitDragZone = function(grid, hd, hd2){
55081 this.view = grid.getView();
55082 this.proxy = this.view.resizeProxy;
55083 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
55084 "gridSplitters" + this.grid.getGridEl().id, {
55085 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
55087 this.setHandleElId(Roo.id(hd));
55088 this.setOuterHandleElId(Roo.id(hd2));
55089 this.scroll = false;
55091 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
55092 fly: Roo.Element.fly,
55094 b4StartDrag : function(x, y){
55095 this.view.headersDisabled = true;
55096 this.proxy.setHeight(this.view.mainWrap.getHeight());
55097 var w = this.cm.getColumnWidth(this.cellIndex);
55098 var minw = Math.max(w-this.grid.minColumnWidth, 0);
55099 this.resetConstraints();
55100 this.setXConstraint(minw, 1000);
55101 this.setYConstraint(0, 0);
55102 this.minX = x - minw;
55103 this.maxX = x + 1000;
55105 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
55109 handleMouseDown : function(e){
55110 ev = Roo.EventObject.setEvent(e);
55111 var t = this.fly(ev.getTarget());
55112 if(t.hasClass("x-grid-split")){
55113 this.cellIndex = this.view.getCellIndex(t.dom);
55114 this.split = t.dom;
55115 this.cm = this.grid.colModel;
55116 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
55117 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
55122 endDrag : function(e){
55123 this.view.headersDisabled = false;
55124 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
55125 var diff = endX - this.startPos;
55126 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
55129 autoOffset : function(){
55130 this.setDelta(0,0);
55134 * Ext JS Library 1.1.1
55135 * Copyright(c) 2006-2007, Ext JS, LLC.
55137 * Originally Released Under LGPL - original licence link has changed is not relivant.
55140 * <script type="text/javascript">
55144 // This is a support class used internally by the Grid components
55145 Roo.grid.GridDragZone = function(grid, config){
55146 this.view = grid.getView();
55147 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
55148 if(this.view.lockedBody){
55149 this.setHandleElId(Roo.id(this.view.mainBody.dom));
55150 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
55152 this.scroll = false;
55154 this.ddel = document.createElement('div');
55155 this.ddel.className = 'x-grid-dd-wrap';
55158 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
55159 ddGroup : "GridDD",
55161 getDragData : function(e){
55162 var t = Roo.lib.Event.getTarget(e);
55163 var rowIndex = this.view.findRowIndex(t);
55164 var sm = this.grid.selModel;
55166 //Roo.log(rowIndex);
55168 if (sm.getSelectedCell) {
55169 // cell selection..
55170 if (!sm.getSelectedCell()) {
55173 if (rowIndex != sm.getSelectedCell()[0]) {
55179 if(rowIndex !== false){
55184 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
55186 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
55189 if (e.hasModifier()){
55190 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
55193 Roo.log("getDragData");
55198 rowIndex: rowIndex,
55199 selections:sm.getSelections ? sm.getSelections() : (
55200 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
55207 onInitDrag : function(e){
55208 var data = this.dragData;
55209 this.ddel.innerHTML = this.grid.getDragDropText();
55210 this.proxy.update(this.ddel);
55211 // fire start drag?
55214 afterRepair : function(){
55215 this.dragging = false;
55218 getRepairXY : function(e, data){
55222 onEndDrag : function(data, e){
55226 onValidDrop : function(dd, e, id){
55231 beforeInvalidDrop : function(e, id){
55236 * Ext JS Library 1.1.1
55237 * Copyright(c) 2006-2007, Ext JS, LLC.
55239 * Originally Released Under LGPL - original licence link has changed is not relivant.
55242 * <script type="text/javascript">
55247 * @class Roo.grid.ColumnModel
55248 * @extends Roo.util.Observable
55249 * This is the default implementation of a ColumnModel used by the Grid. It defines
55250 * the columns in the grid.
55253 var colModel = new Roo.grid.ColumnModel([
55254 {header: "Ticker", width: 60, sortable: true, locked: true},
55255 {header: "Company Name", width: 150, sortable: true},
55256 {header: "Market Cap.", width: 100, sortable: true},
55257 {header: "$ Sales", width: 100, sortable: true, renderer: money},
55258 {header: "Employees", width: 100, sortable: true, resizable: false}
55263 * The config options listed for this class are options which may appear in each
55264 * individual column definition.
55265 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
55267 * @param {Object} config An Array of column config objects. See this class's
55268 * config objects for details.
55270 Roo.grid.ColumnModel = function(config){
55272 * The config passed into the constructor
55274 this.config = config;
55277 // if no id, create one
55278 // if the column does not have a dataIndex mapping,
55279 // map it to the order it is in the config
55280 for(var i = 0, len = config.length; i < len; i++){
55282 if(typeof c.dataIndex == "undefined"){
55285 if(typeof c.renderer == "string"){
55286 c.renderer = Roo.util.Format[c.renderer];
55288 if(typeof c.id == "undefined"){
55291 if(c.editor && c.editor.xtype){
55292 c.editor = Roo.factory(c.editor, Roo.grid);
55294 if(c.editor && c.editor.isFormField){
55295 c.editor = new Roo.grid.GridEditor(c.editor);
55297 this.lookup[c.id] = c;
55301 * The width of columns which have no width specified (defaults to 100)
55304 this.defaultWidth = 100;
55307 * Default sortable of columns which have no sortable specified (defaults to false)
55310 this.defaultSortable = false;
55314 * @event widthchange
55315 * Fires when the width of a column changes.
55316 * @param {ColumnModel} this
55317 * @param {Number} columnIndex The column index
55318 * @param {Number} newWidth The new width
55320 "widthchange": true,
55322 * @event headerchange
55323 * Fires when the text of a header changes.
55324 * @param {ColumnModel} this
55325 * @param {Number} columnIndex The column index
55326 * @param {Number} newText The new header text
55328 "headerchange": true,
55330 * @event hiddenchange
55331 * Fires when a column is hidden or "unhidden".
55332 * @param {ColumnModel} this
55333 * @param {Number} columnIndex The column index
55334 * @param {Boolean} hidden true if hidden, false otherwise
55336 "hiddenchange": true,
55338 * @event columnmoved
55339 * Fires when a column is moved.
55340 * @param {ColumnModel} this
55341 * @param {Number} oldIndex
55342 * @param {Number} newIndex
55344 "columnmoved" : true,
55346 * @event columlockchange
55347 * Fires when a column's locked state is changed
55348 * @param {ColumnModel} this
55349 * @param {Number} colIndex
55350 * @param {Boolean} locked true if locked
55352 "columnlockchange" : true
55354 Roo.grid.ColumnModel.superclass.constructor.call(this);
55356 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
55358 * @cfg {String} header The header text to display in the Grid view.
55361 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
55362 * {@link Roo.data.Record} definition from which to draw the column's value. If not
55363 * specified, the column's index is used as an index into the Record's data Array.
55366 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
55367 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
55370 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
55371 * Defaults to the value of the {@link #defaultSortable} property.
55372 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
55375 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
55378 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
55381 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
55384 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
55387 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
55388 * given the cell's data value. See {@link #setRenderer}. If not specified, the
55389 * default renderer uses the raw data value. If an object is returned (bootstrap only)
55390 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
55393 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
55396 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
55399 * @cfg {String} cursor (Optional)
55402 * @cfg {String} tooltip (Optional)
55405 * Returns the id of the column at the specified index.
55406 * @param {Number} index The column index
55407 * @return {String} the id
55409 getColumnId : function(index){
55410 return this.config[index].id;
55414 * Returns the column for a specified id.
55415 * @param {String} id The column id
55416 * @return {Object} the column
55418 getColumnById : function(id){
55419 return this.lookup[id];
55424 * Returns the column for a specified dataIndex.
55425 * @param {String} dataIndex The column dataIndex
55426 * @return {Object|Boolean} the column or false if not found
55428 getColumnByDataIndex: function(dataIndex){
55429 var index = this.findColumnIndex(dataIndex);
55430 return index > -1 ? this.config[index] : false;
55434 * Returns the index for a specified column id.
55435 * @param {String} id The column id
55436 * @return {Number} the index, or -1 if not found
55438 getIndexById : function(id){
55439 for(var i = 0, len = this.config.length; i < len; i++){
55440 if(this.config[i].id == id){
55448 * Returns the index for a specified column dataIndex.
55449 * @param {String} dataIndex The column dataIndex
55450 * @return {Number} the index, or -1 if not found
55453 findColumnIndex : function(dataIndex){
55454 for(var i = 0, len = this.config.length; i < len; i++){
55455 if(this.config[i].dataIndex == dataIndex){
55463 moveColumn : function(oldIndex, newIndex){
55464 var c = this.config[oldIndex];
55465 this.config.splice(oldIndex, 1);
55466 this.config.splice(newIndex, 0, c);
55467 this.dataMap = null;
55468 this.fireEvent("columnmoved", this, oldIndex, newIndex);
55471 isLocked : function(colIndex){
55472 return this.config[colIndex].locked === true;
55475 setLocked : function(colIndex, value, suppressEvent){
55476 if(this.isLocked(colIndex) == value){
55479 this.config[colIndex].locked = value;
55480 if(!suppressEvent){
55481 this.fireEvent("columnlockchange", this, colIndex, value);
55485 getTotalLockedWidth : function(){
55486 var totalWidth = 0;
55487 for(var i = 0; i < this.config.length; i++){
55488 if(this.isLocked(i) && !this.isHidden(i)){
55489 this.totalWidth += this.getColumnWidth(i);
55495 getLockedCount : function(){
55496 for(var i = 0, len = this.config.length; i < len; i++){
55497 if(!this.isLocked(i)){
55504 * Returns the number of columns.
55507 getColumnCount : function(visibleOnly){
55508 if(visibleOnly === true){
55510 for(var i = 0, len = this.config.length; i < len; i++){
55511 if(!this.isHidden(i)){
55517 return this.config.length;
55521 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
55522 * @param {Function} fn
55523 * @param {Object} scope (optional)
55524 * @return {Array} result
55526 getColumnsBy : function(fn, scope){
55528 for(var i = 0, len = this.config.length; i < len; i++){
55529 var c = this.config[i];
55530 if(fn.call(scope||this, c, i) === true){
55538 * Returns true if the specified column is sortable.
55539 * @param {Number} col The column index
55540 * @return {Boolean}
55542 isSortable : function(col){
55543 if(typeof this.config[col].sortable == "undefined"){
55544 return this.defaultSortable;
55546 return this.config[col].sortable;
55550 * Returns the rendering (formatting) function defined for the column.
55551 * @param {Number} col The column index.
55552 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
55554 getRenderer : function(col){
55555 if(!this.config[col].renderer){
55556 return Roo.grid.ColumnModel.defaultRenderer;
55558 return this.config[col].renderer;
55562 * Sets the rendering (formatting) function for a column.
55563 * @param {Number} col The column index
55564 * @param {Function} fn The function to use to process the cell's raw data
55565 * to return HTML markup for the grid view. The render function is called with
55566 * the following parameters:<ul>
55567 * <li>Data value.</li>
55568 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
55569 * <li>css A CSS style string to apply to the table cell.</li>
55570 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
55571 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
55572 * <li>Row index</li>
55573 * <li>Column index</li>
55574 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
55576 setRenderer : function(col, fn){
55577 this.config[col].renderer = fn;
55581 * Returns the width for the specified column.
55582 * @param {Number} col The column index
55585 getColumnWidth : function(col){
55586 return this.config[col].width * 1 || this.defaultWidth;
55590 * Sets the width for a column.
55591 * @param {Number} col The column index
55592 * @param {Number} width The new width
55594 setColumnWidth : function(col, width, suppressEvent){
55595 this.config[col].width = width;
55596 this.totalWidth = null;
55597 if(!suppressEvent){
55598 this.fireEvent("widthchange", this, col, width);
55603 * Returns the total width of all columns.
55604 * @param {Boolean} includeHidden True to include hidden column widths
55607 getTotalWidth : function(includeHidden){
55608 if(!this.totalWidth){
55609 this.totalWidth = 0;
55610 for(var i = 0, len = this.config.length; i < len; i++){
55611 if(includeHidden || !this.isHidden(i)){
55612 this.totalWidth += this.getColumnWidth(i);
55616 return this.totalWidth;
55620 * Returns the header for the specified column.
55621 * @param {Number} col The column index
55624 getColumnHeader : function(col){
55625 return this.config[col].header;
55629 * Sets the header for a column.
55630 * @param {Number} col The column index
55631 * @param {String} header The new header
55633 setColumnHeader : function(col, header){
55634 this.config[col].header = header;
55635 this.fireEvent("headerchange", this, col, header);
55639 * Returns the tooltip for the specified column.
55640 * @param {Number} col The column index
55643 getColumnTooltip : function(col){
55644 return this.config[col].tooltip;
55647 * Sets the tooltip for a column.
55648 * @param {Number} col The column index
55649 * @param {String} tooltip The new tooltip
55651 setColumnTooltip : function(col, tooltip){
55652 this.config[col].tooltip = tooltip;
55656 * Returns the dataIndex for the specified column.
55657 * @param {Number} col The column index
55660 getDataIndex : function(col){
55661 return this.config[col].dataIndex;
55665 * Sets the dataIndex for a column.
55666 * @param {Number} col The column index
55667 * @param {Number} dataIndex The new dataIndex
55669 setDataIndex : function(col, dataIndex){
55670 this.config[col].dataIndex = dataIndex;
55676 * Returns true if the cell is editable.
55677 * @param {Number} colIndex The column index
55678 * @param {Number} rowIndex The row index
55679 * @return {Boolean}
55681 isCellEditable : function(colIndex, rowIndex){
55682 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55686 * Returns the editor defined for the cell/column.
55687 * return false or null to disable editing.
55688 * @param {Number} colIndex The column index
55689 * @param {Number} rowIndex The row index
55692 getCellEditor : function(colIndex, rowIndex){
55693 return this.config[colIndex].editor;
55697 * Sets if a column is editable.
55698 * @param {Number} col The column index
55699 * @param {Boolean} editable True if the column is editable
55701 setEditable : function(col, editable){
55702 this.config[col].editable = editable;
55707 * Returns true if the column is hidden.
55708 * @param {Number} colIndex The column index
55709 * @return {Boolean}
55711 isHidden : function(colIndex){
55712 return this.config[colIndex].hidden;
55717 * Returns true if the column width cannot be changed
55719 isFixed : function(colIndex){
55720 return this.config[colIndex].fixed;
55724 * Returns true if the column can be resized
55725 * @return {Boolean}
55727 isResizable : function(colIndex){
55728 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55731 * Sets if a column is hidden.
55732 * @param {Number} colIndex The column index
55733 * @param {Boolean} hidden True if the column is hidden
55735 setHidden : function(colIndex, hidden){
55736 this.config[colIndex].hidden = hidden;
55737 this.totalWidth = null;
55738 this.fireEvent("hiddenchange", this, colIndex, hidden);
55742 * Sets the editor for a column.
55743 * @param {Number} col The column index
55744 * @param {Object} editor The editor object
55746 setEditor : function(col, editor){
55747 this.config[col].editor = editor;
55751 Roo.grid.ColumnModel.defaultRenderer = function(value){
55752 if(typeof value == "string" && value.length < 1){
55758 // Alias for backwards compatibility
55759 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55762 * Ext JS Library 1.1.1
55763 * Copyright(c) 2006-2007, Ext JS, LLC.
55765 * Originally Released Under LGPL - original licence link has changed is not relivant.
55768 * <script type="text/javascript">
55772 * @class Roo.grid.AbstractSelectionModel
55773 * @extends Roo.util.Observable
55774 * Abstract base class for grid SelectionModels. It provides the interface that should be
55775 * implemented by descendant classes. This class should not be directly instantiated.
55778 Roo.grid.AbstractSelectionModel = function(){
55779 this.locked = false;
55780 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55783 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55784 /** @ignore Called by the grid automatically. Do not call directly. */
55785 init : function(grid){
55791 * Locks the selections.
55794 this.locked = true;
55798 * Unlocks the selections.
55800 unlock : function(){
55801 this.locked = false;
55805 * Returns true if the selections are locked.
55806 * @return {Boolean}
55808 isLocked : function(){
55809 return this.locked;
55813 * Ext JS Library 1.1.1
55814 * Copyright(c) 2006-2007, Ext JS, LLC.
55816 * Originally Released Under LGPL - original licence link has changed is not relivant.
55819 * <script type="text/javascript">
55822 * @extends Roo.grid.AbstractSelectionModel
55823 * @class Roo.grid.RowSelectionModel
55824 * The default SelectionModel used by {@link Roo.grid.Grid}.
55825 * It supports multiple selections and keyboard selection/navigation.
55827 * @param {Object} config
55829 Roo.grid.RowSelectionModel = function(config){
55830 Roo.apply(this, config);
55831 this.selections = new Roo.util.MixedCollection(false, function(o){
55836 this.lastActive = false;
55840 * @event selectionchange
55841 * Fires when the selection changes
55842 * @param {SelectionModel} this
55844 "selectionchange" : true,
55846 * @event afterselectionchange
55847 * Fires after the selection changes (eg. by key press or clicking)
55848 * @param {SelectionModel} this
55850 "afterselectionchange" : true,
55852 * @event beforerowselect
55853 * Fires when a row is selected being selected, return false to cancel.
55854 * @param {SelectionModel} this
55855 * @param {Number} rowIndex The selected index
55856 * @param {Boolean} keepExisting False if other selections will be cleared
55858 "beforerowselect" : true,
55861 * Fires when a row is selected.
55862 * @param {SelectionModel} this
55863 * @param {Number} rowIndex The selected index
55864 * @param {Roo.data.Record} r The record
55866 "rowselect" : true,
55868 * @event rowdeselect
55869 * Fires when a row is deselected.
55870 * @param {SelectionModel} this
55871 * @param {Number} rowIndex The selected index
55873 "rowdeselect" : true
55875 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55876 this.locked = false;
55879 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55881 * @cfg {Boolean} singleSelect
55882 * True to allow selection of only one row at a time (defaults to false)
55884 singleSelect : false,
55887 initEvents : function(){
55889 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55890 this.grid.on("mousedown", this.handleMouseDown, this);
55891 }else{ // allow click to work like normal
55892 this.grid.on("rowclick", this.handleDragableRowClick, this);
55895 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55896 "up" : function(e){
55898 this.selectPrevious(e.shiftKey);
55899 }else if(this.last !== false && this.lastActive !== false){
55900 var last = this.last;
55901 this.selectRange(this.last, this.lastActive-1);
55902 this.grid.getView().focusRow(this.lastActive);
55903 if(last !== false){
55907 this.selectFirstRow();
55909 this.fireEvent("afterselectionchange", this);
55911 "down" : function(e){
55913 this.selectNext(e.shiftKey);
55914 }else if(this.last !== false && this.lastActive !== false){
55915 var last = this.last;
55916 this.selectRange(this.last, this.lastActive+1);
55917 this.grid.getView().focusRow(this.lastActive);
55918 if(last !== false){
55922 this.selectFirstRow();
55924 this.fireEvent("afterselectionchange", this);
55929 var view = this.grid.view;
55930 view.on("refresh", this.onRefresh, this);
55931 view.on("rowupdated", this.onRowUpdated, this);
55932 view.on("rowremoved", this.onRemove, this);
55936 onRefresh : function(){
55937 var ds = this.grid.dataSource, i, v = this.grid.view;
55938 var s = this.selections;
55939 s.each(function(r){
55940 if((i = ds.indexOfId(r.id)) != -1){
55942 s.add(ds.getAt(i)); // updating the selection relate data
55950 onRemove : function(v, index, r){
55951 this.selections.remove(r);
55955 onRowUpdated : function(v, index, r){
55956 if(this.isSelected(r)){
55957 v.onRowSelect(index);
55963 * @param {Array} records The records to select
55964 * @param {Boolean} keepExisting (optional) True to keep existing selections
55966 selectRecords : function(records, keepExisting){
55968 this.clearSelections();
55970 var ds = this.grid.dataSource;
55971 for(var i = 0, len = records.length; i < len; i++){
55972 this.selectRow(ds.indexOf(records[i]), true);
55977 * Gets the number of selected rows.
55980 getCount : function(){
55981 return this.selections.length;
55985 * Selects the first row in the grid.
55987 selectFirstRow : function(){
55992 * Select the last row.
55993 * @param {Boolean} keepExisting (optional) True to keep existing selections
55995 selectLastRow : function(keepExisting){
55996 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
56000 * Selects the row immediately following the last selected row.
56001 * @param {Boolean} keepExisting (optional) True to keep existing selections
56003 selectNext : function(keepExisting){
56004 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
56005 this.selectRow(this.last+1, keepExisting);
56006 this.grid.getView().focusRow(this.last);
56011 * Selects the row that precedes the last selected row.
56012 * @param {Boolean} keepExisting (optional) True to keep existing selections
56014 selectPrevious : function(keepExisting){
56016 this.selectRow(this.last-1, keepExisting);
56017 this.grid.getView().focusRow(this.last);
56022 * Returns the selected records
56023 * @return {Array} Array of selected records
56025 getSelections : function(){
56026 return [].concat(this.selections.items);
56030 * Returns the first selected record.
56033 getSelected : function(){
56034 return this.selections.itemAt(0);
56039 * Clears all selections.
56041 clearSelections : function(fast){
56042 if(this.locked) return;
56044 var ds = this.grid.dataSource;
56045 var s = this.selections;
56046 s.each(function(r){
56047 this.deselectRow(ds.indexOfId(r.id));
56051 this.selections.clear();
56058 * Selects all rows.
56060 selectAll : function(){
56061 if(this.locked) return;
56062 this.selections.clear();
56063 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
56064 this.selectRow(i, true);
56069 * Returns True if there is a selection.
56070 * @return {Boolean}
56072 hasSelection : function(){
56073 return this.selections.length > 0;
56077 * Returns True if the specified row is selected.
56078 * @param {Number/Record} record The record or index of the record to check
56079 * @return {Boolean}
56081 isSelected : function(index){
56082 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
56083 return (r && this.selections.key(r.id) ? true : false);
56087 * Returns True if the specified record id is selected.
56088 * @param {String} id The id of record to check
56089 * @return {Boolean}
56091 isIdSelected : function(id){
56092 return (this.selections.key(id) ? true : false);
56096 handleMouseDown : function(e, t){
56097 var view = this.grid.getView(), rowIndex;
56098 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
56101 if(e.shiftKey && this.last !== false){
56102 var last = this.last;
56103 this.selectRange(last, rowIndex, e.ctrlKey);
56104 this.last = last; // reset the last
56105 view.focusRow(rowIndex);
56107 var isSelected = this.isSelected(rowIndex);
56108 if(e.button !== 0 && isSelected){
56109 view.focusRow(rowIndex);
56110 }else if(e.ctrlKey && isSelected){
56111 this.deselectRow(rowIndex);
56112 }else if(!isSelected){
56113 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
56114 view.focusRow(rowIndex);
56117 this.fireEvent("afterselectionchange", this);
56120 handleDragableRowClick : function(grid, rowIndex, e)
56122 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
56123 this.selectRow(rowIndex, false);
56124 grid.view.focusRow(rowIndex);
56125 this.fireEvent("afterselectionchange", this);
56130 * Selects multiple rows.
56131 * @param {Array} rows Array of the indexes of the row to select
56132 * @param {Boolean} keepExisting (optional) True to keep existing selections
56134 selectRows : function(rows, keepExisting){
56136 this.clearSelections();
56138 for(var i = 0, len = rows.length; i < len; i++){
56139 this.selectRow(rows[i], true);
56144 * Selects a range of rows. All rows in between startRow and endRow are also selected.
56145 * @param {Number} startRow The index of the first row in the range
56146 * @param {Number} endRow The index of the last row in the range
56147 * @param {Boolean} keepExisting (optional) True to retain existing selections
56149 selectRange : function(startRow, endRow, keepExisting){
56150 if(this.locked) return;
56152 this.clearSelections();
56154 if(startRow <= endRow){
56155 for(var i = startRow; i <= endRow; i++){
56156 this.selectRow(i, true);
56159 for(var i = startRow; i >= endRow; i--){
56160 this.selectRow(i, true);
56166 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
56167 * @param {Number} startRow The index of the first row in the range
56168 * @param {Number} endRow The index of the last row in the range
56170 deselectRange : function(startRow, endRow, preventViewNotify){
56171 if(this.locked) return;
56172 for(var i = startRow; i <= endRow; i++){
56173 this.deselectRow(i, preventViewNotify);
56179 * @param {Number} row The index of the row to select
56180 * @param {Boolean} keepExisting (optional) True to keep existing selections
56182 selectRow : function(index, keepExisting, preventViewNotify){
56183 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
56184 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
56185 if(!keepExisting || this.singleSelect){
56186 this.clearSelections();
56188 var r = this.grid.dataSource.getAt(index);
56189 this.selections.add(r);
56190 this.last = this.lastActive = index;
56191 if(!preventViewNotify){
56192 this.grid.getView().onRowSelect(index);
56194 this.fireEvent("rowselect", this, index, r);
56195 this.fireEvent("selectionchange", this);
56201 * @param {Number} row The index of the row to deselect
56203 deselectRow : function(index, preventViewNotify){
56204 if(this.locked) return;
56205 if(this.last == index){
56208 if(this.lastActive == index){
56209 this.lastActive = false;
56211 var r = this.grid.dataSource.getAt(index);
56212 this.selections.remove(r);
56213 if(!preventViewNotify){
56214 this.grid.getView().onRowDeselect(index);
56216 this.fireEvent("rowdeselect", this, index);
56217 this.fireEvent("selectionchange", this);
56221 restoreLast : function(){
56223 this.last = this._last;
56228 acceptsNav : function(row, col, cm){
56229 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56233 onEditorKey : function(field, e){
56234 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
56239 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56241 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56243 }else if(k == e.ENTER && !e.ctrlKey){
56247 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
56249 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
56251 }else if(k == e.ESC){
56255 g.startEditing(newCell[0], newCell[1]);
56260 * Ext JS Library 1.1.1
56261 * Copyright(c) 2006-2007, Ext JS, LLC.
56263 * Originally Released Under LGPL - original licence link has changed is not relivant.
56266 * <script type="text/javascript">
56269 * @class Roo.grid.CellSelectionModel
56270 * @extends Roo.grid.AbstractSelectionModel
56271 * This class provides the basic implementation for cell selection in a grid.
56273 * @param {Object} config The object containing the configuration of this model.
56274 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
56276 Roo.grid.CellSelectionModel = function(config){
56277 Roo.apply(this, config);
56279 this.selection = null;
56283 * @event beforerowselect
56284 * Fires before a cell is selected.
56285 * @param {SelectionModel} this
56286 * @param {Number} rowIndex The selected row index
56287 * @param {Number} colIndex The selected cell index
56289 "beforecellselect" : true,
56291 * @event cellselect
56292 * Fires when a cell is selected.
56293 * @param {SelectionModel} this
56294 * @param {Number} rowIndex The selected row index
56295 * @param {Number} colIndex The selected cell index
56297 "cellselect" : true,
56299 * @event selectionchange
56300 * Fires when the active selection changes.
56301 * @param {SelectionModel} this
56302 * @param {Object} selection null for no selection or an object (o) with two properties
56304 <li>o.record: the record object for the row the selection is in</li>
56305 <li>o.cell: An array of [rowIndex, columnIndex]</li>
56308 "selectionchange" : true,
56311 * Fires when the tab (or enter) was pressed on the last editable cell
56312 * You can use this to trigger add new row.
56313 * @param {SelectionModel} this
56317 * @event beforeeditnext
56318 * Fires before the next editable sell is made active
56319 * You can use this to skip to another cell or fire the tabend
56320 * if you set cell to false
56321 * @param {Object} eventdata object : { cell : [ row, col ] }
56323 "beforeeditnext" : true
56325 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
56328 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
56330 enter_is_tab: false,
56333 initEvents : function(){
56334 this.grid.on("mousedown", this.handleMouseDown, this);
56335 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
56336 var view = this.grid.view;
56337 view.on("refresh", this.onViewChange, this);
56338 view.on("rowupdated", this.onRowUpdated, this);
56339 view.on("beforerowremoved", this.clearSelections, this);
56340 view.on("beforerowsinserted", this.clearSelections, this);
56341 if(this.grid.isEditor){
56342 this.grid.on("beforeedit", this.beforeEdit, this);
56347 beforeEdit : function(e){
56348 this.select(e.row, e.column, false, true, e.record);
56352 onRowUpdated : function(v, index, r){
56353 if(this.selection && this.selection.record == r){
56354 v.onCellSelect(index, this.selection.cell[1]);
56359 onViewChange : function(){
56360 this.clearSelections(true);
56364 * Returns the currently selected cell,.
56365 * @return {Array} The selected cell (row, column) or null if none selected.
56367 getSelectedCell : function(){
56368 return this.selection ? this.selection.cell : null;
56372 * Clears all selections.
56373 * @param {Boolean} true to prevent the gridview from being notified about the change.
56375 clearSelections : function(preventNotify){
56376 var s = this.selection;
56378 if(preventNotify !== true){
56379 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
56381 this.selection = null;
56382 this.fireEvent("selectionchange", this, null);
56387 * Returns true if there is a selection.
56388 * @return {Boolean}
56390 hasSelection : function(){
56391 return this.selection ? true : false;
56395 handleMouseDown : function(e, t){
56396 var v = this.grid.getView();
56397 if(this.isLocked()){
56400 var row = v.findRowIndex(t);
56401 var cell = v.findCellIndex(t);
56402 if(row !== false && cell !== false){
56403 this.select(row, cell);
56409 * @param {Number} rowIndex
56410 * @param {Number} collIndex
56412 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
56413 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
56414 this.clearSelections();
56415 r = r || this.grid.dataSource.getAt(rowIndex);
56418 cell : [rowIndex, colIndex]
56420 if(!preventViewNotify){
56421 var v = this.grid.getView();
56422 v.onCellSelect(rowIndex, colIndex);
56423 if(preventFocus !== true){
56424 v.focusCell(rowIndex, colIndex);
56427 this.fireEvent("cellselect", this, rowIndex, colIndex);
56428 this.fireEvent("selectionchange", this, this.selection);
56433 isSelectable : function(rowIndex, colIndex, cm){
56434 return !cm.isHidden(colIndex);
56438 handleKeyDown : function(e){
56439 //Roo.log('Cell Sel Model handleKeyDown');
56440 if(!e.isNavKeyPress()){
56443 var g = this.grid, s = this.selection;
56446 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
56448 this.select(cell[0], cell[1]);
56453 var walk = function(row, col, step){
56454 return g.walkCells(row, col, step, sm.isSelectable, sm);
56456 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
56463 // handled by onEditorKey
56464 if (g.isEditor && g.editing) {
56468 newCell = walk(r, c-1, -1);
56470 newCell = walk(r, c+1, 1);
56475 newCell = walk(r+1, c, 1);
56479 newCell = walk(r-1, c, -1);
56483 newCell = walk(r, c+1, 1);
56487 newCell = walk(r, c-1, -1);
56492 if(g.isEditor && !g.editing){
56493 g.startEditing(r, c);
56502 this.select(newCell[0], newCell[1]);
56508 acceptsNav : function(row, col, cm){
56509 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56513 * @param {Number} field (not used) - as it's normally used as a listener
56514 * @param {Number} e - event - fake it by using
56516 * var e = Roo.EventObjectImpl.prototype;
56517 * e.keyCode = e.TAB
56521 onEditorKey : function(field, e){
56523 var k = e.getKey(),
56526 ed = g.activeEditor,
56528 ///Roo.log('onEditorKey' + k);
56531 if (this.enter_is_tab && k == e.ENTER) {
56537 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56539 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56545 } else if(k == e.ENTER && !e.ctrlKey){
56548 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56550 } else if(k == e.ESC){
56555 var ecall = { cell : newCell, forward : forward };
56556 this.fireEvent('beforeeditnext', ecall );
56557 newCell = ecall.cell;
56558 forward = ecall.forward;
56562 //Roo.log('next cell after edit');
56563 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
56564 } else if (forward) {
56565 // tabbed past last
56566 this.fireEvent.defer(100, this, ['tabend',this]);
56571 * Ext JS Library 1.1.1
56572 * Copyright(c) 2006-2007, Ext JS, LLC.
56574 * Originally Released Under LGPL - original licence link has changed is not relivant.
56577 * <script type="text/javascript">
56581 * @class Roo.grid.EditorGrid
56582 * @extends Roo.grid.Grid
56583 * Class for creating and editable grid.
56584 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56585 * The container MUST have some type of size defined for the grid to fill. The container will be
56586 * automatically set to position relative if it isn't already.
56587 * @param {Object} dataSource The data model to bind to
56588 * @param {Object} colModel The column model with info about this grid's columns
56590 Roo.grid.EditorGrid = function(container, config){
56591 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
56592 this.getGridEl().addClass("xedit-grid");
56594 if(!this.selModel){
56595 this.selModel = new Roo.grid.CellSelectionModel();
56598 this.activeEditor = null;
56602 * @event beforeedit
56603 * Fires before cell editing is triggered. The edit event object has the following properties <br />
56604 * <ul style="padding:5px;padding-left:16px;">
56605 * <li>grid - This grid</li>
56606 * <li>record - The record being edited</li>
56607 * <li>field - The field name being edited</li>
56608 * <li>value - The value for the field being edited.</li>
56609 * <li>row - The grid row index</li>
56610 * <li>column - The grid column index</li>
56611 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56613 * @param {Object} e An edit event (see above for description)
56615 "beforeedit" : true,
56618 * Fires after a cell is edited. <br />
56619 * <ul style="padding:5px;padding-left:16px;">
56620 * <li>grid - This grid</li>
56621 * <li>record - The record being edited</li>
56622 * <li>field - The field name being edited</li>
56623 * <li>value - The value being set</li>
56624 * <li>originalValue - The original value for the field, before the edit.</li>
56625 * <li>row - The grid row index</li>
56626 * <li>column - The grid column index</li>
56628 * @param {Object} e An edit event (see above for description)
56630 "afteredit" : true,
56632 * @event validateedit
56633 * Fires after a cell is edited, but before the value is set in the record.
56634 * You can use this to modify the value being set in the field, Return false
56635 * to cancel the change. The edit event object has the following properties <br />
56636 * <ul style="padding:5px;padding-left:16px;">
56637 * <li>editor - This editor</li>
56638 * <li>grid - This grid</li>
56639 * <li>record - The record being edited</li>
56640 * <li>field - The field name being edited</li>
56641 * <li>value - The value being set</li>
56642 * <li>originalValue - The original value for the field, before the edit.</li>
56643 * <li>row - The grid row index</li>
56644 * <li>column - The grid column index</li>
56645 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56647 * @param {Object} e An edit event (see above for description)
56649 "validateedit" : true
56651 this.on("bodyscroll", this.stopEditing, this);
56652 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56655 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56657 * @cfg {Number} clicksToEdit
56658 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56665 trackMouseOver: false, // causes very odd FF errors
56667 onCellDblClick : function(g, row, col){
56668 this.startEditing(row, col);
56671 onEditComplete : function(ed, value, startValue){
56672 this.editing = false;
56673 this.activeEditor = null;
56674 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56676 var field = this.colModel.getDataIndex(ed.col);
56681 originalValue: startValue,
56688 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56691 if(String(value) !== String(startValue)){
56693 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56694 r.set(field, e.value);
56695 // if we are dealing with a combo box..
56696 // then we also set the 'name' colum to be the displayField
56697 if (ed.field.displayField && ed.field.name) {
56698 r.set(ed.field.name, ed.field.el.dom.value);
56701 delete e.cancel; //?? why!!!
56702 this.fireEvent("afteredit", e);
56705 this.fireEvent("afteredit", e); // always fire it!
56707 this.view.focusCell(ed.row, ed.col);
56711 * Starts editing the specified for the specified row/column
56712 * @param {Number} rowIndex
56713 * @param {Number} colIndex
56715 startEditing : function(row, col){
56716 this.stopEditing();
56717 if(this.colModel.isCellEditable(col, row)){
56718 this.view.ensureVisible(row, col, true);
56720 var r = this.dataSource.getAt(row);
56721 var field = this.colModel.getDataIndex(col);
56722 var cell = Roo.get(this.view.getCell(row,col));
56727 value: r.data[field],
56732 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56733 this.editing = true;
56734 var ed = this.colModel.getCellEditor(col, row);
56740 ed.render(ed.parentEl || document.body);
56746 (function(){ // complex but required for focus issues in safari, ie and opera
56750 ed.on("complete", this.onEditComplete, this, {single: true});
56751 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56752 this.activeEditor = ed;
56753 var v = r.data[field];
56754 ed.startEdit(this.view.getCell(row, col), v);
56755 // combo's with 'displayField and name set
56756 if (ed.field.displayField && ed.field.name) {
56757 ed.field.el.dom.value = r.data[ed.field.name];
56761 }).defer(50, this);
56767 * Stops any active editing
56769 stopEditing : function(){
56770 if(this.activeEditor){
56771 this.activeEditor.completeEdit();
56773 this.activeEditor = null;
56777 * Called to get grid's drag proxy text, by default returns this.ddText.
56780 getDragDropText : function(){
56781 var count = this.selModel.getSelectedCell() ? 1 : 0;
56782 return String.format(this.ddText, count, count == 1 ? '' : 's');
56787 * Ext JS Library 1.1.1
56788 * Copyright(c) 2006-2007, Ext JS, LLC.
56790 * Originally Released Under LGPL - original licence link has changed is not relivant.
56793 * <script type="text/javascript">
56796 // private - not really -- you end up using it !
56797 // This is a support class used internally by the Grid components
56800 * @class Roo.grid.GridEditor
56801 * @extends Roo.Editor
56802 * Class for creating and editable grid elements.
56803 * @param {Object} config any settings (must include field)
56805 Roo.grid.GridEditor = function(field, config){
56806 if (!config && field.field) {
56808 field = Roo.factory(config.field, Roo.form);
56810 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56811 field.monitorTab = false;
56814 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56817 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56820 alignment: "tl-tl",
56823 cls: "x-small-editor x-grid-editor",
56828 * Ext JS Library 1.1.1
56829 * Copyright(c) 2006-2007, Ext JS, LLC.
56831 * Originally Released Under LGPL - original licence link has changed is not relivant.
56834 * <script type="text/javascript">
56839 Roo.grid.PropertyRecord = Roo.data.Record.create([
56840 {name:'name',type:'string'}, 'value'
56844 Roo.grid.PropertyStore = function(grid, source){
56846 this.store = new Roo.data.Store({
56847 recordType : Roo.grid.PropertyRecord
56849 this.store.on('update', this.onUpdate, this);
56851 this.setSource(source);
56853 Roo.grid.PropertyStore.superclass.constructor.call(this);
56858 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56859 setSource : function(o){
56861 this.store.removeAll();
56864 if(this.isEditableValue(o[k])){
56865 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56868 this.store.loadRecords({records: data}, {}, true);
56871 onUpdate : function(ds, record, type){
56872 if(type == Roo.data.Record.EDIT){
56873 var v = record.data['value'];
56874 var oldValue = record.modified['value'];
56875 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56876 this.source[record.id] = v;
56878 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56885 getProperty : function(row){
56886 return this.store.getAt(row);
56889 isEditableValue: function(val){
56890 if(val && val instanceof Date){
56892 }else if(typeof val == 'object' || typeof val == 'function'){
56898 setValue : function(prop, value){
56899 this.source[prop] = value;
56900 this.store.getById(prop).set('value', value);
56903 getSource : function(){
56904 return this.source;
56908 Roo.grid.PropertyColumnModel = function(grid, store){
56911 g.PropertyColumnModel.superclass.constructor.call(this, [
56912 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56913 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56915 this.store = store;
56916 this.bselect = Roo.DomHelper.append(document.body, {
56917 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56918 {tag: 'option', value: 'true', html: 'true'},
56919 {tag: 'option', value: 'false', html: 'false'}
56922 Roo.id(this.bselect);
56925 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56926 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56927 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56928 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56929 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56931 this.renderCellDelegate = this.renderCell.createDelegate(this);
56932 this.renderPropDelegate = this.renderProp.createDelegate(this);
56935 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56939 valueText : 'Value',
56941 dateFormat : 'm/j/Y',
56944 renderDate : function(dateVal){
56945 return dateVal.dateFormat(this.dateFormat);
56948 renderBool : function(bVal){
56949 return bVal ? 'true' : 'false';
56952 isCellEditable : function(colIndex, rowIndex){
56953 return colIndex == 1;
56956 getRenderer : function(col){
56958 this.renderCellDelegate : this.renderPropDelegate;
56961 renderProp : function(v){
56962 return this.getPropertyName(v);
56965 renderCell : function(val){
56967 if(val instanceof Date){
56968 rv = this.renderDate(val);
56969 }else if(typeof val == 'boolean'){
56970 rv = this.renderBool(val);
56972 return Roo.util.Format.htmlEncode(rv);
56975 getPropertyName : function(name){
56976 var pn = this.grid.propertyNames;
56977 return pn && pn[name] ? pn[name] : name;
56980 getCellEditor : function(colIndex, rowIndex){
56981 var p = this.store.getProperty(rowIndex);
56982 var n = p.data['name'], val = p.data['value'];
56984 if(typeof(this.grid.customEditors[n]) == 'string'){
56985 return this.editors[this.grid.customEditors[n]];
56987 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56988 return this.grid.customEditors[n];
56990 if(val instanceof Date){
56991 return this.editors['date'];
56992 }else if(typeof val == 'number'){
56993 return this.editors['number'];
56994 }else if(typeof val == 'boolean'){
56995 return this.editors['boolean'];
56997 return this.editors['string'];
57003 * @class Roo.grid.PropertyGrid
57004 * @extends Roo.grid.EditorGrid
57005 * This class represents the interface of a component based property grid control.
57006 * <br><br>Usage:<pre><code>
57007 var grid = new Roo.grid.PropertyGrid("my-container-id", {
57015 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57016 * The container MUST have some type of size defined for the grid to fill. The container will be
57017 * automatically set to position relative if it isn't already.
57018 * @param {Object} config A config object that sets properties on this grid.
57020 Roo.grid.PropertyGrid = function(container, config){
57021 config = config || {};
57022 var store = new Roo.grid.PropertyStore(this);
57023 this.store = store;
57024 var cm = new Roo.grid.PropertyColumnModel(this, store);
57025 store.store.sort('name', 'ASC');
57026 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
57029 enableColLock:false,
57030 enableColumnMove:false,
57032 trackMouseOver: false,
57035 this.getGridEl().addClass('x-props-grid');
57036 this.lastEditRow = null;
57037 this.on('columnresize', this.onColumnResize, this);
57040 * @event beforepropertychange
57041 * Fires before a property changes (return false to stop?)
57042 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57043 * @param {String} id Record Id
57044 * @param {String} newval New Value
57045 * @param {String} oldval Old Value
57047 "beforepropertychange": true,
57049 * @event propertychange
57050 * Fires after a property changes
57051 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57052 * @param {String} id Record Id
57053 * @param {String} newval New Value
57054 * @param {String} oldval Old Value
57056 "propertychange": true
57058 this.customEditors = this.customEditors || {};
57060 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
57063 * @cfg {Object} customEditors map of colnames=> custom editors.
57064 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
57065 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
57066 * false disables editing of the field.
57070 * @cfg {Object} propertyNames map of property Names to their displayed value
57073 render : function(){
57074 Roo.grid.PropertyGrid.superclass.render.call(this);
57075 this.autoSize.defer(100, this);
57078 autoSize : function(){
57079 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
57081 this.view.fitColumns();
57085 onColumnResize : function(){
57086 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
57090 * Sets the data for the Grid
57091 * accepts a Key => Value object of all the elements avaiable.
57092 * @param {Object} data to appear in grid.
57094 setSource : function(source){
57095 this.store.setSource(source);
57099 * Gets all the data from the grid.
57100 * @return {Object} data data stored in grid
57102 getSource : function(){
57103 return this.store.getSource();
57112 * @class Roo.grid.Calendar
57113 * @extends Roo.util.Grid
57114 * This class extends the Grid to provide a calendar widget
57115 * <br><br>Usage:<pre><code>
57116 var grid = new Roo.grid.Calendar("my-container-id", {
57119 selModel: mySelectionModel,
57120 autoSizeColumns: true,
57121 monitorWindowResize: false,
57122 trackMouseOver: true
57123 eventstore : real data store..
57129 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57130 * The container MUST have some type of size defined for the grid to fill. The container will be
57131 * automatically set to position relative if it isn't already.
57132 * @param {Object} config A config object that sets properties on this grid.
57134 Roo.grid.Calendar = function(container, config){
57135 // initialize the container
57136 this.container = Roo.get(container);
57137 this.container.update("");
57138 this.container.setStyle("overflow", "hidden");
57139 this.container.addClass('x-grid-container');
57141 this.id = this.container.id;
57143 Roo.apply(this, config);
57144 // check and correct shorthanded configs
57148 for (var r = 0;r < 6;r++) {
57151 for (var c =0;c < 7;c++) {
57155 if (this.eventStore) {
57156 this.eventStore= Roo.factory(this.eventStore, Roo.data);
57157 this.eventStore.on('load',this.onLoad, this);
57158 this.eventStore.on('beforeload',this.clearEvents, this);
57162 this.dataSource = new Roo.data.Store({
57163 proxy: new Roo.data.MemoryProxy(rows),
57164 reader: new Roo.data.ArrayReader({}, [
57165 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
57168 this.dataSource.load();
57169 this.ds = this.dataSource;
57170 this.ds.xmodule = this.xmodule || false;
57173 var cellRender = function(v,x,r)
57175 return String.format(
57176 '<div class="fc-day fc-widget-content"><div>' +
57177 '<div class="fc-event-container"></div>' +
57178 '<div class="fc-day-number">{0}</div>'+
57180 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
57181 '</div></div>', v);
57186 this.colModel = new Roo.grid.ColumnModel( [
57188 xtype: 'ColumnModel',
57190 dataIndex : 'weekday0',
57192 renderer : cellRender
57195 xtype: 'ColumnModel',
57197 dataIndex : 'weekday1',
57199 renderer : cellRender
57202 xtype: 'ColumnModel',
57204 dataIndex : 'weekday2',
57205 header : 'Tuesday',
57206 renderer : cellRender
57209 xtype: 'ColumnModel',
57211 dataIndex : 'weekday3',
57212 header : 'Wednesday',
57213 renderer : cellRender
57216 xtype: 'ColumnModel',
57218 dataIndex : 'weekday4',
57219 header : 'Thursday',
57220 renderer : cellRender
57223 xtype: 'ColumnModel',
57225 dataIndex : 'weekday5',
57227 renderer : cellRender
57230 xtype: 'ColumnModel',
57232 dataIndex : 'weekday6',
57233 header : 'Saturday',
57234 renderer : cellRender
57237 this.cm = this.colModel;
57238 this.cm.xmodule = this.xmodule || false;
57242 //this.selModel = new Roo.grid.CellSelectionModel();
57243 //this.sm = this.selModel;
57244 //this.selModel.init(this);
57248 this.container.setWidth(this.width);
57252 this.container.setHeight(this.height);
57259 * The raw click event for the entire grid.
57260 * @param {Roo.EventObject} e
57265 * The raw dblclick event for the entire grid.
57266 * @param {Roo.EventObject} e
57270 * @event contextmenu
57271 * The raw contextmenu event for the entire grid.
57272 * @param {Roo.EventObject} e
57274 "contextmenu" : true,
57277 * The raw mousedown event for the entire grid.
57278 * @param {Roo.EventObject} e
57280 "mousedown" : true,
57283 * The raw mouseup event for the entire grid.
57284 * @param {Roo.EventObject} e
57289 * The raw mouseover event for the entire grid.
57290 * @param {Roo.EventObject} e
57292 "mouseover" : true,
57295 * The raw mouseout event for the entire grid.
57296 * @param {Roo.EventObject} e
57301 * The raw keypress event for the entire grid.
57302 * @param {Roo.EventObject} e
57307 * The raw keydown event for the entire grid.
57308 * @param {Roo.EventObject} e
57316 * Fires when a cell is clicked
57317 * @param {Grid} this
57318 * @param {Number} rowIndex
57319 * @param {Number} columnIndex
57320 * @param {Roo.EventObject} e
57322 "cellclick" : true,
57324 * @event celldblclick
57325 * Fires when a cell is double clicked
57326 * @param {Grid} this
57327 * @param {Number} rowIndex
57328 * @param {Number} columnIndex
57329 * @param {Roo.EventObject} e
57331 "celldblclick" : true,
57334 * Fires when a row is clicked
57335 * @param {Grid} this
57336 * @param {Number} rowIndex
57337 * @param {Roo.EventObject} e
57341 * @event rowdblclick
57342 * Fires when a row is double clicked
57343 * @param {Grid} this
57344 * @param {Number} rowIndex
57345 * @param {Roo.EventObject} e
57347 "rowdblclick" : true,
57349 * @event headerclick
57350 * Fires when a header is clicked
57351 * @param {Grid} this
57352 * @param {Number} columnIndex
57353 * @param {Roo.EventObject} e
57355 "headerclick" : true,
57357 * @event headerdblclick
57358 * Fires when a header cell is double clicked
57359 * @param {Grid} this
57360 * @param {Number} columnIndex
57361 * @param {Roo.EventObject} e
57363 "headerdblclick" : true,
57365 * @event rowcontextmenu
57366 * Fires when a row is right clicked
57367 * @param {Grid} this
57368 * @param {Number} rowIndex
57369 * @param {Roo.EventObject} e
57371 "rowcontextmenu" : true,
57373 * @event cellcontextmenu
57374 * Fires when a cell is right clicked
57375 * @param {Grid} this
57376 * @param {Number} rowIndex
57377 * @param {Number} cellIndex
57378 * @param {Roo.EventObject} e
57380 "cellcontextmenu" : true,
57382 * @event headercontextmenu
57383 * Fires when a header is right clicked
57384 * @param {Grid} this
57385 * @param {Number} columnIndex
57386 * @param {Roo.EventObject} e
57388 "headercontextmenu" : true,
57390 * @event bodyscroll
57391 * Fires when the body element is scrolled
57392 * @param {Number} scrollLeft
57393 * @param {Number} scrollTop
57395 "bodyscroll" : true,
57397 * @event columnresize
57398 * Fires when the user resizes a column
57399 * @param {Number} columnIndex
57400 * @param {Number} newSize
57402 "columnresize" : true,
57404 * @event columnmove
57405 * Fires when the user moves a column
57406 * @param {Number} oldIndex
57407 * @param {Number} newIndex
57409 "columnmove" : true,
57412 * Fires when row(s) start being dragged
57413 * @param {Grid} this
57414 * @param {Roo.GridDD} dd The drag drop object
57415 * @param {event} e The raw browser event
57417 "startdrag" : true,
57420 * Fires when a drag operation is complete
57421 * @param {Grid} this
57422 * @param {Roo.GridDD} dd The drag drop object
57423 * @param {event} e The raw browser event
57428 * Fires when dragged row(s) are dropped on a valid DD target
57429 * @param {Grid} this
57430 * @param {Roo.GridDD} dd The drag drop object
57431 * @param {String} targetId The target drag drop object
57432 * @param {event} e The raw browser event
57437 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
57438 * @param {Grid} this
57439 * @param {Roo.GridDD} dd The drag drop object
57440 * @param {String} targetId The target drag drop object
57441 * @param {event} e The raw browser event
57446 * Fires when the dragged row(s) first cross another DD target while being dragged
57447 * @param {Grid} this
57448 * @param {Roo.GridDD} dd The drag drop object
57449 * @param {String} targetId The target drag drop object
57450 * @param {event} e The raw browser event
57452 "dragenter" : true,
57455 * Fires when the dragged row(s) leave another DD target while being dragged
57456 * @param {Grid} this
57457 * @param {Roo.GridDD} dd The drag drop object
57458 * @param {String} targetId The target drag drop object
57459 * @param {event} e The raw browser event
57464 * Fires when a row is rendered, so you can change add a style to it.
57465 * @param {GridView} gridview The grid view
57466 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
57472 * Fires when the grid is rendered
57473 * @param {Grid} grid
57478 * Fires when a date is selected
57479 * @param {DatePicker} this
57480 * @param {Date} date The selected date
57484 * @event monthchange
57485 * Fires when the displayed month changes
57486 * @param {DatePicker} this
57487 * @param {Date} date The selected month
57489 'monthchange': true,
57491 * @event evententer
57492 * Fires when mouse over an event
57493 * @param {Calendar} this
57494 * @param {event} Event
57496 'evententer': true,
57498 * @event eventleave
57499 * Fires when the mouse leaves an
57500 * @param {Calendar} this
57503 'eventleave': true,
57505 * @event eventclick
57506 * Fires when the mouse click an
57507 * @param {Calendar} this
57510 'eventclick': true,
57512 * @event eventrender
57513 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
57514 * @param {Calendar} this
57515 * @param {data} data to be modified
57517 'eventrender': true
57521 Roo.grid.Grid.superclass.constructor.call(this);
57522 this.on('render', function() {
57523 this.view.el.addClass('x-grid-cal');
57525 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
57529 if (!Roo.grid.Calendar.style) {
57530 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
57533 '.x-grid-cal .x-grid-col' : {
57534 height: 'auto !important',
57535 'vertical-align': 'top'
57537 '.x-grid-cal .fc-event-hori' : {
57548 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
57550 * @cfg {Store} eventStore The store that loads events.
57555 activeDate : false,
57558 monitorWindowResize : false,
57561 resizeColumns : function() {
57562 var col = (this.view.el.getWidth() / 7) - 3;
57563 // loop through cols, and setWidth
57564 for(var i =0 ; i < 7 ; i++){
57565 this.cm.setColumnWidth(i, col);
57568 setDate :function(date) {
57570 Roo.log('setDate?');
57572 this.resizeColumns();
57573 var vd = this.activeDate;
57574 this.activeDate = date;
57575 // if(vd && this.el){
57576 // var t = date.getTime();
57577 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
57578 // Roo.log('using add remove');
57580 // this.fireEvent('monthchange', this, date);
57582 // this.cells.removeClass("fc-state-highlight");
57583 // this.cells.each(function(c){
57584 // if(c.dateValue == t){
57585 // c.addClass("fc-state-highlight");
57586 // setTimeout(function(){
57587 // try{c.dom.firstChild.focus();}catch(e){}
57597 var days = date.getDaysInMonth();
57599 var firstOfMonth = date.getFirstDateOfMonth();
57600 var startingPos = firstOfMonth.getDay()-this.startDay;
57602 if(startingPos < this.startDay){
57606 var pm = date.add(Date.MONTH, -1);
57607 var prevStart = pm.getDaysInMonth()-startingPos;
57611 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57613 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57614 //this.cells.addClassOnOver('fc-state-hover');
57616 var cells = this.cells.elements;
57617 var textEls = this.textNodes;
57619 //Roo.each(cells, function(cell){
57620 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57623 days += startingPos;
57625 // convert everything to numbers so it's fast
57626 var day = 86400000;
57627 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57630 //Roo.log(prevStart);
57632 var today = new Date().clearTime().getTime();
57633 var sel = date.clearTime().getTime();
57634 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57635 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57636 var ddMatch = this.disabledDatesRE;
57637 var ddText = this.disabledDatesText;
57638 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57639 var ddaysText = this.disabledDaysText;
57640 var format = this.format;
57642 var setCellClass = function(cal, cell){
57644 //Roo.log('set Cell Class');
57646 var t = d.getTime();
57651 cell.dateValue = t;
57653 cell.className += " fc-today";
57654 cell.className += " fc-state-highlight";
57655 cell.title = cal.todayText;
57658 // disable highlight in other month..
57659 cell.className += " fc-state-highlight";
57664 //cell.className = " fc-state-disabled";
57665 cell.title = cal.minText;
57669 //cell.className = " fc-state-disabled";
57670 cell.title = cal.maxText;
57674 if(ddays.indexOf(d.getDay()) != -1){
57675 // cell.title = ddaysText;
57676 // cell.className = " fc-state-disabled";
57679 if(ddMatch && format){
57680 var fvalue = d.dateFormat(format);
57681 if(ddMatch.test(fvalue)){
57682 cell.title = ddText.replace("%0", fvalue);
57683 cell.className = " fc-state-disabled";
57687 if (!cell.initialClassName) {
57688 cell.initialClassName = cell.dom.className;
57691 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57696 for(; i < startingPos; i++) {
57697 cells[i].dayName = (++prevStart);
57698 Roo.log(textEls[i]);
57699 d.setDate(d.getDate()+1);
57701 //cells[i].className = "fc-past fc-other-month";
57702 setCellClass(this, cells[i]);
57707 for(; i < days; i++){
57708 intDay = i - startingPos + 1;
57709 cells[i].dayName = (intDay);
57710 d.setDate(d.getDate()+1);
57712 cells[i].className = ''; // "x-date-active";
57713 setCellClass(this, cells[i]);
57717 for(; i < 42; i++) {
57718 //textEls[i].innerHTML = (++extraDays);
57720 d.setDate(d.getDate()+1);
57721 cells[i].dayName = (++extraDays);
57722 cells[i].className = "fc-future fc-other-month";
57723 setCellClass(this, cells[i]);
57726 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57728 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57730 // this will cause all the cells to mis
57733 for (var r = 0;r < 6;r++) {
57734 for (var c =0;c < 7;c++) {
57735 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57739 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57740 for(i=0;i<cells.length;i++) {
57742 this.cells.elements[i].dayName = cells[i].dayName ;
57743 this.cells.elements[i].className = cells[i].className;
57744 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57745 this.cells.elements[i].title = cells[i].title ;
57746 this.cells.elements[i].dateValue = cells[i].dateValue ;
57752 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57753 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57755 ////if(totalRows != 6){
57756 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57757 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57760 this.fireEvent('monthchange', this, date);
57765 * Returns the grid's SelectionModel.
57766 * @return {SelectionModel}
57768 getSelectionModel : function(){
57769 if(!this.selModel){
57770 this.selModel = new Roo.grid.CellSelectionModel();
57772 return this.selModel;
57776 this.eventStore.load()
57782 findCell : function(dt) {
57783 dt = dt.clearTime().getTime();
57785 this.cells.each(function(c){
57786 //Roo.log("check " +c.dateValue + '?=' + dt);
57787 if(c.dateValue == dt){
57797 findCells : function(rec) {
57798 var s = rec.data.start_dt.clone().clearTime().getTime();
57800 var e= rec.data.end_dt.clone().clearTime().getTime();
57803 this.cells.each(function(c){
57804 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57806 if(c.dateValue > e){
57809 if(c.dateValue < s){
57818 findBestRow: function(cells)
57822 for (var i =0 ; i < cells.length;i++) {
57823 ret = Math.max(cells[i].rows || 0,ret);
57830 addItem : function(rec)
57832 // look for vertical location slot in
57833 var cells = this.findCells(rec);
57835 rec.row = this.findBestRow(cells);
57837 // work out the location.
57841 for(var i =0; i < cells.length; i++) {
57849 if (crow.start.getY() == cells[i].getY()) {
57851 crow.end = cells[i];
57867 for (var i = 0; i < cells.length;i++) {
57868 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57875 clearEvents: function() {
57877 if (!this.eventStore.getCount()) {
57880 // reset number of rows in cells.
57881 Roo.each(this.cells.elements, function(c){
57885 this.eventStore.each(function(e) {
57886 this.clearEvent(e);
57891 clearEvent : function(ev)
57894 Roo.each(ev.els, function(el) {
57895 el.un('mouseenter' ,this.onEventEnter, this);
57896 el.un('mouseleave' ,this.onEventLeave, this);
57904 renderEvent : function(ev,ctr) {
57906 ctr = this.view.el.select('.fc-event-container',true).first();
57910 this.clearEvent(ev);
57916 var cells = ev.cells;
57917 var rows = ev.rows;
57918 this.fireEvent('eventrender', this, ev);
57920 for(var i =0; i < rows.length; i++) {
57924 cls += ' fc-event-start';
57926 if ((i+1) == rows.length) {
57927 cls += ' fc-event-end';
57930 //Roo.log(ev.data);
57931 // how many rows should it span..
57932 var cg = this.eventTmpl.append(ctr,Roo.apply({
57935 }, ev.data) , true);
57938 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57939 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57940 cg.on('click', this.onEventClick, this, ev);
57944 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57945 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57948 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57949 cg.setWidth(ebox.right - sbox.x -2);
57953 renderEvents: function()
57955 // first make sure there is enough space..
57957 if (!this.eventTmpl) {
57958 this.eventTmpl = new Roo.Template(
57959 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57960 '<div class="fc-event-inner">' +
57961 '<span class="fc-event-time">{time}</span>' +
57962 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57964 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57972 this.cells.each(function(c) {
57973 //Roo.log(c.select('.fc-day-content div',true).first());
57974 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57977 var ctr = this.view.el.select('.fc-event-container',true).first();
57980 this.eventStore.each(function(ev){
57982 this.renderEvent(ev);
57986 this.view.layout();
57990 onEventEnter: function (e, el,event,d) {
57991 this.fireEvent('evententer', this, el, event);
57994 onEventLeave: function (e, el,event,d) {
57995 this.fireEvent('eventleave', this, el, event);
57998 onEventClick: function (e, el,event,d) {
57999 this.fireEvent('eventclick', this, el, event);
58002 onMonthChange: function () {
58006 onLoad: function () {
58008 //Roo.log('calendar onload');
58010 if(this.eventStore.getCount() > 0){
58014 this.eventStore.each(function(d){
58019 if (typeof(add.end_dt) == 'undefined') {
58020 Roo.log("Missing End time in calendar data: ");
58024 if (typeof(add.start_dt) == 'undefined') {
58025 Roo.log("Missing Start time in calendar data: ");
58029 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
58030 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
58031 add.id = add.id || d.id;
58032 add.title = add.title || '??';
58040 this.renderEvents();
58050 render : function ()
58054 if (!this.view.el.hasClass('course-timesheet')) {
58055 this.view.el.addClass('course-timesheet');
58057 if (this.tsStyle) {
58062 Roo.log(_this.grid.view.el.getWidth());
58065 this.tsStyle = Roo.util.CSS.createStyleSheet({
58066 '.course-timesheet .x-grid-row' : {
58069 '.x-grid-row td' : {
58070 'vertical-align' : 0
58072 '.course-edit-link' : {
58074 'text-overflow' : 'ellipsis',
58075 'overflow' : 'hidden',
58076 'white-space' : 'nowrap',
58077 'cursor' : 'pointer'
58082 '.de-act-sup-link' : {
58083 'color' : 'purple',
58084 'text-decoration' : 'line-through'
58088 'text-decoration' : 'line-through'
58090 '.course-timesheet .course-highlight' : {
58091 'border-top-style': 'dashed !important',
58092 'border-bottom-bottom': 'dashed !important'
58094 '.course-timesheet .course-item' : {
58095 'font-family' : 'tahoma, arial, helvetica',
58096 'font-size' : '11px',
58097 'overflow' : 'hidden',
58098 'padding-left' : '10px',
58099 'padding-right' : '10px',
58100 'padding-top' : '10px'
58108 monitorWindowResize : false,
58109 cellrenderer : function(v,x,r)
58114 xtype: 'CellSelectionModel',
58121 beforeload : function (_self, options)
58123 options.params = options.params || {};
58124 options.params._month = _this.monthField.getValue();
58125 options.params.limit = 9999;
58126 options.params['sort'] = 'when_dt';
58127 options.params['dir'] = 'ASC';
58128 this.proxy.loadResponse = this.loadResponse;
58130 //this.addColumns();
58132 load : function (_self, records, options)
58134 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
58135 // if you click on the translation.. you can edit it...
58136 var el = Roo.get(this);
58137 var id = el.dom.getAttribute('data-id');
58138 var d = el.dom.getAttribute('data-date');
58139 var t = el.dom.getAttribute('data-time');
58140 //var id = this.child('span').dom.textContent;
58143 Pman.Dialog.CourseCalendar.show({
58147 productitem_active : id ? 1 : 0
58149 _this.grid.ds.load({});
58154 _this.panel.fireEvent('resize', [ '', '' ]);
58157 loadResponse : function(o, success, response){
58158 // this is overridden on before load..
58160 Roo.log("our code?");
58161 //Roo.log(success);
58162 //Roo.log(response)
58163 delete this.activeRequest;
58165 this.fireEvent("loadexception", this, o, response);
58166 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58171 result = o.reader.read(response);
58173 Roo.log("load exception?");
58174 this.fireEvent("loadexception", this, o, response, e);
58175 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58178 Roo.log("ready...");
58179 // loop through result.records;
58180 // and set this.tdate[date] = [] << array of records..
58182 Roo.each(result.records, function(r){
58184 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
58185 _this.tdata[r.data.when_dt.format('j')] = [];
58187 _this.tdata[r.data.when_dt.format('j')].push(r.data);
58190 //Roo.log(_this.tdata);
58192 result.records = [];
58193 result.totalRecords = 6;
58195 // let's generate some duumy records for the rows.
58196 //var st = _this.dateField.getValue();
58198 // work out monday..
58199 //st = st.add(Date.DAY, -1 * st.format('w'));
58201 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58203 var firstOfMonth = date.getFirstDayOfMonth();
58204 var days = date.getDaysInMonth();
58206 var firstAdded = false;
58207 for (var i = 0; i < result.totalRecords ; i++) {
58208 //var d= st.add(Date.DAY, i);
58211 for(var w = 0 ; w < 7 ; w++){
58212 if(!firstAdded && firstOfMonth != w){
58219 var dd = (d > 0 && d < 10) ? "0"+d : d;
58220 row['weekday'+w] = String.format(
58221 '<span style="font-size: 16px;"><b>{0}</b></span>'+
58222 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
58224 date.format('Y-m-')+dd
58227 if(typeof(_this.tdata[d]) != 'undefined'){
58228 Roo.each(_this.tdata[d], function(r){
58232 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
58233 if(r.parent_id*1>0){
58234 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
58237 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
58238 deactive = 'de-act-link';
58241 row['weekday'+w] += String.format(
58242 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
58244 r.product_id_name, //1
58245 r.when_dt.format('h:ia'), //2
58255 // only do this if something added..
58257 result.records.push(_this.grid.dataSource.reader.newRow(row));
58261 // push it twice. (second one with an hour..
58265 this.fireEvent("load", this, o, o.request.arg);
58266 o.request.callback.call(o.request.scope, result, o.request.arg, true);
58268 sortInfo : {field: 'when_dt', direction : 'ASC' },
58270 xtype: 'HttpProxy',
58273 url : baseURL + '/Roo/Shop_course.php'
58276 xtype: 'JsonReader',
58293 'name': 'parent_id',
58297 'name': 'product_id',
58301 'name': 'productitem_id',
58319 click : function (_self, e)
58321 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58322 sd.setMonth(sd.getMonth()-1);
58323 _this.monthField.setValue(sd.format('Y-m-d'));
58324 _this.grid.ds.load({});
58330 xtype: 'Separator',
58334 xtype: 'MonthField',
58337 render : function (_self)
58339 _this.monthField = _self;
58340 // _this.monthField.set today
58342 select : function (combo, date)
58344 _this.grid.ds.load({});
58347 value : (function() { return new Date(); })()
58350 xtype: 'Separator',
58356 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
58366 click : function (_self, e)
58368 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58369 sd.setMonth(sd.getMonth()+1);
58370 _this.monthField.setValue(sd.format('Y-m-d'));
58371 _this.grid.ds.load({});
58384 * Ext JS Library 1.1.1
58385 * Copyright(c) 2006-2007, Ext JS, LLC.
58387 * Originally Released Under LGPL - original licence link has changed is not relivant.
58390 * <script type="text/javascript">
58394 * @class Roo.LoadMask
58395 * A simple utility class for generically masking elements while loading data. If the element being masked has
58396 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
58397 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
58398 * element's UpdateManager load indicator and will be destroyed after the initial load.
58400 * Create a new LoadMask
58401 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
58402 * @param {Object} config The config object
58404 Roo.LoadMask = function(el, config){
58405 this.el = Roo.get(el);
58406 Roo.apply(this, config);
58408 this.store.on('beforeload', this.onBeforeLoad, this);
58409 this.store.on('load', this.onLoad, this);
58410 this.store.on('loadexception', this.onLoadException, this);
58411 this.removeMask = false;
58413 var um = this.el.getUpdateManager();
58414 um.showLoadIndicator = false; // disable the default indicator
58415 um.on('beforeupdate', this.onBeforeLoad, this);
58416 um.on('update', this.onLoad, this);
58417 um.on('failure', this.onLoad, this);
58418 this.removeMask = true;
58422 Roo.LoadMask.prototype = {
58424 * @cfg {Boolean} removeMask
58425 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
58426 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
58429 * @cfg {String} msg
58430 * The text to display in a centered loading message box (defaults to 'Loading...')
58432 msg : 'Loading...',
58434 * @cfg {String} msgCls
58435 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
58437 msgCls : 'x-mask-loading',
58440 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
58446 * Disables the mask to prevent it from being displayed
58448 disable : function(){
58449 this.disabled = true;
58453 * Enables the mask so that it can be displayed
58455 enable : function(){
58456 this.disabled = false;
58459 onLoadException : function()
58461 Roo.log(arguments);
58463 if (typeof(arguments[3]) != 'undefined') {
58464 Roo.MessageBox.alert("Error loading",arguments[3]);
58468 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
58469 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
58478 this.el.unmask(this.removeMask);
58481 onLoad : function()
58483 this.el.unmask(this.removeMask);
58487 onBeforeLoad : function(){
58488 if(!this.disabled){
58489 this.el.mask(this.msg, this.msgCls);
58494 destroy : function(){
58496 this.store.un('beforeload', this.onBeforeLoad, this);
58497 this.store.un('load', this.onLoad, this);
58498 this.store.un('loadexception', this.onLoadException, this);
58500 var um = this.el.getUpdateManager();
58501 um.un('beforeupdate', this.onBeforeLoad, this);
58502 um.un('update', this.onLoad, this);
58503 um.un('failure', this.onLoad, this);
58508 * Ext JS Library 1.1.1
58509 * Copyright(c) 2006-2007, Ext JS, LLC.
58511 * Originally Released Under LGPL - original licence link has changed is not relivant.
58514 * <script type="text/javascript">
58519 * @class Roo.XTemplate
58520 * @extends Roo.Template
58521 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
58523 var t = new Roo.XTemplate(
58524 '<select name="{name}">',
58525 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
58529 // then append, applying the master template values
58532 * Supported features:
58537 {a_variable} - output encoded.
58538 {a_variable.format:("Y-m-d")} - call a method on the variable
58539 {a_variable:raw} - unencoded output
58540 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
58541 {a_variable:this.method_on_template(...)} - call a method on the template object.
58546 <tpl for="a_variable or condition.."></tpl>
58547 <tpl if="a_variable or condition"></tpl>
58548 <tpl exec="some javascript"></tpl>
58549 <tpl name="named_template"></tpl> (experimental)
58551 <tpl for="."></tpl> - just iterate the property..
58552 <tpl for=".."></tpl> - iterates with the parent (probably the template)
58556 Roo.XTemplate = function()
58558 Roo.XTemplate.superclass.constructor.apply(this, arguments);
58565 Roo.extend(Roo.XTemplate, Roo.Template, {
58568 * The various sub templates
58573 * basic tag replacing syntax
58576 * // you can fake an object call by doing this
58580 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
58583 * compile the template
58585 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
58588 compile: function()
58592 s = ['<tpl>', s, '</tpl>'].join('');
58594 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
58595 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
58596 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
58597 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
58598 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
58603 while(true == !!(m = s.match(re))){
58604 var forMatch = m[0].match(nameRe),
58605 ifMatch = m[0].match(ifRe),
58606 execMatch = m[0].match(execRe),
58607 namedMatch = m[0].match(namedRe),
58612 name = forMatch && forMatch[1] ? forMatch[1] : '';
58615 // if - puts fn into test..
58616 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58618 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58623 // exec - calls a function... returns empty if true is returned.
58624 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58626 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58634 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58635 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58636 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58639 var uid = namedMatch ? namedMatch[1] : id;
58643 id: namedMatch ? namedMatch[1] : id,
58650 s = s.replace(m[0], '');
58652 s = s.replace(m[0], '{xtpl'+ id + '}');
58657 for(var i = tpls.length-1; i >= 0; --i){
58658 this.compileTpl(tpls[i]);
58659 this.tpls[tpls[i].id] = tpls[i];
58661 this.master = tpls[tpls.length-1];
58665 * same as applyTemplate, except it's done to one of the subTemplates
58666 * when using named templates, you can do:
58668 * var str = pl.applySubTemplate('your-name', values);
58671 * @param {Number} id of the template
58672 * @param {Object} values to apply to template
58673 * @param {Object} parent (normaly the instance of this object)
58675 applySubTemplate : function(id, values, parent)
58679 var t = this.tpls[id];
58683 if(t.test && !t.test.call(this, values, parent)){
58687 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58688 Roo.log(e.toString());
58694 if(t.exec && t.exec.call(this, values, parent)){
58698 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58699 Roo.log(e.toString());
58704 var vs = t.target ? t.target.call(this, values, parent) : values;
58705 parent = t.target ? values : parent;
58706 if(t.target && vs instanceof Array){
58708 for(var i = 0, len = vs.length; i < len; i++){
58709 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58711 return buf.join('');
58713 return t.compiled.call(this, vs, parent);
58715 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58716 Roo.log(e.toString());
58717 Roo.log(t.compiled);
58722 compileTpl : function(tpl)
58724 var fm = Roo.util.Format;
58725 var useF = this.disableFormats !== true;
58726 var sep = Roo.isGecko ? "+" : ",";
58727 var undef = function(str) {
58728 Roo.log("Property not found :" + str);
58732 var fn = function(m, name, format, args)
58734 //Roo.log(arguments);
58735 args = args ? args.replace(/\\'/g,"'") : args;
58736 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58737 if (typeof(format) == 'undefined') {
58738 format= 'htmlEncode';
58740 if (format == 'raw' ) {
58744 if(name.substr(0, 4) == 'xtpl'){
58745 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58748 // build an array of options to determine if value is undefined..
58750 // basically get 'xxxx.yyyy' then do
58751 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58752 // (function () { Roo.log("Property not found"); return ''; })() :
58757 Roo.each(name.split('.'), function(st) {
58758 lookfor += (lookfor.length ? '.': '') + st;
58759 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58762 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58765 if(format && useF){
58767 args = args ? ',' + args : "";
58769 if(format.substr(0, 5) != "this."){
58770 format = "fm." + format + '(';
58772 format = 'this.call("'+ format.substr(5) + '", ';
58776 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58780 // called with xxyx.yuu:(test,test)
58782 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58784 // raw.. - :raw modifier..
58785 return "'"+ sep + udef_st + name + ")"+sep+"'";
58789 // branched to use + in gecko and [].join() in others
58791 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58792 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58795 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58796 body.push(tpl.body.replace(/(\r\n|\n)/g,
58797 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58798 body.push("'].join('');};};");
58799 body = body.join('');
58802 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58804 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58810 applyTemplate : function(values){
58811 return this.master.compiled.call(this, values, {});
58812 //var s = this.subs;
58815 apply : function(){
58816 return this.applyTemplate.apply(this, arguments);
58821 Roo.XTemplate.from = function(el){
58822 el = Roo.getDom(el);
58823 return new Roo.XTemplate(el.value || el.innerHTML);