4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isGecko = !isSafari && ua.indexOf("gecko") > -1,
61 isBorderBox = isIE && !isStrict,
62 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64 isLinux = (ua.indexOf("linux") != -1),
65 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66 isIOS = /iphone|ipad/.test(ua),
67 isTouch = (function() {
69 document.createEvent("TouchEvent");
76 // remove css image flicker
79 document.execCommand("BackgroundImageCache", false, true);
85 * True if the browser is in strict mode
90 * True if the page is running over SSL
95 * True when the document is fully initialized and ready for action
100 * Turn on debugging output (currently only the factory uses this)
107 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
110 enableGarbageCollector : true,
113 * True to automatically purge event listeners after uncaching an element (defaults to false).
114 * Note: this only happens if enableGarbageCollector is true.
117 enableListenerCollection:false,
120 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
121 * the IE insecure content warning (defaults to javascript:false).
124 SSL_SECURE_URL : "javascript:false",
127 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
128 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
131 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
133 emptyFn : function(){},
136 * Copies all the properties of config to obj if they don't already exist.
137 * @param {Object} obj The receiver of the properties
138 * @param {Object} config The source of the properties
139 * @return {Object} returns obj
141 applyIf : function(o, c){
144 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
151 * Applies event listeners to elements by selectors when the document is ready.
152 * The event name is specified with an @ suffix.
155 // add a listener for click on all anchors in element with id foo
156 '#foo a@click' : function(e, t){
160 // add the same listener to multiple selectors (separated by comma BEFORE the @)
161 '#foo a, #bar span.some-class@mouseover' : function(){
166 * @param {Object} obj The list of behaviors to apply
168 addBehaviors : function(o){
170 Roo.onReady(function(){
175 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
177 var parts = b.split('@');
178 if(parts[1]){ // for Object prototype breakers
181 cache[s] = Roo.select(s);
183 cache[s].on(parts[1], o[b]);
190 * Generates unique ids. If the element already has an id, it is unchanged
191 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
192 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
193 * @return {String} The generated Id.
195 id : function(el, prefix){
196 prefix = prefix || "roo-gen";
198 var id = prefix + (++idSeed);
199 return el ? (el.id ? el.id : (el.id = id)) : id;
204 * Extends one class with another class and optionally overrides members with the passed literal. This class
205 * also adds the function "override()" to the class that can be used to override
206 * members on an instance.
207 * @param {Object} subclass The class inheriting the functionality
208 * @param {Object} superclass The class being extended
209 * @param {Object} overrides (optional) A literal with members
214 var io = function(o){
219 return function(sb, sp, overrides){
220 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
223 sb = function(){sp.apply(this, arguments);};
225 var F = function(){}, sbp, spp = sp.prototype;
227 sbp = sb.prototype = new F();
231 if(spp.constructor == Object.prototype.constructor){
236 sb.override = function(o){
240 Roo.override(sb, overrides);
246 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
248 Roo.override(MyClass, {
249 newMethod1: function(){
252 newMethod2: function(foo){
257 * @param {Object} origclass The class to override
258 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
259 * containing one or more methods.
262 override : function(origclass, overrides){
264 var p = origclass.prototype;
265 for(var method in overrides){
266 p[method] = overrides[method];
271 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
273 Roo.namespace('Company', 'Company.data');
274 Company.Widget = function() { ... }
275 Company.data.CustomStore = function(config) { ... }
277 * @param {String} namespace1
278 * @param {String} namespace2
279 * @param {String} etc
282 namespace : function(){
283 var a=arguments, o=null, i, j, d, rt;
284 for (i=0; i<a.length; ++i) {
288 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
289 for (j=1; j<d.length; ++j) {
290 o[d[j]]=o[d[j]] || {};
296 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
298 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
299 Roo.factory(conf, Roo.data);
301 * @param {String} classname
302 * @param {String} namespace (optional)
306 factory : function(c, ns)
308 // no xtype, no ns or c.xns - or forced off by c.xns
309 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
312 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
313 if (c.constructor == ns[c.xtype]) {// already created...
317 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
318 var ret = new ns[c.xtype](c);
322 c.xns = false; // prevent recursion..
326 * Logs to console if it can.
328 * @param {String|Object} string
333 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
340 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
344 urlEncode : function(o){
350 var ov = o[key], k = Roo.encodeURIComponent(key);
351 var type = typeof ov;
352 if(type == 'undefined'){
354 }else if(type != "function" && type != "object"){
355 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
356 }else if(ov instanceof Array){
358 for(var i = 0, len = ov.length; i < len; i++) {
359 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
370 * Safe version of encodeURIComponent
371 * @param {String} data
375 encodeURIComponent : function (data)
378 return encodeURIComponent(data);
379 } catch(e) {} // should be an uri encode error.
381 if (data == '' || data == null){
384 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
385 function nibble_to_hex(nibble){
386 var chars = '0123456789ABCDEF';
387 return chars.charAt(nibble);
389 data = data.toString();
391 for(var i=0; i<data.length; i++){
392 var c = data.charCodeAt(i);
393 var bs = new Array();
396 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
397 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
398 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
399 bs[3] = 0x80 | (c & 0x3F);
400 }else if (c > 0x800){
402 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
403 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
404 bs[2] = 0x80 | (c & 0x3F);
407 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
408 bs[1] = 0x80 | (c & 0x3F);
413 for(var j=0; j<bs.length; j++){
415 var hex = nibble_to_hex((b & 0xF0) >>> 4)
416 + nibble_to_hex(b &0x0F);
425 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
426 * @param {String} string
427 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
428 * @return {Object} A literal with members
430 urlDecode : function(string, overwrite){
431 if(!string || !string.length){
435 var pairs = string.split('&');
436 var pair, name, value;
437 for(var i = 0, len = pairs.length; i < len; i++){
438 pair = pairs[i].split('=');
439 name = decodeURIComponent(pair[0]);
440 value = decodeURIComponent(pair[1]);
441 if(overwrite !== true){
442 if(typeof obj[name] == "undefined"){
444 }else if(typeof obj[name] == "string"){
445 obj[name] = [obj[name]];
446 obj[name].push(value);
448 obj[name].push(value);
458 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
459 * passed array is not really an array, your function is called once with it.
460 * The supplied function is called with (Object item, Number index, Array allItems).
461 * @param {Array/NodeList/Mixed} array
462 * @param {Function} fn
463 * @param {Object} scope
465 each : function(array, fn, scope){
466 if(typeof array.length == "undefined" || typeof array == "string"){
469 for(var i = 0, len = array.length; i < len; i++){
470 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
475 combine : function(){
476 var as = arguments, l = as.length, r = [];
477 for(var i = 0; i < l; i++){
479 if(a instanceof Array){
481 }else if(a.length !== undefined && !a.substr){
482 r = r.concat(Array.prototype.slice.call(a, 0));
491 * Escapes the passed string for use in a regular expression
492 * @param {String} str
495 escapeRe : function(s) {
496 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
500 callback : function(cb, scope, args, delay){
501 if(typeof cb == "function"){
503 cb.defer(delay, scope, args || []);
505 cb.apply(scope, args || []);
511 * Return the dom node for the passed string (id), dom node, or Roo.Element
512 * @param {String/HTMLElement/Roo.Element} el
513 * @return HTMLElement
515 getDom : function(el){
519 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
523 * Shorthand for {@link Roo.ComponentMgr#get}
525 * @return Roo.Component
527 getCmp : function(id){
528 return Roo.ComponentMgr.get(id);
531 num : function(v, defaultValue){
532 if(typeof v != 'number'){
538 destroy : function(){
539 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
543 as.removeAllListeners();
547 if(typeof as.purgeListeners == 'function'){
550 if(typeof as.destroy == 'function'){
557 // inpired by a similar function in mootools library
559 * Returns the type of object that is passed in. If the object passed in is null or undefined it
560 * return false otherwise it returns one of the following values:<ul>
561 * <li><b>string</b>: If the object passed is a string</li>
562 * <li><b>number</b>: If the object passed is a number</li>
563 * <li><b>boolean</b>: If the object passed is a boolean value</li>
564 * <li><b>function</b>: If the object passed is a function reference</li>
565 * <li><b>object</b>: If the object passed is an object</li>
566 * <li><b>array</b>: If the object passed is an array</li>
567 * <li><b>regexp</b>: If the object passed is a regular expression</li>
568 * <li><b>element</b>: If the object passed is a DOM Element</li>
569 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
570 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
571 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
572 * @param {Mixed} object
576 if(o === undefined || o === null){
583 if(t == 'object' && o.nodeName) {
585 case 1: return 'element';
586 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
589 if(t == 'object' || t == 'function') {
590 switch(o.constructor) {
591 case Array: return 'array';
592 case RegExp: return 'regexp';
594 if(typeof o.length == 'number' && typeof o.item == 'function') {
602 * Returns true if the passed value is null, undefined or an empty string (optional).
603 * @param {Mixed} value The value to test
604 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
607 isEmpty : function(v, allowBlank){
608 return v === null || v === undefined || (!allowBlank ? v === '' : false);
616 isFirefox : isFirefox,
626 isBorderBox : isBorderBox,
628 isWindows : isWindows,
639 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
640 * you may want to set this to true.
643 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
648 * Selects a single element as a Roo Element
649 * This is about as close as you can get to jQuery's $('do crazy stuff')
650 * @param {String} selector The selector/xpath query
651 * @param {Node} root (optional) The start of the query (defaults to document).
652 * @return {Roo.Element}
654 selectNode : function(selector, root)
656 var node = Roo.DomQuery.selectNode(selector,root);
657 return node ? Roo.get(node) : new Roo.Element(false);
665 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
666 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
669 "Roo.bootstrap.dash");
672 * Ext JS Library 1.1.1
673 * Copyright(c) 2006-2007, Ext JS, LLC.
675 * Originally Released Under LGPL - original licence link has changed is not relivant.
678 * <script type="text/javascript">
682 // wrappedn so fnCleanup is not in global scope...
684 function fnCleanUp() {
685 var p = Function.prototype;
686 delete p.createSequence;
688 delete p.createDelegate;
689 delete p.createCallback;
690 delete p.createInterceptor;
692 window.detachEvent("onunload", fnCleanUp);
694 window.attachEvent("onunload", fnCleanUp);
701 * These functions are available on every Function object (any JavaScript function).
703 Roo.apply(Function.prototype, {
705 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
706 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
707 * Will create a function that is bound to those 2 args.
708 * @return {Function} The new function
710 createCallback : function(/*args...*/){
711 // make args available, in function below
712 var args = arguments;
715 return method.apply(window, args);
720 * Creates a delegate (callback) that sets the scope to obj.
721 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
722 * Will create a function that is automatically scoped to this.
723 * @param {Object} obj (optional) The object for which the scope is set
724 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
725 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
726 * if a number the args are inserted at the specified position
727 * @return {Function} The new function
729 createDelegate : function(obj, args, appendArgs){
732 var callArgs = args || arguments;
733 if(appendArgs === true){
734 callArgs = Array.prototype.slice.call(arguments, 0);
735 callArgs = callArgs.concat(args);
736 }else if(typeof appendArgs == "number"){
737 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
738 var applyArgs = [appendArgs, 0].concat(args); // create method call params
739 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
741 return method.apply(obj || window, callArgs);
746 * Calls this function after the number of millseconds specified.
747 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
748 * @param {Object} obj (optional) The object for which the scope is set
749 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
750 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
751 * if a number the args are inserted at the specified position
752 * @return {Number} The timeout id that can be used with clearTimeout
754 defer : function(millis, obj, args, appendArgs){
755 var fn = this.createDelegate(obj, args, appendArgs);
757 return setTimeout(fn, millis);
763 * Create a combined function call sequence of the original function + the passed function.
764 * The resulting function returns the results of the original function.
765 * The passed fcn is called with the parameters of the original function
766 * @param {Function} fcn The function to sequence
767 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
768 * @return {Function} The new function
770 createSequence : function(fcn, scope){
771 if(typeof fcn != "function"){
776 var retval = method.apply(this || window, arguments);
777 fcn.apply(scope || this || window, arguments);
783 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
784 * The resulting function returns the results of the original function.
785 * The passed fcn is called with the parameters of the original function.
787 * @param {Function} fcn The function to call before the original
788 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
789 * @return {Function} The new function
791 createInterceptor : function(fcn, scope){
792 if(typeof fcn != "function"){
799 if(fcn.apply(scope || this || window, arguments) === false){
802 return method.apply(this || window, arguments);
808 * Ext JS Library 1.1.1
809 * Copyright(c) 2006-2007, Ext JS, LLC.
811 * Originally Released Under LGPL - original licence link has changed is not relivant.
814 * <script type="text/javascript">
817 Roo.applyIf(String, {
822 * Escapes the passed string for ' and \
823 * @param {String} string The string to escape
824 * @return {String} The escaped string
827 escape : function(string) {
828 return string.replace(/('|\\)/g, "\\$1");
832 * Pads the left side of a string with a specified character. This is especially useful
833 * for normalizing number and date strings. Example usage:
835 var s = String.leftPad('123', 5, '0');
836 // s now contains the string: '00123'
838 * @param {String} string The original string
839 * @param {Number} size The total length of the output string
840 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
841 * @return {String} The padded string
844 leftPad : function (val, size, ch) {
845 var result = new String(val);
846 if(ch === null || ch === undefined || ch === '') {
849 while (result.length < size) {
850 result = ch + result;
856 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
857 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
859 var cls = 'my-class', text = 'Some text';
860 var s = String.format('<div class="{0}">{1}</div>', cls, text);
861 // s now contains the string: '<div class="my-class">Some text</div>'
863 * @param {String} string The tokenized string to be formatted
864 * @param {String} value1 The value to replace token {0}
865 * @param {String} value2 Etc...
866 * @return {String} The formatted string
869 format : function(format){
870 var args = Array.prototype.slice.call(arguments, 1);
871 return format.replace(/\{(\d+)\}/g, function(m, i){
872 return Roo.util.Format.htmlEncode(args[i]);
878 * Utility function that allows you to easily switch a string between two alternating values. The passed value
879 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
880 * they are already different, the first value passed in is returned. Note that this method returns the new value
881 * but does not change the current string.
883 // alternate sort directions
884 sort = sort.toggle('ASC', 'DESC');
886 // instead of conditional logic:
887 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
889 * @param {String} value The value to compare to the current string
890 * @param {String} other The new value to use if the string already equals the first value passed in
891 * @return {String} The new value
894 String.prototype.toggle = function(value, other){
895 return this == value ? other : value;
898 * Ext JS Library 1.1.1
899 * Copyright(c) 2006-2007, Ext JS, LLC.
901 * Originally Released Under LGPL - original licence link has changed is not relivant.
904 * <script type="text/javascript">
910 Roo.applyIf(Number.prototype, {
912 * Checks whether or not the current number is within a desired range. If the number is already within the
913 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
914 * exceeded. Note that this method returns the constrained value but does not change the current number.
915 * @param {Number} min The minimum number in the range
916 * @param {Number} max The maximum number in the range
917 * @return {Number} The constrained value if outside the range, otherwise the current value
919 constrain : function(min, max){
920 return Math.min(Math.max(this, min), max);
924 * Ext JS Library 1.1.1
925 * Copyright(c) 2006-2007, Ext JS, LLC.
927 * Originally Released Under LGPL - original licence link has changed is not relivant.
930 * <script type="text/javascript">
935 Roo.applyIf(Array.prototype, {
938 * Checks whether or not the specified object exists in the array.
939 * @param {Object} o The object to check for
940 * @return {Number} The index of o in the array (or -1 if it is not found)
942 indexOf : function(o){
943 for (var i = 0, len = this.length; i < len; i++){
944 if(this[i] == o) return i;
950 * Removes the specified object from the array. If the object is not found nothing happens.
951 * @param {Object} o The object to remove
953 remove : function(o){
954 var index = this.indexOf(o);
956 this.splice(index, 1);
960 * Map (JS 1.6 compatibility)
961 * @param {Function} function to call
965 var len = this.length >>> 0;
966 if (typeof fun != "function")
967 throw new TypeError();
969 var res = new Array(len);
970 var thisp = arguments[1];
971 for (var i = 0; i < len; i++)
974 res[i] = fun.call(thisp, this[i], i, this);
985 * Ext JS Library 1.1.1
986 * Copyright(c) 2006-2007, Ext JS, LLC.
988 * Originally Released Under LGPL - original licence link has changed is not relivant.
991 * <script type="text/javascript">
997 * The date parsing and format syntax is a subset of
998 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
999 * supported will provide results equivalent to their PHP versions.
1001 * Following is the list of all currently supported formats:
1004 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1006 Format Output Description
1007 ------ ---------- --------------------------------------------------------------
1008 d 10 Day of the month, 2 digits with leading zeros
1009 D Wed A textual representation of a day, three letters
1010 j 10 Day of the month without leading zeros
1011 l Wednesday A full textual representation of the day of the week
1012 S th English ordinal day of month suffix, 2 chars (use with j)
1013 w 3 Numeric representation of the day of the week
1014 z 9 The julian date, or day of the year (0-365)
1015 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1016 F January A full textual representation of the month
1017 m 01 Numeric representation of a month, with leading zeros
1018 M Jan Month name abbreviation, three letters
1019 n 1 Numeric representation of a month, without leading zeros
1020 t 31 Number of days in the given month
1021 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1022 Y 2007 A full numeric representation of a year, 4 digits
1023 y 07 A two digit representation of a year
1024 a pm Lowercase Ante meridiem and Post meridiem
1025 A PM Uppercase Ante meridiem and Post meridiem
1026 g 3 12-hour format of an hour without leading zeros
1027 G 15 24-hour format of an hour without leading zeros
1028 h 03 12-hour format of an hour with leading zeros
1029 H 15 24-hour format of an hour with leading zeros
1030 i 05 Minutes with leading zeros
1031 s 01 Seconds, with leading zeros
1032 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1033 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1034 T CST Timezone setting of the machine running the code
1035 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1038 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1040 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1041 document.write(dt.format('Y-m-d')); //2007-01-10
1042 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1043 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1046 * Here are some standard date/time patterns that you might find helpful. They
1047 * are not part of the source of Date.js, but to use them you can simply copy this
1048 * block of code into any script that is included after Date.js and they will also become
1049 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1052 ISO8601Long:"Y-m-d H:i:s",
1053 ISO8601Short:"Y-m-d",
1055 LongDate: "l, F d, Y",
1056 FullDateTime: "l, F d, Y g:i:s A",
1059 LongTime: "g:i:s A",
1060 SortableDateTime: "Y-m-d\\TH:i:s",
1061 UniversalSortableDateTime: "Y-m-d H:i:sO",
1068 var dt = new Date();
1069 document.write(dt.format(Date.patterns.ShortDate));
1074 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1075 * They generate precompiled functions from date formats instead of parsing and
1076 * processing the pattern every time you format a date. These functions are available
1077 * on every Date object (any javascript function).
1079 * The original article and download are here:
1080 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1087 Returns the number of milliseconds between this date and date
1088 @param {Date} date (optional) Defaults to now
1089 @return {Number} The diff in milliseconds
1090 @member Date getElapsed
1092 Date.prototype.getElapsed = function(date) {
1093 return Math.abs((date || new Date()).getTime()-this.getTime());
1095 // was in date file..
1099 Date.parseFunctions = {count:0};
1101 Date.parseRegexes = [];
1103 Date.formatFunctions = {count:0};
1106 Date.prototype.dateFormat = function(format) {
1107 if (Date.formatFunctions[format] == null) {
1108 Date.createNewFormat(format);
1110 var func = Date.formatFunctions[format];
1111 return this[func]();
1116 * Formats a date given the supplied format string
1117 * @param {String} format The format string
1118 * @return {String} The formatted date
1121 Date.prototype.format = Date.prototype.dateFormat;
1124 Date.createNewFormat = function(format) {
1125 var funcName = "format" + Date.formatFunctions.count++;
1126 Date.formatFunctions[format] = funcName;
1127 var code = "Date.prototype." + funcName + " = function(){return ";
1128 var special = false;
1130 for (var i = 0; i < format.length; ++i) {
1131 ch = format.charAt(i);
1132 if (!special && ch == "\\") {
1137 code += "'" + String.escape(ch) + "' + ";
1140 code += Date.getFormatCode(ch);
1143 /** eval:var:zzzzzzzzzzzzz */
1144 eval(code.substring(0, code.length - 3) + ";}");
1148 Date.getFormatCode = function(character) {
1149 switch (character) {
1151 return "String.leftPad(this.getDate(), 2, '0') + ";
1153 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1155 return "this.getDate() + ";
1157 return "Date.dayNames[this.getDay()] + ";
1159 return "this.getSuffix() + ";
1161 return "this.getDay() + ";
1163 return "this.getDayOfYear() + ";
1165 return "this.getWeekOfYear() + ";
1167 return "Date.monthNames[this.getMonth()] + ";
1169 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1171 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1173 return "(this.getMonth() + 1) + ";
1175 return "this.getDaysInMonth() + ";
1177 return "(this.isLeapYear() ? 1 : 0) + ";
1179 return "this.getFullYear() + ";
1181 return "('' + this.getFullYear()).substring(2, 4) + ";
1183 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1185 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1187 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1189 return "this.getHours() + ";
1191 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1193 return "String.leftPad(this.getHours(), 2, '0') + ";
1195 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1197 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1199 return "this.getGMTOffset() + ";
1201 return "this.getGMTColonOffset() + ";
1203 return "this.getTimezone() + ";
1205 return "(this.getTimezoneOffset() * -60) + ";
1207 return "'" + String.escape(character) + "' + ";
1212 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1213 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1214 * the date format that is not specified will default to the current date value for that part. Time parts can also
1215 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1216 * string or the parse operation will fail.
1219 //dt = Fri May 25 2007 (current date)
1220 var dt = new Date();
1222 //dt = Thu May 25 2006 (today's month/day in 2006)
1223 dt = Date.parseDate("2006", "Y");
1225 //dt = Sun Jan 15 2006 (all date parts specified)
1226 dt = Date.parseDate("2006-1-15", "Y-m-d");
1228 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1229 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1231 * @param {String} input The unparsed date as a string
1232 * @param {String} format The format the date is in
1233 * @return {Date} The parsed date
1236 Date.parseDate = function(input, format) {
1237 if (Date.parseFunctions[format] == null) {
1238 Date.createParser(format);
1240 var func = Date.parseFunctions[format];
1241 return Date[func](input);
1247 Date.createParser = function(format) {
1248 var funcName = "parse" + Date.parseFunctions.count++;
1249 var regexNum = Date.parseRegexes.length;
1250 var currentGroup = 1;
1251 Date.parseFunctions[format] = funcName;
1253 var code = "Date." + funcName + " = function(input){\n"
1254 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1255 + "var d = new Date();\n"
1256 + "y = d.getFullYear();\n"
1257 + "m = d.getMonth();\n"
1258 + "d = d.getDate();\n"
1259 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1260 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1261 + "if (results && results.length > 0) {";
1264 var special = false;
1266 for (var i = 0; i < format.length; ++i) {
1267 ch = format.charAt(i);
1268 if (!special && ch == "\\") {
1273 regex += String.escape(ch);
1276 var obj = Date.formatCodeToRegex(ch, currentGroup);
1277 currentGroup += obj.g;
1279 if (obj.g && obj.c) {
1285 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1286 + "{v = new Date(y, m, d, h, i, s);}\n"
1287 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1288 + "{v = new Date(y, m, d, h, i);}\n"
1289 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1290 + "{v = new Date(y, m, d, h);}\n"
1291 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1292 + "{v = new Date(y, m, d);}\n"
1293 + "else if (y >= 0 && m >= 0)\n"
1294 + "{v = new Date(y, m);}\n"
1295 + "else if (y >= 0)\n"
1296 + "{v = new Date(y);}\n"
1297 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1298 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1299 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1302 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1303 /** eval:var:zzzzzzzzzzzzz */
1308 Date.formatCodeToRegex = function(character, currentGroup) {
1309 switch (character) {
1313 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1316 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1317 s:"(\\d{1,2})"}; // day of month without leading zeroes
1320 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1321 s:"(\\d{2})"}; // day of month with leading zeroes
1325 s:"(?:" + Date.dayNames.join("|") + ")"};
1329 s:"(?:st|nd|rd|th)"};
1344 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1345 s:"(" + Date.monthNames.join("|") + ")"};
1348 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1349 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1352 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1353 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1356 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1357 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1368 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1372 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1373 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1377 c:"if (results[" + currentGroup + "] == 'am') {\n"
1378 + "if (h == 12) { h = 0; }\n"
1379 + "} else { if (h < 12) { h += 12; }}",
1383 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1384 + "if (h == 12) { h = 0; }\n"
1385 + "} else { if (h < 12) { h += 12; }}",
1390 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1391 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1395 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1396 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1399 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1403 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1408 "o = results[", currentGroup, "];\n",
1409 "var sn = o.substring(0,1);\n", // get + / - sign
1410 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1411 "var mn = o.substring(3,5) % 60;\n", // get minutes
1412 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1413 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1415 s:"([+\-]\\d{2,4})"};
1421 "o = results[", currentGroup, "];\n",
1422 "var sn = o.substring(0,1);\n",
1423 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1424 "var mn = o.substring(4,6) % 60;\n",
1425 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1426 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1432 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1435 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1436 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1437 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1441 s:String.escape(character)};
1446 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1447 * @return {String} The abbreviated timezone name (e.g. 'CST')
1449 Date.prototype.getTimezone = function() {
1450 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1454 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1455 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1457 Date.prototype.getGMTOffset = function() {
1458 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1459 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1460 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1464 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1465 * @return {String} 2-characters representing hours and 2-characters representing minutes
1466 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1468 Date.prototype.getGMTColonOffset = function() {
1469 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1470 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1472 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1476 * Get the numeric day number of the year, adjusted for leap year.
1477 * @return {Number} 0 through 364 (365 in leap years)
1479 Date.prototype.getDayOfYear = function() {
1481 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1482 for (var i = 0; i < this.getMonth(); ++i) {
1483 num += Date.daysInMonth[i];
1485 return num + this.getDate() - 1;
1489 * Get the string representation of the numeric week number of the year
1490 * (equivalent to the format specifier 'W').
1491 * @return {String} '00' through '52'
1493 Date.prototype.getWeekOfYear = function() {
1494 // Skip to Thursday of this week
1495 var now = this.getDayOfYear() + (4 - this.getDay());
1496 // Find the first Thursday of the year
1497 var jan1 = new Date(this.getFullYear(), 0, 1);
1498 var then = (7 - jan1.getDay() + 4);
1499 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1503 * Whether or not the current date is in a leap year.
1504 * @return {Boolean} True if the current date is in a leap year, else false
1506 Date.prototype.isLeapYear = function() {
1507 var year = this.getFullYear();
1508 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1512 * Get the first day of the current month, adjusted for leap year. The returned value
1513 * is the numeric day index within the week (0-6) which can be used in conjunction with
1514 * the {@link #monthNames} array to retrieve the textual day name.
1517 var dt = new Date('1/10/2007');
1518 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1520 * @return {Number} The day number (0-6)
1522 Date.prototype.getFirstDayOfMonth = function() {
1523 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1524 return (day < 0) ? (day + 7) : day;
1528 * Get the last day of the current month, adjusted for leap year. The returned value
1529 * is the numeric day index within the week (0-6) which can be used in conjunction with
1530 * the {@link #monthNames} array to retrieve the textual day name.
1533 var dt = new Date('1/10/2007');
1534 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1536 * @return {Number} The day number (0-6)
1538 Date.prototype.getLastDayOfMonth = function() {
1539 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1540 return (day < 0) ? (day + 7) : day;
1545 * Get the first date of this date's month
1548 Date.prototype.getFirstDateOfMonth = function() {
1549 return new Date(this.getFullYear(), this.getMonth(), 1);
1553 * Get the last date of this date's month
1556 Date.prototype.getLastDateOfMonth = function() {
1557 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1560 * Get the number of days in the current month, adjusted for leap year.
1561 * @return {Number} The number of days in the month
1563 Date.prototype.getDaysInMonth = function() {
1564 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1565 return Date.daysInMonth[this.getMonth()];
1569 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1570 * @return {String} 'st, 'nd', 'rd' or 'th'
1572 Date.prototype.getSuffix = function() {
1573 switch (this.getDate()) {
1590 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1593 * An array of textual month names.
1594 * Override these values for international dates, for example...
1595 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1614 * An array of textual day names.
1615 * Override these values for international dates, for example...
1616 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1632 Date.monthNumbers = {
1647 * Creates and returns a new Date instance with the exact same date value as the called instance.
1648 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1649 * variable will also be changed. When the intention is to create a new variable that will not
1650 * modify the original instance, you should create a clone.
1652 * Example of correctly cloning a date:
1655 var orig = new Date('10/1/2006');
1658 document.write(orig); //returns 'Thu Oct 05 2006'!
1661 var orig = new Date('10/1/2006');
1662 var copy = orig.clone();
1664 document.write(orig); //returns 'Thu Oct 01 2006'
1666 * @return {Date} The new Date instance
1668 Date.prototype.clone = function() {
1669 return new Date(this.getTime());
1673 * Clears any time information from this date
1674 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1675 @return {Date} this or the clone
1677 Date.prototype.clearTime = function(clone){
1679 return this.clone().clearTime();
1684 this.setMilliseconds(0);
1689 // safari setMonth is broken
1691 Date.brokenSetMonth = Date.prototype.setMonth;
1692 Date.prototype.setMonth = function(num){
1694 var n = Math.ceil(-num);
1695 var back_year = Math.ceil(n/12);
1696 var month = (n % 12) ? 12 - n % 12 : 0 ;
1697 this.setFullYear(this.getFullYear() - back_year);
1698 return Date.brokenSetMonth.call(this, month);
1700 return Date.brokenSetMonth.apply(this, arguments);
1705 /** Date interval constant
1709 /** Date interval constant
1713 /** Date interval constant
1717 /** Date interval constant
1721 /** Date interval constant
1725 /** Date interval constant
1729 /** Date interval constant
1735 * Provides a convenient method of performing basic date arithmetic. This method
1736 * does not modify the Date instance being called - it creates and returns
1737 * a new Date instance containing the resulting date value.
1742 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1743 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1745 //Negative values will subtract correctly:
1746 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1747 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1749 //You can even chain several calls together in one line!
1750 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1751 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1754 * @param {String} interval A valid date interval enum value
1755 * @param {Number} value The amount to add to the current date
1756 * @return {Date} The new Date instance
1758 Date.prototype.add = function(interval, value){
1759 var d = this.clone();
1760 if (!interval || value === 0) return d;
1761 switch(interval.toLowerCase()){
1763 d.setMilliseconds(this.getMilliseconds() + value);
1766 d.setSeconds(this.getSeconds() + value);
1769 d.setMinutes(this.getMinutes() + value);
1772 d.setHours(this.getHours() + value);
1775 d.setDate(this.getDate() + value);
1778 var day = this.getDate();
1780 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1783 d.setMonth(this.getMonth() + value);
1786 d.setFullYear(this.getFullYear() + value);
1793 * Ext JS Library 1.1.1
1794 * Copyright(c) 2006-2007, Ext JS, LLC.
1796 * Originally Released Under LGPL - original licence link has changed is not relivant.
1799 * <script type="text/javascript">
1803 * @class Roo.lib.Dom
1806 * Dom utils (from YIU afaik)
1811 * Get the view width
1812 * @param {Boolean} full True will get the full document, otherwise it's the view width
1813 * @return {Number} The width
1816 getViewWidth : function(full) {
1817 return full ? this.getDocumentWidth() : this.getViewportWidth();
1820 * Get the view height
1821 * @param {Boolean} full True will get the full document, otherwise it's the view height
1822 * @return {Number} The height
1824 getViewHeight : function(full) {
1825 return full ? this.getDocumentHeight() : this.getViewportHeight();
1828 getDocumentHeight: function() {
1829 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1830 return Math.max(scrollHeight, this.getViewportHeight());
1833 getDocumentWidth: function() {
1834 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1835 return Math.max(scrollWidth, this.getViewportWidth());
1838 getViewportHeight: function() {
1839 var height = self.innerHeight;
1840 var mode = document.compatMode;
1842 if ((mode || Roo.isIE) && !Roo.isOpera) {
1843 height = (mode == "CSS1Compat") ?
1844 document.documentElement.clientHeight :
1845 document.body.clientHeight;
1851 getViewportWidth: function() {
1852 var width = self.innerWidth;
1853 var mode = document.compatMode;
1855 if (mode || Roo.isIE) {
1856 width = (mode == "CSS1Compat") ?
1857 document.documentElement.clientWidth :
1858 document.body.clientWidth;
1863 isAncestor : function(p, c) {
1870 if (p.contains && !Roo.isSafari) {
1871 return p.contains(c);
1872 } else if (p.compareDocumentPosition) {
1873 return !!(p.compareDocumentPosition(c) & 16);
1875 var parent = c.parentNode;
1880 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1883 parent = parent.parentNode;
1889 getRegion : function(el) {
1890 return Roo.lib.Region.getRegion(el);
1893 getY : function(el) {
1894 return this.getXY(el)[1];
1897 getX : function(el) {
1898 return this.getXY(el)[0];
1901 getXY : function(el) {
1902 var p, pe, b, scroll, bd = document.body;
1903 el = Roo.getDom(el);
1904 var fly = Roo.lib.AnimBase.fly;
1905 if (el.getBoundingClientRect) {
1906 b = el.getBoundingClientRect();
1907 scroll = fly(document).getScroll();
1908 return [b.left + scroll.left, b.top + scroll.top];
1914 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1921 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1928 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1929 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1936 if (p != el && pe.getStyle('overflow') != 'visible') {
1944 if (Roo.isSafari && hasAbsolute) {
1949 if (Roo.isGecko && !hasAbsolute) {
1951 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1952 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1956 while (p && p != bd) {
1957 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1969 setXY : function(el, xy) {
1970 el = Roo.fly(el, '_setXY');
1972 var pts = el.translatePoints(xy);
1973 if (xy[0] !== false) {
1974 el.dom.style.left = pts.left + "px";
1976 if (xy[1] !== false) {
1977 el.dom.style.top = pts.top + "px";
1981 setX : function(el, x) {
1982 this.setXY(el, [x, false]);
1985 setY : function(el, y) {
1986 this.setXY(el, [false, y]);
1990 * Portions of this file are based on pieces of Yahoo User Interface Library
1991 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1992 * YUI licensed under the BSD License:
1993 * http://developer.yahoo.net/yui/license.txt
1994 * <script type="text/javascript">
1998 Roo.lib.Event = function() {
1999 var loadComplete = false;
2001 var unloadListeners = [];
2003 var onAvailStack = [];
2005 var lastError = null;
2018 startInterval: function() {
2019 if (!this._interval) {
2021 var callback = function() {
2022 self._tryPreloadAttach();
2024 this._interval = setInterval(callback, this.POLL_INTERVAL);
2029 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2030 onAvailStack.push({ id: p_id,
2033 override: p_override,
2034 checkReady: false });
2036 retryCount = this.POLL_RETRYS;
2037 this.startInterval();
2041 addListener: function(el, eventName, fn) {
2042 el = Roo.getDom(el);
2047 if ("unload" == eventName) {
2048 unloadListeners[unloadListeners.length] =
2049 [el, eventName, fn];
2053 var wrappedFn = function(e) {
2054 return fn(Roo.lib.Event.getEvent(e));
2057 var li = [el, eventName, fn, wrappedFn];
2059 var index = listeners.length;
2060 listeners[index] = li;
2062 this.doAdd(el, eventName, wrappedFn, false);
2068 removeListener: function(el, eventName, fn) {
2071 el = Roo.getDom(el);
2074 return this.purgeElement(el, false, eventName);
2078 if ("unload" == eventName) {
2080 for (i = 0,len = unloadListeners.length; i < len; i++) {
2081 var li = unloadListeners[i];
2084 li[1] == eventName &&
2086 unloadListeners.splice(i, 1);
2094 var cacheItem = null;
2097 var index = arguments[3];
2099 if ("undefined" == typeof index) {
2100 index = this._getCacheIndex(el, eventName, fn);
2104 cacheItem = listeners[index];
2107 if (!el || !cacheItem) {
2111 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2113 delete listeners[index][this.WFN];
2114 delete listeners[index][this.FN];
2115 listeners.splice(index, 1);
2122 getTarget: function(ev, resolveTextNode) {
2123 ev = ev.browserEvent || ev;
2124 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2125 var t = ev.target || ev.srcElement;
2126 return this.resolveTextNode(t);
2130 resolveTextNode: function(node) {
2131 if (Roo.isSafari && node && 3 == node.nodeType) {
2132 return node.parentNode;
2139 getPageX: function(ev) {
2140 ev = ev.browserEvent || ev;
2141 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2143 if (!x && 0 !== x) {
2144 x = ev.clientX || 0;
2147 x += this.getScroll()[1];
2155 getPageY: function(ev) {
2156 ev = ev.browserEvent || ev;
2157 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2159 if (!y && 0 !== y) {
2160 y = ev.clientY || 0;
2163 y += this.getScroll()[0];
2172 getXY: function(ev) {
2173 ev = ev.browserEvent || ev;
2174 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2175 return [this.getPageX(ev), this.getPageY(ev)];
2179 getRelatedTarget: function(ev) {
2180 ev = ev.browserEvent || ev;
2181 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2182 var t = ev.relatedTarget;
2184 if (ev.type == "mouseout") {
2186 } else if (ev.type == "mouseover") {
2191 return this.resolveTextNode(t);
2195 getTime: function(ev) {
2196 ev = ev.browserEvent || ev;
2197 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2199 var t = new Date().getTime();
2203 this.lastError = ex;
2212 stopEvent: function(ev) {
2213 this.stopPropagation(ev);
2214 this.preventDefault(ev);
2218 stopPropagation: function(ev) {
2219 ev = ev.browserEvent || ev;
2220 if (ev.stopPropagation) {
2221 ev.stopPropagation();
2223 ev.cancelBubble = true;
2228 preventDefault: function(ev) {
2229 ev = ev.browserEvent || ev;
2230 if(ev.preventDefault) {
2231 ev.preventDefault();
2233 ev.returnValue = false;
2238 getEvent: function(e) {
2239 var ev = e || window.event;
2241 var c = this.getEvent.caller;
2243 ev = c.arguments[0];
2244 if (ev && Event == ev.constructor) {
2254 getCharCode: function(ev) {
2255 ev = ev.browserEvent || ev;
2256 return ev.charCode || ev.keyCode || 0;
2260 _getCacheIndex: function(el, eventName, fn) {
2261 for (var i = 0,len = listeners.length; i < len; ++i) {
2262 var li = listeners[i];
2264 li[this.FN] == fn &&
2265 li[this.EL] == el &&
2266 li[this.TYPE] == eventName) {
2278 getEl: function(id) {
2279 return document.getElementById(id);
2283 clearCache: function() {
2287 _load: function(e) {
2288 loadComplete = true;
2289 var EU = Roo.lib.Event;
2293 EU.doRemove(window, "load", EU._load);
2298 _tryPreloadAttach: function() {
2307 var tryAgain = !loadComplete;
2309 tryAgain = (retryCount > 0);
2314 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2315 var item = onAvailStack[i];
2317 var el = this.getEl(item.id);
2320 if (!item.checkReady ||
2323 (document && document.body)) {
2326 if (item.override) {
2327 if (item.override === true) {
2330 scope = item.override;
2333 item.fn.call(scope, item.obj);
2334 onAvailStack[i] = null;
2337 notAvail.push(item);
2342 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2346 this.startInterval();
2348 clearInterval(this._interval);
2349 this._interval = null;
2352 this.locked = false;
2359 purgeElement: function(el, recurse, eventName) {
2360 var elListeners = this.getListeners(el, eventName);
2362 for (var i = 0,len = elListeners.length; i < len; ++i) {
2363 var l = elListeners[i];
2364 this.removeListener(el, l.type, l.fn);
2368 if (recurse && el && el.childNodes) {
2369 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2370 this.purgeElement(el.childNodes[i], recurse, eventName);
2376 getListeners: function(el, eventName) {
2377 var results = [], searchLists;
2379 searchLists = [listeners, unloadListeners];
2380 } else if (eventName == "unload") {
2381 searchLists = [unloadListeners];
2383 searchLists = [listeners];
2386 for (var j = 0; j < searchLists.length; ++j) {
2387 var searchList = searchLists[j];
2388 if (searchList && searchList.length > 0) {
2389 for (var i = 0,len = searchList.length; i < len; ++i) {
2390 var l = searchList[i];
2391 if (l && l[this.EL] === el &&
2392 (!eventName || eventName === l[this.TYPE])) {
2397 adjust: l[this.ADJ_SCOPE],
2405 return (results.length) ? results : null;
2409 _unload: function(e) {
2411 var EU = Roo.lib.Event, i, j, l, len, index;
2413 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2414 l = unloadListeners[i];
2417 if (l[EU.ADJ_SCOPE]) {
2418 if (l[EU.ADJ_SCOPE] === true) {
2421 scope = l[EU.ADJ_SCOPE];
2424 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2425 unloadListeners[i] = null;
2431 unloadListeners = null;
2433 if (listeners && listeners.length > 0) {
2434 j = listeners.length;
2437 l = listeners[index];
2439 EU.removeListener(l[EU.EL], l[EU.TYPE],
2449 EU.doRemove(window, "unload", EU._unload);
2454 getScroll: function() {
2455 var dd = document.documentElement, db = document.body;
2456 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2457 return [dd.scrollTop, dd.scrollLeft];
2459 return [db.scrollTop, db.scrollLeft];
2466 doAdd: function () {
2467 if (window.addEventListener) {
2468 return function(el, eventName, fn, capture) {
2469 el.addEventListener(eventName, fn, (capture));
2471 } else if (window.attachEvent) {
2472 return function(el, eventName, fn, capture) {
2473 el.attachEvent("on" + eventName, fn);
2482 doRemove: function() {
2483 if (window.removeEventListener) {
2484 return function (el, eventName, fn, capture) {
2485 el.removeEventListener(eventName, fn, (capture));
2487 } else if (window.detachEvent) {
2488 return function (el, eventName, fn) {
2489 el.detachEvent("on" + eventName, fn);
2501 var E = Roo.lib.Event;
2502 E.on = E.addListener;
2503 E.un = E.removeListener;
2505 if (document && document.body) {
2508 E.doAdd(window, "load", E._load);
2510 E.doAdd(window, "unload", E._unload);
2511 E._tryPreloadAttach();
2515 * Portions of this file are based on pieces of Yahoo User Interface Library
2516 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2517 * YUI licensed under the BSD License:
2518 * http://developer.yahoo.net/yui/license.txt
2519 * <script type="text/javascript">
2525 * @class Roo.lib.Ajax
2532 request : function(method, uri, cb, data, options) {
2534 var hs = options.headers;
2537 if(hs.hasOwnProperty(h)){
2538 this.initHeader(h, hs[h], false);
2542 if(options.xmlData){
2543 this.initHeader('Content-Type', 'text/xml', false);
2545 data = options.xmlData;
2549 return this.asyncRequest(method, uri, cb, data);
2552 serializeForm : function(form) {
2553 if(typeof form == 'string') {
2554 form = (document.getElementById(form) || document.forms[form]);
2557 var el, name, val, disabled, data = '', hasSubmit = false;
2558 for (var i = 0; i < form.elements.length; i++) {
2559 el = form.elements[i];
2560 disabled = form.elements[i].disabled;
2561 name = form.elements[i].name;
2562 val = form.elements[i].value;
2564 if (!disabled && name){
2568 case 'select-multiple':
2569 for (var j = 0; j < el.options.length; j++) {
2570 if (el.options[j].selected) {
2572 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2575 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2583 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2596 if(hasSubmit == false) {
2597 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2602 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2607 data = data.substr(0, data.length - 1);
2615 useDefaultHeader:true,
2617 defaultPostHeader:'application/x-www-form-urlencoded',
2619 useDefaultXhrHeader:true,
2621 defaultXhrHeader:'XMLHttpRequest',
2623 hasDefaultHeaders:true,
2635 setProgId:function(id)
2637 this.activeX.unshift(id);
2640 setDefaultPostHeader:function(b)
2642 this.useDefaultHeader = b;
2645 setDefaultXhrHeader:function(b)
2647 this.useDefaultXhrHeader = b;
2650 setPollingInterval:function(i)
2652 if (typeof i == 'number' && isFinite(i)) {
2653 this.pollInterval = i;
2657 createXhrObject:function(transactionId)
2663 http = new XMLHttpRequest();
2665 obj = { conn:http, tId:transactionId };
2669 for (var i = 0; i < this.activeX.length; ++i) {
2673 http = new ActiveXObject(this.activeX[i]);
2675 obj = { conn:http, tId:transactionId };
2688 getConnectionObject:function()
2691 var tId = this.transactionId;
2695 o = this.createXhrObject(tId);
2697 this.transactionId++;
2708 asyncRequest:function(method, uri, callback, postData)
2710 var o = this.getConnectionObject();
2716 o.conn.open(method, uri, true);
2718 if (this.useDefaultXhrHeader) {
2719 if (!this.defaultHeaders['X-Requested-With']) {
2720 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2724 if(postData && this.useDefaultHeader){
2725 this.initHeader('Content-Type', this.defaultPostHeader);
2728 if (this.hasDefaultHeaders || this.hasHeaders) {
2732 this.handleReadyState(o, callback);
2733 o.conn.send(postData || null);
2739 handleReadyState:function(o, callback)
2743 if (callback && callback.timeout) {
2745 this.timeout[o.tId] = window.setTimeout(function() {
2746 oConn.abort(o, callback, true);
2747 }, callback.timeout);
2750 this.poll[o.tId] = window.setInterval(
2752 if (o.conn && o.conn.readyState == 4) {
2753 window.clearInterval(oConn.poll[o.tId]);
2754 delete oConn.poll[o.tId];
2756 if(callback && callback.timeout) {
2757 window.clearTimeout(oConn.timeout[o.tId]);
2758 delete oConn.timeout[o.tId];
2761 oConn.handleTransactionResponse(o, callback);
2764 , this.pollInterval);
2767 handleTransactionResponse:function(o, callback, isAbort)
2771 this.releaseObject(o);
2775 var httpStatus, responseObject;
2779 if (o.conn.status !== undefined && o.conn.status != 0) {
2780 httpStatus = o.conn.status;
2792 if (httpStatus >= 200 && httpStatus < 300) {
2793 responseObject = this.createResponseObject(o, callback.argument);
2794 if (callback.success) {
2795 if (!callback.scope) {
2796 callback.success(responseObject);
2801 callback.success.apply(callback.scope, [responseObject]);
2806 switch (httpStatus) {
2814 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2815 if (callback.failure) {
2816 if (!callback.scope) {
2817 callback.failure(responseObject);
2820 callback.failure.apply(callback.scope, [responseObject]);
2825 responseObject = this.createResponseObject(o, callback.argument);
2826 if (callback.failure) {
2827 if (!callback.scope) {
2828 callback.failure(responseObject);
2831 callback.failure.apply(callback.scope, [responseObject]);
2837 this.releaseObject(o);
2838 responseObject = null;
2841 createResponseObject:function(o, callbackArg)
2848 var headerStr = o.conn.getAllResponseHeaders();
2849 var header = headerStr.split('\n');
2850 for (var i = 0; i < header.length; i++) {
2851 var delimitPos = header[i].indexOf(':');
2852 if (delimitPos != -1) {
2853 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2861 obj.status = o.conn.status;
2862 obj.statusText = o.conn.statusText;
2863 obj.getResponseHeader = headerObj;
2864 obj.getAllResponseHeaders = headerStr;
2865 obj.responseText = o.conn.responseText;
2866 obj.responseXML = o.conn.responseXML;
2868 if (typeof callbackArg !== undefined) {
2869 obj.argument = callbackArg;
2875 createExceptionObject:function(tId, callbackArg, isAbort)
2878 var COMM_ERROR = 'communication failure';
2879 var ABORT_CODE = -1;
2880 var ABORT_ERROR = 'transaction aborted';
2886 obj.status = ABORT_CODE;
2887 obj.statusText = ABORT_ERROR;
2890 obj.status = COMM_CODE;
2891 obj.statusText = COMM_ERROR;
2895 obj.argument = callbackArg;
2901 initHeader:function(label, value, isDefault)
2903 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2905 if (headerObj[label] === undefined) {
2906 headerObj[label] = value;
2911 headerObj[label] = value + "," + headerObj[label];
2915 this.hasDefaultHeaders = true;
2918 this.hasHeaders = true;
2923 setHeader:function(o)
2925 if (this.hasDefaultHeaders) {
2926 for (var prop in this.defaultHeaders) {
2927 if (this.defaultHeaders.hasOwnProperty(prop)) {
2928 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2933 if (this.hasHeaders) {
2934 for (var prop in this.headers) {
2935 if (this.headers.hasOwnProperty(prop)) {
2936 o.conn.setRequestHeader(prop, this.headers[prop]);
2940 this.hasHeaders = false;
2944 resetDefaultHeaders:function() {
2945 delete this.defaultHeaders;
2946 this.defaultHeaders = {};
2947 this.hasDefaultHeaders = false;
2950 abort:function(o, callback, isTimeout)
2952 if(this.isCallInProgress(o)) {
2954 window.clearInterval(this.poll[o.tId]);
2955 delete this.poll[o.tId];
2957 delete this.timeout[o.tId];
2960 this.handleTransactionResponse(o, callback, true);
2970 isCallInProgress:function(o)
2973 return o.conn.readyState != 4 && o.conn.readyState != 0;
2982 releaseObject:function(o)
2991 'MSXML2.XMLHTTP.3.0',
2999 * Portions of this file are based on pieces of Yahoo User Interface Library
3000 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3001 * YUI licensed under the BSD License:
3002 * http://developer.yahoo.net/yui/license.txt
3003 * <script type="text/javascript">
3007 Roo.lib.Region = function(t, r, b, l) {
3017 Roo.lib.Region.prototype = {
3018 contains : function(region) {
3019 return ( region.left >= this.left &&
3020 region.right <= this.right &&
3021 region.top >= this.top &&
3022 region.bottom <= this.bottom );
3026 getArea : function() {
3027 return ( (this.bottom - this.top) * (this.right - this.left) );
3030 intersect : function(region) {
3031 var t = Math.max(this.top, region.top);
3032 var r = Math.min(this.right, region.right);
3033 var b = Math.min(this.bottom, region.bottom);
3034 var l = Math.max(this.left, region.left);
3036 if (b >= t && r >= l) {
3037 return new Roo.lib.Region(t, r, b, l);
3042 union : function(region) {
3043 var t = Math.min(this.top, region.top);
3044 var r = Math.max(this.right, region.right);
3045 var b = Math.max(this.bottom, region.bottom);
3046 var l = Math.min(this.left, region.left);
3048 return new Roo.lib.Region(t, r, b, l);
3051 adjust : function(t, l, b, r) {
3060 Roo.lib.Region.getRegion = function(el) {
3061 var p = Roo.lib.Dom.getXY(el);
3064 var r = p[0] + el.offsetWidth;
3065 var b = p[1] + el.offsetHeight;
3068 return new Roo.lib.Region(t, r, b, l);
3071 * Portions of this file are based on pieces of Yahoo User Interface Library
3072 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3073 * YUI licensed under the BSD License:
3074 * http://developer.yahoo.net/yui/license.txt
3075 * <script type="text/javascript">
3078 //@@dep Roo.lib.Region
3081 Roo.lib.Point = function(x, y) {
3082 if (x instanceof Array) {
3086 this.x = this.right = this.left = this[0] = x;
3087 this.y = this.top = this.bottom = this[1] = y;
3090 Roo.lib.Point.prototype = new Roo.lib.Region();
3092 * Portions of this file are based on pieces of Yahoo User Interface Library
3093 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3094 * YUI licensed under the BSD License:
3095 * http://developer.yahoo.net/yui/license.txt
3096 * <script type="text/javascript">
3103 scroll : function(el, args, duration, easing, cb, scope) {
3104 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3107 motion : function(el, args, duration, easing, cb, scope) {
3108 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3111 color : function(el, args, duration, easing, cb, scope) {
3112 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3115 run : function(el, args, duration, easing, cb, scope, type) {
3116 type = type || Roo.lib.AnimBase;
3117 if (typeof easing == "string") {
3118 easing = Roo.lib.Easing[easing];
3120 var anim = new type(el, args, duration, easing);
3121 anim.animateX(function() {
3122 Roo.callback(cb, scope);
3128 * Portions of this file are based on pieces of Yahoo User Interface Library
3129 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3130 * YUI licensed under the BSD License:
3131 * http://developer.yahoo.net/yui/license.txt
3132 * <script type="text/javascript">
3140 if (!libFlyweight) {
3141 libFlyweight = new Roo.Element.Flyweight();
3143 libFlyweight.dom = el;
3144 return libFlyweight;
3147 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3151 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3153 this.init(el, attributes, duration, method);
3157 Roo.lib.AnimBase.fly = fly;
3161 Roo.lib.AnimBase.prototype = {
3163 toString: function() {
3164 var el = this.getEl();
3165 var id = el.id || el.tagName;
3166 return ("Anim " + id);
3170 noNegatives: /width|height|opacity|padding/i,
3171 offsetAttribute: /^((width|height)|(top|left))$/,
3172 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3173 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3177 doMethod: function(attr, start, end) {
3178 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3182 setAttribute: function(attr, val, unit) {
3183 if (this.patterns.noNegatives.test(attr)) {
3184 val = (val > 0) ? val : 0;
3187 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3191 getAttribute: function(attr) {
3192 var el = this.getEl();
3193 var val = fly(el).getStyle(attr);
3195 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3196 return parseFloat(val);
3199 var a = this.patterns.offsetAttribute.exec(attr) || [];
3200 var pos = !!( a[3] );
3201 var box = !!( a[2] );
3204 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3205 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3214 getDefaultUnit: function(attr) {
3215 if (this.patterns.defaultUnit.test(attr)) {
3222 animateX : function(callback, scope) {
3223 var f = function() {
3224 this.onComplete.removeListener(f);
3225 if (typeof callback == "function") {
3226 callback.call(scope || this, this);
3229 this.onComplete.addListener(f, this);
3234 setRuntimeAttribute: function(attr) {
3237 var attributes = this.attributes;
3239 this.runtimeAttributes[attr] = {};
3241 var isset = function(prop) {
3242 return (typeof prop !== 'undefined');
3245 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3249 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3252 if (isset(attributes[attr]['to'])) {
3253 end = attributes[attr]['to'];
3254 } else if (isset(attributes[attr]['by'])) {
3255 if (start.constructor == Array) {
3257 for (var i = 0, len = start.length; i < len; ++i) {
3258 end[i] = start[i] + attributes[attr]['by'][i];
3261 end = start + attributes[attr]['by'];
3265 this.runtimeAttributes[attr].start = start;
3266 this.runtimeAttributes[attr].end = end;
3269 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3273 init: function(el, attributes, duration, method) {
3275 var isAnimated = false;
3278 var startTime = null;
3281 var actualFrames = 0;
3284 el = Roo.getDom(el);
3287 this.attributes = attributes || {};
3290 this.duration = duration || 1;
3293 this.method = method || Roo.lib.Easing.easeNone;
3296 this.useSeconds = true;
3299 this.currentFrame = 0;
3302 this.totalFrames = Roo.lib.AnimMgr.fps;
3305 this.getEl = function() {
3310 this.isAnimated = function() {
3315 this.getStartTime = function() {
3319 this.runtimeAttributes = {};
3322 this.animate = function() {
3323 if (this.isAnimated()) {
3327 this.currentFrame = 0;
3329 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3331 Roo.lib.AnimMgr.registerElement(this);
3335 this.stop = function(finish) {
3337 this.currentFrame = this.totalFrames;
3338 this._onTween.fire();
3340 Roo.lib.AnimMgr.stop(this);
3343 var onStart = function() {
3344 this.onStart.fire();
3346 this.runtimeAttributes = {};
3347 for (var attr in this.attributes) {
3348 this.setRuntimeAttribute(attr);
3353 startTime = new Date();
3357 var onTween = function() {
3359 duration: new Date() - this.getStartTime(),
3360 currentFrame: this.currentFrame
3363 data.toString = function() {
3365 'duration: ' + data.duration +
3366 ', currentFrame: ' + data.currentFrame
3370 this.onTween.fire(data);
3372 var runtimeAttributes = this.runtimeAttributes;
3374 for (var attr in runtimeAttributes) {
3375 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3381 var onComplete = function() {
3382 var actual_duration = (new Date() - startTime) / 1000 ;
3385 duration: actual_duration,
3386 frames: actualFrames,
3387 fps: actualFrames / actual_duration
3390 data.toString = function() {
3392 'duration: ' + data.duration +
3393 ', frames: ' + data.frames +
3394 ', fps: ' + data.fps
3400 this.onComplete.fire(data);
3404 this._onStart = new Roo.util.Event(this);
3405 this.onStart = new Roo.util.Event(this);
3406 this.onTween = new Roo.util.Event(this);
3407 this._onTween = new Roo.util.Event(this);
3408 this.onComplete = new Roo.util.Event(this);
3409 this._onComplete = new Roo.util.Event(this);
3410 this._onStart.addListener(onStart);
3411 this._onTween.addListener(onTween);
3412 this._onComplete.addListener(onComplete);
3417 * Portions of this file are based on pieces of Yahoo User Interface Library
3418 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3419 * YUI licensed under the BSD License:
3420 * http://developer.yahoo.net/yui/license.txt
3421 * <script type="text/javascript">
3425 Roo.lib.AnimMgr = new function() {
3442 this.registerElement = function(tween) {
3443 queue[queue.length] = tween;
3445 tween._onStart.fire();
3450 this.unRegister = function(tween, index) {
3451 tween._onComplete.fire();
3452 index = index || getIndex(tween);
3454 queue.splice(index, 1);
3458 if (tweenCount <= 0) {
3464 this.start = function() {
3465 if (thread === null) {
3466 thread = setInterval(this.run, this.delay);
3471 this.stop = function(tween) {
3473 clearInterval(thread);
3475 for (var i = 0, len = queue.length; i < len; ++i) {
3476 if (queue[0].isAnimated()) {
3477 this.unRegister(queue[0], 0);
3486 this.unRegister(tween);
3491 this.run = function() {
3492 for (var i = 0, len = queue.length; i < len; ++i) {
3493 var tween = queue[i];
3494 if (!tween || !tween.isAnimated()) {
3498 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3500 tween.currentFrame += 1;
3502 if (tween.useSeconds) {
3503 correctFrame(tween);
3505 tween._onTween.fire();
3508 Roo.lib.AnimMgr.stop(tween, i);
3513 var getIndex = function(anim) {
3514 for (var i = 0, len = queue.length; i < len; ++i) {
3515 if (queue[i] == anim) {
3523 var correctFrame = function(tween) {
3524 var frames = tween.totalFrames;
3525 var frame = tween.currentFrame;
3526 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3527 var elapsed = (new Date() - tween.getStartTime());
3530 if (elapsed < tween.duration * 1000) {
3531 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3533 tweak = frames - (frame + 1);
3535 if (tweak > 0 && isFinite(tweak)) {
3536 if (tween.currentFrame + tweak >= frames) {
3537 tweak = frames - (frame + 1);
3540 tween.currentFrame += tweak;
3546 * Portions of this file are based on pieces of Yahoo User Interface Library
3547 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3548 * YUI licensed under the BSD License:
3549 * http://developer.yahoo.net/yui/license.txt
3550 * <script type="text/javascript">
3553 Roo.lib.Bezier = new function() {
3555 this.getPosition = function(points, t) {
3556 var n = points.length;
3559 for (var i = 0; i < n; ++i) {
3560 tmp[i] = [points[i][0], points[i][1]];
3563 for (var j = 1; j < n; ++j) {
3564 for (i = 0; i < n - j; ++i) {
3565 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3566 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3570 return [ tmp[0][0], tmp[0][1] ];
3574 * Portions of this file are based on pieces of Yahoo User Interface Library
3575 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3576 * YUI licensed under the BSD License:
3577 * http://developer.yahoo.net/yui/license.txt
3578 * <script type="text/javascript">
3583 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3584 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3587 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3589 var fly = Roo.lib.AnimBase.fly;
3591 var superclass = Y.ColorAnim.superclass;
3592 var proto = Y.ColorAnim.prototype;
3594 proto.toString = function() {
3595 var el = this.getEl();
3596 var id = el.id || el.tagName;
3597 return ("ColorAnim " + id);
3600 proto.patterns.color = /color$/i;
3601 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3602 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3603 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3604 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3607 proto.parseColor = function(s) {
3608 if (s.length == 3) {
3612 var c = this.patterns.hex.exec(s);
3613 if (c && c.length == 4) {
3614 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3617 c = this.patterns.rgb.exec(s);
3618 if (c && c.length == 4) {
3619 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3622 c = this.patterns.hex3.exec(s);
3623 if (c && c.length == 4) {
3624 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3629 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3630 proto.getAttribute = function(attr) {
3631 var el = this.getEl();
3632 if (this.patterns.color.test(attr)) {
3633 var val = fly(el).getStyle(attr);
3635 if (this.patterns.transparent.test(val)) {
3636 var parent = el.parentNode;
3637 val = fly(parent).getStyle(attr);
3639 while (parent && this.patterns.transparent.test(val)) {
3640 parent = parent.parentNode;
3641 val = fly(parent).getStyle(attr);
3642 if (parent.tagName.toUpperCase() == 'HTML') {
3648 val = superclass.getAttribute.call(this, attr);
3653 proto.getAttribute = function(attr) {
3654 var el = this.getEl();
3655 if (this.patterns.color.test(attr)) {
3656 var val = fly(el).getStyle(attr);
3658 if (this.patterns.transparent.test(val)) {
3659 var parent = el.parentNode;
3660 val = fly(parent).getStyle(attr);
3662 while (parent && this.patterns.transparent.test(val)) {
3663 parent = parent.parentNode;
3664 val = fly(parent).getStyle(attr);
3665 if (parent.tagName.toUpperCase() == 'HTML') {
3671 val = superclass.getAttribute.call(this, attr);
3677 proto.doMethod = function(attr, start, end) {
3680 if (this.patterns.color.test(attr)) {
3682 for (var i = 0, len = start.length; i < len; ++i) {
3683 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3686 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3689 val = superclass.doMethod.call(this, attr, start, end);
3695 proto.setRuntimeAttribute = function(attr) {
3696 superclass.setRuntimeAttribute.call(this, attr);
3698 if (this.patterns.color.test(attr)) {
3699 var attributes = this.attributes;
3700 var start = this.parseColor(this.runtimeAttributes[attr].start);
3701 var end = this.parseColor(this.runtimeAttributes[attr].end);
3703 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3704 end = this.parseColor(attributes[attr].by);
3706 for (var i = 0, len = start.length; i < len; ++i) {
3707 end[i] = start[i] + end[i];
3711 this.runtimeAttributes[attr].start = start;
3712 this.runtimeAttributes[attr].end = end;
3718 * Portions of this file are based on pieces of Yahoo User Interface Library
3719 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3720 * YUI licensed under the BSD License:
3721 * http://developer.yahoo.net/yui/license.txt
3722 * <script type="text/javascript">
3728 easeNone: function (t, b, c, d) {
3729 return c * t / d + b;
3733 easeIn: function (t, b, c, d) {
3734 return c * (t /= d) * t + b;
3738 easeOut: function (t, b, c, d) {
3739 return -c * (t /= d) * (t - 2) + b;
3743 easeBoth: function (t, b, c, d) {
3744 if ((t /= d / 2) < 1) {
3745 return c / 2 * t * t + b;
3748 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3752 easeInStrong: function (t, b, c, d) {
3753 return c * (t /= d) * t * t * t + b;
3757 easeOutStrong: function (t, b, c, d) {
3758 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3762 easeBothStrong: function (t, b, c, d) {
3763 if ((t /= d / 2) < 1) {
3764 return c / 2 * t * t * t * t + b;
3767 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3772 elasticIn: function (t, b, c, d, a, p) {
3776 if ((t /= d) == 1) {
3783 if (!a || a < Math.abs(c)) {
3788 var s = p / (2 * Math.PI) * Math.asin(c / a);
3791 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3795 elasticOut: function (t, b, c, d, a, p) {
3799 if ((t /= d) == 1) {
3806 if (!a || a < Math.abs(c)) {
3811 var s = p / (2 * Math.PI) * Math.asin(c / a);
3814 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3818 elasticBoth: function (t, b, c, d, a, p) {
3823 if ((t /= d / 2) == 2) {
3831 if (!a || a < Math.abs(c)) {
3836 var s = p / (2 * Math.PI) * Math.asin(c / a);
3840 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3841 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3843 return a * Math.pow(2, -10 * (t -= 1)) *
3844 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3849 backIn: function (t, b, c, d, s) {
3850 if (typeof s == 'undefined') {
3853 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3857 backOut: function (t, b, c, d, s) {
3858 if (typeof s == 'undefined') {
3861 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3865 backBoth: function (t, b, c, d, s) {
3866 if (typeof s == 'undefined') {
3870 if ((t /= d / 2 ) < 1) {
3871 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3873 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3877 bounceIn: function (t, b, c, d) {
3878 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3882 bounceOut: function (t, b, c, d) {
3883 if ((t /= d) < (1 / 2.75)) {
3884 return c * (7.5625 * t * t) + b;
3885 } else if (t < (2 / 2.75)) {
3886 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3887 } else if (t < (2.5 / 2.75)) {
3888 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3890 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3894 bounceBoth: function (t, b, c, d) {
3896 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3898 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3901 * Portions of this file are based on pieces of Yahoo User Interface Library
3902 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3903 * YUI licensed under the BSD License:
3904 * http://developer.yahoo.net/yui/license.txt
3905 * <script type="text/javascript">
3909 Roo.lib.Motion = function(el, attributes, duration, method) {
3911 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3915 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3919 var superclass = Y.Motion.superclass;
3920 var proto = Y.Motion.prototype;
3922 proto.toString = function() {
3923 var el = this.getEl();
3924 var id = el.id || el.tagName;
3925 return ("Motion " + id);
3928 proto.patterns.points = /^points$/i;
3930 proto.setAttribute = function(attr, val, unit) {
3931 if (this.patterns.points.test(attr)) {
3932 unit = unit || 'px';
3933 superclass.setAttribute.call(this, 'left', val[0], unit);
3934 superclass.setAttribute.call(this, 'top', val[1], unit);
3936 superclass.setAttribute.call(this, attr, val, unit);
3940 proto.getAttribute = function(attr) {
3941 if (this.patterns.points.test(attr)) {
3943 superclass.getAttribute.call(this, 'left'),
3944 superclass.getAttribute.call(this, 'top')
3947 val = superclass.getAttribute.call(this, attr);
3953 proto.doMethod = function(attr, start, end) {
3956 if (this.patterns.points.test(attr)) {
3957 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3958 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3960 val = superclass.doMethod.call(this, attr, start, end);
3965 proto.setRuntimeAttribute = function(attr) {
3966 if (this.patterns.points.test(attr)) {
3967 var el = this.getEl();
3968 var attributes = this.attributes;
3970 var control = attributes['points']['control'] || [];
3974 if (control.length > 0 && !(control[0] instanceof Array)) {
3975 control = [control];
3978 for (i = 0,len = control.length; i < len; ++i) {
3979 tmp[i] = control[i];
3984 Roo.fly(el).position();
3986 if (isset(attributes['points']['from'])) {
3987 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3990 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3993 start = this.getAttribute('points');
3996 if (isset(attributes['points']['to'])) {
3997 end = translateValues.call(this, attributes['points']['to'], start);
3999 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4000 for (i = 0,len = control.length; i < len; ++i) {
4001 control[i] = translateValues.call(this, control[i], start);
4005 } else if (isset(attributes['points']['by'])) {
4006 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4008 for (i = 0,len = control.length; i < len; ++i) {
4009 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4013 this.runtimeAttributes[attr] = [start];
4015 if (control.length > 0) {
4016 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4019 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4022 superclass.setRuntimeAttribute.call(this, attr);
4026 var translateValues = function(val, start) {
4027 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4028 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4033 var isset = function(prop) {
4034 return (typeof prop !== 'undefined');
4038 * Portions of this file are based on pieces of Yahoo User Interface Library
4039 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4040 * YUI licensed under the BSD License:
4041 * http://developer.yahoo.net/yui/license.txt
4042 * <script type="text/javascript">
4046 Roo.lib.Scroll = function(el, attributes, duration, method) {
4048 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4052 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4056 var superclass = Y.Scroll.superclass;
4057 var proto = Y.Scroll.prototype;
4059 proto.toString = function() {
4060 var el = this.getEl();
4061 var id = el.id || el.tagName;
4062 return ("Scroll " + id);
4065 proto.doMethod = function(attr, start, end) {
4068 if (attr == 'scroll') {
4070 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4071 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4075 val = superclass.doMethod.call(this, attr, start, end);
4080 proto.getAttribute = function(attr) {
4082 var el = this.getEl();
4084 if (attr == 'scroll') {
4085 val = [ el.scrollLeft, el.scrollTop ];
4087 val = superclass.getAttribute.call(this, attr);
4093 proto.setAttribute = function(attr, val, unit) {
4094 var el = this.getEl();
4096 if (attr == 'scroll') {
4097 el.scrollLeft = val[0];
4098 el.scrollTop = val[1];
4100 superclass.setAttribute.call(this, attr, val, unit);
4106 * Ext JS Library 1.1.1
4107 * Copyright(c) 2006-2007, Ext JS, LLC.
4109 * Originally Released Under LGPL - original licence link has changed is not relivant.
4112 * <script type="text/javascript">
4116 // nasty IE9 hack - what a pile of crap that is..
4118 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4119 Range.prototype.createContextualFragment = function (html) {
4120 var doc = window.document;
4121 var container = doc.createElement("div");
4122 container.innerHTML = html;
4123 var frag = doc.createDocumentFragment(), n;
4124 while ((n = container.firstChild)) {
4125 frag.appendChild(n);
4132 * @class Roo.DomHelper
4133 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4134 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4137 Roo.DomHelper = function(){
4138 var tempTableEl = null;
4139 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4140 var tableRe = /^table|tbody|tr|td$/i;
4142 // build as innerHTML where available
4144 var createHtml = function(o){
4145 if(typeof o == 'string'){
4154 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4155 if(attr == "style"){
4157 if(typeof s == "function"){
4160 if(typeof s == "string"){
4161 b += ' style="' + s + '"';
4162 }else if(typeof s == "object"){
4165 if(typeof s[key] != "function"){
4166 b += key + ":" + s[key] + ";";
4173 b += ' class="' + o["cls"] + '"';
4174 }else if(attr == "htmlFor"){
4175 b += ' for="' + o["htmlFor"] + '"';
4177 b += " " + attr + '="' + o[attr] + '"';
4181 if(emptyTags.test(o.tag)){
4185 var cn = o.children || o.cn;
4187 //http://bugs.kde.org/show_bug.cgi?id=71506
4188 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4189 for(var i = 0, len = cn.length; i < len; i++) {
4190 b += createHtml(cn[i], b);
4193 b += createHtml(cn, b);
4199 b += "</" + o.tag + ">";
4206 var createDom = function(o, parentNode){
4208 // defininition craeted..
4210 if (o.ns && o.ns != 'html') {
4212 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4213 xmlns[o.ns] = o.xmlns;
4216 if (typeof(xmlns[o.ns]) == 'undefined') {
4217 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4223 if (typeof(o) == 'string') {
4224 return parentNode.appendChild(document.createTextNode(o));
4226 o.tag = o.tag || div;
4227 if (o.ns && Roo.isIE) {
4229 o.tag = o.ns + ':' + o.tag;
4232 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4233 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4236 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4237 attr == "style" || typeof o[attr] == "function") continue;
4239 if(attr=="cls" && Roo.isIE){
4240 el.className = o["cls"];
4242 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4248 Roo.DomHelper.applyStyles(el, o.style);
4249 var cn = o.children || o.cn;
4251 //http://bugs.kde.org/show_bug.cgi?id=71506
4252 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4253 for(var i = 0, len = cn.length; i < len; i++) {
4254 createDom(cn[i], el);
4261 el.innerHTML = o.html;
4264 parentNode.appendChild(el);
4269 var ieTable = function(depth, s, h, e){
4270 tempTableEl.innerHTML = [s, h, e].join('');
4271 var i = -1, el = tempTableEl;
4278 // kill repeat to save bytes
4282 tbe = '</tbody>'+te,
4288 * Nasty code for IE's broken table implementation
4290 var insertIntoTable = function(tag, where, el, html){
4292 tempTableEl = document.createElement('div');
4297 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4300 if(where == 'beforebegin'){
4304 before = el.nextSibling;
4307 node = ieTable(4, trs, html, tre);
4309 else if(tag == 'tr'){
4310 if(where == 'beforebegin'){
4313 node = ieTable(3, tbs, html, tbe);
4314 } else if(where == 'afterend'){
4315 before = el.nextSibling;
4317 node = ieTable(3, tbs, html, tbe);
4318 } else{ // INTO a TR
4319 if(where == 'afterbegin'){
4320 before = el.firstChild;
4322 node = ieTable(4, trs, html, tre);
4324 } else if(tag == 'tbody'){
4325 if(where == 'beforebegin'){
4328 node = ieTable(2, ts, html, te);
4329 } else if(where == 'afterend'){
4330 before = el.nextSibling;
4332 node = ieTable(2, ts, html, te);
4334 if(where == 'afterbegin'){
4335 before = el.firstChild;
4337 node = ieTable(3, tbs, html, tbe);
4340 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4343 if(where == 'afterbegin'){
4344 before = el.firstChild;
4346 node = ieTable(2, ts, html, te);
4348 el.insertBefore(node, before);
4353 /** True to force the use of DOM instead of html fragments @type Boolean */
4357 * Returns the markup for the passed Element(s) config
4358 * @param {Object} o The Dom object spec (and children)
4361 markup : function(o){
4362 return createHtml(o);
4366 * Applies a style specification to an element
4367 * @param {String/HTMLElement} el The element to apply styles to
4368 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4369 * a function which returns such a specification.
4371 applyStyles : function(el, styles){
4374 if(typeof styles == "string"){
4375 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4377 while ((matches = re.exec(styles)) != null){
4378 el.setStyle(matches[1], matches[2]);
4380 }else if (typeof styles == "object"){
4381 for (var style in styles){
4382 el.setStyle(style, styles[style]);
4384 }else if (typeof styles == "function"){
4385 Roo.DomHelper.applyStyles(el, styles.call());
4391 * Inserts an HTML fragment into the Dom
4392 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4393 * @param {HTMLElement} el The context element
4394 * @param {String} html The HTML fragmenet
4395 * @return {HTMLElement} The new node
4397 insertHtml : function(where, el, html){
4398 where = where.toLowerCase();
4399 if(el.insertAdjacentHTML){
4400 if(tableRe.test(el.tagName)){
4402 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4408 el.insertAdjacentHTML('BeforeBegin', html);
4409 return el.previousSibling;
4411 el.insertAdjacentHTML('AfterBegin', html);
4412 return el.firstChild;
4414 el.insertAdjacentHTML('BeforeEnd', html);
4415 return el.lastChild;
4417 el.insertAdjacentHTML('AfterEnd', html);
4418 return el.nextSibling;
4420 throw 'Illegal insertion point -> "' + where + '"';
4422 var range = el.ownerDocument.createRange();
4426 range.setStartBefore(el);
4427 frag = range.createContextualFragment(html);
4428 el.parentNode.insertBefore(frag, el);
4429 return el.previousSibling;
4432 range.setStartBefore(el.firstChild);
4433 frag = range.createContextualFragment(html);
4434 el.insertBefore(frag, el.firstChild);
4435 return el.firstChild;
4437 el.innerHTML = html;
4438 return el.firstChild;
4442 range.setStartAfter(el.lastChild);
4443 frag = range.createContextualFragment(html);
4444 el.appendChild(frag);
4445 return el.lastChild;
4447 el.innerHTML = html;
4448 return el.lastChild;
4451 range.setStartAfter(el);
4452 frag = range.createContextualFragment(html);
4453 el.parentNode.insertBefore(frag, el.nextSibling);
4454 return el.nextSibling;
4456 throw 'Illegal insertion point -> "' + where + '"';
4460 * Creates new Dom element(s) and inserts them before el
4461 * @param {String/HTMLElement/Element} el The context element
4462 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4463 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4464 * @return {HTMLElement/Roo.Element} The new node
4466 insertBefore : function(el, o, returnElement){
4467 return this.doInsert(el, o, returnElement, "beforeBegin");
4471 * Creates new Dom element(s) and inserts them after el
4472 * @param {String/HTMLElement/Element} el The context element
4473 * @param {Object} o The Dom object spec (and children)
4474 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4475 * @return {HTMLElement/Roo.Element} The new node
4477 insertAfter : function(el, o, returnElement){
4478 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4482 * Creates new Dom element(s) and inserts them as the first child of el
4483 * @param {String/HTMLElement/Element} el The context element
4484 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4485 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4486 * @return {HTMLElement/Roo.Element} The new node
4488 insertFirst : function(el, o, returnElement){
4489 return this.doInsert(el, o, returnElement, "afterBegin");
4493 doInsert : function(el, o, returnElement, pos, sibling){
4494 el = Roo.getDom(el);
4496 if(this.useDom || o.ns){
4497 newNode = createDom(o, null);
4498 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4500 var html = createHtml(o);
4501 newNode = this.insertHtml(pos, el, html);
4503 return returnElement ? Roo.get(newNode, true) : newNode;
4507 * Creates new Dom element(s) and appends them to el
4508 * @param {String/HTMLElement/Element} el The context element
4509 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4510 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4511 * @return {HTMLElement/Roo.Element} The new node
4513 append : function(el, o, returnElement){
4514 el = Roo.getDom(el);
4516 if(this.useDom || o.ns){
4517 newNode = createDom(o, null);
4518 el.appendChild(newNode);
4520 var html = createHtml(o);
4521 newNode = this.insertHtml("beforeEnd", el, html);
4523 return returnElement ? Roo.get(newNode, true) : newNode;
4527 * Creates new Dom element(s) and overwrites the contents of el with them
4528 * @param {String/HTMLElement/Element} el The context element
4529 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4530 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4531 * @return {HTMLElement/Roo.Element} The new node
4533 overwrite : function(el, o, returnElement){
4534 el = Roo.getDom(el);
4537 while (el.childNodes.length) {
4538 el.removeChild(el.firstChild);
4542 el.innerHTML = createHtml(o);
4545 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4549 * Creates a new Roo.DomHelper.Template from the Dom object spec
4550 * @param {Object} o The Dom object spec (and children)
4551 * @return {Roo.DomHelper.Template} The new template
4553 createTemplate : function(o){
4554 var html = createHtml(o);
4555 return new Roo.Template(html);
4561 * Ext JS Library 1.1.1
4562 * Copyright(c) 2006-2007, Ext JS, LLC.
4564 * Originally Released Under LGPL - original licence link has changed is not relivant.
4567 * <script type="text/javascript">
4571 * @class Roo.Template
4572 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4573 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4576 var t = new Roo.Template({
4577 html : '<div name="{id}">' +
4578 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4580 myformat: function (value, allValues) {
4581 return 'XX' + value;
4584 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4586 * For more information see this blog post with examples:
4587 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4588 - Create Elements using DOM, HTML fragments and Templates</a>.
4590 * @param {Object} cfg - Configuration object.
4592 Roo.Template = function(cfg){
4594 if(cfg instanceof Array){
4596 }else if(arguments.length > 1){
4597 cfg = Array.prototype.join.call(arguments, "");
4601 if (typeof(cfg) == 'object') {
4612 Roo.Template.prototype = {
4615 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4616 * it should be fixed so that template is observable...
4620 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4624 * Returns an HTML fragment of this template with the specified values applied.
4625 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4626 * @return {String} The HTML fragment
4628 applyTemplate : function(values){
4632 return this.compiled(values);
4634 var useF = this.disableFormats !== true;
4635 var fm = Roo.util.Format, tpl = this;
4636 var fn = function(m, name, format, args){
4638 if(format.substr(0, 5) == "this."){
4639 return tpl.call(format.substr(5), values[name], values);
4642 // quoted values are required for strings in compiled templates,
4643 // but for non compiled we need to strip them
4644 // quoted reversed for jsmin
4645 var re = /^\s*['"](.*)["']\s*$/;
4646 args = args.split(',');
4647 for(var i = 0, len = args.length; i < len; i++){
4648 args[i] = args[i].replace(re, "$1");
4650 args = [values[name]].concat(args);
4652 args = [values[name]];
4654 return fm[format].apply(fm, args);
4657 return values[name] !== undefined ? values[name] : "";
4660 return this.html.replace(this.re, fn);
4678 this.loading = true;
4679 this.compiled = false;
4681 var cx = new Roo.data.Connection();
4685 success : function (response) {
4687 _t.html = response.responseText;
4691 failure : function(response) {
4692 Roo.log("Template failed to load from " + _t.url);
4699 * Sets the HTML used as the template and optionally compiles it.
4700 * @param {String} html
4701 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4702 * @return {Roo.Template} this
4704 set : function(html, compile){
4706 this.compiled = null;
4714 * True to disable format functions (defaults to false)
4717 disableFormats : false,
4720 * The regular expression used to match template variables
4724 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4727 * Compiles the template into an internal function, eliminating the RegEx overhead.
4728 * @return {Roo.Template} this
4730 compile : function(){
4731 var fm = Roo.util.Format;
4732 var useF = this.disableFormats !== true;
4733 var sep = Roo.isGecko ? "+" : ",";
4734 var fn = function(m, name, format, args){
4736 args = args ? ',' + args : "";
4737 if(format.substr(0, 5) != "this."){
4738 format = "fm." + format + '(';
4740 format = 'this.call("'+ format.substr(5) + '", ';
4744 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4746 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4749 // branched to use + in gecko and [].join() in others
4751 body = "this.compiled = function(values){ return '" +
4752 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4755 body = ["this.compiled = function(values){ return ['"];
4756 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4757 body.push("'].join('');};");
4758 body = body.join('');
4768 // private function used to call members
4769 call : function(fnName, value, allValues){
4770 return this[fnName](value, allValues);
4774 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4775 * @param {String/HTMLElement/Roo.Element} el The context element
4776 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4777 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4778 * @return {HTMLElement/Roo.Element} The new node or Element
4780 insertFirst: function(el, values, returnElement){
4781 return this.doInsert('afterBegin', el, values, returnElement);
4785 * Applies the supplied values to the template and inserts the new node(s) before el.
4786 * @param {String/HTMLElement/Roo.Element} el The context element
4787 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4788 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4789 * @return {HTMLElement/Roo.Element} The new node or Element
4791 insertBefore: function(el, values, returnElement){
4792 return this.doInsert('beforeBegin', el, values, returnElement);
4796 * Applies the supplied values to the template and inserts the new node(s) after el.
4797 * @param {String/HTMLElement/Roo.Element} el The context element
4798 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4799 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4800 * @return {HTMLElement/Roo.Element} The new node or Element
4802 insertAfter : function(el, values, returnElement){
4803 return this.doInsert('afterEnd', el, values, returnElement);
4807 * Applies the supplied values to the template and appends the new node(s) to el.
4808 * @param {String/HTMLElement/Roo.Element} el The context element
4809 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4810 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4811 * @return {HTMLElement/Roo.Element} The new node or Element
4813 append : function(el, values, returnElement){
4814 return this.doInsert('beforeEnd', el, values, returnElement);
4817 doInsert : function(where, el, values, returnEl){
4818 el = Roo.getDom(el);
4819 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4820 return returnEl ? Roo.get(newNode, true) : newNode;
4824 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4825 * @param {String/HTMLElement/Roo.Element} el The context element
4826 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4827 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4828 * @return {HTMLElement/Roo.Element} The new node or Element
4830 overwrite : function(el, values, returnElement){
4831 el = Roo.getDom(el);
4832 el.innerHTML = this.applyTemplate(values);
4833 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4837 * Alias for {@link #applyTemplate}
4840 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4843 Roo.DomHelper.Template = Roo.Template;
4846 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4847 * @param {String/HTMLElement} el A DOM element or its id
4848 * @returns {Roo.Template} The created template
4851 Roo.Template.from = function(el){
4852 el = Roo.getDom(el);
4853 return new Roo.Template(el.value || el.innerHTML);
4856 * Ext JS Library 1.1.1
4857 * Copyright(c) 2006-2007, Ext JS, LLC.
4859 * Originally Released Under LGPL - original licence link has changed is not relivant.
4862 * <script type="text/javascript">
4867 * This is code is also distributed under MIT license for use
4868 * with jQuery and prototype JavaScript libraries.
4871 * @class Roo.DomQuery
4872 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4874 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4877 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4879 <h4>Element Selectors:</h4>
4881 <li> <b>*</b> any element</li>
4882 <li> <b>E</b> an element with the tag E</li>
4883 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4884 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4885 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4886 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4888 <h4>Attribute Selectors:</h4>
4889 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4891 <li> <b>E[foo]</b> has an attribute "foo"</li>
4892 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4893 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4894 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4895 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4896 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4897 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4899 <h4>Pseudo Classes:</h4>
4901 <li> <b>E:first-child</b> E is the first child of its parent</li>
4902 <li> <b>E:last-child</b> E is the last child of its parent</li>
4903 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4904 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4905 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4906 <li> <b>E:only-child</b> E is the only child of its parent</li>
4907 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4908 <li> <b>E:first</b> the first E in the resultset</li>
4909 <li> <b>E:last</b> the last E in the resultset</li>
4910 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4911 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4912 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4913 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4914 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4915 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4916 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4917 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4918 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4920 <h4>CSS Value Selectors:</h4>
4922 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4923 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4924 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4925 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4926 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4927 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4931 Roo.DomQuery = function(){
4932 var cache = {}, simpleCache = {}, valueCache = {};
4933 var nonSpace = /\S/;
4934 var trimRe = /^\s+|\s+$/g;
4935 var tplRe = /\{(\d+)\}/g;
4936 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4937 var tagTokenRe = /^(#)?([\w-\*]+)/;
4938 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4940 function child(p, index){
4942 var n = p.firstChild;
4944 if(n.nodeType == 1){
4955 while((n = n.nextSibling) && n.nodeType != 1);
4960 while((n = n.previousSibling) && n.nodeType != 1);
4964 function children(d){
4965 var n = d.firstChild, ni = -1;
4967 var nx = n.nextSibling;
4968 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4978 function byClassName(c, a, v){
4982 var r = [], ri = -1, cn;
4983 for(var i = 0, ci; ci = c[i]; i++){
4984 if((' '+ci.className+' ').indexOf(v) != -1){
4991 function attrValue(n, attr){
4992 if(!n.tagName && typeof n.length != "undefined"){
5001 if(attr == "class" || attr == "className"){
5004 return n.getAttribute(attr) || n[attr];
5008 function getNodes(ns, mode, tagName){
5009 var result = [], ri = -1, cs;
5013 tagName = tagName || "*";
5014 if(typeof ns.getElementsByTagName != "undefined"){
5018 for(var i = 0, ni; ni = ns[i]; i++){
5019 cs = ni.getElementsByTagName(tagName);
5020 for(var j = 0, ci; ci = cs[j]; j++){
5024 }else if(mode == "/" || mode == ">"){
5025 var utag = tagName.toUpperCase();
5026 for(var i = 0, ni, cn; ni = ns[i]; i++){
5027 cn = ni.children || ni.childNodes;
5028 for(var j = 0, cj; cj = cn[j]; j++){
5029 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5034 }else if(mode == "+"){
5035 var utag = tagName.toUpperCase();
5036 for(var i = 0, n; n = ns[i]; i++){
5037 while((n = n.nextSibling) && n.nodeType != 1);
5038 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5042 }else if(mode == "~"){
5043 for(var i = 0, n; n = ns[i]; i++){
5044 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5053 function concat(a, b){
5057 for(var i = 0, l = b.length; i < l; i++){
5063 function byTag(cs, tagName){
5064 if(cs.tagName || cs == document){
5070 var r = [], ri = -1;
5071 tagName = tagName.toLowerCase();
5072 for(var i = 0, ci; ci = cs[i]; i++){
5073 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5080 function byId(cs, attr, id){
5081 if(cs.tagName || cs == document){
5087 var r = [], ri = -1;
5088 for(var i = 0,ci; ci = cs[i]; i++){
5089 if(ci && ci.id == id){
5097 function byAttribute(cs, attr, value, op, custom){
5098 var r = [], ri = -1, st = custom=="{";
5099 var f = Roo.DomQuery.operators[op];
5100 for(var i = 0, ci; ci = cs[i]; i++){
5103 a = Roo.DomQuery.getStyle(ci, attr);
5105 else if(attr == "class" || attr == "className"){
5107 }else if(attr == "for"){
5109 }else if(attr == "href"){
5110 a = ci.getAttribute("href", 2);
5112 a = ci.getAttribute(attr);
5114 if((f && f(a, value)) || (!f && a)){
5121 function byPseudo(cs, name, value){
5122 return Roo.DomQuery.pseudos[name](cs, value);
5125 // This is for IE MSXML which does not support expandos.
5126 // IE runs the same speed using setAttribute, however FF slows way down
5127 // and Safari completely fails so they need to continue to use expandos.
5128 var isIE = window.ActiveXObject ? true : false;
5130 // this eval is stop the compressor from
5131 // renaming the variable to something shorter
5133 /** eval:var:batch */
5138 function nodupIEXml(cs){
5140 cs[0].setAttribute("_nodup", d);
5142 for(var i = 1, len = cs.length; i < len; i++){
5144 if(!c.getAttribute("_nodup") != d){
5145 c.setAttribute("_nodup", d);
5149 for(var i = 0, len = cs.length; i < len; i++){
5150 cs[i].removeAttribute("_nodup");
5159 var len = cs.length, c, i, r = cs, cj, ri = -1;
5160 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5163 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5164 return nodupIEXml(cs);
5168 for(i = 1; c = cs[i]; i++){
5173 for(var j = 0; j < i; j++){
5176 for(j = i+1; cj = cs[j]; j++){
5188 function quickDiffIEXml(c1, c2){
5190 for(var i = 0, len = c1.length; i < len; i++){
5191 c1[i].setAttribute("_qdiff", d);
5194 for(var i = 0, len = c2.length; i < len; i++){
5195 if(c2[i].getAttribute("_qdiff") != d){
5196 r[r.length] = c2[i];
5199 for(var i = 0, len = c1.length; i < len; i++){
5200 c1[i].removeAttribute("_qdiff");
5205 function quickDiff(c1, c2){
5206 var len1 = c1.length;
5210 if(isIE && c1[0].selectSingleNode){
5211 return quickDiffIEXml(c1, c2);
5214 for(var i = 0; i < len1; i++){
5218 for(var i = 0, len = c2.length; i < len; i++){
5219 if(c2[i]._qdiff != d){
5220 r[r.length] = c2[i];
5226 function quickId(ns, mode, root, id){
5228 var d = root.ownerDocument || root;
5229 return d.getElementById(id);
5231 ns = getNodes(ns, mode, "*");
5232 return byId(ns, null, id);
5236 getStyle : function(el, name){
5237 return Roo.fly(el).getStyle(name);
5240 * Compiles a selector/xpath query into a reusable function. The returned function
5241 * takes one parameter "root" (optional), which is the context node from where the query should start.
5242 * @param {String} selector The selector/xpath query
5243 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5244 * @return {Function}
5246 compile : function(path, type){
5247 type = type || "select";
5249 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5250 var q = path, mode, lq;
5251 var tk = Roo.DomQuery.matchers;
5252 var tklen = tk.length;
5255 // accept leading mode switch
5256 var lmode = q.match(modeRe);
5257 if(lmode && lmode[1]){
5258 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5259 q = q.replace(lmode[1], "");
5261 // strip leading slashes
5262 while(path.substr(0, 1)=="/"){
5263 path = path.substr(1);
5266 while(q && lq != q){
5268 var tm = q.match(tagTokenRe);
5269 if(type == "select"){
5272 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5274 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5276 q = q.replace(tm[0], "");
5277 }else if(q.substr(0, 1) != '@'){
5278 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5283 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5285 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5287 q = q.replace(tm[0], "");
5290 while(!(mm = q.match(modeRe))){
5291 var matched = false;
5292 for(var j = 0; j < tklen; j++){
5294 var m = q.match(t.re);
5296 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5299 q = q.replace(m[0], "");
5304 // prevent infinite loop on bad selector
5306 throw 'Error parsing selector, parsing failed at "' + q + '"';
5310 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5311 q = q.replace(mm[1], "");
5314 fn[fn.length] = "return nodup(n);\n}";
5317 * list of variables that need from compression as they are used by eval.
5327 * eval:var:byClassName
5329 * eval:var:byAttribute
5330 * eval:var:attrValue
5338 * Selects a group of elements.
5339 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5340 * @param {Node} root (optional) The start of the query (defaults to document).
5343 select : function(path, root, type){
5344 if(!root || root == document){
5347 if(typeof root == "string"){
5348 root = document.getElementById(root);
5350 var paths = path.split(",");
5352 for(var i = 0, len = paths.length; i < len; i++){
5353 var p = paths[i].replace(trimRe, "");
5355 cache[p] = Roo.DomQuery.compile(p);
5357 throw p + " is not a valid selector";
5360 var result = cache[p](root);
5361 if(result && result != document){
5362 results = results.concat(result);
5365 if(paths.length > 1){
5366 return nodup(results);
5372 * Selects a single element.
5373 * @param {String} selector The selector/xpath query
5374 * @param {Node} root (optional) The start of the query (defaults to document).
5377 selectNode : function(path, root){
5378 return Roo.DomQuery.select(path, root)[0];
5382 * Selects the value of a node, optionally replacing null with the defaultValue.
5383 * @param {String} selector The selector/xpath query
5384 * @param {Node} root (optional) The start of the query (defaults to document).
5385 * @param {String} defaultValue
5387 selectValue : function(path, root, defaultValue){
5388 path = path.replace(trimRe, "");
5389 if(!valueCache[path]){
5390 valueCache[path] = Roo.DomQuery.compile(path, "select");
5392 var n = valueCache[path](root);
5393 n = n[0] ? n[0] : n;
5394 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5395 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5399 * Selects the value of a node, parsing integers and floats.
5400 * @param {String} selector The selector/xpath query
5401 * @param {Node} root (optional) The start of the query (defaults to document).
5402 * @param {Number} defaultValue
5405 selectNumber : function(path, root, defaultValue){
5406 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5407 return parseFloat(v);
5411 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5412 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5413 * @param {String} selector The simple selector to test
5416 is : function(el, ss){
5417 if(typeof el == "string"){
5418 el = document.getElementById(el);
5420 var isArray = (el instanceof Array);
5421 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5422 return isArray ? (result.length == el.length) : (result.length > 0);
5426 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5427 * @param {Array} el An array of elements to filter
5428 * @param {String} selector The simple selector to test
5429 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5430 * the selector instead of the ones that match
5433 filter : function(els, ss, nonMatches){
5434 ss = ss.replace(trimRe, "");
5435 if(!simpleCache[ss]){
5436 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5438 var result = simpleCache[ss](els);
5439 return nonMatches ? quickDiff(result, els) : result;
5443 * Collection of matching regular expressions and code snippets.
5447 select: 'n = byClassName(n, null, " {1} ");'
5449 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5450 select: 'n = byPseudo(n, "{1}", "{2}");'
5452 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5453 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5456 select: 'n = byId(n, null, "{1}");'
5459 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5464 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5465 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5468 "=" : function(a, v){
5471 "!=" : function(a, v){
5474 "^=" : function(a, v){
5475 return a && a.substr(0, v.length) == v;
5477 "$=" : function(a, v){
5478 return a && a.substr(a.length-v.length) == v;
5480 "*=" : function(a, v){
5481 return a && a.indexOf(v) !== -1;
5483 "%=" : function(a, v){
5484 return (a % v) == 0;
5486 "|=" : function(a, v){
5487 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5489 "~=" : function(a, v){
5490 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5495 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5496 * and the argument (if any) supplied in the selector.
5499 "first-child" : function(c){
5500 var r = [], ri = -1, n;
5501 for(var i = 0, ci; ci = n = c[i]; i++){
5502 while((n = n.previousSibling) && n.nodeType != 1);
5510 "last-child" : function(c){
5511 var r = [], ri = -1, n;
5512 for(var i = 0, ci; ci = n = c[i]; i++){
5513 while((n = n.nextSibling) && n.nodeType != 1);
5521 "nth-child" : function(c, a) {
5522 var r = [], ri = -1;
5523 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5524 var f = (m[1] || 1) - 0, l = m[2] - 0;
5525 for(var i = 0, n; n = c[i]; i++){
5526 var pn = n.parentNode;
5527 if (batch != pn._batch) {
5529 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5530 if(cn.nodeType == 1){
5537 if (l == 0 || n.nodeIndex == l){
5540 } else if ((n.nodeIndex + l) % f == 0){
5548 "only-child" : function(c){
5549 var r = [], ri = -1;;
5550 for(var i = 0, ci; ci = c[i]; i++){
5551 if(!prev(ci) && !next(ci)){
5558 "empty" : function(c){
5559 var r = [], ri = -1;
5560 for(var i = 0, ci; ci = c[i]; i++){
5561 var cns = ci.childNodes, j = 0, cn, empty = true;
5564 if(cn.nodeType == 1 || cn.nodeType == 3){
5576 "contains" : function(c, v){
5577 var r = [], ri = -1;
5578 for(var i = 0, ci; ci = c[i]; i++){
5579 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5586 "nodeValue" : function(c, v){
5587 var r = [], ri = -1;
5588 for(var i = 0, ci; ci = c[i]; i++){
5589 if(ci.firstChild && ci.firstChild.nodeValue == v){
5596 "checked" : function(c){
5597 var r = [], ri = -1;
5598 for(var i = 0, ci; ci = c[i]; i++){
5599 if(ci.checked == true){
5606 "not" : function(c, ss){
5607 return Roo.DomQuery.filter(c, ss, true);
5610 "odd" : function(c){
5611 return this["nth-child"](c, "odd");
5614 "even" : function(c){
5615 return this["nth-child"](c, "even");
5618 "nth" : function(c, a){
5619 return c[a-1] || [];
5622 "first" : function(c){
5626 "last" : function(c){
5627 return c[c.length-1] || [];
5630 "has" : function(c, ss){
5631 var s = Roo.DomQuery.select;
5632 var r = [], ri = -1;
5633 for(var i = 0, ci; ci = c[i]; i++){
5634 if(s(ss, ci).length > 0){
5641 "next" : function(c, ss){
5642 var is = Roo.DomQuery.is;
5643 var r = [], ri = -1;
5644 for(var i = 0, ci; ci = c[i]; i++){
5653 "prev" : function(c, ss){
5654 var is = Roo.DomQuery.is;
5655 var r = [], ri = -1;
5656 for(var i = 0, ci; ci = c[i]; i++){
5669 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5670 * @param {String} path The selector/xpath query
5671 * @param {Node} root (optional) The start of the query (defaults to document).
5676 Roo.query = Roo.DomQuery.select;
5679 * Ext JS Library 1.1.1
5680 * Copyright(c) 2006-2007, Ext JS, LLC.
5682 * Originally Released Under LGPL - original licence link has changed is not relivant.
5685 * <script type="text/javascript">
5689 * @class Roo.util.Observable
5690 * Base class that provides a common interface for publishing events. Subclasses are expected to
5691 * to have a property "events" with all the events defined.<br>
5694 Employee = function(name){
5701 Roo.extend(Employee, Roo.util.Observable);
5703 * @param {Object} config properties to use (incuding events / listeners)
5706 Roo.util.Observable = function(cfg){
5709 this.addEvents(cfg.events || {});
5711 delete cfg.events; // make sure
5714 Roo.apply(this, cfg);
5717 this.on(this.listeners);
5718 delete this.listeners;
5721 Roo.util.Observable.prototype = {
5723 * @cfg {Object} listeners list of events and functions to call for this object,
5727 'click' : function(e) {
5737 * Fires the specified event with the passed parameters (minus the event name).
5738 * @param {String} eventName
5739 * @param {Object...} args Variable number of parameters are passed to handlers
5740 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5742 fireEvent : function(){
5743 var ce = this.events[arguments[0].toLowerCase()];
5744 if(typeof ce == "object"){
5745 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5752 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5755 * Appends an event handler to this component
5756 * @param {String} eventName The type of event to listen for
5757 * @param {Function} handler The method the event invokes
5758 * @param {Object} scope (optional) The scope in which to execute the handler
5759 * function. The handler function's "this" context.
5760 * @param {Object} options (optional) An object containing handler configuration
5761 * properties. This may contain any of the following properties:<ul>
5762 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5763 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5764 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5765 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5766 * by the specified number of milliseconds. If the event fires again within that time, the original
5767 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5770 * <b>Combining Options</b><br>
5771 * Using the options argument, it is possible to combine different types of listeners:<br>
5773 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5775 el.on('click', this.onClick, this, {
5782 * <b>Attaching multiple handlers in 1 call</b><br>
5783 * The method also allows for a single argument to be passed which is a config object containing properties
5784 * which specify multiple handlers.
5793 fn: this.onMouseOver,
5797 fn: this.onMouseOut,
5803 * Or a shorthand syntax which passes the same scope object to all handlers:
5806 'click': this.onClick,
5807 'mouseover': this.onMouseOver,
5808 'mouseout': this.onMouseOut,
5813 addListener : function(eventName, fn, scope, o){
5814 if(typeof eventName == "object"){
5817 if(this.filterOptRe.test(e)){
5820 if(typeof o[e] == "function"){
5822 this.addListener(e, o[e], o.scope, o);
5824 // individual options
5825 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5830 o = (!o || typeof o == "boolean") ? {} : o;
5831 eventName = eventName.toLowerCase();
5832 var ce = this.events[eventName] || true;
5833 if(typeof ce == "boolean"){
5834 ce = new Roo.util.Event(this, eventName);
5835 this.events[eventName] = ce;
5837 ce.addListener(fn, scope, o);
5841 * Removes a listener
5842 * @param {String} eventName The type of event to listen for
5843 * @param {Function} handler The handler to remove
5844 * @param {Object} scope (optional) The scope (this object) for the handler
5846 removeListener : function(eventName, fn, scope){
5847 var ce = this.events[eventName.toLowerCase()];
5848 if(typeof ce == "object"){
5849 ce.removeListener(fn, scope);
5854 * Removes all listeners for this object
5856 purgeListeners : function(){
5857 for(var evt in this.events){
5858 if(typeof this.events[evt] == "object"){
5859 this.events[evt].clearListeners();
5864 relayEvents : function(o, events){
5865 var createHandler = function(ename){
5867 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5870 for(var i = 0, len = events.length; i < len; i++){
5871 var ename = events[i];
5872 if(!this.events[ename]){ this.events[ename] = true; };
5873 o.on(ename, createHandler(ename), this);
5878 * Used to define events on this Observable
5879 * @param {Object} object The object with the events defined
5881 addEvents : function(o){
5885 Roo.applyIf(this.events, o);
5889 * Checks to see if this object has any listeners for a specified event
5890 * @param {String} eventName The name of the event to check for
5891 * @return {Boolean} True if the event is being listened for, else false
5893 hasListener : function(eventName){
5894 var e = this.events[eventName];
5895 return typeof e == "object" && e.listeners.length > 0;
5899 * Appends an event handler to this element (shorthand for addListener)
5900 * @param {String} eventName The type of event to listen for
5901 * @param {Function} handler The method the event invokes
5902 * @param {Object} scope (optional) The scope in which to execute the handler
5903 * function. The handler function's "this" context.
5904 * @param {Object} options (optional)
5907 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5909 * Removes a listener (shorthand for removeListener)
5910 * @param {String} eventName The type of event to listen for
5911 * @param {Function} handler The handler to remove
5912 * @param {Object} scope (optional) The scope (this object) for the handler
5915 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5918 * Starts capture on the specified Observable. All events will be passed
5919 * to the supplied function with the event name + standard signature of the event
5920 * <b>before</b> the event is fired. If the supplied function returns false,
5921 * the event will not fire.
5922 * @param {Observable} o The Observable to capture
5923 * @param {Function} fn The function to call
5924 * @param {Object} scope (optional) The scope (this object) for the fn
5927 Roo.util.Observable.capture = function(o, fn, scope){
5928 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5932 * Removes <b>all</b> added captures from the Observable.
5933 * @param {Observable} o The Observable to release
5936 Roo.util.Observable.releaseCapture = function(o){
5937 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5942 var createBuffered = function(h, o, scope){
5943 var task = new Roo.util.DelayedTask();
5945 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5949 var createSingle = function(h, e, fn, scope){
5951 e.removeListener(fn, scope);
5952 return h.apply(scope, arguments);
5956 var createDelayed = function(h, o, scope){
5958 var args = Array.prototype.slice.call(arguments, 0);
5959 setTimeout(function(){
5960 h.apply(scope, args);
5965 Roo.util.Event = function(obj, name){
5968 this.listeners = [];
5971 Roo.util.Event.prototype = {
5972 addListener : function(fn, scope, options){
5973 var o = options || {};
5974 scope = scope || this.obj;
5975 if(!this.isListening(fn, scope)){
5976 var l = {fn: fn, scope: scope, options: o};
5979 h = createDelayed(h, o, scope);
5982 h = createSingle(h, this, fn, scope);
5985 h = createBuffered(h, o, scope);
5988 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5989 this.listeners.push(l);
5991 this.listeners = this.listeners.slice(0);
5992 this.listeners.push(l);
5997 findListener : function(fn, scope){
5998 scope = scope || this.obj;
5999 var ls = this.listeners;
6000 for(var i = 0, len = ls.length; i < len; i++){
6002 if(l.fn == fn && l.scope == scope){
6009 isListening : function(fn, scope){
6010 return this.findListener(fn, scope) != -1;
6013 removeListener : function(fn, scope){
6015 if((index = this.findListener(fn, scope)) != -1){
6017 this.listeners.splice(index, 1);
6019 this.listeners = this.listeners.slice(0);
6020 this.listeners.splice(index, 1);
6027 clearListeners : function(){
6028 this.listeners = [];
6032 var ls = this.listeners, scope, len = ls.length;
6035 var args = Array.prototype.slice.call(arguments, 0);
6036 for(var i = 0; i < len; i++){
6038 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6039 this.firing = false;
6043 this.firing = false;
6050 * Ext JS Library 1.1.1
6051 * Copyright(c) 2006-2007, Ext JS, LLC.
6053 * Originally Released Under LGPL - original licence link has changed is not relivant.
6056 * <script type="text/javascript">
6060 * @class Roo.EventManager
6061 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6062 * several useful events directly.
6063 * See {@link Roo.EventObject} for more details on normalized event objects.
6066 Roo.EventManager = function(){
6067 var docReadyEvent, docReadyProcId, docReadyState = false;
6068 var resizeEvent, resizeTask, textEvent, textSize;
6069 var E = Roo.lib.Event;
6070 var D = Roo.lib.Dom;
6075 var fireDocReady = function(){
6077 docReadyState = true;
6080 clearInterval(docReadyProcId);
6082 if(Roo.isGecko || Roo.isOpera) {
6083 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6086 var defer = document.getElementById("ie-deferred-loader");
6088 defer.onreadystatechange = null;
6089 defer.parentNode.removeChild(defer);
6093 docReadyEvent.fire();
6094 docReadyEvent.clearListeners();
6099 var initDocReady = function(){
6100 docReadyEvent = new Roo.util.Event();
6101 if(Roo.isGecko || Roo.isOpera) {
6102 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6104 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6105 var defer = document.getElementById("ie-deferred-loader");
6106 defer.onreadystatechange = function(){
6107 if(this.readyState == "complete"){
6111 }else if(Roo.isSafari){
6112 docReadyProcId = setInterval(function(){
6113 var rs = document.readyState;
6114 if(rs == "complete") {
6119 // no matter what, make sure it fires on load
6120 E.on(window, "load", fireDocReady);
6123 var createBuffered = function(h, o){
6124 var task = new Roo.util.DelayedTask(h);
6126 // create new event object impl so new events don't wipe out properties
6127 e = new Roo.EventObjectImpl(e);
6128 task.delay(o.buffer, h, null, [e]);
6132 var createSingle = function(h, el, ename, fn){
6134 Roo.EventManager.removeListener(el, ename, fn);
6139 var createDelayed = function(h, o){
6141 // create new event object impl so new events don't wipe out properties
6142 e = new Roo.EventObjectImpl(e);
6143 setTimeout(function(){
6148 var transitionEndVal = false;
6150 var transitionEnd = function()
6152 if (transitionEndVal) {
6153 return transitionEndVal;
6155 var el = document.createElement('div');
6157 var transEndEventNames = {
6158 WebkitTransition : 'webkitTransitionEnd',
6159 MozTransition : 'transitionend',
6160 OTransition : 'oTransitionEnd otransitionend',
6161 transition : 'transitionend'
6164 for (var name in transEndEventNames) {
6165 if (el.style[name] !== undefined) {
6166 transitionEndVal = transEndEventNames[name];
6167 return transitionEndVal ;
6173 var listen = function(element, ename, opt, fn, scope){
6174 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6175 fn = fn || o.fn; scope = scope || o.scope;
6176 var el = Roo.getDom(element);
6180 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6183 if (ename == 'transitionend') {
6184 ename = transitionEnd();
6186 var h = function(e){
6187 e = Roo.EventObject.setEvent(e);
6190 t = e.getTarget(o.delegate, el);
6197 if(o.stopEvent === true){
6200 if(o.preventDefault === true){
6203 if(o.stopPropagation === true){
6204 e.stopPropagation();
6207 if(o.normalized === false){
6211 fn.call(scope || el, e, t, o);
6214 h = createDelayed(h, o);
6217 h = createSingle(h, el, ename, fn);
6220 h = createBuffered(h, o);
6222 fn._handlers = fn._handlers || [];
6225 fn._handlers.push([Roo.id(el), ename, h]);
6230 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6231 el.addEventListener("DOMMouseScroll", h, false);
6232 E.on(window, 'unload', function(){
6233 el.removeEventListener("DOMMouseScroll", h, false);
6236 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6237 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6242 var stopListening = function(el, ename, fn){
6243 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6245 for(var i = 0, len = hds.length; i < len; i++){
6247 if(h[0] == id && h[1] == ename){
6254 E.un(el, ename, hd);
6255 el = Roo.getDom(el);
6256 if(ename == "mousewheel" && el.addEventListener){
6257 el.removeEventListener("DOMMouseScroll", hd, false);
6259 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6260 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6264 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6271 * @scope Roo.EventManager
6276 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6277 * object with a Roo.EventObject
6278 * @param {Function} fn The method the event invokes
6279 * @param {Object} scope An object that becomes the scope of the handler
6280 * @param {boolean} override If true, the obj passed in becomes
6281 * the execution scope of the listener
6282 * @return {Function} The wrapped function
6285 wrap : function(fn, scope, override){
6287 Roo.EventObject.setEvent(e);
6288 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6293 * Appends an event handler to an element (shorthand for addListener)
6294 * @param {String/HTMLElement} element The html element or id to assign the
6295 * @param {String} eventName The type of event to listen for
6296 * @param {Function} handler The method the event invokes
6297 * @param {Object} scope (optional) The scope in which to execute the handler
6298 * function. The handler function's "this" context.
6299 * @param {Object} options (optional) An object containing handler configuration
6300 * properties. This may contain any of the following properties:<ul>
6301 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6302 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6303 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6304 * <li>preventDefault {Boolean} True to prevent the default action</li>
6305 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6306 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6307 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6308 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6309 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6310 * by the specified number of milliseconds. If the event fires again within that time, the original
6311 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6314 * <b>Combining Options</b><br>
6315 * Using the options argument, it is possible to combine different types of listeners:<br>
6317 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6319 el.on('click', this.onClick, this, {
6326 * <b>Attaching multiple handlers in 1 call</b><br>
6327 * The method also allows for a single argument to be passed which is a config object containing properties
6328 * which specify multiple handlers.
6338 fn: this.onMouseOver
6347 * Or a shorthand syntax:<br>
6350 'click' : this.onClick,
6351 'mouseover' : this.onMouseOver,
6352 'mouseout' : this.onMouseOut
6356 addListener : function(element, eventName, fn, scope, options){
6357 if(typeof eventName == "object"){
6363 if(typeof o[e] == "function"){
6365 listen(element, e, o, o[e], o.scope);
6367 // individual options
6368 listen(element, e, o[e]);
6373 return listen(element, eventName, options, fn, scope);
6377 * Removes an event handler
6379 * @param {String/HTMLElement} element The id or html element to remove the
6381 * @param {String} eventName The type of event
6382 * @param {Function} fn
6383 * @return {Boolean} True if a listener was actually removed
6385 removeListener : function(element, eventName, fn){
6386 return stopListening(element, eventName, fn);
6390 * Fires when the document is ready (before onload and before images are loaded). Can be
6391 * accessed shorthanded Roo.onReady().
6392 * @param {Function} fn The method the event invokes
6393 * @param {Object} scope An object that becomes the scope of the handler
6394 * @param {boolean} options
6396 onDocumentReady : function(fn, scope, options){
6397 if(docReadyState){ // if it already fired
6398 docReadyEvent.addListener(fn, scope, options);
6399 docReadyEvent.fire();
6400 docReadyEvent.clearListeners();
6406 docReadyEvent.addListener(fn, scope, options);
6410 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6411 * @param {Function} fn The method the event invokes
6412 * @param {Object} scope An object that becomes the scope of the handler
6413 * @param {boolean} options
6415 onWindowResize : function(fn, scope, options){
6417 resizeEvent = new Roo.util.Event();
6418 resizeTask = new Roo.util.DelayedTask(function(){
6419 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6421 E.on(window, "resize", function(){
6423 resizeTask.delay(50);
6425 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6429 resizeEvent.addListener(fn, scope, options);
6433 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6434 * @param {Function} fn The method the event invokes
6435 * @param {Object} scope An object that becomes the scope of the handler
6436 * @param {boolean} options
6438 onTextResize : function(fn, scope, options){
6440 textEvent = new Roo.util.Event();
6441 var textEl = new Roo.Element(document.createElement('div'));
6442 textEl.dom.className = 'x-text-resize';
6443 textEl.dom.innerHTML = 'X';
6444 textEl.appendTo(document.body);
6445 textSize = textEl.dom.offsetHeight;
6446 setInterval(function(){
6447 if(textEl.dom.offsetHeight != textSize){
6448 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6450 }, this.textResizeInterval);
6452 textEvent.addListener(fn, scope, options);
6456 * Removes the passed window resize listener.
6457 * @param {Function} fn The method the event invokes
6458 * @param {Object} scope The scope of handler
6460 removeResizeListener : function(fn, scope){
6462 resizeEvent.removeListener(fn, scope);
6467 fireResize : function(){
6469 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6473 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6477 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6479 textResizeInterval : 50
6484 * @scopeAlias pub=Roo.EventManager
6488 * Appends an event handler to an element (shorthand for addListener)
6489 * @param {String/HTMLElement} element The html element or id to assign the
6490 * @param {String} eventName The type of event to listen for
6491 * @param {Function} handler The method the event invokes
6492 * @param {Object} scope (optional) The scope in which to execute the handler
6493 * function. The handler function's "this" context.
6494 * @param {Object} options (optional) An object containing handler configuration
6495 * properties. This may contain any of the following properties:<ul>
6496 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6497 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6498 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6499 * <li>preventDefault {Boolean} True to prevent the default action</li>
6500 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6501 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6502 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6503 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6504 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6505 * by the specified number of milliseconds. If the event fires again within that time, the original
6506 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6509 * <b>Combining Options</b><br>
6510 * Using the options argument, it is possible to combine different types of listeners:<br>
6512 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6514 el.on('click', this.onClick, this, {
6521 * <b>Attaching multiple handlers in 1 call</b><br>
6522 * The method also allows for a single argument to be passed which is a config object containing properties
6523 * which specify multiple handlers.
6533 fn: this.onMouseOver
6542 * Or a shorthand syntax:<br>
6545 'click' : this.onClick,
6546 'mouseover' : this.onMouseOver,
6547 'mouseout' : this.onMouseOut
6551 pub.on = pub.addListener;
6552 pub.un = pub.removeListener;
6554 pub.stoppedMouseDownEvent = new Roo.util.Event();
6558 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6559 * @param {Function} fn The method the event invokes
6560 * @param {Object} scope An object that becomes the scope of the handler
6561 * @param {boolean} override If true, the obj passed in becomes
6562 * the execution scope of the listener
6566 Roo.onReady = Roo.EventManager.onDocumentReady;
6568 Roo.onReady(function(){
6569 var bd = Roo.get(document.body);
6574 : Roo.isGecko ? "roo-gecko"
6575 : Roo.isOpera ? "roo-opera"
6576 : Roo.isSafari ? "roo-safari" : ""];
6579 cls.push("roo-mac");
6582 cls.push("roo-linux");
6585 cls.push("roo-ios");
6588 cls.push("roo-touch");
6590 if(Roo.isBorderBox){
6591 cls.push('roo-border-box');
6593 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6594 var p = bd.dom.parentNode;
6596 p.className += ' roo-strict';
6599 bd.addClass(cls.join(' '));
6603 * @class Roo.EventObject
6604 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6605 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6608 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6610 var target = e.getTarget();
6613 var myDiv = Roo.get("myDiv");
6614 myDiv.on("click", handleClick);
6616 Roo.EventManager.on("myDiv", 'click', handleClick);
6617 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6621 Roo.EventObject = function(){
6623 var E = Roo.lib.Event;
6625 // safari keypress events for special keys return bad keycodes
6628 63235 : 39, // right
6631 63276 : 33, // page up
6632 63277 : 34, // page down
6633 63272 : 46, // delete
6638 // normalize button clicks
6639 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6640 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6642 Roo.EventObjectImpl = function(e){
6644 this.setEvent(e.browserEvent || e);
6647 Roo.EventObjectImpl.prototype = {
6649 * Used to fix doc tools.
6650 * @scope Roo.EventObject.prototype
6656 /** The normal browser event */
6657 browserEvent : null,
6658 /** The button pressed in a mouse event */
6660 /** True if the shift key was down during the event */
6662 /** True if the control key was down during the event */
6664 /** True if the alt key was down during the event */
6723 setEvent : function(e){
6724 if(e == this || (e && e.browserEvent)){ // already wrapped
6727 this.browserEvent = e;
6729 // normalize buttons
6730 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6731 if(e.type == 'click' && this.button == -1){
6735 this.shiftKey = e.shiftKey;
6736 // mac metaKey behaves like ctrlKey
6737 this.ctrlKey = e.ctrlKey || e.metaKey;
6738 this.altKey = e.altKey;
6739 // in getKey these will be normalized for the mac
6740 this.keyCode = e.keyCode;
6741 // keyup warnings on firefox.
6742 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6743 // cache the target for the delayed and or buffered events
6744 this.target = E.getTarget(e);
6746 this.xy = E.getXY(e);
6749 this.shiftKey = false;
6750 this.ctrlKey = false;
6751 this.altKey = false;
6761 * Stop the event (preventDefault and stopPropagation)
6763 stopEvent : function(){
6764 if(this.browserEvent){
6765 if(this.browserEvent.type == 'mousedown'){
6766 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6768 E.stopEvent(this.browserEvent);
6773 * Prevents the browsers default handling of the event.
6775 preventDefault : function(){
6776 if(this.browserEvent){
6777 E.preventDefault(this.browserEvent);
6782 isNavKeyPress : function(){
6783 var k = this.keyCode;
6784 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6785 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6788 isSpecialKey : function(){
6789 var k = this.keyCode;
6790 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6791 (k == 16) || (k == 17) ||
6792 (k >= 18 && k <= 20) ||
6793 (k >= 33 && k <= 35) ||
6794 (k >= 36 && k <= 39) ||
6795 (k >= 44 && k <= 45);
6798 * Cancels bubbling of the event.
6800 stopPropagation : function(){
6801 if(this.browserEvent){
6802 if(this.type == 'mousedown'){
6803 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6805 E.stopPropagation(this.browserEvent);
6810 * Gets the key code for the event.
6813 getCharCode : function(){
6814 return this.charCode || this.keyCode;
6818 * Returns a normalized keyCode for the event.
6819 * @return {Number} The key code
6821 getKey : function(){
6822 var k = this.keyCode || this.charCode;
6823 return Roo.isSafari ? (safariKeys[k] || k) : k;
6827 * Gets the x coordinate of the event.
6830 getPageX : function(){
6835 * Gets the y coordinate of the event.
6838 getPageY : function(){
6843 * Gets the time of the event.
6846 getTime : function(){
6847 if(this.browserEvent){
6848 return E.getTime(this.browserEvent);
6854 * Gets the page coordinates of the event.
6855 * @return {Array} The xy values like [x, y]
6862 * Gets the target for the event.
6863 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6864 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6865 search as a number or element (defaults to 10 || document.body)
6866 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6867 * @return {HTMLelement}
6869 getTarget : function(selector, maxDepth, returnEl){
6870 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6873 * Gets the related target.
6874 * @return {HTMLElement}
6876 getRelatedTarget : function(){
6877 if(this.browserEvent){
6878 return E.getRelatedTarget(this.browserEvent);
6884 * Normalizes mouse wheel delta across browsers
6885 * @return {Number} The delta
6887 getWheelDelta : function(){
6888 var e = this.browserEvent;
6890 if(e.wheelDelta){ /* IE/Opera. */
6891 delta = e.wheelDelta/120;
6892 }else if(e.detail){ /* Mozilla case. */
6893 delta = -e.detail/3;
6899 * Returns true if the control, meta, shift or alt key was pressed during this event.
6902 hasModifier : function(){
6903 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6907 * Returns true if the target of this event equals el or is a child of el
6908 * @param {String/HTMLElement/Element} el
6909 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6912 within : function(el, related){
6913 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6914 return t && Roo.fly(el).contains(t);
6917 getPoint : function(){
6918 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6922 return new Roo.EventObjectImpl();
6927 * Ext JS Library 1.1.1
6928 * Copyright(c) 2006-2007, Ext JS, LLC.
6930 * Originally Released Under LGPL - original licence link has changed is not relivant.
6933 * <script type="text/javascript">
6937 // was in Composite Element!??!?!
6940 var D = Roo.lib.Dom;
6941 var E = Roo.lib.Event;
6942 var A = Roo.lib.Anim;
6944 // local style camelizing for speed
6946 var camelRe = /(-[a-z])/gi;
6947 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6948 var view = document.defaultView;
6951 * @class Roo.Element
6952 * Represents an Element in the DOM.<br><br>
6955 var el = Roo.get("my-div");
6958 var el = getEl("my-div");
6960 // or with a DOM element
6961 var el = Roo.get(myDivElement);
6963 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6964 * each call instead of constructing a new one.<br><br>
6965 * <b>Animations</b><br />
6966 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6967 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6969 Option Default Description
6970 --------- -------- ---------------------------------------------
6971 duration .35 The duration of the animation in seconds
6972 easing easeOut The YUI easing method
6973 callback none A function to execute when the anim completes
6974 scope this The scope (this) of the callback function
6976 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6977 * manipulate the animation. Here's an example:
6979 var el = Roo.get("my-div");
6984 // default animation
6985 el.setWidth(100, true);
6987 // animation with some options set
6994 // using the "anim" property to get the Anim object
7000 el.setWidth(100, opt);
7002 if(opt.anim.isAnimated()){
7006 * <b> Composite (Collections of) Elements</b><br />
7007 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7008 * @constructor Create a new Element directly.
7009 * @param {String/HTMLElement} element
7010 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
7012 Roo.Element = function(element, forceNew){
7013 var dom = typeof element == "string" ?
7014 document.getElementById(element) : element;
7015 if(!dom){ // invalid id/element
7019 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7020 return Roo.Element.cache[id];
7030 * The DOM element ID
7033 this.id = id || Roo.id(dom);
7036 var El = Roo.Element;
7040 * The element's default display mode (defaults to "")
7043 originalDisplay : "",
7047 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7053 * Sets the element's visibility mode. When setVisible() is called it
7054 * will use this to determine whether to set the visibility or the display property.
7055 * @param visMode Element.VISIBILITY or Element.DISPLAY
7056 * @return {Roo.Element} this
7058 setVisibilityMode : function(visMode){
7059 this.visibilityMode = visMode;
7063 * Convenience method for setVisibilityMode(Element.DISPLAY)
7064 * @param {String} display (optional) What to set display to when visible
7065 * @return {Roo.Element} this
7067 enableDisplayMode : function(display){
7068 this.setVisibilityMode(El.DISPLAY);
7069 if(typeof display != "undefined") this.originalDisplay = display;
7074 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7075 * @param {String} selector The simple selector to test
7076 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7077 search as a number or element (defaults to 10 || document.body)
7078 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7079 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7081 findParent : function(simpleSelector, maxDepth, returnEl){
7082 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7083 maxDepth = maxDepth || 50;
7084 if(typeof maxDepth != "number"){
7085 stopEl = Roo.getDom(maxDepth);
7088 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7089 if(dq.is(p, simpleSelector)){
7090 return returnEl ? Roo.get(p) : p;
7100 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7101 * @param {String} selector The simple selector to test
7102 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7103 search as a number or element (defaults to 10 || document.body)
7104 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7105 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7107 findParentNode : function(simpleSelector, maxDepth, returnEl){
7108 var p = Roo.fly(this.dom.parentNode, '_internal');
7109 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7113 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7114 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7115 * @param {String} selector The simple selector to test
7116 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7117 search as a number or element (defaults to 10 || document.body)
7118 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7120 up : function(simpleSelector, maxDepth){
7121 return this.findParentNode(simpleSelector, maxDepth, true);
7127 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7128 * @param {String} selector The simple selector to test
7129 * @return {Boolean} True if this element matches the selector, else false
7131 is : function(simpleSelector){
7132 return Roo.DomQuery.is(this.dom, simpleSelector);
7136 * Perform animation on this element.
7137 * @param {Object} args The YUI animation control args
7138 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7139 * @param {Function} onComplete (optional) Function to call when animation completes
7140 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7141 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7142 * @return {Roo.Element} this
7144 animate : function(args, duration, onComplete, easing, animType){
7145 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7150 * @private Internal animation call
7152 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7153 animType = animType || 'run';
7155 var anim = Roo.lib.Anim[animType](
7157 (opt.duration || defaultDur) || .35,
7158 (opt.easing || defaultEase) || 'easeOut',
7160 Roo.callback(cb, this);
7161 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7169 // private legacy anim prep
7170 preanim : function(a, i){
7171 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7175 * Removes worthless text nodes
7176 * @param {Boolean} forceReclean (optional) By default the element
7177 * keeps track if it has been cleaned already so
7178 * you can call this over and over. However, if you update the element and
7179 * need to force a reclean, you can pass true.
7181 clean : function(forceReclean){
7182 if(this.isCleaned && forceReclean !== true){
7186 var d = this.dom, n = d.firstChild, ni = -1;
7188 var nx = n.nextSibling;
7189 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7196 this.isCleaned = true;
7201 calcOffsetsTo : function(el){
7204 var restorePos = false;
7205 if(el.getStyle('position') == 'static'){
7206 el.position('relative');
7211 while(op && op != d && op.tagName != 'HTML'){
7214 op = op.offsetParent;
7217 el.position('static');
7223 * Scrolls this element into view within the passed container.
7224 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7225 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7226 * @return {Roo.Element} this
7228 scrollIntoView : function(container, hscroll){
7229 var c = Roo.getDom(container) || document.body;
7232 var o = this.calcOffsetsTo(c),
7235 b = t+el.offsetHeight,
7236 r = l+el.offsetWidth;
7238 var ch = c.clientHeight;
7239 var ct = parseInt(c.scrollTop, 10);
7240 var cl = parseInt(c.scrollLeft, 10);
7242 var cr = cl + c.clientWidth;
7250 if(hscroll !== false){
7254 c.scrollLeft = r-c.clientWidth;
7261 scrollChildIntoView : function(child, hscroll){
7262 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7266 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7267 * the new height may not be available immediately.
7268 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7269 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7270 * @param {Function} onComplete (optional) Function to call when animation completes
7271 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7272 * @return {Roo.Element} this
7274 autoHeight : function(animate, duration, onComplete, easing){
7275 var oldHeight = this.getHeight();
7277 this.setHeight(1); // force clipping
7278 setTimeout(function(){
7279 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7281 this.setHeight(height);
7283 if(typeof onComplete == "function"){
7287 this.setHeight(oldHeight); // restore original height
7288 this.setHeight(height, animate, duration, function(){
7290 if(typeof onComplete == "function") onComplete();
7291 }.createDelegate(this), easing);
7293 }.createDelegate(this), 0);
7298 * Returns true if this element is an ancestor of the passed element
7299 * @param {HTMLElement/String} el The element to check
7300 * @return {Boolean} True if this element is an ancestor of el, else false
7302 contains : function(el){
7303 if(!el){return false;}
7304 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7308 * Checks whether the element is currently visible using both visibility and display properties.
7309 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7310 * @return {Boolean} True if the element is currently visible, else false
7312 isVisible : function(deep) {
7313 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7314 if(deep !== true || !vis){
7317 var p = this.dom.parentNode;
7318 while(p && p.tagName.toLowerCase() != "body"){
7319 if(!Roo.fly(p, '_isVisible').isVisible()){
7328 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7329 * @param {String} selector The CSS selector
7330 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7331 * @return {CompositeElement/CompositeElementLite} The composite element
7333 select : function(selector, unique){
7334 return El.select(selector, unique, this.dom);
7338 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7339 * @param {String} selector The CSS selector
7340 * @return {Array} An array of the matched nodes
7342 query : function(selector, unique){
7343 return Roo.DomQuery.select(selector, this.dom);
7347 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7348 * @param {String} selector The CSS selector
7349 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7350 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7352 child : function(selector, returnDom){
7353 var n = Roo.DomQuery.selectNode(selector, this.dom);
7354 return returnDom ? n : Roo.get(n);
7358 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7359 * @param {String} selector The CSS selector
7360 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7361 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7363 down : function(selector, returnDom){
7364 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7365 return returnDom ? n : Roo.get(n);
7369 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7370 * @param {String} group The group the DD object is member of
7371 * @param {Object} config The DD config object
7372 * @param {Object} overrides An object containing methods to override/implement on the DD object
7373 * @return {Roo.dd.DD} The DD object
7375 initDD : function(group, config, overrides){
7376 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7377 return Roo.apply(dd, overrides);
7381 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7382 * @param {String} group The group the DDProxy object is member of
7383 * @param {Object} config The DDProxy config object
7384 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7385 * @return {Roo.dd.DDProxy} The DDProxy object
7387 initDDProxy : function(group, config, overrides){
7388 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7389 return Roo.apply(dd, overrides);
7393 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7394 * @param {String} group The group the DDTarget object is member of
7395 * @param {Object} config The DDTarget config object
7396 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7397 * @return {Roo.dd.DDTarget} The DDTarget object
7399 initDDTarget : function(group, config, overrides){
7400 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7401 return Roo.apply(dd, overrides);
7405 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7406 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7407 * @param {Boolean} visible Whether the element is visible
7408 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7409 * @return {Roo.Element} this
7411 setVisible : function(visible, animate){
7413 if(this.visibilityMode == El.DISPLAY){
7414 this.setDisplayed(visible);
7417 this.dom.style.visibility = visible ? "visible" : "hidden";
7420 // closure for composites
7422 var visMode = this.visibilityMode;
7424 this.setOpacity(.01);
7425 this.setVisible(true);
7427 this.anim({opacity: { to: (visible?1:0) }},
7428 this.preanim(arguments, 1),
7429 null, .35, 'easeIn', function(){
7431 if(visMode == El.DISPLAY){
7432 dom.style.display = "none";
7434 dom.style.visibility = "hidden";
7436 Roo.get(dom).setOpacity(1);
7444 * Returns true if display is not "none"
7447 isDisplayed : function() {
7448 return this.getStyle("display") != "none";
7452 * Toggles the element's visibility or display, depending on visibility mode.
7453 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7454 * @return {Roo.Element} this
7456 toggle : function(animate){
7457 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7462 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7463 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7464 * @return {Roo.Element} this
7466 setDisplayed : function(value) {
7467 if(typeof value == "boolean"){
7468 value = value ? this.originalDisplay : "none";
7470 this.setStyle("display", value);
7475 * Tries to focus the element. Any exceptions are caught and ignored.
7476 * @return {Roo.Element} this
7478 focus : function() {
7486 * Tries to blur the element. Any exceptions are caught and ignored.
7487 * @return {Roo.Element} this
7497 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7498 * @param {String/Array} className The CSS class to add, or an array of classes
7499 * @return {Roo.Element} this
7501 addClass : function(className){
7502 if(className instanceof Array){
7503 for(var i = 0, len = className.length; i < len; i++) {
7504 this.addClass(className[i]);
7507 if(className && !this.hasClass(className)){
7508 this.dom.className = this.dom.className + " " + className;
7515 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7516 * @param {String/Array} className The CSS class to add, or an array of classes
7517 * @return {Roo.Element} this
7519 radioClass : function(className){
7520 var siblings = this.dom.parentNode.childNodes;
7521 for(var i = 0; i < siblings.length; i++) {
7522 var s = siblings[i];
7523 if(s.nodeType == 1){
7524 Roo.get(s).removeClass(className);
7527 this.addClass(className);
7532 * Removes one or more CSS classes from the element.
7533 * @param {String/Array} className The CSS class to remove, or an array of classes
7534 * @return {Roo.Element} this
7536 removeClass : function(className){
7537 if(!className || !this.dom.className){
7540 if(className instanceof Array){
7541 for(var i = 0, len = className.length; i < len; i++) {
7542 this.removeClass(className[i]);
7545 if(this.hasClass(className)){
7546 var re = this.classReCache[className];
7548 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7549 this.classReCache[className] = re;
7551 this.dom.className =
7552 this.dom.className.replace(re, " ");
7562 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7563 * @param {String} className The CSS class to toggle
7564 * @return {Roo.Element} this
7566 toggleClass : function(className){
7567 if(this.hasClass(className)){
7568 this.removeClass(className);
7570 this.addClass(className);
7576 * Checks if the specified CSS class exists on this element's DOM node.
7577 * @param {String} className The CSS class to check for
7578 * @return {Boolean} True if the class exists, else false
7580 hasClass : function(className){
7581 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7585 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7586 * @param {String} oldClassName The CSS class to replace
7587 * @param {String} newClassName The replacement CSS class
7588 * @return {Roo.Element} this
7590 replaceClass : function(oldClassName, newClassName){
7591 this.removeClass(oldClassName);
7592 this.addClass(newClassName);
7597 * Returns an object with properties matching the styles requested.
7598 * For example, el.getStyles('color', 'font-size', 'width') might return
7599 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7600 * @param {String} style1 A style name
7601 * @param {String} style2 A style name
7602 * @param {String} etc.
7603 * @return {Object} The style object
7605 getStyles : function(){
7606 var a = arguments, len = a.length, r = {};
7607 for(var i = 0; i < len; i++){
7608 r[a[i]] = this.getStyle(a[i]);
7614 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7615 * @param {String} property The style property whose value is returned.
7616 * @return {String} The current value of the style property for this element.
7618 getStyle : function(){
7619 return view && view.getComputedStyle ?
7621 var el = this.dom, v, cs, camel;
7622 if(prop == 'float'){
7625 if(el.style && (v = el.style[prop])){
7628 if(cs = view.getComputedStyle(el, "")){
7629 if(!(camel = propCache[prop])){
7630 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7637 var el = this.dom, v, cs, camel;
7638 if(prop == 'opacity'){
7639 if(typeof el.style.filter == 'string'){
7640 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7642 var fv = parseFloat(m[1]);
7644 return fv ? fv / 100 : 0;
7649 }else if(prop == 'float'){
7650 prop = "styleFloat";
7652 if(!(camel = propCache[prop])){
7653 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7655 if(v = el.style[camel]){
7658 if(cs = el.currentStyle){
7666 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7667 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7668 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7669 * @return {Roo.Element} this
7671 setStyle : function(prop, value){
7672 if(typeof prop == "string"){
7674 if (prop == 'float') {
7675 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7680 if(!(camel = propCache[prop])){
7681 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7684 if(camel == 'opacity') {
7685 this.setOpacity(value);
7687 this.dom.style[camel] = value;
7690 for(var style in prop){
7691 if(typeof prop[style] != "function"){
7692 this.setStyle(style, prop[style]);
7700 * More flexible version of {@link #setStyle} for setting style properties.
7701 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7702 * a function which returns such a specification.
7703 * @return {Roo.Element} this
7705 applyStyles : function(style){
7706 Roo.DomHelper.applyStyles(this.dom, style);
7711 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7712 * @return {Number} The X position of the element
7715 return D.getX(this.dom);
7719 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7720 * @return {Number} The Y position of the element
7723 return D.getY(this.dom);
7727 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7728 * @return {Array} The XY position of the element
7731 return D.getXY(this.dom);
7735 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7736 * @param {Number} The X position of the element
7737 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7738 * @return {Roo.Element} this
7740 setX : function(x, animate){
7742 D.setX(this.dom, x);
7744 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7750 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7751 * @param {Number} The Y position of the element
7752 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7753 * @return {Roo.Element} this
7755 setY : function(y, animate){
7757 D.setY(this.dom, y);
7759 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7765 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7766 * @param {String} left The left CSS property value
7767 * @return {Roo.Element} this
7769 setLeft : function(left){
7770 this.setStyle("left", this.addUnits(left));
7775 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7776 * @param {String} top The top CSS property value
7777 * @return {Roo.Element} this
7779 setTop : function(top){
7780 this.setStyle("top", this.addUnits(top));
7785 * Sets the element's CSS right style.
7786 * @param {String} right The right CSS property value
7787 * @return {Roo.Element} this
7789 setRight : function(right){
7790 this.setStyle("right", this.addUnits(right));
7795 * Sets the element's CSS bottom style.
7796 * @param {String} bottom The bottom CSS property value
7797 * @return {Roo.Element} this
7799 setBottom : function(bottom){
7800 this.setStyle("bottom", this.addUnits(bottom));
7805 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7806 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7807 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7808 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7809 * @return {Roo.Element} this
7811 setXY : function(pos, animate){
7813 D.setXY(this.dom, pos);
7815 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7821 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7822 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7823 * @param {Number} x X value for new position (coordinates are page-based)
7824 * @param {Number} y Y value for new position (coordinates are page-based)
7825 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7826 * @return {Roo.Element} this
7828 setLocation : function(x, y, animate){
7829 this.setXY([x, y], this.preanim(arguments, 2));
7834 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7835 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7836 * @param {Number} x X value for new position (coordinates are page-based)
7837 * @param {Number} y Y value for new position (coordinates are page-based)
7838 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7839 * @return {Roo.Element} this
7841 moveTo : function(x, y, animate){
7842 this.setXY([x, y], this.preanim(arguments, 2));
7847 * Returns the region of the given element.
7848 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7849 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7851 getRegion : function(){
7852 return D.getRegion(this.dom);
7856 * Returns the offset height of the element
7857 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7858 * @return {Number} The element's height
7860 getHeight : function(contentHeight){
7861 var h = this.dom.offsetHeight || 0;
7862 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7866 * Returns the offset width of the element
7867 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7868 * @return {Number} The element's width
7870 getWidth : function(contentWidth){
7871 var w = this.dom.offsetWidth || 0;
7872 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7876 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7877 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7878 * if a height has not been set using CSS.
7881 getComputedHeight : function(){
7882 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7884 h = parseInt(this.getStyle('height'), 10) || 0;
7885 if(!this.isBorderBox()){
7886 h += this.getFrameWidth('tb');
7893 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7894 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7895 * if a width has not been set using CSS.
7898 getComputedWidth : function(){
7899 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7901 w = parseInt(this.getStyle('width'), 10) || 0;
7902 if(!this.isBorderBox()){
7903 w += this.getFrameWidth('lr');
7910 * Returns the size of the element.
7911 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7912 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7914 getSize : function(contentSize){
7915 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7919 * Returns the width and height of the viewport.
7920 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7922 getViewSize : function(){
7923 var d = this.dom, doc = document, aw = 0, ah = 0;
7924 if(d == doc || d == doc.body){
7925 return {width : D.getViewWidth(), height: D.getViewHeight()};
7928 width : d.clientWidth,
7929 height: d.clientHeight
7935 * Returns the value of the "value" attribute
7936 * @param {Boolean} asNumber true to parse the value as a number
7937 * @return {String/Number}
7939 getValue : function(asNumber){
7940 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7944 adjustWidth : function(width){
7945 if(typeof width == "number"){
7946 if(this.autoBoxAdjust && !this.isBorderBox()){
7947 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7957 adjustHeight : function(height){
7958 if(typeof height == "number"){
7959 if(this.autoBoxAdjust && !this.isBorderBox()){
7960 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7970 * Set the width of the element
7971 * @param {Number} width The new width
7972 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7973 * @return {Roo.Element} this
7975 setWidth : function(width, animate){
7976 width = this.adjustWidth(width);
7978 this.dom.style.width = this.addUnits(width);
7980 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7986 * Set the height of the element
7987 * @param {Number} height The new height
7988 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7989 * @return {Roo.Element} this
7991 setHeight : function(height, animate){
7992 height = this.adjustHeight(height);
7994 this.dom.style.height = this.addUnits(height);
7996 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8002 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8003 * @param {Number} width The new width
8004 * @param {Number} height The new height
8005 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8006 * @return {Roo.Element} this
8008 setSize : function(width, height, animate){
8009 if(typeof width == "object"){ // in case of object from getSize()
8010 height = width.height; width = width.width;
8012 width = this.adjustWidth(width); height = this.adjustHeight(height);
8014 this.dom.style.width = this.addUnits(width);
8015 this.dom.style.height = this.addUnits(height);
8017 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8023 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8024 * @param {Number} x X value for new position (coordinates are page-based)
8025 * @param {Number} y Y value for new position (coordinates are page-based)
8026 * @param {Number} width The new width
8027 * @param {Number} height The new height
8028 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8029 * @return {Roo.Element} this
8031 setBounds : function(x, y, width, height, animate){
8033 this.setSize(width, height);
8034 this.setLocation(x, y);
8036 width = this.adjustWidth(width); height = this.adjustHeight(height);
8037 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8038 this.preanim(arguments, 4), 'motion');
8044 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
8045 * @param {Roo.lib.Region} region The region to fill
8046 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8047 * @return {Roo.Element} this
8049 setRegion : function(region, animate){
8050 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8055 * Appends an event handler
8057 * @param {String} eventName The type of event to append
8058 * @param {Function} fn The method the event invokes
8059 * @param {Object} scope (optional) The scope (this object) of the fn
8060 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8062 addListener : function(eventName, fn, scope, options){
8064 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8069 * Removes an event handler from this element
8070 * @param {String} eventName the type of event to remove
8071 * @param {Function} fn the method the event invokes
8072 * @return {Roo.Element} this
8074 removeListener : function(eventName, fn){
8075 Roo.EventManager.removeListener(this.dom, eventName, fn);
8080 * Removes all previous added listeners from this element
8081 * @return {Roo.Element} this
8083 removeAllListeners : function(){
8084 E.purgeElement(this.dom);
8088 relayEvent : function(eventName, observable){
8089 this.on(eventName, function(e){
8090 observable.fireEvent(eventName, e);
8095 * Set the opacity of the element
8096 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8097 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8098 * @return {Roo.Element} this
8100 setOpacity : function(opacity, animate){
8102 var s = this.dom.style;
8105 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8106 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8108 s.opacity = opacity;
8111 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8117 * Gets the left X coordinate
8118 * @param {Boolean} local True to get the local css position instead of page coordinate
8121 getLeft : function(local){
8125 return parseInt(this.getStyle("left"), 10) || 0;
8130 * Gets the right X coordinate of the element (element X position + element width)
8131 * @param {Boolean} local True to get the local css position instead of page coordinate
8134 getRight : function(local){
8136 return this.getX() + this.getWidth();
8138 return (this.getLeft(true) + this.getWidth()) || 0;
8143 * Gets the top Y coordinate
8144 * @param {Boolean} local True to get the local css position instead of page coordinate
8147 getTop : function(local) {
8151 return parseInt(this.getStyle("top"), 10) || 0;
8156 * Gets the bottom Y coordinate of the element (element Y position + element height)
8157 * @param {Boolean} local True to get the local css position instead of page coordinate
8160 getBottom : function(local){
8162 return this.getY() + this.getHeight();
8164 return (this.getTop(true) + this.getHeight()) || 0;
8169 * Initializes positioning on this element. If a desired position is not passed, it will make the
8170 * the element positioned relative IF it is not already positioned.
8171 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8172 * @param {Number} zIndex (optional) The zIndex to apply
8173 * @param {Number} x (optional) Set the page X position
8174 * @param {Number} y (optional) Set the page Y position
8176 position : function(pos, zIndex, x, y){
8178 if(this.getStyle('position') == 'static'){
8179 this.setStyle('position', 'relative');
8182 this.setStyle("position", pos);
8185 this.setStyle("z-index", zIndex);
8187 if(x !== undefined && y !== undefined){
8189 }else if(x !== undefined){
8191 }else if(y !== undefined){
8197 * Clear positioning back to the default when the document was loaded
8198 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8199 * @return {Roo.Element} this
8201 clearPositioning : function(value){
8209 "position" : "static"
8215 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8216 * snapshot before performing an update and then restoring the element.
8219 getPositioning : function(){
8220 var l = this.getStyle("left");
8221 var t = this.getStyle("top");
8223 "position" : this.getStyle("position"),
8225 "right" : l ? "" : this.getStyle("right"),
8227 "bottom" : t ? "" : this.getStyle("bottom"),
8228 "z-index" : this.getStyle("z-index")
8233 * Gets the width of the border(s) for the specified side(s)
8234 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8235 * passing lr would get the border (l)eft width + the border (r)ight width.
8236 * @return {Number} The width of the sides passed added together
8238 getBorderWidth : function(side){
8239 return this.addStyles(side, El.borders);
8243 * Gets the width of the padding(s) for the specified side(s)
8244 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8245 * passing lr would get the padding (l)eft + the padding (r)ight.
8246 * @return {Number} The padding of the sides passed added together
8248 getPadding : function(side){
8249 return this.addStyles(side, El.paddings);
8253 * Set positioning with an object returned by getPositioning().
8254 * @param {Object} posCfg
8255 * @return {Roo.Element} this
8257 setPositioning : function(pc){
8258 this.applyStyles(pc);
8259 if(pc.right == "auto"){
8260 this.dom.style.right = "";
8262 if(pc.bottom == "auto"){
8263 this.dom.style.bottom = "";
8269 fixDisplay : function(){
8270 if(this.getStyle("display") == "none"){
8271 this.setStyle("visibility", "hidden");
8272 this.setStyle("display", this.originalDisplay); // first try reverting to default
8273 if(this.getStyle("display") == "none"){ // if that fails, default to block
8274 this.setStyle("display", "block");
8280 * Quick set left and top adding default units
8281 * @param {String} left The left CSS property value
8282 * @param {String} top The top CSS property value
8283 * @return {Roo.Element} this
8285 setLeftTop : function(left, top){
8286 this.dom.style.left = this.addUnits(left);
8287 this.dom.style.top = this.addUnits(top);
8292 * Move this element relative to its current position.
8293 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8294 * @param {Number} distance How far to move the element in pixels
8295 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8296 * @return {Roo.Element} this
8298 move : function(direction, distance, animate){
8299 var xy = this.getXY();
8300 direction = direction.toLowerCase();
8304 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8308 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8313 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8318 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8325 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8326 * @return {Roo.Element} this
8329 if(!this.isClipped){
8330 this.isClipped = true;
8331 this.originalClip = {
8332 "o": this.getStyle("overflow"),
8333 "x": this.getStyle("overflow-x"),
8334 "y": this.getStyle("overflow-y")
8336 this.setStyle("overflow", "hidden");
8337 this.setStyle("overflow-x", "hidden");
8338 this.setStyle("overflow-y", "hidden");
8344 * Return clipping (overflow) to original clipping before clip() was called
8345 * @return {Roo.Element} this
8347 unclip : function(){
8349 this.isClipped = false;
8350 var o = this.originalClip;
8351 if(o.o){this.setStyle("overflow", o.o);}
8352 if(o.x){this.setStyle("overflow-x", o.x);}
8353 if(o.y){this.setStyle("overflow-y", o.y);}
8360 * Gets the x,y coordinates specified by the anchor position on the element.
8361 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8362 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8363 * {width: (target width), height: (target height)} (defaults to the element's current size)
8364 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8365 * @return {Array} [x, y] An array containing the element's x and y coordinates
8367 getAnchorXY : function(anchor, local, s){
8368 //Passing a different size is useful for pre-calculating anchors,
8369 //especially for anchored animations that change the el size.
8371 var w, h, vp = false;
8374 if(d == document.body || d == document){
8376 w = D.getViewWidth(); h = D.getViewHeight();
8378 w = this.getWidth(); h = this.getHeight();
8381 w = s.width; h = s.height;
8383 var x = 0, y = 0, r = Math.round;
8384 switch((anchor || "tl").toLowerCase()){
8426 var sc = this.getScroll();
8427 return [x + sc.left, y + sc.top];
8429 //Add the element's offset xy
8430 var o = this.getXY();
8431 return [x+o[0], y+o[1]];
8435 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8436 * supported position values.
8437 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8438 * @param {String} position The position to align to.
8439 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8440 * @return {Array} [x, y]
8442 getAlignToXY : function(el, p, o){
8446 throw "Element.alignTo with an element that doesn't exist";
8448 var c = false; //constrain to viewport
8449 var p1 = "", p2 = "";
8456 }else if(p.indexOf("-") == -1){
8459 p = p.toLowerCase();
8460 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8462 throw "Element.alignTo with an invalid alignment " + p;
8464 p1 = m[1]; p2 = m[2]; c = !!m[3];
8466 //Subtract the aligned el's internal xy from the target's offset xy
8467 //plus custom offset to get the aligned el's new offset xy
8468 var a1 = this.getAnchorXY(p1, true);
8469 var a2 = el.getAnchorXY(p2, false);
8470 var x = a2[0] - a1[0] + o[0];
8471 var y = a2[1] - a1[1] + o[1];
8473 //constrain the aligned el to viewport if necessary
8474 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8475 // 5px of margin for ie
8476 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8478 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8479 //perpendicular to the vp border, allow the aligned el to slide on that border,
8480 //otherwise swap the aligned el to the opposite border of the target.
8481 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8482 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8483 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8484 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8487 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8488 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8490 if((x+w) > dw + scrollX){
8491 x = swapX ? r.left-w : dw+scrollX-w;
8494 x = swapX ? r.right : scrollX;
8496 if((y+h) > dh + scrollY){
8497 y = swapY ? r.top-h : dh+scrollY-h;
8500 y = swapY ? r.bottom : scrollY;
8507 getConstrainToXY : function(){
8508 var os = {top:0, left:0, bottom:0, right: 0};
8510 return function(el, local, offsets, proposedXY){
8512 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8514 var vw, vh, vx = 0, vy = 0;
8515 if(el.dom == document.body || el.dom == document){
8516 vw = Roo.lib.Dom.getViewWidth();
8517 vh = Roo.lib.Dom.getViewHeight();
8519 vw = el.dom.clientWidth;
8520 vh = el.dom.clientHeight;
8522 var vxy = el.getXY();
8528 var s = el.getScroll();
8530 vx += offsets.left + s.left;
8531 vy += offsets.top + s.top;
8533 vw -= offsets.right;
8534 vh -= offsets.bottom;
8539 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8540 var x = xy[0], y = xy[1];
8541 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8543 // only move it if it needs it
8546 // first validate right/bottom
8555 // then make sure top/left isn't negative
8564 return moved ? [x, y] : false;
8569 adjustForConstraints : function(xy, parent, offsets){
8570 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8574 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8575 * document it aligns it to the viewport.
8576 * The position parameter is optional, and can be specified in any one of the following formats:
8578 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8579 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8580 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8581 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8582 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8583 * element's anchor point, and the second value is used as the target's anchor point.</li>
8585 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8586 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8587 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8588 * that specified in order to enforce the viewport constraints.
8589 * Following are all of the supported anchor positions:
8592 ----- -----------------------------
8593 tl The top left corner (default)
8594 t The center of the top edge
8595 tr The top right corner
8596 l The center of the left edge
8597 c In the center of the element
8598 r The center of the right edge
8599 bl The bottom left corner
8600 b The center of the bottom edge
8601 br The bottom right corner
8605 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8606 el.alignTo("other-el");
8608 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8609 el.alignTo("other-el", "tr?");
8611 // align the bottom right corner of el with the center left edge of other-el
8612 el.alignTo("other-el", "br-l?");
8614 // align the center of el with the bottom left corner of other-el and
8615 // adjust the x position by -6 pixels (and the y position by 0)
8616 el.alignTo("other-el", "c-bl", [-6, 0]);
8618 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8619 * @param {String} position The position to align to.
8620 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8621 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8622 * @return {Roo.Element} this
8624 alignTo : function(element, position, offsets, animate){
8625 var xy = this.getAlignToXY(element, position, offsets);
8626 this.setXY(xy, this.preanim(arguments, 3));
8631 * Anchors an element to another element and realigns it when the window is resized.
8632 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8633 * @param {String} position The position to align to.
8634 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8635 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8636 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8637 * is a number, it is used as the buffer delay (defaults to 50ms).
8638 * @param {Function} callback The function to call after the animation finishes
8639 * @return {Roo.Element} this
8641 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8642 var action = function(){
8643 this.alignTo(el, alignment, offsets, animate);
8644 Roo.callback(callback, this);
8646 Roo.EventManager.onWindowResize(action, this);
8647 var tm = typeof monitorScroll;
8648 if(tm != 'undefined'){
8649 Roo.EventManager.on(window, 'scroll', action, this,
8650 {buffer: tm == 'number' ? monitorScroll : 50});
8652 action.call(this); // align immediately
8656 * Clears any opacity settings from this element. Required in some cases for IE.
8657 * @return {Roo.Element} this
8659 clearOpacity : function(){
8660 if (window.ActiveXObject) {
8661 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8662 this.dom.style.filter = "";
8665 this.dom.style.opacity = "";
8666 this.dom.style["-moz-opacity"] = "";
8667 this.dom.style["-khtml-opacity"] = "";
8673 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8674 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8675 * @return {Roo.Element} this
8677 hide : function(animate){
8678 this.setVisible(false, this.preanim(arguments, 0));
8683 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8684 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8685 * @return {Roo.Element} this
8687 show : function(animate){
8688 this.setVisible(true, this.preanim(arguments, 0));
8693 * @private Test if size has a unit, otherwise appends the default
8695 addUnits : function(size){
8696 return Roo.Element.addUnits(size, this.defaultUnit);
8700 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8701 * @return {Roo.Element} this
8703 beginMeasure : function(){
8705 if(el.offsetWidth || el.offsetHeight){
8706 return this; // offsets work already
8709 var p = this.dom, b = document.body; // start with this element
8710 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8711 var pe = Roo.get(p);
8712 if(pe.getStyle('display') == 'none'){
8713 changed.push({el: p, visibility: pe.getStyle("visibility")});
8714 p.style.visibility = "hidden";
8715 p.style.display = "block";
8719 this._measureChanged = changed;
8725 * Restores displays to before beginMeasure was called
8726 * @return {Roo.Element} this
8728 endMeasure : function(){
8729 var changed = this._measureChanged;
8731 for(var i = 0, len = changed.length; i < len; i++) {
8733 r.el.style.visibility = r.visibility;
8734 r.el.style.display = "none";
8736 this._measureChanged = null;
8742 * Update the innerHTML of this element, optionally searching for and processing scripts
8743 * @param {String} html The new HTML
8744 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8745 * @param {Function} callback For async script loading you can be noticed when the update completes
8746 * @return {Roo.Element} this
8748 update : function(html, loadScripts, callback){
8749 if(typeof html == "undefined"){
8752 if(loadScripts !== true){
8753 this.dom.innerHTML = html;
8754 if(typeof callback == "function"){
8762 html += '<span id="' + id + '"></span>';
8764 E.onAvailable(id, function(){
8765 var hd = document.getElementsByTagName("head")[0];
8766 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8767 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8768 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8771 while(match = re.exec(html)){
8772 var attrs = match[1];
8773 var srcMatch = attrs ? attrs.match(srcRe) : false;
8774 if(srcMatch && srcMatch[2]){
8775 var s = document.createElement("script");
8776 s.src = srcMatch[2];
8777 var typeMatch = attrs.match(typeRe);
8778 if(typeMatch && typeMatch[2]){
8779 s.type = typeMatch[2];
8782 }else if(match[2] && match[2].length > 0){
8783 if(window.execScript) {
8784 window.execScript(match[2]);
8792 window.eval(match[2]);
8796 var el = document.getElementById(id);
8797 if(el){el.parentNode.removeChild(el);}
8798 if(typeof callback == "function"){
8802 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8807 * Direct access to the UpdateManager update() method (takes the same parameters).
8808 * @param {String/Function} url The url for this request or a function to call to get the url
8809 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8810 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8811 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8812 * @return {Roo.Element} this
8815 var um = this.getUpdateManager();
8816 um.update.apply(um, arguments);
8821 * Gets this element's UpdateManager
8822 * @return {Roo.UpdateManager} The UpdateManager
8824 getUpdateManager : function(){
8825 if(!this.updateManager){
8826 this.updateManager = new Roo.UpdateManager(this);
8828 return this.updateManager;
8832 * Disables text selection for this element (normalized across browsers)
8833 * @return {Roo.Element} this
8835 unselectable : function(){
8836 this.dom.unselectable = "on";
8837 this.swallowEvent("selectstart", true);
8838 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8839 this.addClass("x-unselectable");
8844 * Calculates the x, y to center this element on the screen
8845 * @return {Array} The x, y values [x, y]
8847 getCenterXY : function(){
8848 return this.getAlignToXY(document, 'c-c');
8852 * Centers the Element in either the viewport, or another Element.
8853 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8855 center : function(centerIn){
8856 this.alignTo(centerIn || document, 'c-c');
8861 * Tests various css rules/browsers to determine if this element uses a border box
8864 isBorderBox : function(){
8865 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8869 * Return a box {x, y, width, height} that can be used to set another elements
8870 * size/location to match this element.
8871 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8872 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8873 * @return {Object} box An object in the format {x, y, width, height}
8875 getBox : function(contentBox, local){
8880 var left = parseInt(this.getStyle("left"), 10) || 0;
8881 var top = parseInt(this.getStyle("top"), 10) || 0;
8884 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8886 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8888 var l = this.getBorderWidth("l")+this.getPadding("l");
8889 var r = this.getBorderWidth("r")+this.getPadding("r");
8890 var t = this.getBorderWidth("t")+this.getPadding("t");
8891 var b = this.getBorderWidth("b")+this.getPadding("b");
8892 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8894 bx.right = bx.x + bx.width;
8895 bx.bottom = bx.y + bx.height;
8900 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8901 for more information about the sides.
8902 * @param {String} sides
8905 getFrameWidth : function(sides, onlyContentBox){
8906 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8910 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8911 * @param {Object} box The box to fill {x, y, width, height}
8912 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8913 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8914 * @return {Roo.Element} this
8916 setBox : function(box, adjust, animate){
8917 var w = box.width, h = box.height;
8918 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8919 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8920 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8922 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8927 * Forces the browser to repaint this element
8928 * @return {Roo.Element} this
8930 repaint : function(){
8932 this.addClass("x-repaint");
8933 setTimeout(function(){
8934 Roo.get(dom).removeClass("x-repaint");
8940 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8941 * then it returns the calculated width of the sides (see getPadding)
8942 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8943 * @return {Object/Number}
8945 getMargins : function(side){
8948 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8949 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8950 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8951 right: parseInt(this.getStyle("margin-right"), 10) || 0
8954 return this.addStyles(side, El.margins);
8959 addStyles : function(sides, styles){
8961 for(var i = 0, len = sides.length; i < len; i++){
8962 v = this.getStyle(styles[sides.charAt(i)]);
8964 w = parseInt(v, 10);
8972 * Creates a proxy element of this element
8973 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8974 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8975 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8976 * @return {Roo.Element} The new proxy element
8978 createProxy : function(config, renderTo, matchBox){
8980 renderTo = Roo.getDom(renderTo);
8982 renderTo = document.body;
8984 config = typeof config == "object" ?
8985 config : {tag : "div", cls: config};
8986 var proxy = Roo.DomHelper.append(renderTo, config, true);
8988 proxy.setBox(this.getBox());
8994 * Puts a mask over this element to disable user interaction. Requires core.css.
8995 * This method can only be applied to elements which accept child nodes.
8996 * @param {String} msg (optional) A message to display in the mask
8997 * @param {String} msgCls (optional) A css class to apply to the msg element
8998 * @return {Element} The mask element
9000 mask : function(msg, msgCls)
9002 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9003 this.setStyle("position", "relative");
9006 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9008 this.addClass("x-masked");
9009 this._mask.setDisplayed(true);
9014 while (dom && dom.style) {
9015 if (!isNaN(parseInt(dom.style.zIndex))) {
9016 z = Math.max(z, parseInt(dom.style.zIndex));
9018 dom = dom.parentNode;
9020 // if we are masking the body - then it hides everything..
9021 if (this.dom == document.body) {
9023 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9024 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9027 if(typeof msg == 'string'){
9029 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9031 var mm = this._maskMsg;
9032 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9033 if (mm.dom.firstChild) { // weird IE issue?
9034 mm.dom.firstChild.innerHTML = msg;
9036 mm.setDisplayed(true);
9038 mm.setStyle('z-index', z + 102);
9040 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9041 this._mask.setHeight(this.getHeight());
9043 this._mask.setStyle('z-index', z + 100);
9049 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9050 * it is cached for reuse.
9052 unmask : function(removeEl){
9054 if(removeEl === true){
9055 this._mask.remove();
9058 this._maskMsg.remove();
9059 delete this._maskMsg;
9062 this._mask.setDisplayed(false);
9064 this._maskMsg.setDisplayed(false);
9068 this.removeClass("x-masked");
9072 * Returns true if this element is masked
9075 isMasked : function(){
9076 return this._mask && this._mask.isVisible();
9080 * Creates an iframe shim for this element to keep selects and other windowed objects from
9082 * @return {Roo.Element} The new shim element
9084 createShim : function(){
9085 var el = document.createElement('iframe');
9086 el.frameBorder = 'no';
9087 el.className = 'roo-shim';
9088 if(Roo.isIE && Roo.isSecure){
9089 el.src = Roo.SSL_SECURE_URL;
9091 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9092 shim.autoBoxAdjust = false;
9097 * Removes this element from the DOM and deletes it from the cache
9099 remove : function(){
9100 if(this.dom.parentNode){
9101 this.dom.parentNode.removeChild(this.dom);
9103 delete El.cache[this.dom.id];
9107 * Sets up event handlers to add and remove a css class when the mouse is over this element
9108 * @param {String} className
9109 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9110 * mouseout events for children elements
9111 * @return {Roo.Element} this
9113 addClassOnOver : function(className, preventFlicker){
9114 this.on("mouseover", function(){
9115 Roo.fly(this, '_internal').addClass(className);
9117 var removeFn = function(e){
9118 if(preventFlicker !== true || !e.within(this, true)){
9119 Roo.fly(this, '_internal').removeClass(className);
9122 this.on("mouseout", removeFn, this.dom);
9127 * Sets up event handlers to add and remove a css class when this element has the focus
9128 * @param {String} className
9129 * @return {Roo.Element} this
9131 addClassOnFocus : function(className){
9132 this.on("focus", function(){
9133 Roo.fly(this, '_internal').addClass(className);
9135 this.on("blur", function(){
9136 Roo.fly(this, '_internal').removeClass(className);
9141 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
9142 * @param {String} className
9143 * @return {Roo.Element} this
9145 addClassOnClick : function(className){
9147 this.on("mousedown", function(){
9148 Roo.fly(dom, '_internal').addClass(className);
9149 var d = Roo.get(document);
9150 var fn = function(){
9151 Roo.fly(dom, '_internal').removeClass(className);
9152 d.removeListener("mouseup", fn);
9154 d.on("mouseup", fn);
9160 * Stops the specified event from bubbling and optionally prevents the default action
9161 * @param {String} eventName
9162 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9163 * @return {Roo.Element} this
9165 swallowEvent : function(eventName, preventDefault){
9166 var fn = function(e){
9167 e.stopPropagation();
9172 if(eventName instanceof Array){
9173 for(var i = 0, len = eventName.length; i < len; i++){
9174 this.on(eventName[i], fn);
9178 this.on(eventName, fn);
9185 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9188 * Sizes this element to its parent element's dimensions performing
9189 * neccessary box adjustments.
9190 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9191 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9192 * @return {Roo.Element} this
9194 fitToParent : function(monitorResize, targetParent) {
9195 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9196 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9197 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9200 var p = Roo.get(targetParent || this.dom.parentNode);
9201 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9202 if (monitorResize === true) {
9203 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9204 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9210 * Gets the next sibling, skipping text nodes
9211 * @return {HTMLElement} The next sibling or null
9213 getNextSibling : function(){
9214 var n = this.dom.nextSibling;
9215 while(n && n.nodeType != 1){
9222 * Gets the previous sibling, skipping text nodes
9223 * @return {HTMLElement} The previous sibling or null
9225 getPrevSibling : function(){
9226 var n = this.dom.previousSibling;
9227 while(n && n.nodeType != 1){
9228 n = n.previousSibling;
9235 * Appends the passed element(s) to this element
9236 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9237 * @return {Roo.Element} this
9239 appendChild: function(el){
9246 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9247 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9248 * automatically generated with the specified attributes.
9249 * @param {HTMLElement} insertBefore (optional) a child element of this element
9250 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9251 * @return {Roo.Element} The new child element
9253 createChild: function(config, insertBefore, returnDom){
9254 config = config || {tag:'div'};
9256 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9258 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9262 * Appends this element to the passed element
9263 * @param {String/HTMLElement/Element} el The new parent element
9264 * @return {Roo.Element} this
9266 appendTo: function(el){
9267 el = Roo.getDom(el);
9268 el.appendChild(this.dom);
9273 * Inserts this element before the passed element in the DOM
9274 * @param {String/HTMLElement/Element} el The element to insert before
9275 * @return {Roo.Element} this
9277 insertBefore: function(el){
9278 el = Roo.getDom(el);
9279 el.parentNode.insertBefore(this.dom, el);
9284 * Inserts this element after the passed element in the DOM
9285 * @param {String/HTMLElement/Element} el The element to insert after
9286 * @return {Roo.Element} this
9288 insertAfter: function(el){
9289 el = Roo.getDom(el);
9290 el.parentNode.insertBefore(this.dom, el.nextSibling);
9295 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9296 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9297 * @return {Roo.Element} The new child
9299 insertFirst: function(el, returnDom){
9301 if(typeof el == 'object' && !el.nodeType){ // dh config
9302 return this.createChild(el, this.dom.firstChild, returnDom);
9304 el = Roo.getDom(el);
9305 this.dom.insertBefore(el, this.dom.firstChild);
9306 return !returnDom ? Roo.get(el) : el;
9311 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9312 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9313 * @param {String} where (optional) 'before' or 'after' defaults to before
9314 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9315 * @return {Roo.Element} the inserted Element
9317 insertSibling: function(el, where, returnDom){
9318 where = where ? where.toLowerCase() : 'before';
9320 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9322 if(typeof el == 'object' && !el.nodeType){ // dh config
9323 if(where == 'after' && !this.dom.nextSibling){
9324 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9326 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9330 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9331 where == 'before' ? this.dom : this.dom.nextSibling);
9340 * Creates and wraps this element with another element
9341 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9342 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9343 * @return {HTMLElement/Element} The newly created wrapper element
9345 wrap: function(config, returnDom){
9347 config = {tag: "div"};
9349 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9350 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9355 * Replaces the passed element with this element
9356 * @param {String/HTMLElement/Element} el The element to replace
9357 * @return {Roo.Element} this
9359 replace: function(el){
9361 this.insertBefore(el);
9367 * Inserts an html fragment into this element
9368 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9369 * @param {String} html The HTML fragment
9370 * @param {Boolean} returnEl True to return an Roo.Element
9371 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9373 insertHtml : function(where, html, returnEl){
9374 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9375 return returnEl ? Roo.get(el) : el;
9379 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9380 * @param {Object} o The object with the attributes
9381 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9382 * @return {Roo.Element} this
9384 set : function(o, useSet){
9386 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9388 if(attr == "style" || typeof o[attr] == "function") continue;
9390 el.className = o["cls"];
9392 if(useSet) el.setAttribute(attr, o[attr]);
9393 else el[attr] = o[attr];
9397 Roo.DomHelper.applyStyles(el, o.style);
9403 * Convenience method for constructing a KeyMap
9404 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9405 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9406 * @param {Function} fn The function to call
9407 * @param {Object} scope (optional) The scope of the function
9408 * @return {Roo.KeyMap} The KeyMap created
9410 addKeyListener : function(key, fn, scope){
9412 if(typeof key != "object" || key instanceof Array){
9428 return new Roo.KeyMap(this, config);
9432 * Creates a KeyMap for this element
9433 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9434 * @return {Roo.KeyMap} The KeyMap created
9436 addKeyMap : function(config){
9437 return new Roo.KeyMap(this, config);
9441 * Returns true if this element is scrollable.
9444 isScrollable : function(){
9446 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9450 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9451 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9452 * @param {Number} value The new scroll value
9453 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9454 * @return {Element} this
9457 scrollTo : function(side, value, animate){
9458 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9460 this.dom[prop] = value;
9462 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9463 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9469 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9470 * within this element's scrollable range.
9471 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9472 * @param {Number} distance How far to scroll the element in pixels
9473 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9474 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9475 * was scrolled as far as it could go.
9477 scroll : function(direction, distance, animate){
9478 if(!this.isScrollable()){
9482 var l = el.scrollLeft, t = el.scrollTop;
9483 var w = el.scrollWidth, h = el.scrollHeight;
9484 var cw = el.clientWidth, ch = el.clientHeight;
9485 direction = direction.toLowerCase();
9486 var scrolled = false;
9487 var a = this.preanim(arguments, 2);
9492 var v = Math.min(l + distance, w-cw);
9493 this.scrollTo("left", v, a);
9500 var v = Math.max(l - distance, 0);
9501 this.scrollTo("left", v, a);
9509 var v = Math.max(t - distance, 0);
9510 this.scrollTo("top", v, a);
9518 var v = Math.min(t + distance, h-ch);
9519 this.scrollTo("top", v, a);
9528 * Translates the passed page coordinates into left/top css values for this element
9529 * @param {Number/Array} x The page x or an array containing [x, y]
9530 * @param {Number} y The page y
9531 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9533 translatePoints : function(x, y){
9534 if(typeof x == 'object' || x instanceof Array){
9537 var p = this.getStyle('position');
9538 var o = this.getXY();
9540 var l = parseInt(this.getStyle('left'), 10);
9541 var t = parseInt(this.getStyle('top'), 10);
9544 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9547 t = (p == "relative") ? 0 : this.dom.offsetTop;
9550 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9554 * Returns the current scroll position of the element.
9555 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9557 getScroll : function(){
9558 var d = this.dom, doc = document;
9559 if(d == doc || d == doc.body){
9560 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9561 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9562 return {left: l, top: t};
9564 return {left: d.scrollLeft, top: d.scrollTop};
9569 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9570 * are convert to standard 6 digit hex color.
9571 * @param {String} attr The css attribute
9572 * @param {String} defaultValue The default value to use when a valid color isn't found
9573 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9576 getColor : function(attr, defaultValue, prefix){
9577 var v = this.getStyle(attr);
9578 if(!v || v == "transparent" || v == "inherit") {
9579 return defaultValue;
9581 var color = typeof prefix == "undefined" ? "#" : prefix;
9582 if(v.substr(0, 4) == "rgb("){
9583 var rvs = v.slice(4, v.length -1).split(",");
9584 for(var i = 0; i < 3; i++){
9585 var h = parseInt(rvs[i]).toString(16);
9592 if(v.substr(0, 1) == "#"){
9594 for(var i = 1; i < 4; i++){
9595 var c = v.charAt(i);
9598 }else if(v.length == 7){
9599 color += v.substr(1);
9603 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9607 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9608 * gradient background, rounded corners and a 4-way shadow.
9609 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9610 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9611 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9612 * @return {Roo.Element} this
9614 boxWrap : function(cls){
9615 cls = cls || 'x-box';
9616 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9617 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9622 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9623 * @param {String} namespace The namespace in which to look for the attribute
9624 * @param {String} name The attribute name
9625 * @return {String} The attribute value
9627 getAttributeNS : Roo.isIE ? function(ns, name){
9629 var type = typeof d[ns+":"+name];
9630 if(type != 'undefined' && type != 'unknown'){
9631 return d[ns+":"+name];
9634 } : function(ns, name){
9636 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9641 * Sets or Returns the value the dom attribute value
9642 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9643 * @param {String} value (optional) The value to set the attribute to
9644 * @return {String} The attribute value
9646 attr : function(name){
9647 if (arguments.length > 1) {
9648 this.dom.setAttribute(name, arguments[1]);
9649 return arguments[1];
9651 if (typeof(name) == 'object') {
9652 for(var i in name) {
9653 this.attr(i, name[i]);
9659 if (!this.dom.hasAttribute(name)) {
9662 return this.dom.getAttribute(name);
9669 var ep = El.prototype;
9672 * Appends an event handler (Shorthand for addListener)
9673 * @param {String} eventName The type of event to append
9674 * @param {Function} fn The method the event invokes
9675 * @param {Object} scope (optional) The scope (this object) of the fn
9676 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9679 ep.on = ep.addListener;
9681 ep.mon = ep.addListener;
9684 * Removes an event handler from this element (shorthand for removeListener)
9685 * @param {String} eventName the type of event to remove
9686 * @param {Function} fn the method the event invokes
9687 * @return {Roo.Element} this
9690 ep.un = ep.removeListener;
9693 * true to automatically adjust width and height settings for box-model issues (default to true)
9695 ep.autoBoxAdjust = true;
9698 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9701 El.addUnits = function(v, defaultUnit){
9702 if(v === "" || v == "auto"){
9705 if(v === undefined){
9708 if(typeof v == "number" || !El.unitPattern.test(v)){
9709 return v + (defaultUnit || 'px');
9714 // special markup used throughout Roo when box wrapping elements
9715 El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9717 * Visibility mode constant - Use visibility to hide element
9723 * Visibility mode constant - Use display to hide element
9729 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9730 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9731 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9743 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9744 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9745 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9746 * @return {Element} The Element object
9749 El.get = function(el){
9751 if(!el){ return null; }
9752 if(typeof el == "string"){ // element id
9753 if(!(elm = document.getElementById(el))){
9756 if(ex = El.cache[el]){
9759 ex = El.cache[el] = new El(elm);
9762 }else if(el.tagName){ // dom element
9766 if(ex = El.cache[id]){
9769 ex = El.cache[id] = new El(el);
9772 }else if(el instanceof El){
9774 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9775 // catch case where it hasn't been appended
9776 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9779 }else if(el.isComposite){
9781 }else if(el instanceof Array){
9782 return El.select(el);
9783 }else if(el == document){
9784 // create a bogus element object representing the document object
9786 var f = function(){};
9787 f.prototype = El.prototype;
9789 docEl.dom = document;
9797 El.uncache = function(el){
9798 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9800 delete El.cache[a[i].id || a[i]];
9806 // Garbage collection - uncache elements/purge listeners on orphaned elements
9807 // so we don't hold a reference and cause the browser to retain them
9808 El.garbageCollect = function(){
9809 if(!Roo.enableGarbageCollector){
9810 clearInterval(El.collectorThread);
9813 for(var eid in El.cache){
9814 var el = El.cache[eid], d = el.dom;
9815 // -------------------------------------------------------
9816 // Determining what is garbage:
9817 // -------------------------------------------------------
9819 // dom node is null, definitely garbage
9820 // -------------------------------------------------------
9822 // no parentNode == direct orphan, definitely garbage
9823 // -------------------------------------------------------
9824 // !d.offsetParent && !document.getElementById(eid)
9825 // display none elements have no offsetParent so we will
9826 // also try to look it up by it's id. However, check
9827 // offsetParent first so we don't do unneeded lookups.
9828 // This enables collection of elements that are not orphans
9829 // directly, but somewhere up the line they have an orphan
9831 // -------------------------------------------------------
9832 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9833 delete El.cache[eid];
9834 if(d && Roo.enableListenerCollection){
9840 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9844 El.Flyweight = function(dom){
9847 El.Flyweight.prototype = El.prototype;
9849 El._flyweights = {};
9851 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9852 * the dom node can be overwritten by other code.
9853 * @param {String/HTMLElement} el The dom node or id
9854 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9855 * prevent conflicts (e.g. internally Roo uses "_internal")
9857 * @return {Element} The shared Element object
9859 El.fly = function(el, named){
9860 named = named || '_global';
9861 el = Roo.getDom(el);
9865 if(!El._flyweights[named]){
9866 El._flyweights[named] = new El.Flyweight();
9868 El._flyweights[named].dom = el;
9869 return El._flyweights[named];
9873 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9874 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9875 * Shorthand of {@link Roo.Element#get}
9876 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9877 * @return {Element} The Element object
9883 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9884 * the dom node can be overwritten by other code.
9885 * Shorthand of {@link Roo.Element#fly}
9886 * @param {String/HTMLElement} el The dom node or id
9887 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9888 * prevent conflicts (e.g. internally Roo uses "_internal")
9890 * @return {Element} The shared Element object
9896 // speedy lookup for elements never to box adjust
9897 var noBoxAdjust = Roo.isStrict ? {
9900 input:1, select:1, textarea:1
9902 if(Roo.isIE || Roo.isGecko){
9903 noBoxAdjust['button'] = 1;
9907 Roo.EventManager.on(window, 'unload', function(){
9909 delete El._flyweights;
9917 Roo.Element.selectorFunction = Roo.DomQuery.select;
9920 Roo.Element.select = function(selector, unique, root){
9922 if(typeof selector == "string"){
9923 els = Roo.Element.selectorFunction(selector, root);
9924 }else if(selector.length !== undefined){
9927 throw "Invalid selector";
9929 if(unique === true){
9930 return new Roo.CompositeElement(els);
9932 return new Roo.CompositeElementLite(els);
9936 * Selects elements based on the passed CSS selector to enable working on them as 1.
9937 * @param {String/Array} selector The CSS selector or an array of elements
9938 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9939 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9940 * @return {CompositeElementLite/CompositeElement}
9944 Roo.select = Roo.Element.select;
9961 * Ext JS Library 1.1.1
9962 * Copyright(c) 2006-2007, Ext JS, LLC.
9964 * Originally Released Under LGPL - original licence link has changed is not relivant.
9967 * <script type="text/javascript">
9972 //Notifies Element that fx methods are available
9973 Roo.enableFx = true;
9977 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9978 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9979 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9980 * Element effects to work.</p><br/>
9982 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9983 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9984 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9985 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9986 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9987 * expected results and should be done with care.</p><br/>
9989 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9990 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9993 ----- -----------------------------
9994 tl The top left corner
9995 t The center of the top edge
9996 tr The top right corner
9997 l The center of the left edge
9998 r The center of the right edge
9999 bl The bottom left corner
10000 b The center of the bottom edge
10001 br The bottom right corner
10003 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10004 * below are common options that can be passed to any Fx method.</b>
10005 * @cfg {Function} callback A function called when the effect is finished
10006 * @cfg {Object} scope The scope of the effect function
10007 * @cfg {String} easing A valid Easing value for the effect
10008 * @cfg {String} afterCls A css class to apply after the effect
10009 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10010 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10011 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10012 * effects that end with the element being visually hidden, ignored otherwise)
10013 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10014 * a function which returns such a specification that will be applied to the Element after the effect finishes
10015 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10016 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
10017 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10021 * Slides the element into view. An anchor point can be optionally passed to set the point of
10022 * origin for the slide effect. This function automatically handles wrapping the element with
10023 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10026 // default: slide the element in from the top
10029 // custom: slide the element in from the right with a 2-second duration
10030 el.slideIn('r', { duration: 2 });
10032 // common config options shown with default values
10038 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10039 * @param {Object} options (optional) Object literal with any of the Fx config options
10040 * @return {Roo.Element} The Element
10042 slideIn : function(anchor, o){
10043 var el = this.getFxEl();
10046 el.queueFx(o, function(){
10048 anchor = anchor || "t";
10050 // fix display to visibility
10053 // restore values after effect
10054 var r = this.getFxRestore();
10055 var b = this.getBox();
10056 // fixed size for slide
10060 var wrap = this.fxWrap(r.pos, o, "hidden");
10062 var st = this.dom.style;
10063 st.visibility = "visible";
10064 st.position = "absolute";
10066 // clear out temp styles after slide and unwrap
10067 var after = function(){
10068 el.fxUnwrap(wrap, r.pos, o);
10069 st.width = r.width;
10070 st.height = r.height;
10073 // time to calc the positions
10074 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10076 switch(anchor.toLowerCase()){
10078 wrap.setSize(b.width, 0);
10079 st.left = st.bottom = "0";
10083 wrap.setSize(0, b.height);
10084 st.right = st.top = "0";
10088 wrap.setSize(0, b.height);
10089 wrap.setX(b.right);
10090 st.left = st.top = "0";
10091 a = {width: bw, points: pt};
10094 wrap.setSize(b.width, 0);
10095 wrap.setY(b.bottom);
10096 st.left = st.top = "0";
10097 a = {height: bh, points: pt};
10100 wrap.setSize(0, 0);
10101 st.right = st.bottom = "0";
10102 a = {width: bw, height: bh};
10105 wrap.setSize(0, 0);
10106 wrap.setY(b.y+b.height);
10107 st.right = st.top = "0";
10108 a = {width: bw, height: bh, points: pt};
10111 wrap.setSize(0, 0);
10112 wrap.setXY([b.right, b.bottom]);
10113 st.left = st.top = "0";
10114 a = {width: bw, height: bh, points: pt};
10117 wrap.setSize(0, 0);
10118 wrap.setX(b.x+b.width);
10119 st.left = st.bottom = "0";
10120 a = {width: bw, height: bh, points: pt};
10123 this.dom.style.visibility = "visible";
10126 arguments.callee.anim = wrap.fxanim(a,
10136 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10137 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10138 * 'hidden') but block elements will still take up space in the document. The element must be removed
10139 * from the DOM using the 'remove' config option if desired. This function automatically handles
10140 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10143 // default: slide the element out to the top
10146 // custom: slide the element out to the right with a 2-second duration
10147 el.slideOut('r', { duration: 2 });
10149 // common config options shown with default values
10157 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10158 * @param {Object} options (optional) Object literal with any of the Fx config options
10159 * @return {Roo.Element} The Element
10161 slideOut : function(anchor, o){
10162 var el = this.getFxEl();
10165 el.queueFx(o, function(){
10167 anchor = anchor || "t";
10169 // restore values after effect
10170 var r = this.getFxRestore();
10172 var b = this.getBox();
10173 // fixed size for slide
10177 var wrap = this.fxWrap(r.pos, o, "visible");
10179 var st = this.dom.style;
10180 st.visibility = "visible";
10181 st.position = "absolute";
10185 var after = function(){
10187 el.setDisplayed(false);
10192 el.fxUnwrap(wrap, r.pos, o);
10194 st.width = r.width;
10195 st.height = r.height;
10200 var a, zero = {to: 0};
10201 switch(anchor.toLowerCase()){
10203 st.left = st.bottom = "0";
10204 a = {height: zero};
10207 st.right = st.top = "0";
10211 st.left = st.top = "0";
10212 a = {width: zero, points: {to:[b.right, b.y]}};
10215 st.left = st.top = "0";
10216 a = {height: zero, points: {to:[b.x, b.bottom]}};
10219 st.right = st.bottom = "0";
10220 a = {width: zero, height: zero};
10223 st.right = st.top = "0";
10224 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10227 st.left = st.top = "0";
10228 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10231 st.left = st.bottom = "0";
10232 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10236 arguments.callee.anim = wrap.fxanim(a,
10246 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10247 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10248 * The element must be removed from the DOM using the 'remove' config option if desired.
10254 // common config options shown with default values
10262 * @param {Object} options (optional) Object literal with any of the Fx config options
10263 * @return {Roo.Element} The Element
10265 puff : function(o){
10266 var el = this.getFxEl();
10269 el.queueFx(o, function(){
10270 this.clearOpacity();
10273 // restore values after effect
10274 var r = this.getFxRestore();
10275 var st = this.dom.style;
10277 var after = function(){
10279 el.setDisplayed(false);
10286 el.setPositioning(r.pos);
10287 st.width = r.width;
10288 st.height = r.height;
10293 var width = this.getWidth();
10294 var height = this.getHeight();
10296 arguments.callee.anim = this.fxanim({
10297 width : {to: this.adjustWidth(width * 2)},
10298 height : {to: this.adjustHeight(height * 2)},
10299 points : {by: [-(width * .5), -(height * .5)]},
10301 fontSize: {to:200, unit: "%"}
10312 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10313 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10314 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10320 // all config options shown with default values
10328 * @param {Object} options (optional) Object literal with any of the Fx config options
10329 * @return {Roo.Element} The Element
10331 switchOff : function(o){
10332 var el = this.getFxEl();
10335 el.queueFx(o, function(){
10336 this.clearOpacity();
10339 // restore values after effect
10340 var r = this.getFxRestore();
10341 var st = this.dom.style;
10343 var after = function(){
10345 el.setDisplayed(false);
10351 el.setPositioning(r.pos);
10352 st.width = r.width;
10353 st.height = r.height;
10358 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10359 this.clearOpacity();
10363 points:{by:[0, this.getHeight() * .5]}
10364 }, o, 'motion', 0.3, 'easeIn', after);
10365 }).defer(100, this);
10372 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10373 * changed using the "attr" config option) and then fading back to the original color. If no original
10374 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10377 // default: highlight background to yellow
10380 // custom: highlight foreground text to blue for 2 seconds
10381 el.highlight("0000ff", { attr: 'color', duration: 2 });
10383 // common config options shown with default values
10384 el.highlight("ffff9c", {
10385 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10386 endColor: (current color) or "ffffff",
10391 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10392 * @param {Object} options (optional) Object literal with any of the Fx config options
10393 * @return {Roo.Element} The Element
10395 highlight : function(color, o){
10396 var el = this.getFxEl();
10399 el.queueFx(o, function(){
10400 color = color || "ffff9c";
10401 attr = o.attr || "backgroundColor";
10403 this.clearOpacity();
10406 var origColor = this.getColor(attr);
10407 var restoreColor = this.dom.style[attr];
10408 endColor = (o.endColor || origColor) || "ffffff";
10410 var after = function(){
10411 el.dom.style[attr] = restoreColor;
10416 a[attr] = {from: color, to: endColor};
10417 arguments.callee.anim = this.fxanim(a,
10427 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10430 // default: a single light blue ripple
10433 // custom: 3 red ripples lasting 3 seconds total
10434 el.frame("ff0000", 3, { duration: 3 });
10436 // common config options shown with default values
10437 el.frame("C3DAF9", 1, {
10438 duration: 1 //duration of entire animation (not each individual ripple)
10439 // Note: Easing is not configurable and will be ignored if included
10442 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10443 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10444 * @param {Object} options (optional) Object literal with any of the Fx config options
10445 * @return {Roo.Element} The Element
10447 frame : function(color, count, o){
10448 var el = this.getFxEl();
10451 el.queueFx(o, function(){
10452 color = color || "#C3DAF9";
10453 if(color.length == 6){
10454 color = "#" + color;
10456 count = count || 1;
10457 duration = o.duration || 1;
10460 var b = this.getBox();
10461 var animFn = function(){
10462 var proxy = this.createProxy({
10465 visbility:"hidden",
10466 position:"absolute",
10467 "z-index":"35000", // yee haw
10468 border:"0px solid " + color
10471 var scale = Roo.isBorderBox ? 2 : 1;
10473 top:{from:b.y, to:b.y - 20},
10474 left:{from:b.x, to:b.x - 20},
10475 borderWidth:{from:0, to:10},
10476 opacity:{from:1, to:0},
10477 height:{from:b.height, to:(b.height + (20*scale))},
10478 width:{from:b.width, to:(b.width + (20*scale))}
10479 }, duration, function(){
10483 animFn.defer((duration/2)*1000, this);
10494 * Creates a pause before any subsequent queued effects begin. If there are
10495 * no effects queued after the pause it will have no effect.
10500 * @param {Number} seconds The length of time to pause (in seconds)
10501 * @return {Roo.Element} The Element
10503 pause : function(seconds){
10504 var el = this.getFxEl();
10507 el.queueFx(o, function(){
10508 setTimeout(function(){
10510 }, seconds * 1000);
10516 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10517 * using the "endOpacity" config option.
10520 // default: fade in from opacity 0 to 100%
10523 // custom: fade in from opacity 0 to 75% over 2 seconds
10524 el.fadeIn({ endOpacity: .75, duration: 2});
10526 // common config options shown with default values
10528 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10533 * @param {Object} options (optional) Object literal with any of the Fx config options
10534 * @return {Roo.Element} The Element
10536 fadeIn : function(o){
10537 var el = this.getFxEl();
10539 el.queueFx(o, function(){
10540 this.setOpacity(0);
10542 this.dom.style.visibility = 'visible';
10543 var to = o.endOpacity || 1;
10544 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10545 o, null, .5, "easeOut", function(){
10547 this.clearOpacity();
10556 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10557 * using the "endOpacity" config option.
10560 // default: fade out from the element's current opacity to 0
10563 // custom: fade out from the element's current opacity to 25% over 2 seconds
10564 el.fadeOut({ endOpacity: .25, duration: 2});
10566 // common config options shown with default values
10568 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10575 * @param {Object} options (optional) Object literal with any of the Fx config options
10576 * @return {Roo.Element} The Element
10578 fadeOut : function(o){
10579 var el = this.getFxEl();
10581 el.queueFx(o, function(){
10582 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10583 o, null, .5, "easeOut", function(){
10584 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10585 this.dom.style.display = "none";
10587 this.dom.style.visibility = "hidden";
10589 this.clearOpacity();
10597 * Animates the transition of an element's dimensions from a starting height/width
10598 * to an ending height/width.
10601 // change height and width to 100x100 pixels
10602 el.scale(100, 100);
10604 // common config options shown with default values. The height and width will default to
10605 // the element's existing values if passed as null.
10608 [element's height], {
10613 * @param {Number} width The new width (pass undefined to keep the original width)
10614 * @param {Number} height The new height (pass undefined to keep the original height)
10615 * @param {Object} options (optional) Object literal with any of the Fx config options
10616 * @return {Roo.Element} The Element
10618 scale : function(w, h, o){
10619 this.shift(Roo.apply({}, o, {
10627 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10628 * Any of these properties not specified in the config object will not be changed. This effect
10629 * requires that at least one new dimension, position or opacity setting must be passed in on
10630 * the config object in order for the function to have any effect.
10633 // slide the element horizontally to x position 200 while changing the height and opacity
10634 el.shift({ x: 200, height: 50, opacity: .8 });
10636 // common config options shown with default values.
10638 width: [element's width],
10639 height: [element's height],
10640 x: [element's x position],
10641 y: [element's y position],
10642 opacity: [element's opacity],
10647 * @param {Object} options Object literal with any of the Fx config options
10648 * @return {Roo.Element} The Element
10650 shift : function(o){
10651 var el = this.getFxEl();
10653 el.queueFx(o, function(){
10654 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10655 if(w !== undefined){
10656 a.width = {to: this.adjustWidth(w)};
10658 if(h !== undefined){
10659 a.height = {to: this.adjustHeight(h)};
10661 if(x !== undefined || y !== undefined){
10663 x !== undefined ? x : this.getX(),
10664 y !== undefined ? y : this.getY()
10667 if(op !== undefined){
10668 a.opacity = {to: op};
10670 if(o.xy !== undefined){
10671 a.points = {to: o.xy};
10673 arguments.callee.anim = this.fxanim(a,
10674 o, 'motion', .35, "easeOut", function(){
10682 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10683 * ending point of the effect.
10686 // default: slide the element downward while fading out
10689 // custom: slide the element out to the right with a 2-second duration
10690 el.ghost('r', { duration: 2 });
10692 // common config options shown with default values
10700 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10701 * @param {Object} options (optional) Object literal with any of the Fx config options
10702 * @return {Roo.Element} The Element
10704 ghost : function(anchor, o){
10705 var el = this.getFxEl();
10708 el.queueFx(o, function(){
10709 anchor = anchor || "b";
10711 // restore values after effect
10712 var r = this.getFxRestore();
10713 var w = this.getWidth(),
10714 h = this.getHeight();
10716 var st = this.dom.style;
10718 var after = function(){
10720 el.setDisplayed(false);
10726 el.setPositioning(r.pos);
10727 st.width = r.width;
10728 st.height = r.height;
10733 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10734 switch(anchor.toLowerCase()){
10761 arguments.callee.anim = this.fxanim(a,
10771 * Ensures that all effects queued after syncFx is called on the element are
10772 * run concurrently. This is the opposite of {@link #sequenceFx}.
10773 * @return {Roo.Element} The Element
10775 syncFx : function(){
10776 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10785 * Ensures that all effects queued after sequenceFx is called on the element are
10786 * run in sequence. This is the opposite of {@link #syncFx}.
10787 * @return {Roo.Element} The Element
10789 sequenceFx : function(){
10790 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10792 concurrent : false,
10799 nextFx : function(){
10800 var ef = this.fxQueue[0];
10807 * Returns true if the element has any effects actively running or queued, else returns false.
10808 * @return {Boolean} True if element has active effects, else false
10810 hasActiveFx : function(){
10811 return this.fxQueue && this.fxQueue[0];
10815 * Stops any running effects and clears the element's internal effects queue if it contains
10816 * any additional effects that haven't started yet.
10817 * @return {Roo.Element} The Element
10819 stopFx : function(){
10820 if(this.hasActiveFx()){
10821 var cur = this.fxQueue[0];
10822 if(cur && cur.anim && cur.anim.isAnimated()){
10823 this.fxQueue = [cur]; // clear out others
10824 cur.anim.stop(true);
10831 beforeFx : function(o){
10832 if(this.hasActiveFx() && !o.concurrent){
10843 * Returns true if the element is currently blocking so that no other effect can be queued
10844 * until this effect is finished, else returns false if blocking is not set. This is commonly
10845 * used to ensure that an effect initiated by a user action runs to completion prior to the
10846 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10847 * @return {Boolean} True if blocking, else false
10849 hasFxBlock : function(){
10850 var q = this.fxQueue;
10851 return q && q[0] && q[0].block;
10855 queueFx : function(o, fn){
10859 if(!this.hasFxBlock()){
10860 Roo.applyIf(o, this.fxDefaults);
10862 var run = this.beforeFx(o);
10863 fn.block = o.block;
10864 this.fxQueue.push(fn);
10876 fxWrap : function(pos, o, vis){
10878 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10881 wrapXY = this.getXY();
10883 var div = document.createElement("div");
10884 div.style.visibility = vis;
10885 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10886 wrap.setPositioning(pos);
10887 if(wrap.getStyle("position") == "static"){
10888 wrap.position("relative");
10890 this.clearPositioning('auto');
10892 wrap.dom.appendChild(this.dom);
10894 wrap.setXY(wrapXY);
10901 fxUnwrap : function(wrap, pos, o){
10902 this.clearPositioning();
10903 this.setPositioning(pos);
10905 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10911 getFxRestore : function(){
10912 var st = this.dom.style;
10913 return {pos: this.getPositioning(), width: st.width, height : st.height};
10917 afterFx : function(o){
10919 this.applyStyles(o.afterStyle);
10922 this.addClass(o.afterCls);
10924 if(o.remove === true){
10927 Roo.callback(o.callback, o.scope, [this]);
10929 this.fxQueue.shift();
10935 getFxEl : function(){ // support for composite element fx
10936 return Roo.get(this.dom);
10940 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10941 animType = animType || 'run';
10943 var anim = Roo.lib.Anim[animType](
10945 (opt.duration || defaultDur) || .35,
10946 (opt.easing || defaultEase) || 'easeOut',
10948 Roo.callback(cb, this);
10957 // backwords compat
10958 Roo.Fx.resize = Roo.Fx.scale;
10960 //When included, Roo.Fx is automatically applied to Element so that all basic
10961 //effects are available directly via the Element API
10962 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10964 * Ext JS Library 1.1.1
10965 * Copyright(c) 2006-2007, Ext JS, LLC.
10967 * Originally Released Under LGPL - original licence link has changed is not relivant.
10970 * <script type="text/javascript">
10975 * @class Roo.CompositeElement
10976 * Standard composite class. Creates a Roo.Element for every element in the collection.
10978 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10979 * actions will be performed on all the elements in this collection.</b>
10981 * All methods return <i>this</i> and can be chained.
10983 var els = Roo.select("#some-el div.some-class", true);
10984 // or select directly from an existing element
10985 var el = Roo.get('some-el');
10986 el.select('div.some-class', true);
10988 els.setWidth(100); // all elements become 100 width
10989 els.hide(true); // all elements fade out and hide
10991 els.setWidth(100).hide(true);
10994 Roo.CompositeElement = function(els){
10995 this.elements = [];
10996 this.addElements(els);
10998 Roo.CompositeElement.prototype = {
11000 addElements : function(els){
11001 if(!els) return this;
11002 if(typeof els == "string"){
11003 els = Roo.Element.selectorFunction(els);
11005 var yels = this.elements;
11006 var index = yels.length-1;
11007 for(var i = 0, len = els.length; i < len; i++) {
11008 yels[++index] = Roo.get(els[i]);
11014 * Clears this composite and adds the elements returned by the passed selector.
11015 * @param {String/Array} els A string CSS selector, an array of elements or an element
11016 * @return {CompositeElement} this
11018 fill : function(els){
11019 this.elements = [];
11025 * Filters this composite to only elements that match the passed selector.
11026 * @param {String} selector A string CSS selector
11027 * @param {Boolean} inverse return inverse filter (not matches)
11028 * @return {CompositeElement} this
11030 filter : function(selector, inverse){
11032 inverse = inverse || false;
11033 this.each(function(el){
11034 var match = inverse ? !el.is(selector) : el.is(selector);
11036 els[els.length] = el.dom;
11043 invoke : function(fn, args){
11044 var els = this.elements;
11045 for(var i = 0, len = els.length; i < len; i++) {
11046 Roo.Element.prototype[fn].apply(els[i], args);
11051 * Adds elements to this composite.
11052 * @param {String/Array} els A string CSS selector, an array of elements or an element
11053 * @return {CompositeElement} this
11055 add : function(els){
11056 if(typeof els == "string"){
11057 this.addElements(Roo.Element.selectorFunction(els));
11058 }else if(els.length !== undefined){
11059 this.addElements(els);
11061 this.addElements([els]);
11066 * Calls the passed function passing (el, this, index) for each element in this composite.
11067 * @param {Function} fn The function to call
11068 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11069 * @return {CompositeElement} this
11071 each : function(fn, scope){
11072 var els = this.elements;
11073 for(var i = 0, len = els.length; i < len; i++){
11074 if(fn.call(scope || els[i], els[i], this, i) === false) {
11082 * Returns the Element object at the specified index
11083 * @param {Number} index
11084 * @return {Roo.Element}
11086 item : function(index){
11087 return this.elements[index] || null;
11091 * Returns the first Element
11092 * @return {Roo.Element}
11094 first : function(){
11095 return this.item(0);
11099 * Returns the last Element
11100 * @return {Roo.Element}
11103 return this.item(this.elements.length-1);
11107 * Returns the number of elements in this composite
11110 getCount : function(){
11111 return this.elements.length;
11115 * Returns true if this composite contains the passed element
11118 contains : function(el){
11119 return this.indexOf(el) !== -1;
11123 * Returns true if this composite contains the passed element
11126 indexOf : function(el){
11127 return this.elements.indexOf(Roo.get(el));
11132 * Removes the specified element(s).
11133 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11134 * or an array of any of those.
11135 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11136 * @return {CompositeElement} this
11138 removeElement : function(el, removeDom){
11139 if(el instanceof Array){
11140 for(var i = 0, len = el.length; i < len; i++){
11141 this.removeElement(el[i]);
11145 var index = typeof el == 'number' ? el : this.indexOf(el);
11148 var d = this.elements[index];
11152 d.parentNode.removeChild(d);
11155 this.elements.splice(index, 1);
11161 * Replaces the specified element with the passed element.
11162 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11164 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11165 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11166 * @return {CompositeElement} this
11168 replaceElement : function(el, replacement, domReplace){
11169 var index = typeof el == 'number' ? el : this.indexOf(el);
11172 this.elements[index].replaceWith(replacement);
11174 this.elements.splice(index, 1, Roo.get(replacement))
11181 * Removes all elements.
11183 clear : function(){
11184 this.elements = [];
11188 Roo.CompositeElement.createCall = function(proto, fnName){
11189 if(!proto[fnName]){
11190 proto[fnName] = function(){
11191 return this.invoke(fnName, arguments);
11195 for(var fnName in Roo.Element.prototype){
11196 if(typeof Roo.Element.prototype[fnName] == "function"){
11197 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11203 * Ext JS Library 1.1.1
11204 * Copyright(c) 2006-2007, Ext JS, LLC.
11206 * Originally Released Under LGPL - original licence link has changed is not relivant.
11209 * <script type="text/javascript">
11213 * @class Roo.CompositeElementLite
11214 * @extends Roo.CompositeElement
11215 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11217 var els = Roo.select("#some-el div.some-class");
11218 // or select directly from an existing element
11219 var el = Roo.get('some-el');
11220 el.select('div.some-class');
11222 els.setWidth(100); // all elements become 100 width
11223 els.hide(true); // all elements fade out and hide
11225 els.setWidth(100).hide(true);
11226 </code></pre><br><br>
11227 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11228 * actions will be performed on all the elements in this collection.</b>
11230 Roo.CompositeElementLite = function(els){
11231 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11232 this.el = new Roo.Element.Flyweight();
11234 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11235 addElements : function(els){
11237 if(els instanceof Array){
11238 this.elements = this.elements.concat(els);
11240 var yels = this.elements;
11241 var index = yels.length-1;
11242 for(var i = 0, len = els.length; i < len; i++) {
11243 yels[++index] = els[i];
11249 invoke : function(fn, args){
11250 var els = this.elements;
11252 for(var i = 0, len = els.length; i < len; i++) {
11254 Roo.Element.prototype[fn].apply(el, args);
11259 * Returns a flyweight Element of the dom element object at the specified index
11260 * @param {Number} index
11261 * @return {Roo.Element}
11263 item : function(index){
11264 if(!this.elements[index]){
11267 this.el.dom = this.elements[index];
11271 // fixes scope with flyweight
11272 addListener : function(eventName, handler, scope, opt){
11273 var els = this.elements;
11274 for(var i = 0, len = els.length; i < len; i++) {
11275 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11281 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11282 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11283 * a reference to the dom node, use el.dom.</b>
11284 * @param {Function} fn The function to call
11285 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11286 * @return {CompositeElement} this
11288 each : function(fn, scope){
11289 var els = this.elements;
11291 for(var i = 0, len = els.length; i < len; i++){
11293 if(fn.call(scope || el, el, this, i) === false){
11300 indexOf : function(el){
11301 return this.elements.indexOf(Roo.getDom(el));
11304 replaceElement : function(el, replacement, domReplace){
11305 var index = typeof el == 'number' ? el : this.indexOf(el);
11307 replacement = Roo.getDom(replacement);
11309 var d = this.elements[index];
11310 d.parentNode.insertBefore(replacement, d);
11311 d.parentNode.removeChild(d);
11313 this.elements.splice(index, 1, replacement);
11318 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11322 * Ext JS Library 1.1.1
11323 * Copyright(c) 2006-2007, Ext JS, LLC.
11325 * Originally Released Under LGPL - original licence link has changed is not relivant.
11328 * <script type="text/javascript">
11334 * @class Roo.data.Connection
11335 * @extends Roo.util.Observable
11336 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11337 * either to a configured URL, or to a URL specified at request time.<br><br>
11339 * Requests made by this class are asynchronous, and will return immediately. No data from
11340 * the server will be available to the statement immediately following the {@link #request} call.
11341 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11343 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11344 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11345 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11346 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11347 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11348 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11349 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11350 * standard DOM methods.
11352 * @param {Object} config a configuration object.
11354 Roo.data.Connection = function(config){
11355 Roo.apply(this, config);
11358 * @event beforerequest
11359 * Fires before a network request is made to retrieve a data object.
11360 * @param {Connection} conn This Connection object.
11361 * @param {Object} options The options config object passed to the {@link #request} method.
11363 "beforerequest" : true,
11365 * @event requestcomplete
11366 * Fires if the request was successfully completed.
11367 * @param {Connection} conn This Connection object.
11368 * @param {Object} response The XHR object containing the response data.
11369 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11370 * @param {Object} options The options config object passed to the {@link #request} method.
11372 "requestcomplete" : true,
11374 * @event requestexception
11375 * Fires if an error HTTP status was returned from the server.
11376 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11377 * @param {Connection} conn This Connection object.
11378 * @param {Object} response The XHR object containing the response data.
11379 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11380 * @param {Object} options The options config object passed to the {@link #request} method.
11382 "requestexception" : true
11384 Roo.data.Connection.superclass.constructor.call(this);
11387 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11389 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11392 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11393 * extra parameters to each request made by this object. (defaults to undefined)
11396 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11397 * to each request made by this object. (defaults to undefined)
11400 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11403 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11407 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11413 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11416 disableCaching: true,
11419 * Sends an HTTP request to a remote server.
11420 * @param {Object} options An object which may contain the following properties:<ul>
11421 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11422 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11423 * request, a url encoded string or a function to call to get either.</li>
11424 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11425 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11426 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11427 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11428 * <li>options {Object} The parameter to the request call.</li>
11429 * <li>success {Boolean} True if the request succeeded.</li>
11430 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11432 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11433 * The callback is passed the following parameters:<ul>
11434 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11435 * <li>options {Object} The parameter to the request call.</li>
11437 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11438 * The callback is passed the following parameters:<ul>
11439 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11440 * <li>options {Object} The parameter to the request call.</li>
11442 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11443 * for the callback function. Defaults to the browser window.</li>
11444 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11445 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11446 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11447 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11448 * params for the post data. Any params will be appended to the URL.</li>
11449 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11451 * @return {Number} transactionId
11453 request : function(o){
11454 if(this.fireEvent("beforerequest", this, o) !== false){
11457 if(typeof p == "function"){
11458 p = p.call(o.scope||window, o);
11460 if(typeof p == "object"){
11461 p = Roo.urlEncode(o.params);
11463 if(this.extraParams){
11464 var extras = Roo.urlEncode(this.extraParams);
11465 p = p ? (p + '&' + extras) : extras;
11468 var url = o.url || this.url;
11469 if(typeof url == 'function'){
11470 url = url.call(o.scope||window, o);
11474 var form = Roo.getDom(o.form);
11475 url = url || form.action;
11477 var enctype = form.getAttribute("enctype");
11478 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11479 return this.doFormUpload(o, p, url);
11481 var f = Roo.lib.Ajax.serializeForm(form);
11482 p = p ? (p + '&' + f) : f;
11485 var hs = o.headers;
11486 if(this.defaultHeaders){
11487 hs = Roo.apply(hs || {}, this.defaultHeaders);
11494 success: this.handleResponse,
11495 failure: this.handleFailure,
11497 argument: {options: o},
11498 timeout : o.timeout || this.timeout
11501 var method = o.method||this.method||(p ? "POST" : "GET");
11503 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11504 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11507 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11511 }else if(this.autoAbort !== false){
11515 if((method == 'GET' && p) || o.xmlData){
11516 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11519 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11520 return this.transId;
11522 Roo.callback(o.callback, o.scope, [o, null, null]);
11528 * Determine whether this object has a request outstanding.
11529 * @param {Number} transactionId (Optional) defaults to the last transaction
11530 * @return {Boolean} True if there is an outstanding request.
11532 isLoading : function(transId){
11534 return Roo.lib.Ajax.isCallInProgress(transId);
11536 return this.transId ? true : false;
11541 * Aborts any outstanding request.
11542 * @param {Number} transactionId (Optional) defaults to the last transaction
11544 abort : function(transId){
11545 if(transId || this.isLoading()){
11546 Roo.lib.Ajax.abort(transId || this.transId);
11551 handleResponse : function(response){
11552 this.transId = false;
11553 var options = response.argument.options;
11554 response.argument = options ? options.argument : null;
11555 this.fireEvent("requestcomplete", this, response, options);
11556 Roo.callback(options.success, options.scope, [response, options]);
11557 Roo.callback(options.callback, options.scope, [options, true, response]);
11561 handleFailure : function(response, e){
11562 this.transId = false;
11563 var options = response.argument.options;
11564 response.argument = options ? options.argument : null;
11565 this.fireEvent("requestexception", this, response, options, e);
11566 Roo.callback(options.failure, options.scope, [response, options]);
11567 Roo.callback(options.callback, options.scope, [options, false, response]);
11571 doFormUpload : function(o, ps, url){
11573 var frame = document.createElement('iframe');
11576 frame.className = 'x-hidden';
11578 frame.src = Roo.SSL_SECURE_URL;
11580 document.body.appendChild(frame);
11583 document.frames[id].name = id;
11586 var form = Roo.getDom(o.form);
11588 form.method = 'POST';
11589 form.enctype = form.encoding = 'multipart/form-data';
11595 if(ps){ // add dynamic params
11597 ps = Roo.urlDecode(ps, false);
11599 if(ps.hasOwnProperty(k)){
11600 hd = document.createElement('input');
11601 hd.type = 'hidden';
11604 form.appendChild(hd);
11611 var r = { // bogus response object
11616 r.argument = o ? o.argument : null;
11621 doc = frame.contentWindow.document;
11623 doc = (frame.contentDocument || window.frames[id].document);
11625 if(doc && doc.body){
11626 r.responseText = doc.body.innerHTML;
11628 if(doc && doc.XMLDocument){
11629 r.responseXML = doc.XMLDocument;
11631 r.responseXML = doc;
11638 Roo.EventManager.removeListener(frame, 'load', cb, this);
11640 this.fireEvent("requestcomplete", this, r, o);
11641 Roo.callback(o.success, o.scope, [r, o]);
11642 Roo.callback(o.callback, o.scope, [o, true, r]);
11644 setTimeout(function(){document.body.removeChild(frame);}, 100);
11647 Roo.EventManager.on(frame, 'load', cb, this);
11650 if(hiddens){ // remove dynamic params
11651 for(var i = 0, len = hiddens.length; i < len; i++){
11652 form.removeChild(hiddens[i]);
11659 * Ext JS Library 1.1.1
11660 * Copyright(c) 2006-2007, Ext JS, LLC.
11662 * Originally Released Under LGPL - original licence link has changed is not relivant.
11665 * <script type="text/javascript">
11669 * Global Ajax request class.
11672 * @extends Roo.data.Connection
11675 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11676 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11677 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11678 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11679 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11680 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11681 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11683 Roo.Ajax = new Roo.data.Connection({
11692 * Serialize the passed form into a url encoded string
11694 * @param {String/HTMLElement} form
11697 serializeForm : function(form){
11698 return Roo.lib.Ajax.serializeForm(form);
11702 * Ext JS Library 1.1.1
11703 * Copyright(c) 2006-2007, Ext JS, LLC.
11705 * Originally Released Under LGPL - original licence link has changed is not relivant.
11708 * <script type="text/javascript">
11713 * @class Roo.UpdateManager
11714 * @extends Roo.util.Observable
11715 * Provides AJAX-style update for Element object.<br><br>
11718 * // Get it from a Roo.Element object
11719 * var el = Roo.get("foo");
11720 * var mgr = el.getUpdateManager();
11721 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11723 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11725 * // or directly (returns the same UpdateManager instance)
11726 * var mgr = new Roo.UpdateManager("myElementId");
11727 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11728 * mgr.on("update", myFcnNeedsToKnow);
11730 // short handed call directly from the element object
11731 Roo.get("foo").load({
11735 text: "Loading Foo..."
11739 * Create new UpdateManager directly.
11740 * @param {String/HTMLElement/Roo.Element} el The element to update
11741 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11743 Roo.UpdateManager = function(el, forceNew){
11745 if(!forceNew && el.updateManager){
11746 return el.updateManager;
11749 * The Element object
11750 * @type Roo.Element
11754 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11757 this.defaultUrl = null;
11761 * @event beforeupdate
11762 * Fired before an update is made, return false from your handler and the update is cancelled.
11763 * @param {Roo.Element} el
11764 * @param {String/Object/Function} url
11765 * @param {String/Object} params
11767 "beforeupdate": true,
11770 * Fired after successful update is made.
11771 * @param {Roo.Element} el
11772 * @param {Object} oResponseObject The response Object
11777 * Fired on update failure.
11778 * @param {Roo.Element} el
11779 * @param {Object} oResponseObject The response Object
11783 var d = Roo.UpdateManager.defaults;
11785 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11788 this.sslBlankUrl = d.sslBlankUrl;
11790 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11793 this.disableCaching = d.disableCaching;
11795 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11798 this.indicatorText = d.indicatorText;
11800 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11803 this.showLoadIndicator = d.showLoadIndicator;
11805 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11808 this.timeout = d.timeout;
11811 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11814 this.loadScripts = d.loadScripts;
11817 * Transaction object of current executing transaction
11819 this.transaction = null;
11824 this.autoRefreshProcId = null;
11826 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11829 this.refreshDelegate = this.refresh.createDelegate(this);
11831 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11834 this.updateDelegate = this.update.createDelegate(this);
11836 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11839 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11843 this.successDelegate = this.processSuccess.createDelegate(this);
11847 this.failureDelegate = this.processFailure.createDelegate(this);
11849 if(!this.renderer){
11851 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11853 this.renderer = new Roo.UpdateManager.BasicRenderer();
11856 Roo.UpdateManager.superclass.constructor.call(this);
11859 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11861 * Get the Element this UpdateManager is bound to
11862 * @return {Roo.Element} The element
11864 getEl : function(){
11868 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11869 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11872 url: "your-url.php",<br/>
11873 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11874 callback: yourFunction,<br/>
11875 scope: yourObject, //(optional scope) <br/>
11876 discardUrl: false, <br/>
11877 nocache: false,<br/>
11878 text: "Loading...",<br/>
11880 scripts: false<br/>
11883 * The only required property is url. The optional properties nocache, text and scripts
11884 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11885 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
11886 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11887 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11889 update : function(url, params, callback, discardUrl){
11890 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11891 var method = this.method,
11893 if(typeof url == "object"){ // must be config object
11896 params = params || cfg.params;
11897 callback = callback || cfg.callback;
11898 discardUrl = discardUrl || cfg.discardUrl;
11899 if(callback && cfg.scope){
11900 callback = callback.createDelegate(cfg.scope);
11902 if(typeof cfg.method != "undefined"){method = cfg.method;};
11903 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11904 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11905 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11906 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11908 this.showLoading();
11910 this.defaultUrl = url;
11912 if(typeof url == "function"){
11913 url = url.call(this);
11916 method = method || (params ? "POST" : "GET");
11917 if(method == "GET"){
11918 url = this.prepareUrl(url);
11921 var o = Roo.apply(cfg ||{}, {
11924 success: this.successDelegate,
11925 failure: this.failureDelegate,
11926 callback: undefined,
11927 timeout: (this.timeout*1000),
11928 argument: {"url": url, "form": null, "callback": callback, "params": params}
11930 Roo.log("updated manager called with timeout of " + o.timeout);
11931 this.transaction = Roo.Ajax.request(o);
11936 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11937 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11938 * @param {String/HTMLElement} form The form Id or form element
11939 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11940 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11941 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11943 formUpdate : function(form, url, reset, callback){
11944 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11945 if(typeof url == "function"){
11946 url = url.call(this);
11948 form = Roo.getDom(form);
11949 this.transaction = Roo.Ajax.request({
11952 success: this.successDelegate,
11953 failure: this.failureDelegate,
11954 timeout: (this.timeout*1000),
11955 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11957 this.showLoading.defer(1, this);
11962 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11963 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11965 refresh : function(callback){
11966 if(this.defaultUrl == null){
11969 this.update(this.defaultUrl, null, callback, true);
11973 * Set this element to auto refresh.
11974 * @param {Number} interval How often to update (in seconds).
11975 * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11976 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
11977 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11978 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11980 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11982 this.update(url || this.defaultUrl, params, callback, true);
11984 if(this.autoRefreshProcId){
11985 clearInterval(this.autoRefreshProcId);
11987 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11991 * Stop auto refresh on this element.
11993 stopAutoRefresh : function(){
11994 if(this.autoRefreshProcId){
11995 clearInterval(this.autoRefreshProcId);
11996 delete this.autoRefreshProcId;
12000 isAutoRefreshing : function(){
12001 return this.autoRefreshProcId ? true : false;
12004 * Called to update the element to "Loading" state. Override to perform custom action.
12006 showLoading : function(){
12007 if(this.showLoadIndicator){
12008 this.el.update(this.indicatorText);
12013 * Adds unique parameter to query string if disableCaching = true
12016 prepareUrl : function(url){
12017 if(this.disableCaching){
12018 var append = "_dc=" + (new Date().getTime());
12019 if(url.indexOf("?") !== -1){
12020 url += "&" + append;
12022 url += "?" + append;
12031 processSuccess : function(response){
12032 this.transaction = null;
12033 if(response.argument.form && response.argument.reset){
12034 try{ // put in try/catch since some older FF releases had problems with this
12035 response.argument.form.reset();
12038 if(this.loadScripts){
12039 this.renderer.render(this.el, response, this,
12040 this.updateComplete.createDelegate(this, [response]));
12042 this.renderer.render(this.el, response, this);
12043 this.updateComplete(response);
12047 updateComplete : function(response){
12048 this.fireEvent("update", this.el, response);
12049 if(typeof response.argument.callback == "function"){
12050 response.argument.callback(this.el, true, response);
12057 processFailure : function(response){
12058 this.transaction = null;
12059 this.fireEvent("failure", this.el, response);
12060 if(typeof response.argument.callback == "function"){
12061 response.argument.callback(this.el, false, response);
12066 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12067 * @param {Object} renderer The object implementing the render() method
12069 setRenderer : function(renderer){
12070 this.renderer = renderer;
12073 getRenderer : function(){
12074 return this.renderer;
12078 * Set the defaultUrl used for updates
12079 * @param {String/Function} defaultUrl The url or a function to call to get the url
12081 setDefaultUrl : function(defaultUrl){
12082 this.defaultUrl = defaultUrl;
12086 * Aborts the executing transaction
12088 abort : function(){
12089 if(this.transaction){
12090 Roo.Ajax.abort(this.transaction);
12095 * Returns true if an update is in progress
12096 * @return {Boolean}
12098 isUpdating : function(){
12099 if(this.transaction){
12100 return Roo.Ajax.isLoading(this.transaction);
12107 * @class Roo.UpdateManager.defaults
12108 * @static (not really - but it helps the doc tool)
12109 * The defaults collection enables customizing the default properties of UpdateManager
12111 Roo.UpdateManager.defaults = {
12113 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12119 * True to process scripts by default (Defaults to false).
12122 loadScripts : false,
12125 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12128 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12130 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12133 disableCaching : false,
12135 * Whether to show indicatorText when loading (Defaults to true).
12138 showLoadIndicator : true,
12140 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12143 indicatorText : '<div class="loading-indicator">Loading...</div>'
12147 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12149 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12150 * @param {String/HTMLElement/Roo.Element} el The element to update
12151 * @param {String} url The url
12152 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12153 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12156 * @member Roo.UpdateManager
12158 Roo.UpdateManager.updateElement = function(el, url, params, options){
12159 var um = Roo.get(el, true).getUpdateManager();
12160 Roo.apply(um, options);
12161 um.update(url, params, options ? options.callback : null);
12163 // alias for backwards compat
12164 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12166 * @class Roo.UpdateManager.BasicRenderer
12167 * Default Content renderer. Updates the elements innerHTML with the responseText.
12169 Roo.UpdateManager.BasicRenderer = function(){};
12171 Roo.UpdateManager.BasicRenderer.prototype = {
12173 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12174 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12175 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12176 * @param {Roo.Element} el The element being rendered
12177 * @param {Object} response The YUI Connect response object
12178 * @param {UpdateManager} updateManager The calling update manager
12179 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12181 render : function(el, response, updateManager, callback){
12182 el.update(response.responseText, updateManager.loadScripts, callback);
12188 * (c)) Alan Knowles
12194 * @class Roo.DomTemplate
12195 * @extends Roo.Template
12196 * An effort at a dom based template engine..
12198 * Similar to XTemplate, except it uses dom parsing to create the template..
12200 * Supported features:
12205 {a_variable} - output encoded.
12206 {a_variable.format:("Y-m-d")} - call a method on the variable
12207 {a_variable:raw} - unencoded output
12208 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12209 {a_variable:this.method_on_template(...)} - call a method on the template object.
12214 <div roo-for="a_variable or condition.."></div>
12215 <div roo-if="a_variable or condition"></div>
12216 <div roo-exec="some javascript"></div>
12217 <div roo-name="named_template"></div>
12222 Roo.DomTemplate = function()
12224 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12231 Roo.extend(Roo.DomTemplate, Roo.Template, {
12233 * id counter for sub templates.
12237 * flag to indicate if dom parser is inside a pre,
12238 * it will strip whitespace if not.
12243 * The various sub templates
12251 * basic tag replacing syntax
12254 * // you can fake an object call by doing this
12258 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12259 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12261 iterChild : function (node, method) {
12263 var oldPre = this.inPre;
12264 if (node.tagName == 'PRE') {
12267 for( var i = 0; i < node.childNodes.length; i++) {
12268 method.call(this, node.childNodes[i]);
12270 this.inPre = oldPre;
12276 * compile the template
12278 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12281 compile: function()
12285 // covert the html into DOM...
12289 doc = document.implementation.createHTMLDocument("");
12290 doc.documentElement.innerHTML = this.html ;
12291 div = doc.documentElement;
12293 // old IE... - nasty -- it causes all sorts of issues.. with
12294 // images getting pulled from server..
12295 div = document.createElement('div');
12296 div.innerHTML = this.html;
12298 //doc.documentElement.innerHTML = htmlBody
12304 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12306 var tpls = this.tpls;
12308 // create a top level template from the snippet..
12310 //Roo.log(div.innerHTML);
12317 body : div.innerHTML,
12330 Roo.each(tpls, function(tp){
12331 this.compileTpl(tp);
12332 this.tpls[tp.id] = tp;
12335 this.master = tpls[0];
12341 compileNode : function(node, istop) {
12346 // skip anything not a tag..
12347 if (node.nodeType != 1) {
12348 if (node.nodeType == 3 && !this.inPre) {
12349 // reduce white space..
12350 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12373 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12374 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12375 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12376 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12382 // just itterate children..
12383 this.iterChild(node,this.compileNode);
12386 tpl.uid = this.id++;
12387 tpl.value = node.getAttribute('roo-' + tpl.attr);
12388 node.removeAttribute('roo-'+ tpl.attr);
12389 if (tpl.attr != 'name') {
12390 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12391 node.parentNode.replaceChild(placeholder, node);
12394 var placeholder = document.createElement('span');
12395 placeholder.className = 'roo-tpl-' + tpl.value;
12396 node.parentNode.replaceChild(placeholder, node);
12399 // parent now sees '{domtplXXXX}
12400 this.iterChild(node,this.compileNode);
12402 // we should now have node body...
12403 var div = document.createElement('div');
12404 div.appendChild(node);
12406 // this has the unfortunate side effect of converting tagged attributes
12407 // eg. href="{...}" into %7C...%7D
12408 // this has been fixed by searching for those combo's although it's a bit hacky..
12411 tpl.body = div.innerHTML;
12418 switch (tpl.value) {
12419 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12420 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12421 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12426 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12430 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12434 tpl.id = tpl.value; // replace non characters???
12440 this.tpls.push(tpl);
12450 * Compile a segment of the template into a 'sub-template'
12456 compileTpl : function(tpl)
12458 var fm = Roo.util.Format;
12459 var useF = this.disableFormats !== true;
12461 var sep = Roo.isGecko ? "+\n" : ",\n";
12463 var undef = function(str) {
12464 Roo.debug && Roo.log("Property not found :" + str);
12468 //Roo.log(tpl.body);
12472 var fn = function(m, lbrace, name, format, args)
12475 //Roo.log(arguments);
12476 args = args ? args.replace(/\\'/g,"'") : args;
12477 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12478 if (typeof(format) == 'undefined') {
12479 format = 'htmlEncode';
12481 if (format == 'raw' ) {
12485 if(name.substr(0, 6) == 'domtpl'){
12486 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12489 // build an array of options to determine if value is undefined..
12491 // basically get 'xxxx.yyyy' then do
12492 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12493 // (function () { Roo.log("Property not found"); return ''; })() :
12498 Roo.each(name.split('.'), function(st) {
12499 lookfor += (lookfor.length ? '.': '') + st;
12500 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12503 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12506 if(format && useF){
12508 args = args ? ',' + args : "";
12510 if(format.substr(0, 5) != "this."){
12511 format = "fm." + format + '(';
12513 format = 'this.call("'+ format.substr(5) + '", ';
12517 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12520 if (args && args.length) {
12521 // called with xxyx.yuu:(test,test)
12523 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12525 // raw.. - :raw modifier..
12526 return "'"+ sep + udef_st + name + ")"+sep+"'";
12530 // branched to use + in gecko and [].join() in others
12532 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12533 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12536 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12537 body.push(tpl.body.replace(/(\r\n|\n)/g,
12538 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12539 body.push("'].join('');};};");
12540 body = body.join('');
12543 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12545 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12552 * same as applyTemplate, except it's done to one of the subTemplates
12553 * when using named templates, you can do:
12555 * var str = pl.applySubTemplate('your-name', values);
12558 * @param {Number} id of the template
12559 * @param {Object} values to apply to template
12560 * @param {Object} parent (normaly the instance of this object)
12562 applySubTemplate : function(id, values, parent)
12566 var t = this.tpls[id];
12570 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12571 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12575 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12582 if(t.execCall && t.execCall.call(this, values, parent)){
12586 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12592 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12593 parent = t.target ? values : parent;
12594 if(t.forCall && vs instanceof Array){
12596 for(var i = 0, len = vs.length; i < len; i++){
12598 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12600 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12602 //Roo.log(t.compiled);
12606 return buf.join('');
12609 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12614 return t.compiled.call(this, vs, parent);
12616 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12618 //Roo.log(t.compiled);
12626 applyTemplate : function(values){
12627 return this.master.compiled.call(this, values, {});
12628 //var s = this.subs;
12631 apply : function(){
12632 return this.applyTemplate.apply(this, arguments);
12637 Roo.DomTemplate.from = function(el){
12638 el = Roo.getDom(el);
12639 return new Roo.Domtemplate(el.value || el.innerHTML);
12642 * Ext JS Library 1.1.1
12643 * Copyright(c) 2006-2007, Ext JS, LLC.
12645 * Originally Released Under LGPL - original licence link has changed is not relivant.
12648 * <script type="text/javascript">
12652 * @class Roo.util.DelayedTask
12653 * Provides a convenient method of performing setTimeout where a new
12654 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12655 * You can use this class to buffer
12656 * the keypress events for a certain number of milliseconds, and perform only if they stop
12657 * for that amount of time.
12658 * @constructor The parameters to this constructor serve as defaults and are not required.
12659 * @param {Function} fn (optional) The default function to timeout
12660 * @param {Object} scope (optional) The default scope of that timeout
12661 * @param {Array} args (optional) The default Array of arguments
12663 Roo.util.DelayedTask = function(fn, scope, args){
12664 var id = null, d, t;
12666 var call = function(){
12667 var now = new Date().getTime();
12671 fn.apply(scope, args || []);
12675 * Cancels any pending timeout and queues a new one
12676 * @param {Number} delay The milliseconds to delay
12677 * @param {Function} newFn (optional) Overrides function passed to constructor
12678 * @param {Object} newScope (optional) Overrides scope passed to constructor
12679 * @param {Array} newArgs (optional) Overrides args passed to constructor
12681 this.delay = function(delay, newFn, newScope, newArgs){
12682 if(id && delay != d){
12686 t = new Date().getTime();
12688 scope = newScope || scope;
12689 args = newArgs || args;
12691 id = setInterval(call, d);
12696 * Cancel the last queued timeout
12698 this.cancel = function(){
12706 * Ext JS Library 1.1.1
12707 * Copyright(c) 2006-2007, Ext JS, LLC.
12709 * Originally Released Under LGPL - original licence link has changed is not relivant.
12712 * <script type="text/javascript">
12716 Roo.util.TaskRunner = function(interval){
12717 interval = interval || 10;
12718 var tasks = [], removeQueue = [];
12720 var running = false;
12722 var stopThread = function(){
12728 var startThread = function(){
12731 id = setInterval(runTasks, interval);
12735 var removeTask = function(task){
12736 removeQueue.push(task);
12742 var runTasks = function(){
12743 if(removeQueue.length > 0){
12744 for(var i = 0, len = removeQueue.length; i < len; i++){
12745 tasks.remove(removeQueue[i]);
12748 if(tasks.length < 1){
12753 var now = new Date().getTime();
12754 for(var i = 0, len = tasks.length; i < len; ++i){
12756 var itime = now - t.taskRunTime;
12757 if(t.interval <= itime){
12758 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12759 t.taskRunTime = now;
12760 if(rt === false || t.taskRunCount === t.repeat){
12765 if(t.duration && t.duration <= (now - t.taskStartTime)){
12772 * Queues a new task.
12773 * @param {Object} task
12775 this.start = function(task){
12777 task.taskStartTime = new Date().getTime();
12778 task.taskRunTime = 0;
12779 task.taskRunCount = 0;
12784 this.stop = function(task){
12789 this.stopAll = function(){
12791 for(var i = 0, len = tasks.length; i < len; i++){
12792 if(tasks[i].onStop){
12801 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12803 * Ext JS Library 1.1.1
12804 * Copyright(c) 2006-2007, Ext JS, LLC.
12806 * Originally Released Under LGPL - original licence link has changed is not relivant.
12809 * <script type="text/javascript">
12814 * @class Roo.util.MixedCollection
12815 * @extends Roo.util.Observable
12816 * A Collection class that maintains both numeric indexes and keys and exposes events.
12818 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12819 * collection (defaults to false)
12820 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12821 * and return the key value for that item. This is used when available to look up the key on items that
12822 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12823 * equivalent to providing an implementation for the {@link #getKey} method.
12825 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12833 * Fires when the collection is cleared.
12838 * Fires when an item is added to the collection.
12839 * @param {Number} index The index at which the item was added.
12840 * @param {Object} o The item added.
12841 * @param {String} key The key associated with the added item.
12846 * Fires when an item is replaced in the collection.
12847 * @param {String} key he key associated with the new added.
12848 * @param {Object} old The item being replaced.
12849 * @param {Object} new The new item.
12854 * Fires when an item is removed from the collection.
12855 * @param {Object} o The item being removed.
12856 * @param {String} key (optional) The key associated with the removed item.
12861 this.allowFunctions = allowFunctions === true;
12863 this.getKey = keyFn;
12865 Roo.util.MixedCollection.superclass.constructor.call(this);
12868 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12869 allowFunctions : false,
12872 * Adds an item to the collection.
12873 * @param {String} key The key to associate with the item
12874 * @param {Object} o The item to add.
12875 * @return {Object} The item added.
12877 add : function(key, o){
12878 if(arguments.length == 1){
12880 key = this.getKey(o);
12882 if(typeof key == "undefined" || key === null){
12884 this.items.push(o);
12885 this.keys.push(null);
12887 var old = this.map[key];
12889 return this.replace(key, o);
12892 this.items.push(o);
12894 this.keys.push(key);
12896 this.fireEvent("add", this.length-1, o, key);
12901 * MixedCollection has a generic way to fetch keys if you implement getKey.
12904 var mc = new Roo.util.MixedCollection();
12905 mc.add(someEl.dom.id, someEl);
12906 mc.add(otherEl.dom.id, otherEl);
12910 var mc = new Roo.util.MixedCollection();
12911 mc.getKey = function(el){
12917 // or via the constructor
12918 var mc = new Roo.util.MixedCollection(false, function(el){
12924 * @param o {Object} The item for which to find the key.
12925 * @return {Object} The key for the passed item.
12927 getKey : function(o){
12932 * Replaces an item in the collection.
12933 * @param {String} key The key associated with the item to replace, or the item to replace.
12934 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12935 * @return {Object} The new item.
12937 replace : function(key, o){
12938 if(arguments.length == 1){
12940 key = this.getKey(o);
12942 var old = this.item(key);
12943 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12944 return this.add(key, o);
12946 var index = this.indexOfKey(key);
12947 this.items[index] = o;
12949 this.fireEvent("replace", key, old, o);
12954 * Adds all elements of an Array or an Object to the collection.
12955 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12956 * an Array of values, each of which are added to the collection.
12958 addAll : function(objs){
12959 if(arguments.length > 1 || objs instanceof Array){
12960 var args = arguments.length > 1 ? arguments : objs;
12961 for(var i = 0, len = args.length; i < len; i++){
12965 for(var key in objs){
12966 if(this.allowFunctions || typeof objs[key] != "function"){
12967 this.add(key, objs[key]);
12974 * Executes the specified function once for every item in the collection, passing each
12975 * item as the first and only parameter. returning false from the function will stop the iteration.
12976 * @param {Function} fn The function to execute for each item.
12977 * @param {Object} scope (optional) The scope in which to execute the function.
12979 each : function(fn, scope){
12980 var items = [].concat(this.items); // each safe for removal
12981 for(var i = 0, len = items.length; i < len; i++){
12982 if(fn.call(scope || items[i], items[i], i, len) === false){
12989 * Executes the specified function once for every key in the collection, passing each
12990 * key, and its associated item as the first two parameters.
12991 * @param {Function} fn The function to execute for each item.
12992 * @param {Object} scope (optional) The scope in which to execute the function.
12994 eachKey : function(fn, scope){
12995 for(var i = 0, len = this.keys.length; i < len; i++){
12996 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13001 * Returns the first item in the collection which elicits a true return value from the
13002 * passed selection function.
13003 * @param {Function} fn The selection function to execute for each item.
13004 * @param {Object} scope (optional) The scope in which to execute the function.
13005 * @return {Object} The first item in the collection which returned true from the selection function.
13007 find : function(fn, scope){
13008 for(var i = 0, len = this.items.length; i < len; i++){
13009 if(fn.call(scope || window, this.items[i], this.keys[i])){
13010 return this.items[i];
13017 * Inserts an item at the specified index in the collection.
13018 * @param {Number} index The index to insert the item at.
13019 * @param {String} key The key to associate with the new item, or the item itself.
13020 * @param {Object} o (optional) If the second parameter was a key, the new item.
13021 * @return {Object} The item inserted.
13023 insert : function(index, key, o){
13024 if(arguments.length == 2){
13026 key = this.getKey(o);
13028 if(index >= this.length){
13029 return this.add(key, o);
13032 this.items.splice(index, 0, o);
13033 if(typeof key != "undefined" && key != null){
13036 this.keys.splice(index, 0, key);
13037 this.fireEvent("add", index, o, key);
13042 * Removed an item from the collection.
13043 * @param {Object} o The item to remove.
13044 * @return {Object} The item removed.
13046 remove : function(o){
13047 return this.removeAt(this.indexOf(o));
13051 * Remove an item from a specified index in the collection.
13052 * @param {Number} index The index within the collection of the item to remove.
13054 removeAt : function(index){
13055 if(index < this.length && index >= 0){
13057 var o = this.items[index];
13058 this.items.splice(index, 1);
13059 var key = this.keys[index];
13060 if(typeof key != "undefined"){
13061 delete this.map[key];
13063 this.keys.splice(index, 1);
13064 this.fireEvent("remove", o, key);
13069 * Removed an item associated with the passed key fom the collection.
13070 * @param {String} key The key of the item to remove.
13072 removeKey : function(key){
13073 return this.removeAt(this.indexOfKey(key));
13077 * Returns the number of items in the collection.
13078 * @return {Number} the number of items in the collection.
13080 getCount : function(){
13081 return this.length;
13085 * Returns index within the collection of the passed Object.
13086 * @param {Object} o The item to find the index of.
13087 * @return {Number} index of the item.
13089 indexOf : function(o){
13090 if(!this.items.indexOf){
13091 for(var i = 0, len = this.items.length; i < len; i++){
13092 if(this.items[i] == o) return i;
13096 return this.items.indexOf(o);
13101 * Returns index within the collection of the passed key.
13102 * @param {String} key The key to find the index of.
13103 * @return {Number} index of the key.
13105 indexOfKey : function(key){
13106 if(!this.keys.indexOf){
13107 for(var i = 0, len = this.keys.length; i < len; i++){
13108 if(this.keys[i] == key) return i;
13112 return this.keys.indexOf(key);
13117 * Returns the item associated with the passed key OR index. Key has priority over index.
13118 * @param {String/Number} key The key or index of the item.
13119 * @return {Object} The item associated with the passed key.
13121 item : function(key){
13122 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13123 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13127 * Returns the item at the specified index.
13128 * @param {Number} index The index of the item.
13131 itemAt : function(index){
13132 return this.items[index];
13136 * Returns the item associated with the passed key.
13137 * @param {String/Number} key The key of the item.
13138 * @return {Object} The item associated with the passed key.
13140 key : function(key){
13141 return this.map[key];
13145 * Returns true if the collection contains the passed Object as an item.
13146 * @param {Object} o The Object to look for in the collection.
13147 * @return {Boolean} True if the collection contains the Object as an item.
13149 contains : function(o){
13150 return this.indexOf(o) != -1;
13154 * Returns true if the collection contains the passed Object as a key.
13155 * @param {String} key The key to look for in the collection.
13156 * @return {Boolean} True if the collection contains the Object as a key.
13158 containsKey : function(key){
13159 return typeof this.map[key] != "undefined";
13163 * Removes all items from the collection.
13165 clear : function(){
13170 this.fireEvent("clear");
13174 * Returns the first item in the collection.
13175 * @return {Object} the first item in the collection..
13177 first : function(){
13178 return this.items[0];
13182 * Returns the last item in the collection.
13183 * @return {Object} the last item in the collection..
13186 return this.items[this.length-1];
13189 _sort : function(property, dir, fn){
13190 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13191 fn = fn || function(a, b){
13194 var c = [], k = this.keys, items = this.items;
13195 for(var i = 0, len = items.length; i < len; i++){
13196 c[c.length] = {key: k[i], value: items[i], index: i};
13198 c.sort(function(a, b){
13199 var v = fn(a[property], b[property]) * dsc;
13201 v = (a.index < b.index ? -1 : 1);
13205 for(var i = 0, len = c.length; i < len; i++){
13206 items[i] = c[i].value;
13209 this.fireEvent("sort", this);
13213 * Sorts this collection with the passed comparison function
13214 * @param {String} direction (optional) "ASC" or "DESC"
13215 * @param {Function} fn (optional) comparison function
13217 sort : function(dir, fn){
13218 this._sort("value", dir, fn);
13222 * Sorts this collection by keys
13223 * @param {String} direction (optional) "ASC" or "DESC"
13224 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13226 keySort : function(dir, fn){
13227 this._sort("key", dir, fn || function(a, b){
13228 return String(a).toUpperCase()-String(b).toUpperCase();
13233 * Returns a range of items in this collection
13234 * @param {Number} startIndex (optional) defaults to 0
13235 * @param {Number} endIndex (optional) default to the last item
13236 * @return {Array} An array of items
13238 getRange : function(start, end){
13239 var items = this.items;
13240 if(items.length < 1){
13243 start = start || 0;
13244 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13247 for(var i = start; i <= end; i++) {
13248 r[r.length] = items[i];
13251 for(var i = start; i >= end; i--) {
13252 r[r.length] = items[i];
13259 * Filter the <i>objects</i> in this collection by a specific property.
13260 * Returns a new collection that has been filtered.
13261 * @param {String} property A property on your objects
13262 * @param {String/RegExp} value Either string that the property values
13263 * should start with or a RegExp to test against the property
13264 * @return {MixedCollection} The new filtered collection
13266 filter : function(property, value){
13267 if(!value.exec){ // not a regex
13268 value = String(value);
13269 if(value.length == 0){
13270 return this.clone();
13272 value = new RegExp("^" + Roo.escapeRe(value), "i");
13274 return this.filterBy(function(o){
13275 return o && value.test(o[property]);
13280 * Filter by a function. * Returns a new collection that has been filtered.
13281 * The passed function will be called with each
13282 * object in the collection. If the function returns true, the value is included
13283 * otherwise it is filtered.
13284 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13285 * @param {Object} scope (optional) The scope of the function (defaults to this)
13286 * @return {MixedCollection} The new filtered collection
13288 filterBy : function(fn, scope){
13289 var r = new Roo.util.MixedCollection();
13290 r.getKey = this.getKey;
13291 var k = this.keys, it = this.items;
13292 for(var i = 0, len = it.length; i < len; i++){
13293 if(fn.call(scope||this, it[i], k[i])){
13294 r.add(k[i], it[i]);
13301 * Creates a duplicate of this collection
13302 * @return {MixedCollection}
13304 clone : function(){
13305 var r = new Roo.util.MixedCollection();
13306 var k = this.keys, it = this.items;
13307 for(var i = 0, len = it.length; i < len; i++){
13308 r.add(k[i], it[i]);
13310 r.getKey = this.getKey;
13315 * Returns the item associated with the passed key or index.
13317 * @param {String/Number} key The key or index of the item.
13318 * @return {Object} The item associated with the passed key.
13320 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13322 * Ext JS Library 1.1.1
13323 * Copyright(c) 2006-2007, Ext JS, LLC.
13325 * Originally Released Under LGPL - original licence link has changed is not relivant.
13328 * <script type="text/javascript">
13331 * @class Roo.util.JSON
13332 * Modified version of Douglas Crockford"s json.js that doesn"t
13333 * mess with the Object prototype
13334 * http://www.json.org/js.html
13337 Roo.util.JSON = new (function(){
13338 var useHasOwn = {}.hasOwnProperty ? true : false;
13340 // crashes Safari in some instances
13341 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13343 var pad = function(n) {
13344 return n < 10 ? "0" + n : n;
13357 var encodeString = function(s){
13358 if (/["\\\x00-\x1f]/.test(s)) {
13359 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13364 c = b.charCodeAt();
13366 Math.floor(c / 16).toString(16) +
13367 (c % 16).toString(16);
13370 return '"' + s + '"';
13373 var encodeArray = function(o){
13374 var a = ["["], b, i, l = o.length, v;
13375 for (i = 0; i < l; i += 1) {
13377 switch (typeof v) {
13386 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13394 var encodeDate = function(o){
13395 return '"' + o.getFullYear() + "-" +
13396 pad(o.getMonth() + 1) + "-" +
13397 pad(o.getDate()) + "T" +
13398 pad(o.getHours()) + ":" +
13399 pad(o.getMinutes()) + ":" +
13400 pad(o.getSeconds()) + '"';
13404 * Encodes an Object, Array or other value
13405 * @param {Mixed} o The variable to encode
13406 * @return {String} The JSON string
13408 this.encode = function(o)
13410 // should this be extended to fully wrap stringify..
13412 if(typeof o == "undefined" || o === null){
13414 }else if(o instanceof Array){
13415 return encodeArray(o);
13416 }else if(o instanceof Date){
13417 return encodeDate(o);
13418 }else if(typeof o == "string"){
13419 return encodeString(o);
13420 }else if(typeof o == "number"){
13421 return isFinite(o) ? String(o) : "null";
13422 }else if(typeof o == "boolean"){
13425 var a = ["{"], b, i, v;
13427 if(!useHasOwn || o.hasOwnProperty(i)) {
13429 switch (typeof v) {
13438 a.push(this.encode(i), ":",
13439 v === null ? "null" : this.encode(v));
13450 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13451 * @param {String} json The JSON string
13452 * @return {Object} The resulting object
13454 this.decode = function(json){
13456 return /** eval:var:json */ eval("(" + json + ')');
13460 * Shorthand for {@link Roo.util.JSON#encode}
13461 * @member Roo encode
13463 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13465 * Shorthand for {@link Roo.util.JSON#decode}
13466 * @member Roo decode
13468 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13471 * Ext JS Library 1.1.1
13472 * Copyright(c) 2006-2007, Ext JS, LLC.
13474 * Originally Released Under LGPL - original licence link has changed is not relivant.
13477 * <script type="text/javascript">
13481 * @class Roo.util.Format
13482 * Reusable data formatting functions
13485 Roo.util.Format = function(){
13486 var trimRe = /^\s+|\s+$/g;
13489 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13490 * @param {String} value The string to truncate
13491 * @param {Number} length The maximum length to allow before truncating
13492 * @return {String} The converted text
13494 ellipsis : function(value, len){
13495 if(value && value.length > len){
13496 return value.substr(0, len-3)+"...";
13502 * Checks a reference and converts it to empty string if it is undefined
13503 * @param {Mixed} value Reference to check
13504 * @return {Mixed} Empty string if converted, otherwise the original value
13506 undef : function(value){
13507 return typeof value != "undefined" ? value : "";
13511 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13512 * @param {String} value The string to encode
13513 * @return {String} The encoded text
13515 htmlEncode : function(value){
13516 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13520 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13521 * @param {String} value The string to decode
13522 * @return {String} The decoded text
13524 htmlDecode : function(value){
13525 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13529 * Trims any whitespace from either side of a string
13530 * @param {String} value The text to trim
13531 * @return {String} The trimmed text
13533 trim : function(value){
13534 return String(value).replace(trimRe, "");
13538 * Returns a substring from within an original string
13539 * @param {String} value The original text
13540 * @param {Number} start The start index of the substring
13541 * @param {Number} length The length of the substring
13542 * @return {String} The substring
13544 substr : function(value, start, length){
13545 return String(value).substr(start, length);
13549 * Converts a string to all lower case letters
13550 * @param {String} value The text to convert
13551 * @return {String} The converted text
13553 lowercase : function(value){
13554 return String(value).toLowerCase();
13558 * Converts a string to all upper case letters
13559 * @param {String} value The text to convert
13560 * @return {String} The converted text
13562 uppercase : function(value){
13563 return String(value).toUpperCase();
13567 * Converts the first character only of a string to upper case
13568 * @param {String} value The text to convert
13569 * @return {String} The converted text
13571 capitalize : function(value){
13572 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13576 call : function(value, fn){
13577 if(arguments.length > 2){
13578 var args = Array.prototype.slice.call(arguments, 2);
13579 args.unshift(value);
13581 return /** eval:var:value */ eval(fn).apply(window, args);
13583 /** eval:var:value */
13584 return /** eval:var:value */ eval(fn).call(window, value);
13590 * safer version of Math.toFixed..??/
13591 * @param {Number/String} value The numeric value to format
13592 * @param {Number/String} value Decimal places
13593 * @return {String} The formatted currency string
13595 toFixed : function(v, n)
13597 // why not use to fixed - precision is buggered???
13599 return Math.round(v-0);
13601 var fact = Math.pow(10,n+1);
13602 v = (Math.round((v-0)*fact))/fact;
13603 var z = (''+fact).substring(2);
13604 if (v == Math.floor(v)) {
13605 return Math.floor(v) + '.' + z;
13608 // now just padd decimals..
13609 var ps = String(v).split('.');
13610 var fd = (ps[1] + z);
13611 var r = fd.substring(0,n);
13612 var rm = fd.substring(n);
13614 return ps[0] + '.' + r;
13616 r*=1; // turn it into a number;
13618 if (String(r).length != n) {
13621 r = String(r).substring(1); // chop the end off.
13624 return ps[0] + '.' + r;
13629 * Format a number as US currency
13630 * @param {Number/String} value The numeric value to format
13631 * @return {String} The formatted currency string
13633 usMoney : function(v){
13634 return '$' + Roo.util.Format.number(v);
13639 * eventually this should probably emulate php's number_format
13640 * @param {Number/String} value The numeric value to format
13641 * @param {Number} decimals number of decimal places
13642 * @return {String} The formatted currency string
13644 number : function(v,decimals)
13646 // multiply and round.
13647 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13648 var mul = Math.pow(10, decimals);
13649 var zero = String(mul).substring(1);
13650 v = (Math.round((v-0)*mul))/mul;
13652 // if it's '0' number.. then
13654 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13656 var ps = v.split('.');
13660 var r = /(\d+)(\d{3})/;
13662 while (r.test(whole)) {
13663 whole = whole.replace(r, '$1' + ',' + '$2');
13669 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13670 // does not have decimals
13671 (decimals ? ('.' + zero) : '');
13674 return whole + sub ;
13678 * Parse a value into a formatted date using the specified format pattern.
13679 * @param {Mixed} value The value to format
13680 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13681 * @return {String} The formatted date string
13683 date : function(v, format){
13687 if(!(v instanceof Date)){
13688 v = new Date(Date.parse(v));
13690 return v.dateFormat(format || Roo.util.Format.defaults.date);
13694 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13695 * @param {String} format Any valid date format string
13696 * @return {Function} The date formatting function
13698 dateRenderer : function(format){
13699 return function(v){
13700 return Roo.util.Format.date(v, format);
13705 stripTagsRE : /<\/?[^>]+>/gi,
13708 * Strips all HTML tags
13709 * @param {Mixed} value The text from which to strip tags
13710 * @return {String} The stripped text
13712 stripTags : function(v){
13713 return !v ? v : String(v).replace(this.stripTagsRE, "");
13717 Roo.util.Format.defaults = {
13721 * Ext JS Library 1.1.1
13722 * Copyright(c) 2006-2007, Ext JS, LLC.
13724 * Originally Released Under LGPL - original licence link has changed is not relivant.
13727 * <script type="text/javascript">
13734 * @class Roo.MasterTemplate
13735 * @extends Roo.Template
13736 * Provides a template that can have child templates. The syntax is:
13738 var t = new Roo.MasterTemplate(
13739 '<select name="{name}">',
13740 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13743 t.add('options', {value: 'foo', text: 'bar'});
13744 // or you can add multiple child elements in one shot
13745 t.addAll('options', [
13746 {value: 'foo', text: 'bar'},
13747 {value: 'foo2', text: 'bar2'},
13748 {value: 'foo3', text: 'bar3'}
13750 // then append, applying the master template values
13751 t.append('my-form', {name: 'my-select'});
13753 * A name attribute for the child template is not required if you have only one child
13754 * template or you want to refer to them by index.
13756 Roo.MasterTemplate = function(){
13757 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13758 this.originalHtml = this.html;
13760 var m, re = this.subTemplateRe;
13763 while(m = re.exec(this.html)){
13764 var name = m[1], content = m[2];
13769 tpl : new Roo.Template(content)
13772 st[name] = st[subIndex];
13774 st[subIndex].tpl.compile();
13775 st[subIndex].tpl.call = this.call.createDelegate(this);
13778 this.subCount = subIndex;
13781 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13783 * The regular expression used to match sub templates
13787 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13790 * Applies the passed values to a child template.
13791 * @param {String/Number} name (optional) The name or index of the child template
13792 * @param {Array/Object} values The values to be applied to the template
13793 * @return {MasterTemplate} this
13795 add : function(name, values){
13796 if(arguments.length == 1){
13797 values = arguments[0];
13800 var s = this.subs[name];
13801 s.buffer[s.buffer.length] = s.tpl.apply(values);
13806 * Applies all the passed values to a child template.
13807 * @param {String/Number} name (optional) The name or index of the child template
13808 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13809 * @param {Boolean} reset (optional) True to reset the template first
13810 * @return {MasterTemplate} this
13812 fill : function(name, values, reset){
13814 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13822 for(var i = 0, len = values.length; i < len; i++){
13823 this.add(name, values[i]);
13829 * Resets the template for reuse
13830 * @return {MasterTemplate} this
13832 reset : function(){
13834 for(var i = 0; i < this.subCount; i++){
13840 applyTemplate : function(values){
13842 var replaceIndex = -1;
13843 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13844 return s[++replaceIndex].buffer.join("");
13846 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13849 apply : function(){
13850 return this.applyTemplate.apply(this, arguments);
13853 compile : function(){return this;}
13857 * Alias for fill().
13860 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13862 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13863 * var tpl = Roo.MasterTemplate.from('element-id');
13864 * @param {String/HTMLElement} el
13865 * @param {Object} config
13868 Roo.MasterTemplate.from = function(el, config){
13869 el = Roo.getDom(el);
13870 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13873 * Ext JS Library 1.1.1
13874 * Copyright(c) 2006-2007, Ext JS, LLC.
13876 * Originally Released Under LGPL - original licence link has changed is not relivant.
13879 * <script type="text/javascript">
13884 * @class Roo.util.CSS
13885 * Utility class for manipulating CSS rules
13888 Roo.util.CSS = function(){
13890 var doc = document;
13892 var camelRe = /(-[a-z])/gi;
13893 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13897 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13898 * tag and appended to the HEAD of the document.
13899 * @param {String|Object} cssText The text containing the css rules
13900 * @param {String} id An id to add to the stylesheet for later removal
13901 * @return {StyleSheet}
13903 createStyleSheet : function(cssText, id){
13905 var head = doc.getElementsByTagName("head")[0];
13906 var nrules = doc.createElement("style");
13907 nrules.setAttribute("type", "text/css");
13909 nrules.setAttribute("id", id);
13911 if (typeof(cssText) != 'string') {
13912 // support object maps..
13913 // not sure if this a good idea..
13914 // perhaps it should be merged with the general css handling
13915 // and handle js style props.
13916 var cssTextNew = [];
13917 for(var n in cssText) {
13919 for(var k in cssText[n]) {
13920 citems.push( k + ' : ' +cssText[n][k] + ';' );
13922 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13925 cssText = cssTextNew.join("\n");
13931 head.appendChild(nrules);
13932 ss = nrules.styleSheet;
13933 ss.cssText = cssText;
13936 nrules.appendChild(doc.createTextNode(cssText));
13938 nrules.cssText = cssText;
13940 head.appendChild(nrules);
13941 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13943 this.cacheStyleSheet(ss);
13948 * Removes a style or link tag by id
13949 * @param {String} id The id of the tag
13951 removeStyleSheet : function(id){
13952 var existing = doc.getElementById(id);
13954 existing.parentNode.removeChild(existing);
13959 * Dynamically swaps an existing stylesheet reference for a new one
13960 * @param {String} id The id of an existing link tag to remove
13961 * @param {String} url The href of the new stylesheet to include
13963 swapStyleSheet : function(id, url){
13964 this.removeStyleSheet(id);
13965 var ss = doc.createElement("link");
13966 ss.setAttribute("rel", "stylesheet");
13967 ss.setAttribute("type", "text/css");
13968 ss.setAttribute("id", id);
13969 ss.setAttribute("href", url);
13970 doc.getElementsByTagName("head")[0].appendChild(ss);
13974 * Refresh the rule cache if you have dynamically added stylesheets
13975 * @return {Object} An object (hash) of rules indexed by selector
13977 refreshCache : function(){
13978 return this.getRules(true);
13982 cacheStyleSheet : function(stylesheet){
13986 try{// try catch for cross domain access issue
13987 var ssRules = stylesheet.cssRules || stylesheet.rules;
13988 for(var j = ssRules.length-1; j >= 0; --j){
13989 rules[ssRules[j].selectorText] = ssRules[j];
13995 * Gets all css rules for the document
13996 * @param {Boolean} refreshCache true to refresh the internal cache
13997 * @return {Object} An object (hash) of rules indexed by selector
13999 getRules : function(refreshCache){
14000 if(rules == null || refreshCache){
14002 var ds = doc.styleSheets;
14003 for(var i =0, len = ds.length; i < len; i++){
14005 this.cacheStyleSheet(ds[i]);
14013 * Gets an an individual CSS rule by selector(s)
14014 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14015 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14016 * @return {CSSRule} The CSS rule or null if one is not found
14018 getRule : function(selector, refreshCache){
14019 var rs = this.getRules(refreshCache);
14020 if(!(selector instanceof Array)){
14021 return rs[selector];
14023 for(var i = 0; i < selector.length; i++){
14024 if(rs[selector[i]]){
14025 return rs[selector[i]];
14033 * Updates a rule property
14034 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14035 * @param {String} property The css property
14036 * @param {String} value The new value for the property
14037 * @return {Boolean} true If a rule was found and updated
14039 updateRule : function(selector, property, value){
14040 if(!(selector instanceof Array)){
14041 var rule = this.getRule(selector);
14043 rule.style[property.replace(camelRe, camelFn)] = value;
14047 for(var i = 0; i < selector.length; i++){
14048 if(this.updateRule(selector[i], property, value)){
14058 * Ext JS Library 1.1.1
14059 * Copyright(c) 2006-2007, Ext JS, LLC.
14061 * Originally Released Under LGPL - original licence link has changed is not relivant.
14064 * <script type="text/javascript">
14070 * @class Roo.util.ClickRepeater
14071 * @extends Roo.util.Observable
14073 * A wrapper class which can be applied to any element. Fires a "click" event while the
14074 * mouse is pressed. The interval between firings may be specified in the config but
14075 * defaults to 10 milliseconds.
14077 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14079 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14080 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14081 * Similar to an autorepeat key delay.
14082 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14083 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14084 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14085 * "interval" and "delay" are ignored. "immediate" is honored.
14086 * @cfg {Boolean} preventDefault True to prevent the default click event
14087 * @cfg {Boolean} stopDefault True to stop the default click event
14090 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14091 * 2007-02-02 jvs Renamed to ClickRepeater
14092 * 2007-02-03 jvs Modifications for FF Mac and Safari
14095 * @param {String/HTMLElement/Element} el The element to listen on
14096 * @param {Object} config
14098 Roo.util.ClickRepeater = function(el, config)
14100 this.el = Roo.get(el);
14101 this.el.unselectable();
14103 Roo.apply(this, config);
14108 * Fires when the mouse button is depressed.
14109 * @param {Roo.util.ClickRepeater} this
14111 "mousedown" : true,
14114 * Fires on a specified interval during the time the element is pressed.
14115 * @param {Roo.util.ClickRepeater} this
14120 * Fires when the mouse key is released.
14121 * @param {Roo.util.ClickRepeater} this
14126 this.el.on("mousedown", this.handleMouseDown, this);
14127 if(this.preventDefault || this.stopDefault){
14128 this.el.on("click", function(e){
14129 if(this.preventDefault){
14130 e.preventDefault();
14132 if(this.stopDefault){
14138 // allow inline handler
14140 this.on("click", this.handler, this.scope || this);
14143 Roo.util.ClickRepeater.superclass.constructor.call(this);
14146 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14149 preventDefault : true,
14150 stopDefault : false,
14154 handleMouseDown : function(){
14155 clearTimeout(this.timer);
14157 if(this.pressClass){
14158 this.el.addClass(this.pressClass);
14160 this.mousedownTime = new Date();
14162 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14163 this.el.on("mouseout", this.handleMouseOut, this);
14165 this.fireEvent("mousedown", this);
14166 this.fireEvent("click", this);
14168 this.timer = this.click.defer(this.delay || this.interval, this);
14172 click : function(){
14173 this.fireEvent("click", this);
14174 this.timer = this.click.defer(this.getInterval(), this);
14178 getInterval: function(){
14179 if(!this.accelerate){
14180 return this.interval;
14182 var pressTime = this.mousedownTime.getElapsed();
14183 if(pressTime < 500){
14185 }else if(pressTime < 1700){
14187 }else if(pressTime < 2600){
14189 }else if(pressTime < 3500){
14191 }else if(pressTime < 4400){
14193 }else if(pressTime < 5300){
14195 }else if(pressTime < 6200){
14203 handleMouseOut : function(){
14204 clearTimeout(this.timer);
14205 if(this.pressClass){
14206 this.el.removeClass(this.pressClass);
14208 this.el.on("mouseover", this.handleMouseReturn, this);
14212 handleMouseReturn : function(){
14213 this.el.un("mouseover", this.handleMouseReturn);
14214 if(this.pressClass){
14215 this.el.addClass(this.pressClass);
14221 handleMouseUp : function(){
14222 clearTimeout(this.timer);
14223 this.el.un("mouseover", this.handleMouseReturn);
14224 this.el.un("mouseout", this.handleMouseOut);
14225 Roo.get(document).un("mouseup", this.handleMouseUp);
14226 this.el.removeClass(this.pressClass);
14227 this.fireEvent("mouseup", this);
14231 * Ext JS Library 1.1.1
14232 * Copyright(c) 2006-2007, Ext JS, LLC.
14234 * Originally Released Under LGPL - original licence link has changed is not relivant.
14237 * <script type="text/javascript">
14242 * @class Roo.KeyNav
14243 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14244 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14245 * way to implement custom navigation schemes for any UI component.</p>
14246 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14247 * pageUp, pageDown, del, home, end. Usage:</p>
14249 var nav = new Roo.KeyNav("my-element", {
14250 "left" : function(e){
14251 this.moveLeft(e.ctrlKey);
14253 "right" : function(e){
14254 this.moveRight(e.ctrlKey);
14256 "enter" : function(e){
14263 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14264 * @param {Object} config The config
14266 Roo.KeyNav = function(el, config){
14267 this.el = Roo.get(el);
14268 Roo.apply(this, config);
14269 if(!this.disabled){
14270 this.disabled = true;
14275 Roo.KeyNav.prototype = {
14277 * @cfg {Boolean} disabled
14278 * True to disable this KeyNav instance (defaults to false)
14282 * @cfg {String} defaultEventAction
14283 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14284 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14285 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14287 defaultEventAction: "stopEvent",
14289 * @cfg {Boolean} forceKeyDown
14290 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14291 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14292 * handle keydown instead of keypress.
14294 forceKeyDown : false,
14297 prepareEvent : function(e){
14298 var k = e.getKey();
14299 var h = this.keyToHandler[k];
14300 //if(h && this[h]){
14301 // e.stopPropagation();
14303 if(Roo.isSafari && h && k >= 37 && k <= 40){
14309 relay : function(e){
14310 var k = e.getKey();
14311 var h = this.keyToHandler[k];
14313 if(this.doRelay(e, this[h], h) !== true){
14314 e[this.defaultEventAction]();
14320 doRelay : function(e, h, hname){
14321 return h.call(this.scope || this, e);
14324 // possible handlers
14338 // quick lookup hash
14355 * Enable this KeyNav
14357 enable: function(){
14359 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14360 // the EventObject will normalize Safari automatically
14361 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14362 this.el.on("keydown", this.relay, this);
14364 this.el.on("keydown", this.prepareEvent, this);
14365 this.el.on("keypress", this.relay, this);
14367 this.disabled = false;
14372 * Disable this KeyNav
14374 disable: function(){
14375 if(!this.disabled){
14376 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14377 this.el.un("keydown", this.relay);
14379 this.el.un("keydown", this.prepareEvent);
14380 this.el.un("keypress", this.relay);
14382 this.disabled = true;
14387 * Ext JS Library 1.1.1
14388 * Copyright(c) 2006-2007, Ext JS, LLC.
14390 * Originally Released Under LGPL - original licence link has changed is not relivant.
14393 * <script type="text/javascript">
14398 * @class Roo.KeyMap
14399 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14400 * The constructor accepts the same config object as defined by {@link #addBinding}.
14401 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14402 * combination it will call the function with this signature (if the match is a multi-key
14403 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14404 * A KeyMap can also handle a string representation of keys.<br />
14407 // map one key by key code
14408 var map = new Roo.KeyMap("my-element", {
14409 key: 13, // or Roo.EventObject.ENTER
14414 // map multiple keys to one action by string
14415 var map = new Roo.KeyMap("my-element", {
14421 // map multiple keys to multiple actions by strings and array of codes
14422 var map = new Roo.KeyMap("my-element", [
14425 fn: function(){ alert("Return was pressed"); }
14428 fn: function(){ alert('a, b or c was pressed'); }
14433 fn: function(){ alert('Control + shift + tab was pressed.'); }
14437 * <b>Note: A KeyMap starts enabled</b>
14439 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14440 * @param {Object} config The config (see {@link #addBinding})
14441 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14443 Roo.KeyMap = function(el, config, eventName){
14444 this.el = Roo.get(el);
14445 this.eventName = eventName || "keydown";
14446 this.bindings = [];
14448 this.addBinding(config);
14453 Roo.KeyMap.prototype = {
14455 * True to stop the event from bubbling and prevent the default browser action if the
14456 * key was handled by the KeyMap (defaults to false)
14462 * Add a new binding to this KeyMap. The following config object properties are supported:
14464 Property Type Description
14465 ---------- --------------- ----------------------------------------------------------------------
14466 key String/Array A single keycode or an array of keycodes to handle
14467 shift Boolean True to handle key only when shift is pressed (defaults to false)
14468 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14469 alt Boolean True to handle key only when alt is pressed (defaults to false)
14470 fn Function The function to call when KeyMap finds the expected key combination
14471 scope Object The scope of the callback function
14477 var map = new Roo.KeyMap(document, {
14478 key: Roo.EventObject.ENTER,
14483 //Add a new binding to the existing KeyMap later
14491 * @param {Object/Array} config A single KeyMap config or an array of configs
14493 addBinding : function(config){
14494 if(config instanceof Array){
14495 for(var i = 0, len = config.length; i < len; i++){
14496 this.addBinding(config[i]);
14500 var keyCode = config.key,
14501 shift = config.shift,
14502 ctrl = config.ctrl,
14505 scope = config.scope;
14506 if(typeof keyCode == "string"){
14508 var keyString = keyCode.toUpperCase();
14509 for(var j = 0, len = keyString.length; j < len; j++){
14510 ks.push(keyString.charCodeAt(j));
14514 var keyArray = keyCode instanceof Array;
14515 var handler = function(e){
14516 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14517 var k = e.getKey();
14519 for(var i = 0, len = keyCode.length; i < len; i++){
14520 if(keyCode[i] == k){
14521 if(this.stopEvent){
14524 fn.call(scope || window, k, e);
14530 if(this.stopEvent){
14533 fn.call(scope || window, k, e);
14538 this.bindings.push(handler);
14542 * Shorthand for adding a single key listener
14543 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14544 * following options:
14545 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14546 * @param {Function} fn The function to call
14547 * @param {Object} scope (optional) The scope of the function
14549 on : function(key, fn, scope){
14550 var keyCode, shift, ctrl, alt;
14551 if(typeof key == "object" && !(key instanceof Array)){
14570 handleKeyDown : function(e){
14571 if(this.enabled){ //just in case
14572 var b = this.bindings;
14573 for(var i = 0, len = b.length; i < len; i++){
14574 b[i].call(this, e);
14580 * Returns true if this KeyMap is enabled
14581 * @return {Boolean}
14583 isEnabled : function(){
14584 return this.enabled;
14588 * Enables this KeyMap
14590 enable: function(){
14592 this.el.on(this.eventName, this.handleKeyDown, this);
14593 this.enabled = true;
14598 * Disable this KeyMap
14600 disable: function(){
14602 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14603 this.enabled = false;
14608 * Ext JS Library 1.1.1
14609 * Copyright(c) 2006-2007, Ext JS, LLC.
14611 * Originally Released Under LGPL - original licence link has changed is not relivant.
14614 * <script type="text/javascript">
14619 * @class Roo.util.TextMetrics
14620 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14621 * wide, in pixels, a given block of text will be.
14624 Roo.util.TextMetrics = function(){
14628 * Measures the size of the specified text
14629 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14630 * that can affect the size of the rendered text
14631 * @param {String} text The text to measure
14632 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14633 * in order to accurately measure the text height
14634 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14636 measure : function(el, text, fixedWidth){
14638 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14641 shared.setFixedWidth(fixedWidth || 'auto');
14642 return shared.getSize(text);
14646 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14647 * the overhead of multiple calls to initialize the style properties on each measurement.
14648 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14649 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14650 * in order to accurately measure the text height
14651 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14653 createInstance : function(el, fixedWidth){
14654 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14661 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14662 var ml = new Roo.Element(document.createElement('div'));
14663 document.body.appendChild(ml.dom);
14664 ml.position('absolute');
14665 ml.setLeftTop(-1000, -1000);
14669 ml.setWidth(fixedWidth);
14674 * Returns the size of the specified text based on the internal element's style and width properties
14675 * @memberOf Roo.util.TextMetrics.Instance#
14676 * @param {String} text The text to measure
14677 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14679 getSize : function(text){
14681 var s = ml.getSize();
14687 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14688 * that can affect the size of the rendered text
14689 * @memberOf Roo.util.TextMetrics.Instance#
14690 * @param {String/HTMLElement} el The element, dom node or id
14692 bind : function(el){
14694 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14699 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14700 * to set a fixed width in order to accurately measure the text height.
14701 * @memberOf Roo.util.TextMetrics.Instance#
14702 * @param {Number} width The width to set on the element
14704 setFixedWidth : function(width){
14705 ml.setWidth(width);
14709 * Returns the measured width of the specified text
14710 * @memberOf Roo.util.TextMetrics.Instance#
14711 * @param {String} text The text to measure
14712 * @return {Number} width The width in pixels
14714 getWidth : function(text){
14715 ml.dom.style.width = 'auto';
14716 return this.getSize(text).width;
14720 * Returns the measured height of the specified text. For multiline text, be sure to call
14721 * {@link #setFixedWidth} if necessary.
14722 * @memberOf Roo.util.TextMetrics.Instance#
14723 * @param {String} text The text to measure
14724 * @return {Number} height The height in pixels
14726 getHeight : function(text){
14727 return this.getSize(text).height;
14731 instance.bind(bindTo);
14736 // backwards compat
14737 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14739 * Ext JS Library 1.1.1
14740 * Copyright(c) 2006-2007, Ext JS, LLC.
14742 * Originally Released Under LGPL - original licence link has changed is not relivant.
14745 * <script type="text/javascript">
14749 * @class Roo.state.Provider
14750 * Abstract base class for state provider implementations. This class provides methods
14751 * for encoding and decoding <b>typed</b> variables including dates and defines the
14752 * Provider interface.
14754 Roo.state.Provider = function(){
14756 * @event statechange
14757 * Fires when a state change occurs.
14758 * @param {Provider} this This state provider
14759 * @param {String} key The state key which was changed
14760 * @param {String} value The encoded value for the state
14763 "statechange": true
14766 Roo.state.Provider.superclass.constructor.call(this);
14768 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14770 * Returns the current value for a key
14771 * @param {String} name The key name
14772 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14773 * @return {Mixed} The state data
14775 get : function(name, defaultValue){
14776 return typeof this.state[name] == "undefined" ?
14777 defaultValue : this.state[name];
14781 * Clears a value from the state
14782 * @param {String} name The key name
14784 clear : function(name){
14785 delete this.state[name];
14786 this.fireEvent("statechange", this, name, null);
14790 * Sets the value for a key
14791 * @param {String} name The key name
14792 * @param {Mixed} value The value to set
14794 set : function(name, value){
14795 this.state[name] = value;
14796 this.fireEvent("statechange", this, name, value);
14800 * Decodes a string previously encoded with {@link #encodeValue}.
14801 * @param {String} value The value to decode
14802 * @return {Mixed} The decoded value
14804 decodeValue : function(cookie){
14805 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14806 var matches = re.exec(unescape(cookie));
14807 if(!matches || !matches[1]) return; // non state cookie
14808 var type = matches[1];
14809 var v = matches[2];
14812 return parseFloat(v);
14814 return new Date(Date.parse(v));
14819 var values = v.split("^");
14820 for(var i = 0, len = values.length; i < len; i++){
14821 all.push(this.decodeValue(values[i]));
14826 var values = v.split("^");
14827 for(var i = 0, len = values.length; i < len; i++){
14828 var kv = values[i].split("=");
14829 all[kv[0]] = this.decodeValue(kv[1]);
14838 * Encodes a value including type information. Decode with {@link #decodeValue}.
14839 * @param {Mixed} value The value to encode
14840 * @return {String} The encoded value
14842 encodeValue : function(v){
14844 if(typeof v == "number"){
14846 }else if(typeof v == "boolean"){
14847 enc = "b:" + (v ? "1" : "0");
14848 }else if(v instanceof Date){
14849 enc = "d:" + v.toGMTString();
14850 }else if(v instanceof Array){
14852 for(var i = 0, len = v.length; i < len; i++){
14853 flat += this.encodeValue(v[i]);
14854 if(i != len-1) flat += "^";
14857 }else if(typeof v == "object"){
14860 if(typeof v[key] != "function"){
14861 flat += key + "=" + this.encodeValue(v[key]) + "^";
14864 enc = "o:" + flat.substring(0, flat.length-1);
14868 return escape(enc);
14874 * Ext JS Library 1.1.1
14875 * Copyright(c) 2006-2007, Ext JS, LLC.
14877 * Originally Released Under LGPL - original licence link has changed is not relivant.
14880 * <script type="text/javascript">
14883 * @class Roo.state.Manager
14884 * This is the global state manager. By default all components that are "state aware" check this class
14885 * for state information if you don't pass them a custom state provider. In order for this class
14886 * to be useful, it must be initialized with a provider when your application initializes.
14888 // in your initialization function
14890 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14892 // supposed you have a {@link Roo.BorderLayout}
14893 var layout = new Roo.BorderLayout(...);
14894 layout.restoreState();
14895 // or a {Roo.BasicDialog}
14896 var dialog = new Roo.BasicDialog(...);
14897 dialog.restoreState();
14901 Roo.state.Manager = function(){
14902 var provider = new Roo.state.Provider();
14906 * Configures the default state provider for your application
14907 * @param {Provider} stateProvider The state provider to set
14909 setProvider : function(stateProvider){
14910 provider = stateProvider;
14914 * Returns the current value for a key
14915 * @param {String} name The key name
14916 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14917 * @return {Mixed} The state data
14919 get : function(key, defaultValue){
14920 return provider.get(key, defaultValue);
14924 * Sets the value for a key
14925 * @param {String} name The key name
14926 * @param {Mixed} value The state data
14928 set : function(key, value){
14929 provider.set(key, value);
14933 * Clears a value from the state
14934 * @param {String} name The key name
14936 clear : function(key){
14937 provider.clear(key);
14941 * Gets the currently configured state provider
14942 * @return {Provider} The state provider
14944 getProvider : function(){
14951 * Ext JS Library 1.1.1
14952 * Copyright(c) 2006-2007, Ext JS, LLC.
14954 * Originally Released Under LGPL - original licence link has changed is not relivant.
14957 * <script type="text/javascript">
14960 * @class Roo.state.CookieProvider
14961 * @extends Roo.state.Provider
14962 * The default Provider implementation which saves state via cookies.
14965 var cp = new Roo.state.CookieProvider({
14967 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14968 domain: "roojs.com"
14970 Roo.state.Manager.setProvider(cp);
14972 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14973 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14974 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14975 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14976 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14977 * domain the page is running on including the 'www' like 'www.roojs.com')
14978 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14980 * Create a new CookieProvider
14981 * @param {Object} config The configuration object
14983 Roo.state.CookieProvider = function(config){
14984 Roo.state.CookieProvider.superclass.constructor.call(this);
14986 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14987 this.domain = null;
14988 this.secure = false;
14989 Roo.apply(this, config);
14990 this.state = this.readCookies();
14993 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14995 set : function(name, value){
14996 if(typeof value == "undefined" || value === null){
15000 this.setCookie(name, value);
15001 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15005 clear : function(name){
15006 this.clearCookie(name);
15007 Roo.state.CookieProvider.superclass.clear.call(this, name);
15011 readCookies : function(){
15013 var c = document.cookie + ";";
15014 var re = /\s?(.*?)=(.*?);/g;
15016 while((matches = re.exec(c)) != null){
15017 var name = matches[1];
15018 var value = matches[2];
15019 if(name && name.substring(0,3) == "ys-"){
15020 cookies[name.substr(3)] = this.decodeValue(value);
15027 setCookie : function(name, value){
15028 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15029 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15030 ((this.path == null) ? "" : ("; path=" + this.path)) +
15031 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15032 ((this.secure == true) ? "; secure" : "");
15036 clearCookie : function(name){
15037 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15038 ((this.path == null) ? "" : ("; path=" + this.path)) +
15039 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15040 ((this.secure == true) ? "; secure" : "");
15044 * Ext JS Library 1.1.1
15045 * Copyright(c) 2006-2007, Ext JS, LLC.
15047 * Originally Released Under LGPL - original licence link has changed is not relivant.
15050 * <script type="text/javascript">
15055 * @class Roo.ComponentMgr
15056 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15059 Roo.ComponentMgr = function(){
15060 var all = new Roo.util.MixedCollection();
15064 * Registers a component.
15065 * @param {Roo.Component} c The component
15067 register : function(c){
15072 * Unregisters a component.
15073 * @param {Roo.Component} c The component
15075 unregister : function(c){
15080 * Returns a component by id
15081 * @param {String} id The component id
15083 get : function(id){
15084 return all.get(id);
15088 * Registers a function that will be called when a specified component is added to ComponentMgr
15089 * @param {String} id The component id
15090 * @param {Funtction} fn The callback function
15091 * @param {Object} scope The scope of the callback
15093 onAvailable : function(id, fn, scope){
15094 all.on("add", function(index, o){
15096 fn.call(scope || o, o);
15097 all.un("add", fn, scope);
15104 * Ext JS Library 1.1.1
15105 * Copyright(c) 2006-2007, Ext JS, LLC.
15107 * Originally Released Under LGPL - original licence link has changed is not relivant.
15110 * <script type="text/javascript">
15114 * @class Roo.Component
15115 * @extends Roo.util.Observable
15116 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15117 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15118 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15119 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15120 * All visual components (widgets) that require rendering into a layout should subclass Component.
15122 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15123 * element and its id used as the component id. If a string is passed, it is assumed to be the id of an existing element
15124 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15126 Roo.Component = function(config){
15127 config = config || {};
15128 if(config.tagName || config.dom || typeof config == "string"){ // element object
15129 config = {el: config, id: config.id || config};
15131 this.initialConfig = config;
15133 Roo.apply(this, config);
15137 * Fires after the component is disabled.
15138 * @param {Roo.Component} this
15143 * Fires after the component is enabled.
15144 * @param {Roo.Component} this
15148 * @event beforeshow
15149 * Fires before the component is shown. Return false to stop the show.
15150 * @param {Roo.Component} this
15155 * Fires after the component is shown.
15156 * @param {Roo.Component} this
15160 * @event beforehide
15161 * Fires before the component is hidden. Return false to stop the hide.
15162 * @param {Roo.Component} this
15167 * Fires after the component is hidden.
15168 * @param {Roo.Component} this
15172 * @event beforerender
15173 * Fires before the component is rendered. Return false to stop the render.
15174 * @param {Roo.Component} this
15176 beforerender : true,
15179 * Fires after the component is rendered.
15180 * @param {Roo.Component} this
15184 * @event beforedestroy
15185 * Fires before the component is destroyed. Return false to stop the destroy.
15186 * @param {Roo.Component} this
15188 beforedestroy : true,
15191 * Fires after the component is destroyed.
15192 * @param {Roo.Component} this
15197 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15199 Roo.ComponentMgr.register(this);
15200 Roo.Component.superclass.constructor.call(this);
15201 this.initComponent();
15202 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15203 this.render(this.renderTo);
15204 delete this.renderTo;
15209 Roo.Component.AUTO_ID = 1000;
15211 Roo.extend(Roo.Component, Roo.util.Observable, {
15213 * @scope Roo.Component.prototype
15215 * true if this component is hidden. Read-only.
15220 * true if this component is disabled. Read-only.
15225 * true if this component has been rendered. Read-only.
15229 /** @cfg {String} disableClass
15230 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15232 disabledClass : "x-item-disabled",
15233 /** @cfg {Boolean} allowDomMove
15234 * Whether the component can move the Dom node when rendering (defaults to true).
15236 allowDomMove : true,
15237 /** @cfg {String} hideMode (display|visibility)
15238 * How this component should hidden. Supported values are
15239 * "visibility" (css visibility), "offsets" (negative offset position) and
15240 * "display" (css display) - defaults to "display".
15242 hideMode: 'display',
15245 ctype : "Roo.Component",
15248 * @cfg {String} actionMode
15249 * which property holds the element that used for hide() / show() / disable() / enable()
15255 getActionEl : function(){
15256 return this[this.actionMode];
15259 initComponent : Roo.emptyFn,
15261 * If this is a lazy rendering component, render it to its container element.
15262 * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
15264 render : function(container, position){
15265 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15266 if(!container && this.el){
15267 this.el = Roo.get(this.el);
15268 container = this.el.dom.parentNode;
15269 this.allowDomMove = false;
15271 this.container = Roo.get(container);
15272 this.rendered = true;
15273 if(position !== undefined){
15274 if(typeof position == 'number'){
15275 position = this.container.dom.childNodes[position];
15277 position = Roo.getDom(position);
15280 this.onRender(this.container, position || null);
15282 this.el.addClass(this.cls);
15286 this.el.applyStyles(this.style);
15289 this.fireEvent("render", this);
15290 this.afterRender(this.container);
15302 // default function is not really useful
15303 onRender : function(ct, position){
15305 this.el = Roo.get(this.el);
15306 if(this.allowDomMove !== false){
15307 ct.dom.insertBefore(this.el.dom, position);
15313 getAutoCreate : function(){
15314 var cfg = typeof this.autoCreate == "object" ?
15315 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15316 if(this.id && !cfg.id){
15323 afterRender : Roo.emptyFn,
15326 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15327 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15329 destroy : function(){
15330 if(this.fireEvent("beforedestroy", this) !== false){
15331 this.purgeListeners();
15332 this.beforeDestroy();
15334 this.el.removeAllListeners();
15336 if(this.actionMode == "container"){
15337 this.container.remove();
15341 Roo.ComponentMgr.unregister(this);
15342 this.fireEvent("destroy", this);
15347 beforeDestroy : function(){
15352 onDestroy : function(){
15357 * Returns the underlying {@link Roo.Element}.
15358 * @return {Roo.Element} The element
15360 getEl : function(){
15365 * Returns the id of this component.
15368 getId : function(){
15373 * Try to focus this component.
15374 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15375 * @return {Roo.Component} this
15377 focus : function(selectText){
15380 if(selectText === true){
15381 this.el.dom.select();
15396 * Disable this component.
15397 * @return {Roo.Component} this
15399 disable : function(){
15403 this.disabled = true;
15404 this.fireEvent("disable", this);
15409 onDisable : function(){
15410 this.getActionEl().addClass(this.disabledClass);
15411 this.el.dom.disabled = true;
15415 * Enable this component.
15416 * @return {Roo.Component} this
15418 enable : function(){
15422 this.disabled = false;
15423 this.fireEvent("enable", this);
15428 onEnable : function(){
15429 this.getActionEl().removeClass(this.disabledClass);
15430 this.el.dom.disabled = false;
15434 * Convenience function for setting disabled/enabled by boolean.
15435 * @param {Boolean} disabled
15437 setDisabled : function(disabled){
15438 this[disabled ? "disable" : "enable"]();
15442 * Show this component.
15443 * @return {Roo.Component} this
15446 if(this.fireEvent("beforeshow", this) !== false){
15447 this.hidden = false;
15451 this.fireEvent("show", this);
15457 onShow : function(){
15458 var ae = this.getActionEl();
15459 if(this.hideMode == 'visibility'){
15460 ae.dom.style.visibility = "visible";
15461 }else if(this.hideMode == 'offsets'){
15462 ae.removeClass('x-hidden');
15464 ae.dom.style.display = "";
15469 * Hide this component.
15470 * @return {Roo.Component} this
15473 if(this.fireEvent("beforehide", this) !== false){
15474 this.hidden = true;
15478 this.fireEvent("hide", this);
15484 onHide : function(){
15485 var ae = this.getActionEl();
15486 if(this.hideMode == 'visibility'){
15487 ae.dom.style.visibility = "hidden";
15488 }else if(this.hideMode == 'offsets'){
15489 ae.addClass('x-hidden');
15491 ae.dom.style.display = "none";
15496 * Convenience function to hide or show this component by boolean.
15497 * @param {Boolean} visible True to show, false to hide
15498 * @return {Roo.Component} this
15500 setVisible: function(visible){
15510 * Returns true if this component is visible.
15512 isVisible : function(){
15513 return this.getActionEl().isVisible();
15516 cloneConfig : function(overrides){
15517 overrides = overrides || {};
15518 var id = overrides.id || Roo.id();
15519 var cfg = Roo.applyIf(overrides, this.initialConfig);
15520 cfg.id = id; // prevent dup id
15521 return new this.constructor(cfg);
15525 * Ext JS Library 1.1.1
15526 * Copyright(c) 2006-2007, Ext JS, LLC.
15528 * Originally Released Under LGPL - original licence link has changed is not relivant.
15531 * <script type="text/javascript">
15535 * @class Roo.BoxComponent
15536 * @extends Roo.Component
15537 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15538 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15539 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15540 * layout containers.
15542 * @param {Roo.Element/String/Object} config The configuration options.
15544 Roo.BoxComponent = function(config){
15545 Roo.Component.call(this, config);
15549 * Fires after the component is resized.
15550 * @param {Roo.Component} this
15551 * @param {Number} adjWidth The box-adjusted width that was set
15552 * @param {Number} adjHeight The box-adjusted height that was set
15553 * @param {Number} rawWidth The width that was originally specified
15554 * @param {Number} rawHeight The height that was originally specified
15559 * Fires after the component is moved.
15560 * @param {Roo.Component} this
15561 * @param {Number} x The new x position
15562 * @param {Number} y The new y position
15568 Roo.extend(Roo.BoxComponent, Roo.Component, {
15569 // private, set in afterRender to signify that the component has been rendered
15571 // private, used to defer height settings to subclasses
15572 deferHeight: false,
15573 /** @cfg {Number} width
15574 * width (optional) size of component
15576 /** @cfg {Number} height
15577 * height (optional) size of component
15581 * Sets the width and height of the component. This method fires the resize event. This method can accept
15582 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15583 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15584 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15585 * @return {Roo.BoxComponent} this
15587 setSize : function(w, h){
15588 // support for standard size objects
15589 if(typeof w == 'object'){
15594 if(!this.boxReady){
15600 // prevent recalcs when not needed
15601 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15604 this.lastSize = {width: w, height: h};
15606 var adj = this.adjustSize(w, h);
15607 var aw = adj.width, ah = adj.height;
15608 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15609 var rz = this.getResizeEl();
15610 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15611 rz.setSize(aw, ah);
15612 }else if(!this.deferHeight && ah !== undefined){
15614 }else if(aw !== undefined){
15617 this.onResize(aw, ah, w, h);
15618 this.fireEvent('resize', this, aw, ah, w, h);
15624 * Gets the current size of the component's underlying element.
15625 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15627 getSize : function(){
15628 return this.el.getSize();
15632 * Gets the current XY position of the component's underlying element.
15633 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15634 * @return {Array} The XY position of the element (e.g., [100, 200])
15636 getPosition : function(local){
15637 if(local === true){
15638 return [this.el.getLeft(true), this.el.getTop(true)];
15640 return this.xy || this.el.getXY();
15644 * Gets the current box measurements of the component's underlying element.
15645 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15646 * @returns {Object} box An object in the format {x, y, width, height}
15648 getBox : function(local){
15649 var s = this.el.getSize();
15651 s.x = this.el.getLeft(true);
15652 s.y = this.el.getTop(true);
15654 var xy = this.xy || this.el.getXY();
15662 * Sets the current box measurements of the component's underlying element.
15663 * @param {Object} box An object in the format {x, y, width, height}
15664 * @returns {Roo.BoxComponent} this
15666 updateBox : function(box){
15667 this.setSize(box.width, box.height);
15668 this.setPagePosition(box.x, box.y);
15673 getResizeEl : function(){
15674 return this.resizeEl || this.el;
15678 getPositionEl : function(){
15679 return this.positionEl || this.el;
15683 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15684 * This method fires the move event.
15685 * @param {Number} left The new left
15686 * @param {Number} top The new top
15687 * @returns {Roo.BoxComponent} this
15689 setPosition : function(x, y){
15692 if(!this.boxReady){
15695 var adj = this.adjustPosition(x, y);
15696 var ax = adj.x, ay = adj.y;
15698 var el = this.getPositionEl();
15699 if(ax !== undefined || ay !== undefined){
15700 if(ax !== undefined && ay !== undefined){
15701 el.setLeftTop(ax, ay);
15702 }else if(ax !== undefined){
15704 }else if(ay !== undefined){
15707 this.onPosition(ax, ay);
15708 this.fireEvent('move', this, ax, ay);
15714 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15715 * This method fires the move event.
15716 * @param {Number} x The new x position
15717 * @param {Number} y The new y position
15718 * @returns {Roo.BoxComponent} this
15720 setPagePosition : function(x, y){
15723 if(!this.boxReady){
15726 if(x === undefined || y === undefined){ // cannot translate undefined points
15729 var p = this.el.translatePoints(x, y);
15730 this.setPosition(p.left, p.top);
15735 onRender : function(ct, position){
15736 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15738 this.resizeEl = Roo.get(this.resizeEl);
15740 if(this.positionEl){
15741 this.positionEl = Roo.get(this.positionEl);
15746 afterRender : function(){
15747 Roo.BoxComponent.superclass.afterRender.call(this);
15748 this.boxReady = true;
15749 this.setSize(this.width, this.height);
15750 if(this.x || this.y){
15751 this.setPosition(this.x, this.y);
15753 if(this.pageX || this.pageY){
15754 this.setPagePosition(this.pageX, this.pageY);
15759 * Force the component's size to recalculate based on the underlying element's current height and width.
15760 * @returns {Roo.BoxComponent} this
15762 syncSize : function(){
15763 delete this.lastSize;
15764 this.setSize(this.el.getWidth(), this.el.getHeight());
15769 * Called after the component is resized, this method is empty by default but can be implemented by any
15770 * subclass that needs to perform custom logic after a resize occurs.
15771 * @param {Number} adjWidth The box-adjusted width that was set
15772 * @param {Number} adjHeight The box-adjusted height that was set
15773 * @param {Number} rawWidth The width that was originally specified
15774 * @param {Number} rawHeight The height that was originally specified
15776 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15781 * Called after the component is moved, this method is empty by default but can be implemented by any
15782 * subclass that needs to perform custom logic after a move occurs.
15783 * @param {Number} x The new x position
15784 * @param {Number} y The new y position
15786 onPosition : function(x, y){
15791 adjustSize : function(w, h){
15792 if(this.autoWidth){
15795 if(this.autoHeight){
15798 return {width : w, height: h};
15802 adjustPosition : function(x, y){
15803 return {x : x, y: y};
15806 * Original code for Roojs - LGPL
15807 * <script type="text/javascript">
15811 * @class Roo.XComponent
15812 * A delayed Element creator...
15813 * Or a way to group chunks of interface together.
15814 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15815 * used in conjunction with XComponent.build() it will create an instance of each element,
15816 * then call addxtype() to build the User interface.
15818 * Mypart.xyx = new Roo.XComponent({
15820 parent : 'Mypart.xyz', // empty == document.element.!!
15824 disabled : function() {}
15826 tree : function() { // return an tree of xtype declared components
15830 xtype : 'NestedLayoutPanel',
15837 * It can be used to build a big heiracy, with parent etc.
15838 * or you can just use this to render a single compoent to a dom element
15839 * MYPART.render(Roo.Element | String(id) | dom_element )
15846 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15847 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15849 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15851 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15852 * - if mulitple topModules exist, the last one is defined as the top module.
15856 * When the top level or multiple modules are to embedded into a existing HTML page,
15857 * the parent element can container '#id' of the element where the module will be drawn.
15861 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15862 * it relies more on a include mechanism, where sub modules are included into an outer page.
15863 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15865 * Bootstrap Roo Included elements
15867 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15868 * hence confusing the component builder as it thinks there are multiple top level elements.
15872 * @extends Roo.util.Observable
15874 * @param cfg {Object} configuration of component
15877 Roo.XComponent = function(cfg) {
15878 Roo.apply(this, cfg);
15882 * Fires when this the componnt is built
15883 * @param {Roo.XComponent} c the component
15888 this.region = this.region || 'center'; // default..
15889 Roo.XComponent.register(this);
15890 this.modules = false;
15891 this.el = false; // where the layout goes..
15895 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15898 * The created element (with Roo.factory())
15899 * @type {Roo.Layout}
15905 * for BC - use el in new code
15906 * @type {Roo.Layout}
15912 * for BC - use el in new code
15913 * @type {Roo.Layout}
15918 * @cfg {Function|boolean} disabled
15919 * If this module is disabled by some rule, return true from the funtion
15924 * @cfg {String} parent
15925 * Name of parent element which it get xtype added to..
15930 * @cfg {String} order
15931 * Used to set the order in which elements are created (usefull for multiple tabs)
15936 * @cfg {String} name
15937 * String to display while loading.
15941 * @cfg {String} region
15942 * Region to render component to (defaults to center)
15947 * @cfg {Array} items
15948 * A single item array - the first element is the root of the tree..
15949 * It's done this way to stay compatible with the Xtype system...
15955 * The method that retuns the tree of parts that make up this compoennt
15962 * render element to dom or tree
15963 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15966 render : function(el)
15970 var hp = this.parent ? 1 : 0;
15971 Roo.debug && Roo.log(this);
15973 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15974 // if parent is a '#.....' string, then let's use that..
15975 var ename = this.parent.substr(1);
15976 this.parent = false;
15977 Roo.debug && Roo.log(ename);
15979 case 'bootstrap-body' :
15980 if (typeof(Roo.bootstrap.Body) != 'undefined') {
15981 this.parent = { el : new Roo.bootstrap.Body() };
15982 Roo.debug && Roo.log("setting el to doc body");
15985 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15989 this.parent = { el : true};
15992 el = Roo.get(ename);
15997 if (!el && !this.parent) {
15998 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16002 Roo.debug && Roo.log("EL:");
16003 Roo.debug && Roo.log(el);
16004 Roo.debug && Roo.log("this.parent.el:");
16005 Roo.debug && Roo.log(this.parent.el);
16007 var tree = this._tree ? this._tree() : this.tree();
16009 // altertive root elements ??? - we need a better way to indicate these.
16010 var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16011 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16013 if (!this.parent && is_alt) {
16014 //el = Roo.get(document.body);
16015 this.parent = { el : true };
16020 if (!this.parent) {
16022 Roo.debug && Roo.log("no parent - creating one");
16024 el = el ? Roo.get(el) : false;
16026 // it's a top level one..
16028 el : new Roo.BorderLayout(el || document.body, {
16034 tabPosition: 'top',
16035 //resizeTabs: true,
16036 alwaysShowTabs: el && hp? false : true,
16037 hideTabs: el || !hp ? true : false,
16044 if (!this.parent.el) {
16045 // probably an old style ctor, which has been disabled.
16049 // The 'tree' method is '_tree now'
16051 tree.region = tree.region || this.region;
16053 if (this.parent.el === true) {
16054 // bootstrap... - body..
16055 this.parent.el = Roo.factory(tree);
16058 this.el = this.parent.el.addxtype(tree);
16059 this.fireEvent('built', this);
16061 this.panel = this.el;
16062 this.layout = this.panel.layout;
16063 this.parentLayout = this.parent.layout || false;
16069 Roo.apply(Roo.XComponent, {
16071 * @property hideProgress
16072 * true to disable the building progress bar.. usefull on single page renders.
16075 hideProgress : false,
16077 * @property buildCompleted
16078 * True when the builder has completed building the interface.
16081 buildCompleted : false,
16084 * @property topModule
16085 * the upper most module - uses document.element as it's constructor.
16092 * @property modules
16093 * array of modules to be created by registration system.
16094 * @type {Array} of Roo.XComponent
16099 * @property elmodules
16100 * array of modules to be created by which use #ID
16101 * @type {Array} of Roo.XComponent
16107 * @property build_from_html
16108 * Build elements from html - used by bootstrap HTML stuff
16109 * - this is cleared after build is completed
16110 * @type {boolean} true (default false)
16113 build_from_html : false,
16116 * Register components to be built later.
16118 * This solves the following issues
16119 * - Building is not done on page load, but after an authentication process has occured.
16120 * - Interface elements are registered on page load
16121 * - Parent Interface elements may not be loaded before child, so this handles that..
16128 module : 'Pman.Tab.projectMgr',
16130 parent : 'Pman.layout',
16131 disabled : false, // or use a function..
16134 * * @param {Object} details about module
16136 register : function(obj) {
16138 Roo.XComponent.event.fireEvent('register', obj);
16139 switch(typeof(obj.disabled) ) {
16145 if ( obj.disabled() ) {
16151 if (obj.disabled) {
16157 this.modules.push(obj);
16161 * convert a string to an object..
16162 * eg. 'AAA.BBB' -> finds AAA.BBB
16166 toObject : function(str)
16168 if (!str || typeof(str) == 'object') {
16171 if (str.substring(0,1) == '#') {
16175 var ar = str.split('.');
16180 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16182 throw "Module not found : " + str;
16186 throw "Module not found : " + str;
16188 Roo.each(ar, function(e) {
16189 if (typeof(o[e]) == 'undefined') {
16190 throw "Module not found : " + str;
16201 * move modules into their correct place in the tree..
16204 preBuild : function ()
16207 Roo.each(this.modules , function (obj)
16209 Roo.XComponent.event.fireEvent('beforebuild', obj);
16211 var opar = obj.parent;
16213 obj.parent = this.toObject(opar);
16215 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16220 Roo.debug && Roo.log("GOT top level module");
16221 Roo.debug && Roo.log(obj);
16222 obj.modules = new Roo.util.MixedCollection(false,
16223 function(o) { return o.order + '' }
16225 this.topModule = obj;
16228 // parent is a string (usually a dom element name..)
16229 if (typeof(obj.parent) == 'string') {
16230 this.elmodules.push(obj);
16233 if (obj.parent.constructor != Roo.XComponent) {
16234 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16236 if (!obj.parent.modules) {
16237 obj.parent.modules = new Roo.util.MixedCollection(false,
16238 function(o) { return o.order + '' }
16241 if (obj.parent.disabled) {
16242 obj.disabled = true;
16244 obj.parent.modules.add(obj);
16249 * make a list of modules to build.
16250 * @return {Array} list of modules.
16253 buildOrder : function()
16256 var cmp = function(a,b) {
16257 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16259 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16260 throw "No top level modules to build";
16263 // make a flat list in order of modules to build.
16264 var mods = this.topModule ? [ this.topModule ] : [];
16267 // elmodules (is a list of DOM based modules )
16268 Roo.each(this.elmodules, function(e) {
16270 if (!this.topModule &&
16271 typeof(e.parent) == 'string' &&
16272 e.parent.substring(0,1) == '#' &&
16273 Roo.get(e.parent.substr(1))
16276 _this.topModule = e;
16282 // add modules to their parents..
16283 var addMod = function(m) {
16284 Roo.debug && Roo.log("build Order: add: " + m.name);
16287 if (m.modules && !m.disabled) {
16288 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16289 m.modules.keySort('ASC', cmp );
16290 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16292 m.modules.each(addMod);
16294 Roo.debug && Roo.log("build Order: no child modules");
16296 // not sure if this is used any more..
16298 m.finalize.name = m.name + " (clean up) ";
16299 mods.push(m.finalize);
16303 if (this.topModule && this.topModule.modules) {
16304 this.topModule.modules.keySort('ASC', cmp );
16305 this.topModule.modules.each(addMod);
16311 * Build the registered modules.
16312 * @param {Object} parent element.
16313 * @param {Function} optional method to call after module has been added.
16317 build : function(opts)
16320 if (typeof(opts) != 'undefined') {
16321 Roo.apply(this,opts);
16325 var mods = this.buildOrder();
16327 //this.allmods = mods;
16328 //Roo.debug && Roo.log(mods);
16330 if (!mods.length) { // should not happen
16331 throw "NO modules!!!";
16335 var msg = "Building Interface...";
16336 // flash it up as modal - so we store the mask!?
16337 if (!this.hideProgress && Roo.MessageBox) {
16338 Roo.MessageBox.show({ title: 'loading' });
16339 Roo.MessageBox.show({
16340 title: "Please wait...",
16349 var total = mods.length;
16352 var progressRun = function() {
16353 if (!mods.length) {
16354 Roo.debug && Roo.log('hide?');
16355 if (!this.hideProgress && Roo.MessageBox) {
16356 Roo.MessageBox.hide();
16358 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16360 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16366 var m = mods.shift();
16369 Roo.debug && Roo.log(m);
16370 // not sure if this is supported any more.. - modules that are are just function
16371 if (typeof(m) == 'function') {
16373 return progressRun.defer(10, _this);
16377 msg = "Building Interface " + (total - mods.length) +
16379 (m.name ? (' - ' + m.name) : '');
16380 Roo.debug && Roo.log(msg);
16381 if (!this.hideProgress && Roo.MessageBox) {
16382 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16386 // is the module disabled?
16387 var disabled = (typeof(m.disabled) == 'function') ?
16388 m.disabled.call(m.module.disabled) : m.disabled;
16392 return progressRun(); // we do not update the display!
16400 // it's 10 on top level, and 1 on others??? why...
16401 return progressRun.defer(10, _this);
16404 progressRun.defer(1, _this);
16418 * wrapper for event.on - aliased later..
16419 * Typically use to register a event handler for register:
16421 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16430 Roo.XComponent.event = new Roo.util.Observable({
16434 * Fires when an Component is registered,
16435 * set the disable property on the Component to stop registration.
16436 * @param {Roo.XComponent} c the component being registerd.
16441 * @event beforebuild
16442 * Fires before each Component is built
16443 * can be used to apply permissions.
16444 * @param {Roo.XComponent} c the component being registerd.
16447 'beforebuild' : true,
16449 * @event buildcomplete
16450 * Fires on the top level element when all elements have been built
16451 * @param {Roo.XComponent} the top level component.
16453 'buildcomplete' : true
16458 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16461 * Ext JS Library 1.1.1
16462 * Copyright(c) 2006-2007, Ext JS, LLC.
16464 * Originally Released Under LGPL - original licence link has changed is not relivant.
16467 * <script type="text/javascript">
16473 * These classes are derivatives of the similarly named classes in the YUI Library.
16474 * The original license:
16475 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16476 * Code licensed under the BSD License:
16477 * http://developer.yahoo.net/yui/license.txt
16482 var Event=Roo.EventManager;
16483 var Dom=Roo.lib.Dom;
16486 * @class Roo.dd.DragDrop
16487 * @extends Roo.util.Observable
16488 * Defines the interface and base operation of items that that can be
16489 * dragged or can be drop targets. It was designed to be extended, overriding
16490 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16491 * Up to three html elements can be associated with a DragDrop instance:
16493 * <li>linked element: the element that is passed into the constructor.
16494 * This is the element which defines the boundaries for interaction with
16495 * other DragDrop objects.</li>
16496 * <li>handle element(s): The drag operation only occurs if the element that
16497 * was clicked matches a handle element. By default this is the linked
16498 * element, but there are times that you will want only a portion of the
16499 * linked element to initiate the drag operation, and the setHandleElId()
16500 * method provides a way to define this.</li>
16501 * <li>drag element: this represents the element that would be moved along
16502 * with the cursor during a drag operation. By default, this is the linked
16503 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16504 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16507 * This class should not be instantiated until the onload event to ensure that
16508 * the associated elements are available.
16509 * The following would define a DragDrop obj that would interact with any
16510 * other DragDrop obj in the "group1" group:
16512 * dd = new Roo.dd.DragDrop("div1", "group1");
16514 * Since none of the event handlers have been implemented, nothing would
16515 * actually happen if you were to run the code above. Normally you would
16516 * override this class or one of the default implementations, but you can
16517 * also override the methods you want on an instance of the class...
16519 * dd.onDragDrop = function(e, id) {
16520 * alert("dd was dropped on " + id);
16524 * @param {String} id of the element that is linked to this instance
16525 * @param {String} sGroup the group of related DragDrop objects
16526 * @param {object} config an object containing configurable attributes
16527 * Valid properties for DragDrop:
16528 * padding, isTarget, maintainOffset, primaryButtonOnly
16530 Roo.dd.DragDrop = function(id, sGroup, config) {
16532 this.init(id, sGroup, config);
16537 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16540 * The id of the element associated with this object. This is what we
16541 * refer to as the "linked element" because the size and position of
16542 * this element is used to determine when the drag and drop objects have
16550 * Configuration attributes passed into the constructor
16557 * The id of the element that will be dragged. By default this is same
16558 * as the linked element , but could be changed to another element. Ex:
16560 * @property dragElId
16567 * the id of the element that initiates the drag operation. By default
16568 * this is the linked element, but could be changed to be a child of this
16569 * element. This lets us do things like only starting the drag when the
16570 * header element within the linked html element is clicked.
16571 * @property handleElId
16578 * An associative array of HTML tags that will be ignored if clicked.
16579 * @property invalidHandleTypes
16580 * @type {string: string}
16582 invalidHandleTypes: null,
16585 * An associative array of ids for elements that will be ignored if clicked
16586 * @property invalidHandleIds
16587 * @type {string: string}
16589 invalidHandleIds: null,
16592 * An indexted array of css class names for elements that will be ignored
16594 * @property invalidHandleClasses
16597 invalidHandleClasses: null,
16600 * The linked element's absolute X position at the time the drag was
16602 * @property startPageX
16609 * The linked element's absolute X position at the time the drag was
16611 * @property startPageY
16618 * The group defines a logical collection of DragDrop objects that are
16619 * related. Instances only get events when interacting with other
16620 * DragDrop object in the same group. This lets us define multiple
16621 * groups using a single DragDrop subclass if we want.
16623 * @type {string: string}
16628 * Individual drag/drop instances can be locked. This will prevent
16629 * onmousedown start drag.
16637 * Lock this instance
16640 lock: function() { this.locked = true; },
16643 * Unlock this instace
16646 unlock: function() { this.locked = false; },
16649 * By default, all insances can be a drop target. This can be disabled by
16650 * setting isTarget to false.
16657 * The padding configured for this drag and drop object for calculating
16658 * the drop zone intersection with this object.
16665 * Cached reference to the linked element
16666 * @property _domRef
16672 * Internal typeof flag
16673 * @property __ygDragDrop
16676 __ygDragDrop: true,
16679 * Set to true when horizontal contraints are applied
16680 * @property constrainX
16687 * Set to true when vertical contraints are applied
16688 * @property constrainY
16695 * The left constraint
16703 * The right constraint
16711 * The up constraint
16720 * The down constraint
16728 * Maintain offsets when we resetconstraints. Set to true when you want
16729 * the position of the element relative to its parent to stay the same
16730 * when the page changes
16732 * @property maintainOffset
16735 maintainOffset: false,
16738 * Array of pixel locations the element will snap to if we specified a
16739 * horizontal graduation/interval. This array is generated automatically
16740 * when you define a tick interval.
16747 * Array of pixel locations the element will snap to if we specified a
16748 * vertical graduation/interval. This array is generated automatically
16749 * when you define a tick interval.
16756 * By default the drag and drop instance will only respond to the primary
16757 * button click (left button for a right-handed mouse). Set to true to
16758 * allow drag and drop to start with any mouse click that is propogated
16760 * @property primaryButtonOnly
16763 primaryButtonOnly: true,
16766 * The availabe property is false until the linked dom element is accessible.
16767 * @property available
16773 * By default, drags can only be initiated if the mousedown occurs in the
16774 * region the linked element is. This is done in part to work around a
16775 * bug in some browsers that mis-report the mousedown if the previous
16776 * mouseup happened outside of the window. This property is set to true
16777 * if outer handles are defined.
16779 * @property hasOuterHandles
16783 hasOuterHandles: false,
16786 * Code that executes immediately before the startDrag event
16787 * @method b4StartDrag
16790 b4StartDrag: function(x, y) { },
16793 * Abstract method called after a drag/drop object is clicked
16794 * and the drag or mousedown time thresholds have beeen met.
16795 * @method startDrag
16796 * @param {int} X click location
16797 * @param {int} Y click location
16799 startDrag: function(x, y) { /* override this */ },
16802 * Code that executes immediately before the onDrag event
16806 b4Drag: function(e) { },
16809 * Abstract method called during the onMouseMove event while dragging an
16812 * @param {Event} e the mousemove event
16814 onDrag: function(e) { /* override this */ },
16817 * Abstract method called when this element fist begins hovering over
16818 * another DragDrop obj
16819 * @method onDragEnter
16820 * @param {Event} e the mousemove event
16821 * @param {String|DragDrop[]} id In POINT mode, the element
16822 * id this is hovering over. In INTERSECT mode, an array of one or more
16823 * dragdrop items being hovered over.
16825 onDragEnter: function(e, id) { /* override this */ },
16828 * Code that executes immediately before the onDragOver event
16829 * @method b4DragOver
16832 b4DragOver: function(e) { },
16835 * Abstract method called when this element is hovering over another
16837 * @method onDragOver
16838 * @param {Event} e the mousemove event
16839 * @param {String|DragDrop[]} id In POINT mode, the element
16840 * id this is hovering over. In INTERSECT mode, an array of dd items
16841 * being hovered over.
16843 onDragOver: function(e, id) { /* override this */ },
16846 * Code that executes immediately before the onDragOut event
16847 * @method b4DragOut
16850 b4DragOut: function(e) { },
16853 * Abstract method called when we are no longer hovering over an element
16854 * @method onDragOut
16855 * @param {Event} e the mousemove event
16856 * @param {String|DragDrop[]} id In POINT mode, the element
16857 * id this was hovering over. In INTERSECT mode, an array of dd items
16858 * that the mouse is no longer over.
16860 onDragOut: function(e, id) { /* override this */ },
16863 * Code that executes immediately before the onDragDrop event
16864 * @method b4DragDrop
16867 b4DragDrop: function(e) { },
16870 * Abstract method called when this item is dropped on another DragDrop
16872 * @method onDragDrop
16873 * @param {Event} e the mouseup event
16874 * @param {String|DragDrop[]} id In POINT mode, the element
16875 * id this was dropped on. In INTERSECT mode, an array of dd items this
16878 onDragDrop: function(e, id) { /* override this */ },
16881 * Abstract method called when this item is dropped on an area with no
16883 * @method onInvalidDrop
16884 * @param {Event} e the mouseup event
16886 onInvalidDrop: function(e) { /* override this */ },
16889 * Code that executes immediately before the endDrag event
16890 * @method b4EndDrag
16893 b4EndDrag: function(e) { },
16896 * Fired when we are done dragging the object
16898 * @param {Event} e the mouseup event
16900 endDrag: function(e) { /* override this */ },
16903 * Code executed immediately before the onMouseDown event
16904 * @method b4MouseDown
16905 * @param {Event} e the mousedown event
16908 b4MouseDown: function(e) { },
16911 * Event handler that fires when a drag/drop obj gets a mousedown
16912 * @method onMouseDown
16913 * @param {Event} e the mousedown event
16915 onMouseDown: function(e) { /* override this */ },
16918 * Event handler that fires when a drag/drop obj gets a mouseup
16919 * @method onMouseUp
16920 * @param {Event} e the mouseup event
16922 onMouseUp: function(e) { /* override this */ },
16925 * Override the onAvailable method to do what is needed after the initial
16926 * position was determined.
16927 * @method onAvailable
16929 onAvailable: function () {
16933 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16936 defaultPadding : {left:0, right:0, top:0, bottom:0},
16939 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16943 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16944 { dragElId: "existingProxyDiv" });
16945 dd.startDrag = function(){
16946 this.constrainTo("parent-id");
16949 * Or you can initalize it using the {@link Roo.Element} object:
16951 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16952 startDrag : function(){
16953 this.constrainTo("parent-id");
16957 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16958 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16959 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16960 * an object containing the sides to pad. For example: {right:10, bottom:10}
16961 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16963 constrainTo : function(constrainTo, pad, inContent){
16964 if(typeof pad == "number"){
16965 pad = {left: pad, right:pad, top:pad, bottom:pad};
16967 pad = pad || this.defaultPadding;
16968 var b = Roo.get(this.getEl()).getBox();
16969 var ce = Roo.get(constrainTo);
16970 var s = ce.getScroll();
16971 var c, cd = ce.dom;
16972 if(cd == document.body){
16973 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16976 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16980 var topSpace = b.y - c.y;
16981 var leftSpace = b.x - c.x;
16983 this.resetConstraints();
16984 this.setXConstraint(leftSpace - (pad.left||0), // left
16985 c.width - leftSpace - b.width - (pad.right||0) //right
16987 this.setYConstraint(topSpace - (pad.top||0), //top
16988 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16993 * Returns a reference to the linked element
16995 * @return {HTMLElement} the html element
16997 getEl: function() {
16998 if (!this._domRef) {
16999 this._domRef = Roo.getDom(this.id);
17002 return this._domRef;
17006 * Returns a reference to the actual element to drag. By default this is
17007 * the same as the html element, but it can be assigned to another
17008 * element. An example of this can be found in Roo.dd.DDProxy
17009 * @method getDragEl
17010 * @return {HTMLElement} the html element
17012 getDragEl: function() {
17013 return Roo.getDom(this.dragElId);
17017 * Sets up the DragDrop object. Must be called in the constructor of any
17018 * Roo.dd.DragDrop subclass
17020 * @param id the id of the linked element
17021 * @param {String} sGroup the group of related items
17022 * @param {object} config configuration attributes
17024 init: function(id, sGroup, config) {
17025 this.initTarget(id, sGroup, config);
17026 if (!Roo.isTouch) {
17027 Event.on(this.id, "mousedown", this.handleMouseDown, this);
17029 Event.on(this.id, "touchstart", this.handleMouseDown, this);
17030 // Event.on(this.id, "selectstart", Event.preventDefault);
17034 * Initializes Targeting functionality only... the object does not
17035 * get a mousedown handler.
17036 * @method initTarget
17037 * @param id the id of the linked element
17038 * @param {String} sGroup the group of related items
17039 * @param {object} config configuration attributes
17041 initTarget: function(id, sGroup, config) {
17043 // configuration attributes
17044 this.config = config || {};
17046 // create a local reference to the drag and drop manager
17047 this.DDM = Roo.dd.DDM;
17048 // initialize the groups array
17051 // assume that we have an element reference instead of an id if the
17052 // parameter is not a string
17053 if (typeof id !== "string") {
17060 // add to an interaction group
17061 this.addToGroup((sGroup) ? sGroup : "default");
17063 // We don't want to register this as the handle with the manager
17064 // so we just set the id rather than calling the setter.
17065 this.handleElId = id;
17067 // the linked element is the element that gets dragged by default
17068 this.setDragElId(id);
17070 // by default, clicked anchors will not start drag operations.
17071 this.invalidHandleTypes = { A: "A" };
17072 this.invalidHandleIds = {};
17073 this.invalidHandleClasses = [];
17075 this.applyConfig();
17077 this.handleOnAvailable();
17081 * Applies the configuration parameters that were passed into the constructor.
17082 * This is supposed to happen at each level through the inheritance chain. So
17083 * a DDProxy implentation will execute apply config on DDProxy, DD, and
17084 * DragDrop in order to get all of the parameters that are available in
17086 * @method applyConfig
17088 applyConfig: function() {
17090 // configurable properties:
17091 // padding, isTarget, maintainOffset, primaryButtonOnly
17092 this.padding = this.config.padding || [0, 0, 0, 0];
17093 this.isTarget = (this.config.isTarget !== false);
17094 this.maintainOffset = (this.config.maintainOffset);
17095 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
17100 * Executed when the linked element is available
17101 * @method handleOnAvailable
17104 handleOnAvailable: function() {
17105 this.available = true;
17106 this.resetConstraints();
17107 this.onAvailable();
17111 * Configures the padding for the target zone in px. Effectively expands
17112 * (or reduces) the virtual object size for targeting calculations.
17113 * Supports css-style shorthand; if only one parameter is passed, all sides
17114 * will have that padding, and if only two are passed, the top and bottom
17115 * will have the first param, the left and right the second.
17116 * @method setPadding
17117 * @param {int} iTop Top pad
17118 * @param {int} iRight Right pad
17119 * @param {int} iBot Bot pad
17120 * @param {int} iLeft Left pad
17122 setPadding: function(iTop, iRight, iBot, iLeft) {
17123 // this.padding = [iLeft, iRight, iTop, iBot];
17124 if (!iRight && 0 !== iRight) {
17125 this.padding = [iTop, iTop, iTop, iTop];
17126 } else if (!iBot && 0 !== iBot) {
17127 this.padding = [iTop, iRight, iTop, iRight];
17129 this.padding = [iTop, iRight, iBot, iLeft];
17134 * Stores the initial placement of the linked element.
17135 * @method setInitialPosition
17136 * @param {int} diffX the X offset, default 0
17137 * @param {int} diffY the Y offset, default 0
17139 setInitPosition: function(diffX, diffY) {
17140 var el = this.getEl();
17142 if (!this.DDM.verifyEl(el)) {
17146 var dx = diffX || 0;
17147 var dy = diffY || 0;
17149 var p = Dom.getXY( el );
17151 this.initPageX = p[0] - dx;
17152 this.initPageY = p[1] - dy;
17154 this.lastPageX = p[0];
17155 this.lastPageY = p[1];
17158 this.setStartPosition(p);
17162 * Sets the start position of the element. This is set when the obj
17163 * is initialized, the reset when a drag is started.
17164 * @method setStartPosition
17165 * @param pos current position (from previous lookup)
17168 setStartPosition: function(pos) {
17169 var p = pos || Dom.getXY( this.getEl() );
17170 this.deltaSetXY = null;
17172 this.startPageX = p[0];
17173 this.startPageY = p[1];
17177 * Add this instance to a group of related drag/drop objects. All
17178 * instances belong to at least one group, and can belong to as many
17179 * groups as needed.
17180 * @method addToGroup
17181 * @param sGroup {string} the name of the group
17183 addToGroup: function(sGroup) {
17184 this.groups[sGroup] = true;
17185 this.DDM.regDragDrop(this, sGroup);
17189 * Remove's this instance from the supplied interaction group
17190 * @method removeFromGroup
17191 * @param {string} sGroup The group to drop
17193 removeFromGroup: function(sGroup) {
17194 if (this.groups[sGroup]) {
17195 delete this.groups[sGroup];
17198 this.DDM.removeDDFromGroup(this, sGroup);
17202 * Allows you to specify that an element other than the linked element
17203 * will be moved with the cursor during a drag
17204 * @method setDragElId
17205 * @param id {string} the id of the element that will be used to initiate the drag
17207 setDragElId: function(id) {
17208 this.dragElId = id;
17212 * Allows you to specify a child of the linked element that should be
17213 * used to initiate the drag operation. An example of this would be if
17214 * you have a content div with text and links. Clicking anywhere in the
17215 * content area would normally start the drag operation. Use this method
17216 * to specify that an element inside of the content div is the element
17217 * that starts the drag operation.
17218 * @method setHandleElId
17219 * @param id {string} the id of the element that will be used to
17220 * initiate the drag.
17222 setHandleElId: function(id) {
17223 if (typeof id !== "string") {
17226 this.handleElId = id;
17227 this.DDM.regHandle(this.id, id);
17231 * Allows you to set an element outside of the linked element as a drag
17233 * @method setOuterHandleElId
17234 * @param id the id of the element that will be used to initiate the drag
17236 setOuterHandleElId: function(id) {
17237 if (typeof id !== "string") {
17240 Event.on(id, "mousedown",
17241 this.handleMouseDown, this);
17242 this.setHandleElId(id);
17244 this.hasOuterHandles = true;
17248 * Remove all drag and drop hooks for this element
17251 unreg: function() {
17252 Event.un(this.id, "mousedown",
17253 this.handleMouseDown);
17254 Event.un(this.id, "touchstart",
17255 this.handleMouseDown);
17256 this._domRef = null;
17257 this.DDM._remove(this);
17260 destroy : function(){
17265 * Returns true if this instance is locked, or the drag drop mgr is locked
17266 * (meaning that all drag/drop is disabled on the page.)
17268 * @return {boolean} true if this obj or all drag/drop is locked, else
17271 isLocked: function() {
17272 return (this.DDM.isLocked() || this.locked);
17276 * Fired when this object is clicked
17277 * @method handleMouseDown
17279 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17282 handleMouseDown: function(e, oDD){
17284 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17285 //Roo.log('not touch/ button !=0');
17288 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17289 return; // double touch..
17293 if (this.isLocked()) {
17294 //Roo.log('locked');
17298 this.DDM.refreshCache(this.groups);
17299 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17300 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17301 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17302 //Roo.log('no outer handes or not over target');
17305 // Roo.log('check validator');
17306 if (this.clickValidator(e)) {
17307 // Roo.log('validate success');
17308 // set the initial element position
17309 this.setStartPosition();
17312 this.b4MouseDown(e);
17313 this.onMouseDown(e);
17315 this.DDM.handleMouseDown(e, this);
17317 this.DDM.stopEvent(e);
17325 clickValidator: function(e) {
17326 var target = e.getTarget();
17327 return ( this.isValidHandleChild(target) &&
17328 (this.id == this.handleElId ||
17329 this.DDM.handleWasClicked(target, this.id)) );
17333 * Allows you to specify a tag name that should not start a drag operation
17334 * when clicked. This is designed to facilitate embedding links within a
17335 * drag handle that do something other than start the drag.
17336 * @method addInvalidHandleType
17337 * @param {string} tagName the type of element to exclude
17339 addInvalidHandleType: function(tagName) {
17340 var type = tagName.toUpperCase();
17341 this.invalidHandleTypes[type] = type;
17345 * Lets you to specify an element id for a child of a drag handle
17346 * that should not initiate a drag
17347 * @method addInvalidHandleId
17348 * @param {string} id the element id of the element you wish to ignore
17350 addInvalidHandleId: function(id) {
17351 if (typeof id !== "string") {
17354 this.invalidHandleIds[id] = id;
17358 * Lets you specify a css class of elements that will not initiate a drag
17359 * @method addInvalidHandleClass
17360 * @param {string} cssClass the class of the elements you wish to ignore
17362 addInvalidHandleClass: function(cssClass) {
17363 this.invalidHandleClasses.push(cssClass);
17367 * Unsets an excluded tag name set by addInvalidHandleType
17368 * @method removeInvalidHandleType
17369 * @param {string} tagName the type of element to unexclude
17371 removeInvalidHandleType: function(tagName) {
17372 var type = tagName.toUpperCase();
17373 // this.invalidHandleTypes[type] = null;
17374 delete this.invalidHandleTypes[type];
17378 * Unsets an invalid handle id
17379 * @method removeInvalidHandleId
17380 * @param {string} id the id of the element to re-enable
17382 removeInvalidHandleId: function(id) {
17383 if (typeof id !== "string") {
17386 delete this.invalidHandleIds[id];
17390 * Unsets an invalid css class
17391 * @method removeInvalidHandleClass
17392 * @param {string} cssClass the class of the element(s) you wish to
17395 removeInvalidHandleClass: function(cssClass) {
17396 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17397 if (this.invalidHandleClasses[i] == cssClass) {
17398 delete this.invalidHandleClasses[i];
17404 * Checks the tag exclusion list to see if this click should be ignored
17405 * @method isValidHandleChild
17406 * @param {HTMLElement} node the HTMLElement to evaluate
17407 * @return {boolean} true if this is a valid tag type, false if not
17409 isValidHandleChild: function(node) {
17412 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17415 nodeName = node.nodeName.toUpperCase();
17417 nodeName = node.nodeName;
17419 valid = valid && !this.invalidHandleTypes[nodeName];
17420 valid = valid && !this.invalidHandleIds[node.id];
17422 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17423 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17432 * Create the array of horizontal tick marks if an interval was specified
17433 * in setXConstraint().
17434 * @method setXTicks
17437 setXTicks: function(iStartX, iTickSize) {
17439 this.xTickSize = iTickSize;
17443 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17445 this.xTicks[this.xTicks.length] = i;
17450 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17452 this.xTicks[this.xTicks.length] = i;
17457 this.xTicks.sort(this.DDM.numericSort) ;
17461 * Create the array of vertical tick marks if an interval was specified in
17462 * setYConstraint().
17463 * @method setYTicks
17466 setYTicks: function(iStartY, iTickSize) {
17468 this.yTickSize = iTickSize;
17472 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17474 this.yTicks[this.yTicks.length] = i;
17479 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17481 this.yTicks[this.yTicks.length] = i;
17486 this.yTicks.sort(this.DDM.numericSort) ;
17490 * By default, the element can be dragged any place on the screen. Use
17491 * this method to limit the horizontal travel of the element. Pass in
17492 * 0,0 for the parameters if you want to lock the drag to the y axis.
17493 * @method setXConstraint
17494 * @param {int} iLeft the number of pixels the element can move to the left
17495 * @param {int} iRight the number of pixels the element can move to the
17497 * @param {int} iTickSize optional parameter for specifying that the
17499 * should move iTickSize pixels at a time.
17501 setXConstraint: function(iLeft, iRight, iTickSize) {
17502 this.leftConstraint = iLeft;
17503 this.rightConstraint = iRight;
17505 this.minX = this.initPageX - iLeft;
17506 this.maxX = this.initPageX + iRight;
17507 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17509 this.constrainX = true;
17513 * Clears any constraints applied to this instance. Also clears ticks
17514 * since they can't exist independent of a constraint at this time.
17515 * @method clearConstraints
17517 clearConstraints: function() {
17518 this.constrainX = false;
17519 this.constrainY = false;
17524 * Clears any tick interval defined for this instance
17525 * @method clearTicks
17527 clearTicks: function() {
17528 this.xTicks = null;
17529 this.yTicks = null;
17530 this.xTickSize = 0;
17531 this.yTickSize = 0;
17535 * By default, the element can be dragged any place on the screen. Set
17536 * this to limit the vertical travel of the element. Pass in 0,0 for the
17537 * parameters if you want to lock the drag to the x axis.
17538 * @method setYConstraint
17539 * @param {int} iUp the number of pixels the element can move up
17540 * @param {int} iDown the number of pixels the element can move down
17541 * @param {int} iTickSize optional parameter for specifying that the
17542 * element should move iTickSize pixels at a time.
17544 setYConstraint: function(iUp, iDown, iTickSize) {
17545 this.topConstraint = iUp;
17546 this.bottomConstraint = iDown;
17548 this.minY = this.initPageY - iUp;
17549 this.maxY = this.initPageY + iDown;
17550 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17552 this.constrainY = true;
17557 * resetConstraints must be called if you manually reposition a dd element.
17558 * @method resetConstraints
17559 * @param {boolean} maintainOffset
17561 resetConstraints: function() {
17564 // Maintain offsets if necessary
17565 if (this.initPageX || this.initPageX === 0) {
17566 // figure out how much this thing has moved
17567 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17568 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17570 this.setInitPosition(dx, dy);
17572 // This is the first time we have detected the element's position
17574 this.setInitPosition();
17577 if (this.constrainX) {
17578 this.setXConstraint( this.leftConstraint,
17579 this.rightConstraint,
17583 if (this.constrainY) {
17584 this.setYConstraint( this.topConstraint,
17585 this.bottomConstraint,
17591 * Normally the drag element is moved pixel by pixel, but we can specify
17592 * that it move a number of pixels at a time. This method resolves the
17593 * location when we have it set up like this.
17595 * @param {int} val where we want to place the object
17596 * @param {int[]} tickArray sorted array of valid points
17597 * @return {int} the closest tick
17600 getTick: function(val, tickArray) {
17603 // If tick interval is not defined, it is effectively 1 pixel,
17604 // so we return the value passed to us.
17606 } else if (tickArray[0] >= val) {
17607 // The value is lower than the first tick, so we return the first
17609 return tickArray[0];
17611 for (var i=0, len=tickArray.length; i<len; ++i) {
17613 if (tickArray[next] && tickArray[next] >= val) {
17614 var diff1 = val - tickArray[i];
17615 var diff2 = tickArray[next] - val;
17616 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17620 // The value is larger than the last tick, so we return the last
17622 return tickArray[tickArray.length - 1];
17629 * @return {string} string representation of the dd obj
17631 toString: function() {
17632 return ("DragDrop " + this.id);
17640 * Ext JS Library 1.1.1
17641 * Copyright(c) 2006-2007, Ext JS, LLC.
17643 * Originally Released Under LGPL - original licence link has changed is not relivant.
17646 * <script type="text/javascript">
17651 * The drag and drop utility provides a framework for building drag and drop
17652 * applications. In addition to enabling drag and drop for specific elements,
17653 * the drag and drop elements are tracked by the manager class, and the
17654 * interactions between the various elements are tracked during the drag and
17655 * the implementing code is notified about these important moments.
17658 // Only load the library once. Rewriting the manager class would orphan
17659 // existing drag and drop instances.
17660 if (!Roo.dd.DragDropMgr) {
17663 * @class Roo.dd.DragDropMgr
17664 * DragDropMgr is a singleton that tracks the element interaction for
17665 * all DragDrop items in the window. Generally, you will not call
17666 * this class directly, but it does have helper methods that could
17667 * be useful in your DragDrop implementations.
17670 Roo.dd.DragDropMgr = function() {
17672 var Event = Roo.EventManager;
17677 * Two dimensional Array of registered DragDrop objects. The first
17678 * dimension is the DragDrop item group, the second the DragDrop
17681 * @type {string: string}
17688 * Array of element ids defined as drag handles. Used to determine
17689 * if the element that generated the mousedown event is actually the
17690 * handle and not the html element itself.
17691 * @property handleIds
17692 * @type {string: string}
17699 * the DragDrop object that is currently being dragged
17700 * @property dragCurrent
17708 * the DragDrop object(s) that are being hovered over
17709 * @property dragOvers
17717 * the X distance between the cursor and the object being dragged
17726 * the Y distance between the cursor and the object being dragged
17735 * Flag to determine if we should prevent the default behavior of the
17736 * events we define. By default this is true, but this can be set to
17737 * false if you need the default behavior (not recommended)
17738 * @property preventDefault
17742 preventDefault: true,
17745 * Flag to determine if we should stop the propagation of the events
17746 * we generate. This is true by default but you may want to set it to
17747 * false if the html element contains other features that require the
17749 * @property stopPropagation
17753 stopPropagation: true,
17756 * Internal flag that is set to true when drag and drop has been
17758 * @property initialized
17765 * All drag and drop can be disabled.
17773 * Called the first time an element is registered.
17779 this.initialized = true;
17783 * In point mode, drag and drop interaction is defined by the
17784 * location of the cursor during the drag/drop
17792 * In intersect mode, drag and drop interactio nis defined by the
17793 * overlap of two or more drag and drop objects.
17794 * @property INTERSECT
17801 * The current drag and drop mode. Default: POINT
17809 * Runs method on all drag and drop objects
17810 * @method _execOnAll
17814 _execOnAll: function(sMethod, args) {
17815 for (var i in this.ids) {
17816 for (var j in this.ids[i]) {
17817 var oDD = this.ids[i][j];
17818 if (! this.isTypeOfDD(oDD)) {
17821 oDD[sMethod].apply(oDD, args);
17827 * Drag and drop initialization. Sets up the global event handlers
17832 _onLoad: function() {
17836 if (!Roo.isTouch) {
17837 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17838 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17840 Event.on(document, "touchend", this.handleMouseUp, this, true);
17841 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17843 Event.on(window, "unload", this._onUnload, this, true);
17844 Event.on(window, "resize", this._onResize, this, true);
17845 // Event.on(window, "mouseout", this._test);
17850 * Reset constraints on all drag and drop objs
17851 * @method _onResize
17855 _onResize: function(e) {
17856 this._execOnAll("resetConstraints", []);
17860 * Lock all drag and drop functionality
17864 lock: function() { this.locked = true; },
17867 * Unlock all drag and drop functionality
17871 unlock: function() { this.locked = false; },
17874 * Is drag and drop locked?
17876 * @return {boolean} True if drag and drop is locked, false otherwise.
17879 isLocked: function() { return this.locked; },
17882 * Location cache that is set for all drag drop objects when a drag is
17883 * initiated, cleared when the drag is finished.
17884 * @property locationCache
17891 * Set useCache to false if you want to force object the lookup of each
17892 * drag and drop linked element constantly during a drag.
17893 * @property useCache
17900 * The number of pixels that the mouse needs to move after the
17901 * mousedown before the drag is initiated. Default=3;
17902 * @property clickPixelThresh
17906 clickPixelThresh: 3,
17909 * The number of milliseconds after the mousedown event to initiate the
17910 * drag if we don't get a mouseup event. Default=1000
17911 * @property clickTimeThresh
17915 clickTimeThresh: 350,
17918 * Flag that indicates that either the drag pixel threshold or the
17919 * mousdown time threshold has been met
17920 * @property dragThreshMet
17925 dragThreshMet: false,
17928 * Timeout used for the click time threshold
17929 * @property clickTimeout
17934 clickTimeout: null,
17937 * The X position of the mousedown event stored for later use when a
17938 * drag threshold is met.
17947 * The Y position of the mousedown event stored for later use when a
17948 * drag threshold is met.
17957 * Each DragDrop instance must be registered with the DragDropMgr.
17958 * This is executed in DragDrop.init()
17959 * @method regDragDrop
17960 * @param {DragDrop} oDD the DragDrop object to register
17961 * @param {String} sGroup the name of the group this element belongs to
17964 regDragDrop: function(oDD, sGroup) {
17965 if (!this.initialized) { this.init(); }
17967 if (!this.ids[sGroup]) {
17968 this.ids[sGroup] = {};
17970 this.ids[sGroup][oDD.id] = oDD;
17974 * Removes the supplied dd instance from the supplied group. Executed
17975 * by DragDrop.removeFromGroup, so don't call this function directly.
17976 * @method removeDDFromGroup
17980 removeDDFromGroup: function(oDD, sGroup) {
17981 if (!this.ids[sGroup]) {
17982 this.ids[sGroup] = {};
17985 var obj = this.ids[sGroup];
17986 if (obj && obj[oDD.id]) {
17987 delete obj[oDD.id];
17992 * Unregisters a drag and drop item. This is executed in
17993 * DragDrop.unreg, use that method instead of calling this directly.
17998 _remove: function(oDD) {
17999 for (var g in oDD.groups) {
18000 if (g && this.ids[g][oDD.id]) {
18001 delete this.ids[g][oDD.id];
18004 delete this.handleIds[oDD.id];
18008 * Each DragDrop handle element must be registered. This is done
18009 * automatically when executing DragDrop.setHandleElId()
18010 * @method regHandle
18011 * @param {String} sDDId the DragDrop id this element is a handle for
18012 * @param {String} sHandleId the id of the element that is the drag
18016 regHandle: function(sDDId, sHandleId) {
18017 if (!this.handleIds[sDDId]) {
18018 this.handleIds[sDDId] = {};
18020 this.handleIds[sDDId][sHandleId] = sHandleId;
18024 * Utility function to determine if a given element has been
18025 * registered as a drag drop item.
18026 * @method isDragDrop
18027 * @param {String} id the element id to check
18028 * @return {boolean} true if this element is a DragDrop item,
18032 isDragDrop: function(id) {
18033 return ( this.getDDById(id) ) ? true : false;
18037 * Returns the drag and drop instances that are in all groups the
18038 * passed in instance belongs to.
18039 * @method getRelated
18040 * @param {DragDrop} p_oDD the obj to get related data for
18041 * @param {boolean} bTargetsOnly if true, only return targetable objs
18042 * @return {DragDrop[]} the related instances
18045 getRelated: function(p_oDD, bTargetsOnly) {
18047 for (var i in p_oDD.groups) {
18048 for (j in this.ids[i]) {
18049 var dd = this.ids[i][j];
18050 if (! this.isTypeOfDD(dd)) {
18053 if (!bTargetsOnly || dd.isTarget) {
18054 oDDs[oDDs.length] = dd;
18063 * Returns true if the specified dd target is a legal target for
18064 * the specifice drag obj
18065 * @method isLegalTarget
18066 * @param {DragDrop} the drag obj
18067 * @param {DragDrop} the target
18068 * @return {boolean} true if the target is a legal target for the
18072 isLegalTarget: function (oDD, oTargetDD) {
18073 var targets = this.getRelated(oDD, true);
18074 for (var i=0, len=targets.length;i<len;++i) {
18075 if (targets[i].id == oTargetDD.id) {
18084 * My goal is to be able to transparently determine if an object is
18085 * typeof DragDrop, and the exact subclass of DragDrop. typeof
18086 * returns "object", oDD.constructor.toString() always returns
18087 * "DragDrop" and not the name of the subclass. So for now it just
18088 * evaluates a well-known variable in DragDrop.
18089 * @method isTypeOfDD
18090 * @param {Object} the object to evaluate
18091 * @return {boolean} true if typeof oDD = DragDrop
18094 isTypeOfDD: function (oDD) {
18095 return (oDD && oDD.__ygDragDrop);
18099 * Utility function to determine if a given element has been
18100 * registered as a drag drop handle for the given Drag Drop object.
18102 * @param {String} id the element id to check
18103 * @return {boolean} true if this element is a DragDrop handle, false
18107 isHandle: function(sDDId, sHandleId) {
18108 return ( this.handleIds[sDDId] &&
18109 this.handleIds[sDDId][sHandleId] );
18113 * Returns the DragDrop instance for a given id
18114 * @method getDDById
18115 * @param {String} id the id of the DragDrop object
18116 * @return {DragDrop} the drag drop object, null if it is not found
18119 getDDById: function(id) {
18120 for (var i in this.ids) {
18121 if (this.ids[i][id]) {
18122 return this.ids[i][id];
18129 * Fired after a registered DragDrop object gets the mousedown event.
18130 * Sets up the events required to track the object being dragged
18131 * @method handleMouseDown
18132 * @param {Event} e the event
18133 * @param oDD the DragDrop object being dragged
18137 handleMouseDown: function(e, oDD) {
18139 Roo.QuickTips.disable();
18141 this.currentTarget = e.getTarget();
18143 this.dragCurrent = oDD;
18145 var el = oDD.getEl();
18147 // track start position
18148 this.startX = e.getPageX();
18149 this.startY = e.getPageY();
18151 this.deltaX = this.startX - el.offsetLeft;
18152 this.deltaY = this.startY - el.offsetTop;
18154 this.dragThreshMet = false;
18156 this.clickTimeout = setTimeout(
18158 var DDM = Roo.dd.DDM;
18159 DDM.startDrag(DDM.startX, DDM.startY);
18161 this.clickTimeThresh );
18165 * Fired when either the drag pixel threshol or the mousedown hold
18166 * time threshold has been met.
18167 * @method startDrag
18168 * @param x {int} the X position of the original mousedown
18169 * @param y {int} the Y position of the original mousedown
18172 startDrag: function(x, y) {
18173 clearTimeout(this.clickTimeout);
18174 if (this.dragCurrent) {
18175 this.dragCurrent.b4StartDrag(x, y);
18176 this.dragCurrent.startDrag(x, y);
18178 this.dragThreshMet = true;
18182 * Internal function to handle the mouseup event. Will be invoked
18183 * from the context of the document.
18184 * @method handleMouseUp
18185 * @param {Event} e the event
18189 handleMouseUp: function(e) {
18192 Roo.QuickTips.enable();
18194 if (! this.dragCurrent) {
18198 clearTimeout(this.clickTimeout);
18200 if (this.dragThreshMet) {
18201 this.fireEvents(e, true);
18211 * Utility to stop event propagation and event default, if these
18212 * features are turned on.
18213 * @method stopEvent
18214 * @param {Event} e the event as returned by this.getEvent()
18217 stopEvent: function(e){
18218 if(this.stopPropagation) {
18219 e.stopPropagation();
18222 if (this.preventDefault) {
18223 e.preventDefault();
18228 * Internal function to clean up event handlers after the drag
18229 * operation is complete
18231 * @param {Event} e the event
18235 stopDrag: function(e) {
18236 // Fire the drag end event for the item that was dragged
18237 if (this.dragCurrent) {
18238 if (this.dragThreshMet) {
18239 this.dragCurrent.b4EndDrag(e);
18240 this.dragCurrent.endDrag(e);
18243 this.dragCurrent.onMouseUp(e);
18246 this.dragCurrent = null;
18247 this.dragOvers = {};
18251 * Internal function to handle the mousemove event. Will be invoked
18252 * from the context of the html element.
18254 * @TODO figure out what we can do about mouse events lost when the
18255 * user drags objects beyond the window boundary. Currently we can
18256 * detect this in internet explorer by verifying that the mouse is
18257 * down during the mousemove event. Firefox doesn't give us the
18258 * button state on the mousemove event.
18259 * @method handleMouseMove
18260 * @param {Event} e the event
18264 handleMouseMove: function(e) {
18265 if (! this.dragCurrent) {
18269 // var button = e.which || e.button;
18271 // check for IE mouseup outside of page boundary
18272 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18274 return this.handleMouseUp(e);
18277 if (!this.dragThreshMet) {
18278 var diffX = Math.abs(this.startX - e.getPageX());
18279 var diffY = Math.abs(this.startY - e.getPageY());
18280 if (diffX > this.clickPixelThresh ||
18281 diffY > this.clickPixelThresh) {
18282 this.startDrag(this.startX, this.startY);
18286 if (this.dragThreshMet) {
18287 this.dragCurrent.b4Drag(e);
18288 this.dragCurrent.onDrag(e);
18289 if(!this.dragCurrent.moveOnly){
18290 this.fireEvents(e, false);
18300 * Iterates over all of the DragDrop elements to find ones we are
18301 * hovering over or dropping on
18302 * @method fireEvents
18303 * @param {Event} e the event
18304 * @param {boolean} isDrop is this a drop op or a mouseover op?
18308 fireEvents: function(e, isDrop) {
18309 var dc = this.dragCurrent;
18311 // If the user did the mouse up outside of the window, we could
18312 // get here even though we have ended the drag.
18313 if (!dc || dc.isLocked()) {
18317 var pt = e.getPoint();
18319 // cache the previous dragOver array
18325 var enterEvts = [];
18327 // Check to see if the object(s) we were hovering over is no longer
18328 // being hovered over so we can fire the onDragOut event
18329 for (var i in this.dragOvers) {
18331 var ddo = this.dragOvers[i];
18333 if (! this.isTypeOfDD(ddo)) {
18337 if (! this.isOverTarget(pt, ddo, this.mode)) {
18338 outEvts.push( ddo );
18341 oldOvers[i] = true;
18342 delete this.dragOvers[i];
18345 for (var sGroup in dc.groups) {
18347 if ("string" != typeof sGroup) {
18351 for (i in this.ids[sGroup]) {
18352 var oDD = this.ids[sGroup][i];
18353 if (! this.isTypeOfDD(oDD)) {
18357 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18358 if (this.isOverTarget(pt, oDD, this.mode)) {
18359 // look for drop interactions
18361 dropEvts.push( oDD );
18362 // look for drag enter and drag over interactions
18365 // initial drag over: dragEnter fires
18366 if (!oldOvers[oDD.id]) {
18367 enterEvts.push( oDD );
18368 // subsequent drag overs: dragOver fires
18370 overEvts.push( oDD );
18373 this.dragOvers[oDD.id] = oDD;
18381 if (outEvts.length) {
18382 dc.b4DragOut(e, outEvts);
18383 dc.onDragOut(e, outEvts);
18386 if (enterEvts.length) {
18387 dc.onDragEnter(e, enterEvts);
18390 if (overEvts.length) {
18391 dc.b4DragOver(e, overEvts);
18392 dc.onDragOver(e, overEvts);
18395 if (dropEvts.length) {
18396 dc.b4DragDrop(e, dropEvts);
18397 dc.onDragDrop(e, dropEvts);
18401 // fire dragout events
18403 for (i=0, len=outEvts.length; i<len; ++i) {
18404 dc.b4DragOut(e, outEvts[i].id);
18405 dc.onDragOut(e, outEvts[i].id);
18408 // fire enter events
18409 for (i=0,len=enterEvts.length; i<len; ++i) {
18410 // dc.b4DragEnter(e, oDD.id);
18411 dc.onDragEnter(e, enterEvts[i].id);
18414 // fire over events
18415 for (i=0,len=overEvts.length; i<len; ++i) {
18416 dc.b4DragOver(e, overEvts[i].id);
18417 dc.onDragOver(e, overEvts[i].id);
18420 // fire drop events
18421 for (i=0, len=dropEvts.length; i<len; ++i) {
18422 dc.b4DragDrop(e, dropEvts[i].id);
18423 dc.onDragDrop(e, dropEvts[i].id);
18428 // notify about a drop that did not find a target
18429 if (isDrop && !dropEvts.length) {
18430 dc.onInvalidDrop(e);
18436 * Helper function for getting the best match from the list of drag
18437 * and drop objects returned by the drag and drop events when we are
18438 * in INTERSECT mode. It returns either the first object that the
18439 * cursor is over, or the object that has the greatest overlap with
18440 * the dragged element.
18441 * @method getBestMatch
18442 * @param {DragDrop[]} dds The array of drag and drop objects
18444 * @return {DragDrop} The best single match
18447 getBestMatch: function(dds) {
18449 // Return null if the input is not what we expect
18450 //if (!dds || !dds.length || dds.length == 0) {
18452 // If there is only one item, it wins
18453 //} else if (dds.length == 1) {
18455 var len = dds.length;
18460 // Loop through the targeted items
18461 for (var i=0; i<len; ++i) {
18463 // If the cursor is over the object, it wins. If the
18464 // cursor is over multiple matches, the first one we come
18466 if (dd.cursorIsOver) {
18469 // Otherwise the object with the most overlap wins
18472 winner.overlap.getArea() < dd.overlap.getArea()) {
18483 * Refreshes the cache of the top-left and bottom-right points of the
18484 * drag and drop objects in the specified group(s). This is in the
18485 * format that is stored in the drag and drop instance, so typical
18488 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18492 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18494 * @TODO this really should be an indexed array. Alternatively this
18495 * method could accept both.
18496 * @method refreshCache
18497 * @param {Object} groups an associative array of groups to refresh
18500 refreshCache: function(groups) {
18501 for (var sGroup in groups) {
18502 if ("string" != typeof sGroup) {
18505 for (var i in this.ids[sGroup]) {
18506 var oDD = this.ids[sGroup][i];
18508 if (this.isTypeOfDD(oDD)) {
18509 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18510 var loc = this.getLocation(oDD);
18512 this.locationCache[oDD.id] = loc;
18514 delete this.locationCache[oDD.id];
18515 // this will unregister the drag and drop object if
18516 // the element is not in a usable state
18525 * This checks to make sure an element exists and is in the DOM. The
18526 * main purpose is to handle cases where innerHTML is used to remove
18527 * drag and drop objects from the DOM. IE provides an 'unspecified
18528 * error' when trying to access the offsetParent of such an element
18530 * @param {HTMLElement} el the element to check
18531 * @return {boolean} true if the element looks usable
18534 verifyEl: function(el) {
18539 parent = el.offsetParent;
18542 parent = el.offsetParent;
18553 * Returns a Region object containing the drag and drop element's position
18554 * and size, including the padding configured for it
18555 * @method getLocation
18556 * @param {DragDrop} oDD the drag and drop object to get the
18558 * @return {Roo.lib.Region} a Region object representing the total area
18559 * the element occupies, including any padding
18560 * the instance is configured for.
18563 getLocation: function(oDD) {
18564 if (! this.isTypeOfDD(oDD)) {
18568 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18571 pos= Roo.lib.Dom.getXY(el);
18579 x2 = x1 + el.offsetWidth;
18581 y2 = y1 + el.offsetHeight;
18583 t = y1 - oDD.padding[0];
18584 r = x2 + oDD.padding[1];
18585 b = y2 + oDD.padding[2];
18586 l = x1 - oDD.padding[3];
18588 return new Roo.lib.Region( t, r, b, l );
18592 * Checks the cursor location to see if it over the target
18593 * @method isOverTarget
18594 * @param {Roo.lib.Point} pt The point to evaluate
18595 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18596 * @return {boolean} true if the mouse is over the target
18600 isOverTarget: function(pt, oTarget, intersect) {
18601 // use cache if available
18602 var loc = this.locationCache[oTarget.id];
18603 if (!loc || !this.useCache) {
18604 loc = this.getLocation(oTarget);
18605 this.locationCache[oTarget.id] = loc;
18613 oTarget.cursorIsOver = loc.contains( pt );
18615 // DragDrop is using this as a sanity check for the initial mousedown
18616 // in this case we are done. In POINT mode, if the drag obj has no
18617 // contraints, we are also done. Otherwise we need to evaluate the
18618 // location of the target as related to the actual location of the
18619 // dragged element.
18620 var dc = this.dragCurrent;
18621 if (!dc || !dc.getTargetCoord ||
18622 (!intersect && !dc.constrainX && !dc.constrainY)) {
18623 return oTarget.cursorIsOver;
18626 oTarget.overlap = null;
18628 // Get the current location of the drag element, this is the
18629 // location of the mouse event less the delta that represents
18630 // where the original mousedown happened on the element. We
18631 // need to consider constraints and ticks as well.
18632 var pos = dc.getTargetCoord(pt.x, pt.y);
18634 var el = dc.getDragEl();
18635 var curRegion = new Roo.lib.Region( pos.y,
18636 pos.x + el.offsetWidth,
18637 pos.y + el.offsetHeight,
18640 var overlap = curRegion.intersect(loc);
18643 oTarget.overlap = overlap;
18644 return (intersect) ? true : oTarget.cursorIsOver;
18651 * unload event handler
18652 * @method _onUnload
18656 _onUnload: function(e, me) {
18657 Roo.dd.DragDropMgr.unregAll();
18661 * Cleans up the drag and drop events and objects.
18666 unregAll: function() {
18668 if (this.dragCurrent) {
18670 this.dragCurrent = null;
18673 this._execOnAll("unreg", []);
18675 for (i in this.elementCache) {
18676 delete this.elementCache[i];
18679 this.elementCache = {};
18684 * A cache of DOM elements
18685 * @property elementCache
18692 * Get the wrapper for the DOM element specified
18693 * @method getElWrapper
18694 * @param {String} id the id of the element to get
18695 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18697 * @deprecated This wrapper isn't that useful
18700 getElWrapper: function(id) {
18701 var oWrapper = this.elementCache[id];
18702 if (!oWrapper || !oWrapper.el) {
18703 oWrapper = this.elementCache[id] =
18704 new this.ElementWrapper(Roo.getDom(id));
18710 * Returns the actual DOM element
18711 * @method getElement
18712 * @param {String} id the id of the elment to get
18713 * @return {Object} The element
18714 * @deprecated use Roo.getDom instead
18717 getElement: function(id) {
18718 return Roo.getDom(id);
18722 * Returns the style property for the DOM element (i.e.,
18723 * document.getElById(id).style)
18725 * @param {String} id the id of the elment to get
18726 * @return {Object} The style property of the element
18727 * @deprecated use Roo.getDom instead
18730 getCss: function(id) {
18731 var el = Roo.getDom(id);
18732 return (el) ? el.style : null;
18736 * Inner class for cached elements
18737 * @class DragDropMgr.ElementWrapper
18742 ElementWrapper: function(el) {
18747 this.el = el || null;
18752 this.id = this.el && el.id;
18754 * A reference to the style property
18757 this.css = this.el && el.style;
18761 * Returns the X position of an html element
18763 * @param el the element for which to get the position
18764 * @return {int} the X coordinate
18766 * @deprecated use Roo.lib.Dom.getX instead
18769 getPosX: function(el) {
18770 return Roo.lib.Dom.getX(el);
18774 * Returns the Y position of an html element
18776 * @param el the element for which to get the position
18777 * @return {int} the Y coordinate
18778 * @deprecated use Roo.lib.Dom.getY instead
18781 getPosY: function(el) {
18782 return Roo.lib.Dom.getY(el);
18786 * Swap two nodes. In IE, we use the native method, for others we
18787 * emulate the IE behavior
18789 * @param n1 the first node to swap
18790 * @param n2 the other node to swap
18793 swapNode: function(n1, n2) {
18797 var p = n2.parentNode;
18798 var s = n2.nextSibling;
18801 p.insertBefore(n1, n2);
18802 } else if (n2 == n1.nextSibling) {
18803 p.insertBefore(n2, n1);
18805 n1.parentNode.replaceChild(n2, n1);
18806 p.insertBefore(n1, s);
18812 * Returns the current scroll position
18813 * @method getScroll
18817 getScroll: function () {
18818 var t, l, dde=document.documentElement, db=document.body;
18819 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18821 l = dde.scrollLeft;
18828 return { top: t, left: l };
18832 * Returns the specified element style property
18834 * @param {HTMLElement} el the element
18835 * @param {string} styleProp the style property
18836 * @return {string} The value of the style property
18837 * @deprecated use Roo.lib.Dom.getStyle
18840 getStyle: function(el, styleProp) {
18841 return Roo.fly(el).getStyle(styleProp);
18845 * Gets the scrollTop
18846 * @method getScrollTop
18847 * @return {int} the document's scrollTop
18850 getScrollTop: function () { return this.getScroll().top; },
18853 * Gets the scrollLeft
18854 * @method getScrollLeft
18855 * @return {int} the document's scrollTop
18858 getScrollLeft: function () { return this.getScroll().left; },
18861 * Sets the x/y position of an element to the location of the
18864 * @param {HTMLElement} moveEl The element to move
18865 * @param {HTMLElement} targetEl The position reference element
18868 moveToEl: function (moveEl, targetEl) {
18869 var aCoord = Roo.lib.Dom.getXY(targetEl);
18870 Roo.lib.Dom.setXY(moveEl, aCoord);
18874 * Numeric array sort function
18875 * @method numericSort
18878 numericSort: function(a, b) { return (a - b); },
18882 * @property _timeoutCount
18889 * Trying to make the load order less important. Without this we get
18890 * an error if this file is loaded before the Event Utility.
18891 * @method _addListeners
18895 _addListeners: function() {
18896 var DDM = Roo.dd.DDM;
18897 if ( Roo.lib.Event && document ) {
18900 if (DDM._timeoutCount > 2000) {
18902 setTimeout(DDM._addListeners, 10);
18903 if (document && document.body) {
18904 DDM._timeoutCount += 1;
18911 * Recursively searches the immediate parent and all child nodes for
18912 * the handle element in order to determine wheter or not it was
18914 * @method handleWasClicked
18915 * @param node the html element to inspect
18918 handleWasClicked: function(node, id) {
18919 if (this.isHandle(id, node.id)) {
18922 // check to see if this is a text node child of the one we want
18923 var p = node.parentNode;
18926 if (this.isHandle(id, p.id)) {
18941 // shorter alias, save a few bytes
18942 Roo.dd.DDM = Roo.dd.DragDropMgr;
18943 Roo.dd.DDM._addListeners();
18947 * Ext JS Library 1.1.1
18948 * Copyright(c) 2006-2007, Ext JS, LLC.
18950 * Originally Released Under LGPL - original licence link has changed is not relivant.
18953 * <script type="text/javascript">
18958 * A DragDrop implementation where the linked element follows the
18959 * mouse cursor during a drag.
18960 * @extends Roo.dd.DragDrop
18962 * @param {String} id the id of the linked element
18963 * @param {String} sGroup the group of related DragDrop items
18964 * @param {object} config an object containing configurable attributes
18965 * Valid properties for DD:
18968 Roo.dd.DD = function(id, sGroup, config) {
18970 this.init(id, sGroup, config);
18974 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18977 * When set to true, the utility automatically tries to scroll the browser
18978 * window wehn a drag and drop element is dragged near the viewport boundary.
18979 * Defaults to true.
18986 * Sets the pointer offset to the distance between the linked element's top
18987 * left corner and the location the element was clicked
18988 * @method autoOffset
18989 * @param {int} iPageX the X coordinate of the click
18990 * @param {int} iPageY the Y coordinate of the click
18992 autoOffset: function(iPageX, iPageY) {
18993 var x = iPageX - this.startPageX;
18994 var y = iPageY - this.startPageY;
18995 this.setDelta(x, y);
18999 * Sets the pointer offset. You can call this directly to force the
19000 * offset to be in a particular location (e.g., pass in 0,0 to set it
19001 * to the center of the object)
19003 * @param {int} iDeltaX the distance from the left
19004 * @param {int} iDeltaY the distance from the top
19006 setDelta: function(iDeltaX, iDeltaY) {
19007 this.deltaX = iDeltaX;
19008 this.deltaY = iDeltaY;
19012 * Sets the drag element to the location of the mousedown or click event,
19013 * maintaining the cursor location relative to the location on the element
19014 * that was clicked. Override this if you want to place the element in a
19015 * location other than where the cursor is.
19016 * @method setDragElPos
19017 * @param {int} iPageX the X coordinate of the mousedown or drag event
19018 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19020 setDragElPos: function(iPageX, iPageY) {
19021 // the first time we do this, we are going to check to make sure
19022 // the element has css positioning
19024 var el = this.getDragEl();
19025 this.alignElWithMouse(el, iPageX, iPageY);
19029 * Sets the element to the location of the mousedown or click event,
19030 * maintaining the cursor location relative to the location on the element
19031 * that was clicked. Override this if you want to place the element in a
19032 * location other than where the cursor is.
19033 * @method alignElWithMouse
19034 * @param {HTMLElement} el the element to move
19035 * @param {int} iPageX the X coordinate of the mousedown or drag event
19036 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19038 alignElWithMouse: function(el, iPageX, iPageY) {
19039 var oCoord = this.getTargetCoord(iPageX, iPageY);
19040 var fly = el.dom ? el : Roo.fly(el);
19041 if (!this.deltaSetXY) {
19042 var aCoord = [oCoord.x, oCoord.y];
19044 var newLeft = fly.getLeft(true);
19045 var newTop = fly.getTop(true);
19046 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
19048 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
19051 this.cachePosition(oCoord.x, oCoord.y);
19052 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
19057 * Saves the most recent position so that we can reset the constraints and
19058 * tick marks on-demand. We need to know this so that we can calculate the
19059 * number of pixels the element is offset from its original position.
19060 * @method cachePosition
19061 * @param iPageX the current x position (optional, this just makes it so we
19062 * don't have to look it up again)
19063 * @param iPageY the current y position (optional, this just makes it so we
19064 * don't have to look it up again)
19066 cachePosition: function(iPageX, iPageY) {
19068 this.lastPageX = iPageX;
19069 this.lastPageY = iPageY;
19071 var aCoord = Roo.lib.Dom.getXY(this.getEl());
19072 this.lastPageX = aCoord[0];
19073 this.lastPageY = aCoord[1];
19078 * Auto-scroll the window if the dragged object has been moved beyond the
19079 * visible window boundary.
19080 * @method autoScroll
19081 * @param {int} x the drag element's x position
19082 * @param {int} y the drag element's y position
19083 * @param {int} h the height of the drag element
19084 * @param {int} w the width of the drag element
19087 autoScroll: function(x, y, h, w) {
19090 // The client height
19091 var clientH = Roo.lib.Dom.getViewWidth();
19093 // The client width
19094 var clientW = Roo.lib.Dom.getViewHeight();
19096 // The amt scrolled down
19097 var st = this.DDM.getScrollTop();
19099 // The amt scrolled right
19100 var sl = this.DDM.getScrollLeft();
19102 // Location of the bottom of the element
19105 // Location of the right of the element
19108 // The distance from the cursor to the bottom of the visible area,
19109 // adjusted so that we don't scroll if the cursor is beyond the
19110 // element drag constraints
19111 var toBot = (clientH + st - y - this.deltaY);
19113 // The distance from the cursor to the right of the visible area
19114 var toRight = (clientW + sl - x - this.deltaX);
19117 // How close to the edge the cursor must be before we scroll
19118 // var thresh = (document.all) ? 100 : 40;
19121 // How many pixels to scroll per autoscroll op. This helps to reduce
19122 // clunky scrolling. IE is more sensitive about this ... it needs this
19123 // value to be higher.
19124 var scrAmt = (document.all) ? 80 : 30;
19126 // Scroll down if we are near the bottom of the visible page and the
19127 // obj extends below the crease
19128 if ( bot > clientH && toBot < thresh ) {
19129 window.scrollTo(sl, st + scrAmt);
19132 // Scroll up if the window is scrolled down and the top of the object
19133 // goes above the top border
19134 if ( y < st && st > 0 && y - st < thresh ) {
19135 window.scrollTo(sl, st - scrAmt);
19138 // Scroll right if the obj is beyond the right border and the cursor is
19139 // near the border.
19140 if ( right > clientW && toRight < thresh ) {
19141 window.scrollTo(sl + scrAmt, st);
19144 // Scroll left if the window has been scrolled to the right and the obj
19145 // extends past the left border
19146 if ( x < sl && sl > 0 && x - sl < thresh ) {
19147 window.scrollTo(sl - scrAmt, st);
19153 * Finds the location the element should be placed if we want to move
19154 * it to where the mouse location less the click offset would place us.
19155 * @method getTargetCoord
19156 * @param {int} iPageX the X coordinate of the click
19157 * @param {int} iPageY the Y coordinate of the click
19158 * @return an object that contains the coordinates (Object.x and Object.y)
19161 getTargetCoord: function(iPageX, iPageY) {
19164 var x = iPageX - this.deltaX;
19165 var y = iPageY - this.deltaY;
19167 if (this.constrainX) {
19168 if (x < this.minX) { x = this.minX; }
19169 if (x > this.maxX) { x = this.maxX; }
19172 if (this.constrainY) {
19173 if (y < this.minY) { y = this.minY; }
19174 if (y > this.maxY) { y = this.maxY; }
19177 x = this.getTick(x, this.xTicks);
19178 y = this.getTick(y, this.yTicks);
19185 * Sets up config options specific to this class. Overrides
19186 * Roo.dd.DragDrop, but all versions of this method through the
19187 * inheritance chain are called
19189 applyConfig: function() {
19190 Roo.dd.DD.superclass.applyConfig.call(this);
19191 this.scroll = (this.config.scroll !== false);
19195 * Event that fires prior to the onMouseDown event. Overrides
19198 b4MouseDown: function(e) {
19199 // this.resetConstraints();
19200 this.autoOffset(e.getPageX(),
19205 * Event that fires prior to the onDrag event. Overrides
19208 b4Drag: function(e) {
19209 this.setDragElPos(e.getPageX(),
19213 toString: function() {
19214 return ("DD " + this.id);
19217 //////////////////////////////////////////////////////////////////////////
19218 // Debugging ygDragDrop events that can be overridden
19219 //////////////////////////////////////////////////////////////////////////
19221 startDrag: function(x, y) {
19224 onDrag: function(e) {
19227 onDragEnter: function(e, id) {
19230 onDragOver: function(e, id) {
19233 onDragOut: function(e, id) {
19236 onDragDrop: function(e, id) {
19239 endDrag: function(e) {
19246 * Ext JS Library 1.1.1
19247 * Copyright(c) 2006-2007, Ext JS, LLC.
19249 * Originally Released Under LGPL - original licence link has changed is not relivant.
19252 * <script type="text/javascript">
19256 * @class Roo.dd.DDProxy
19257 * A DragDrop implementation that inserts an empty, bordered div into
19258 * the document that follows the cursor during drag operations. At the time of
19259 * the click, the frame div is resized to the dimensions of the linked html
19260 * element, and moved to the exact location of the linked element.
19262 * References to the "frame" element refer to the single proxy element that
19263 * was created to be dragged in place of all DDProxy elements on the
19266 * @extends Roo.dd.DD
19268 * @param {String} id the id of the linked html element
19269 * @param {String} sGroup the group of related DragDrop objects
19270 * @param {object} config an object containing configurable attributes
19271 * Valid properties for DDProxy in addition to those in DragDrop:
19272 * resizeFrame, centerFrame, dragElId
19274 Roo.dd.DDProxy = function(id, sGroup, config) {
19276 this.init(id, sGroup, config);
19282 * The default drag frame div id
19283 * @property Roo.dd.DDProxy.dragElId
19287 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19289 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19292 * By default we resize the drag frame to be the same size as the element
19293 * we want to drag (this is to get the frame effect). We can turn it off
19294 * if we want a different behavior.
19295 * @property resizeFrame
19301 * By default the frame is positioned exactly where the drag element is, so
19302 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19303 * you do not have constraints on the obj is to have the drag frame centered
19304 * around the cursor. Set centerFrame to true for this effect.
19305 * @property centerFrame
19308 centerFrame: false,
19311 * Creates the proxy element if it does not yet exist
19312 * @method createFrame
19314 createFrame: function() {
19316 var body = document.body;
19318 if (!body || !body.firstChild) {
19319 setTimeout( function() { self.createFrame(); }, 50 );
19323 var div = this.getDragEl();
19326 div = document.createElement("div");
19327 div.id = this.dragElId;
19330 s.position = "absolute";
19331 s.visibility = "hidden";
19333 s.border = "2px solid #aaa";
19336 // appendChild can blow up IE if invoked prior to the window load event
19337 // while rendering a table. It is possible there are other scenarios
19338 // that would cause this to happen as well.
19339 body.insertBefore(div, body.firstChild);
19344 * Initialization for the drag frame element. Must be called in the
19345 * constructor of all subclasses
19346 * @method initFrame
19348 initFrame: function() {
19349 this.createFrame();
19352 applyConfig: function() {
19353 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19355 this.resizeFrame = (this.config.resizeFrame !== false);
19356 this.centerFrame = (this.config.centerFrame);
19357 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19361 * Resizes the drag frame to the dimensions of the clicked object, positions
19362 * it over the object, and finally displays it
19363 * @method showFrame
19364 * @param {int} iPageX X click position
19365 * @param {int} iPageY Y click position
19368 showFrame: function(iPageX, iPageY) {
19369 var el = this.getEl();
19370 var dragEl = this.getDragEl();
19371 var s = dragEl.style;
19373 this._resizeProxy();
19375 if (this.centerFrame) {
19376 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19377 Math.round(parseInt(s.height, 10)/2) );
19380 this.setDragElPos(iPageX, iPageY);
19382 Roo.fly(dragEl).show();
19386 * The proxy is automatically resized to the dimensions of the linked
19387 * element when a drag is initiated, unless resizeFrame is set to false
19388 * @method _resizeProxy
19391 _resizeProxy: function() {
19392 if (this.resizeFrame) {
19393 var el = this.getEl();
19394 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19398 // overrides Roo.dd.DragDrop
19399 b4MouseDown: function(e) {
19400 var x = e.getPageX();
19401 var y = e.getPageY();
19402 this.autoOffset(x, y);
19403 this.setDragElPos(x, y);
19406 // overrides Roo.dd.DragDrop
19407 b4StartDrag: function(x, y) {
19408 // show the drag frame
19409 this.showFrame(x, y);
19412 // overrides Roo.dd.DragDrop
19413 b4EndDrag: function(e) {
19414 Roo.fly(this.getDragEl()).hide();
19417 // overrides Roo.dd.DragDrop
19418 // By default we try to move the element to the last location of the frame.
19419 // This is so that the default behavior mirrors that of Roo.dd.DD.
19420 endDrag: function(e) {
19422 var lel = this.getEl();
19423 var del = this.getDragEl();
19425 // Show the drag frame briefly so we can get its position
19426 del.style.visibility = "";
19429 // Hide the linked element before the move to get around a Safari
19431 lel.style.visibility = "hidden";
19432 Roo.dd.DDM.moveToEl(lel, del);
19433 del.style.visibility = "hidden";
19434 lel.style.visibility = "";
19439 beforeMove : function(){
19443 afterDrag : function(){
19447 toString: function() {
19448 return ("DDProxy " + this.id);
19454 * Ext JS Library 1.1.1
19455 * Copyright(c) 2006-2007, Ext JS, LLC.
19457 * Originally Released Under LGPL - original licence link has changed is not relivant.
19460 * <script type="text/javascript">
19464 * @class Roo.dd.DDTarget
19465 * A DragDrop implementation that does not move, but can be a drop
19466 * target. You would get the same result by simply omitting implementation
19467 * for the event callbacks, but this way we reduce the processing cost of the
19468 * event listener and the callbacks.
19469 * @extends Roo.dd.DragDrop
19471 * @param {String} id the id of the element that is a drop target
19472 * @param {String} sGroup the group of related DragDrop objects
19473 * @param {object} config an object containing configurable attributes
19474 * Valid properties for DDTarget in addition to those in
19478 Roo.dd.DDTarget = function(id, sGroup, config) {
19480 this.initTarget(id, sGroup, config);
19482 if (config.listeners || config.events) {
19483 Roo.dd.DragDrop.superclass.constructor.call(this, {
19484 listeners : config.listeners || {},
19485 events : config.events || {}
19490 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19491 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19492 toString: function() {
19493 return ("DDTarget " + this.id);
19498 * Ext JS Library 1.1.1
19499 * Copyright(c) 2006-2007, Ext JS, LLC.
19501 * Originally Released Under LGPL - original licence link has changed is not relivant.
19504 * <script type="text/javascript">
19509 * @class Roo.dd.ScrollManager
19510 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19511 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19514 Roo.dd.ScrollManager = function(){
19515 var ddm = Roo.dd.DragDropMgr;
19522 var onStop = function(e){
19527 var triggerRefresh = function(){
19528 if(ddm.dragCurrent){
19529 ddm.refreshCache(ddm.dragCurrent.groups);
19533 var doScroll = function(){
19534 if(ddm.dragCurrent){
19535 var dds = Roo.dd.ScrollManager;
19537 if(proc.el.scroll(proc.dir, dds.increment)){
19541 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19546 var clearProc = function(){
19548 clearInterval(proc.id);
19555 var startProc = function(el, dir){
19556 Roo.log('scroll startproc');
19560 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19563 var onFire = function(e, isDrop){
19565 if(isDrop || !ddm.dragCurrent){ return; }
19566 var dds = Roo.dd.ScrollManager;
19567 if(!dragEl || dragEl != ddm.dragCurrent){
19568 dragEl = ddm.dragCurrent;
19569 // refresh regions on drag start
19570 dds.refreshCache();
19573 var xy = Roo.lib.Event.getXY(e);
19574 var pt = new Roo.lib.Point(xy[0], xy[1]);
19575 for(var id in els){
19576 var el = els[id], r = el._region;
19577 if(r && r.contains(pt) && el.isScrollable()){
19578 if(r.bottom - pt.y <= dds.thresh){
19580 startProc(el, "down");
19583 }else if(r.right - pt.x <= dds.thresh){
19585 startProc(el, "left");
19588 }else if(pt.y - r.top <= dds.thresh){
19590 startProc(el, "up");
19593 }else if(pt.x - r.left <= dds.thresh){
19595 startProc(el, "right");
19604 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19605 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19609 * Registers new overflow element(s) to auto scroll
19610 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19612 register : function(el){
19613 if(el instanceof Array){
19614 for(var i = 0, len = el.length; i < len; i++) {
19615 this.register(el[i]);
19621 Roo.dd.ScrollManager.els = els;
19625 * Unregisters overflow element(s) so they are no longer scrolled
19626 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19628 unregister : function(el){
19629 if(el instanceof Array){
19630 for(var i = 0, len = el.length; i < len; i++) {
19631 this.unregister(el[i]);
19640 * The number of pixels from the edge of a container the pointer needs to be to
19641 * trigger scrolling (defaults to 25)
19647 * The number of pixels to scroll in each scroll increment (defaults to 50)
19653 * The frequency of scrolls in milliseconds (defaults to 500)
19659 * True to animate the scroll (defaults to true)
19665 * The animation duration in seconds -
19666 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19672 * Manually trigger a cache refresh.
19674 refreshCache : function(){
19675 for(var id in els){
19676 if(typeof els[id] == 'object'){ // for people extending the object prototype
19677 els[id]._region = els[id].getRegion();
19684 * Ext JS Library 1.1.1
19685 * Copyright(c) 2006-2007, Ext JS, LLC.
19687 * Originally Released Under LGPL - original licence link has changed is not relivant.
19690 * <script type="text/javascript">
19695 * @class Roo.dd.Registry
19696 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19697 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19700 Roo.dd.Registry = function(){
19703 var autoIdSeed = 0;
19705 var getId = function(el, autogen){
19706 if(typeof el == "string"){
19710 if(!id && autogen !== false){
19711 id = "roodd-" + (++autoIdSeed);
19719 * Register a drag drop element
19720 * @param {String|HTMLElement} element The id or DOM node to register
19721 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19722 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19723 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19724 * populated in the data object (if applicable):
19726 Value Description<br />
19727 --------- ------------------------------------------<br />
19728 handles Array of DOM nodes that trigger dragging<br />
19729 for the element being registered<br />
19730 isHandle True if the element passed in triggers<br />
19731 dragging itself, else false
19734 register : function(el, data){
19736 if(typeof el == "string"){
19737 el = document.getElementById(el);
19740 elements[getId(el)] = data;
19741 if(data.isHandle !== false){
19742 handles[data.ddel.id] = data;
19745 var hs = data.handles;
19746 for(var i = 0, len = hs.length; i < len; i++){
19747 handles[getId(hs[i])] = data;
19753 * Unregister a drag drop element
19754 * @param {String|HTMLElement} element The id or DOM node to unregister
19756 unregister : function(el){
19757 var id = getId(el, false);
19758 var data = elements[id];
19760 delete elements[id];
19762 var hs = data.handles;
19763 for(var i = 0, len = hs.length; i < len; i++){
19764 delete handles[getId(hs[i], false)];
19771 * Returns the handle registered for a DOM Node by id
19772 * @param {String|HTMLElement} id The DOM node or id to look up
19773 * @return {Object} handle The custom handle data
19775 getHandle : function(id){
19776 if(typeof id != "string"){ // must be element?
19779 return handles[id];
19783 * Returns the handle that is registered for the DOM node that is the target of the event
19784 * @param {Event} e The event
19785 * @return {Object} handle The custom handle data
19787 getHandleFromEvent : function(e){
19788 var t = Roo.lib.Event.getTarget(e);
19789 return t ? handles[t.id] : null;
19793 * Returns a custom data object that is registered for a DOM node by id
19794 * @param {String|HTMLElement} id The DOM node or id to look up
19795 * @return {Object} data The custom data
19797 getTarget : function(id){
19798 if(typeof id != "string"){ // must be element?
19801 return elements[id];
19805 * Returns a custom data object that is registered for the DOM node that is the target of the event
19806 * @param {Event} e The event
19807 * @return {Object} data The custom data
19809 getTargetFromEvent : function(e){
19810 var t = Roo.lib.Event.getTarget(e);
19811 return t ? elements[t.id] || handles[t.id] : null;
19816 * Ext JS Library 1.1.1
19817 * Copyright(c) 2006-2007, Ext JS, LLC.
19819 * Originally Released Under LGPL - original licence link has changed is not relivant.
19822 * <script type="text/javascript">
19827 * @class Roo.dd.StatusProxy
19828 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19829 * default drag proxy used by all Roo.dd components.
19831 * @param {Object} config
19833 Roo.dd.StatusProxy = function(config){
19834 Roo.apply(this, config);
19835 this.id = this.id || Roo.id();
19836 this.el = new Roo.Layer({
19838 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19839 {tag: "div", cls: "x-dd-drop-icon"},
19840 {tag: "div", cls: "x-dd-drag-ghost"}
19843 shadow: !config || config.shadow !== false
19845 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19846 this.dropStatus = this.dropNotAllowed;
19849 Roo.dd.StatusProxy.prototype = {
19851 * @cfg {String} dropAllowed
19852 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19854 dropAllowed : "x-dd-drop-ok",
19856 * @cfg {String} dropNotAllowed
19857 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19859 dropNotAllowed : "x-dd-drop-nodrop",
19862 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19863 * over the current target element.
19864 * @param {String} cssClass The css class for the new drop status indicator image
19866 setStatus : function(cssClass){
19867 cssClass = cssClass || this.dropNotAllowed;
19868 if(this.dropStatus != cssClass){
19869 this.el.replaceClass(this.dropStatus, cssClass);
19870 this.dropStatus = cssClass;
19875 * Resets the status indicator to the default dropNotAllowed value
19876 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19878 reset : function(clearGhost){
19879 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19880 this.dropStatus = this.dropNotAllowed;
19882 this.ghost.update("");
19887 * Updates the contents of the ghost element
19888 * @param {String} html The html that will replace the current innerHTML of the ghost element
19890 update : function(html){
19891 if(typeof html == "string"){
19892 this.ghost.update(html);
19894 this.ghost.update("");
19895 html.style.margin = "0";
19896 this.ghost.dom.appendChild(html);
19898 // ensure float = none set?? cant remember why though.
19899 var el = this.ghost.dom.firstChild;
19901 Roo.fly(el).setStyle('float', 'none');
19906 * Returns the underlying proxy {@link Roo.Layer}
19907 * @return {Roo.Layer} el
19909 getEl : function(){
19914 * Returns the ghost element
19915 * @return {Roo.Element} el
19917 getGhost : function(){
19923 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19925 hide : function(clear){
19933 * Stops the repair animation if it's currently running
19936 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19942 * Displays this proxy
19949 * Force the Layer to sync its shadow and shim positions to the element
19956 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19957 * invalid drop operation by the item being dragged.
19958 * @param {Array} xy The XY position of the element ([x, y])
19959 * @param {Function} callback The function to call after the repair is complete
19960 * @param {Object} scope The scope in which to execute the callback
19962 repair : function(xy, callback, scope){
19963 this.callback = callback;
19964 this.scope = scope;
19965 if(xy && this.animRepair !== false){
19966 this.el.addClass("x-dd-drag-repair");
19967 this.el.hideUnders(true);
19968 this.anim = this.el.shift({
19969 duration: this.repairDuration || .5,
19973 callback: this.afterRepair,
19977 this.afterRepair();
19982 afterRepair : function(){
19984 if(typeof this.callback == "function"){
19985 this.callback.call(this.scope || this);
19987 this.callback = null;
19992 * Ext JS Library 1.1.1
19993 * Copyright(c) 2006-2007, Ext JS, LLC.
19995 * Originally Released Under LGPL - original licence link has changed is not relivant.
19998 * <script type="text/javascript">
20002 * @class Roo.dd.DragSource
20003 * @extends Roo.dd.DDProxy
20004 * A simple class that provides the basic implementation needed to make any element draggable.
20006 * @param {String/HTMLElement/Element} el The container element
20007 * @param {Object} config
20009 Roo.dd.DragSource = function(el, config){
20010 this.el = Roo.get(el);
20011 this.dragData = {};
20013 Roo.apply(this, config);
20016 this.proxy = new Roo.dd.StatusProxy();
20019 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
20020 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
20022 this.dragging = false;
20025 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
20027 * @cfg {String} dropAllowed
20028 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20030 dropAllowed : "x-dd-drop-ok",
20032 * @cfg {String} dropNotAllowed
20033 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20035 dropNotAllowed : "x-dd-drop-nodrop",
20038 * Returns the data object associated with this drag source
20039 * @return {Object} data An object containing arbitrary data
20041 getDragData : function(e){
20042 return this.dragData;
20046 onDragEnter : function(e, id){
20047 var target = Roo.dd.DragDropMgr.getDDById(id);
20048 this.cachedTarget = target;
20049 if(this.beforeDragEnter(target, e, id) !== false){
20050 if(target.isNotifyTarget){
20051 var status = target.notifyEnter(this, e, this.dragData);
20052 this.proxy.setStatus(status);
20054 this.proxy.setStatus(this.dropAllowed);
20057 if(this.afterDragEnter){
20059 * An empty function by default, but provided so that you can perform a custom action
20060 * when the dragged item enters the drop target by providing an implementation.
20061 * @param {Roo.dd.DragDrop} target The drop target
20062 * @param {Event} e The event object
20063 * @param {String} id The id of the dragged element
20064 * @method afterDragEnter
20066 this.afterDragEnter(target, e, id);
20072 * An empty function by default, but provided so that you can perform a custom action
20073 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
20074 * @param {Roo.dd.DragDrop} target The drop target
20075 * @param {Event} e The event object
20076 * @param {String} id The id of the dragged element
20077 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20079 beforeDragEnter : function(target, e, id){
20084 alignElWithMouse: function() {
20085 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
20090 onDragOver : function(e, id){
20091 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20092 if(this.beforeDragOver(target, e, id) !== false){
20093 if(target.isNotifyTarget){
20094 var status = target.notifyOver(this, e, this.dragData);
20095 this.proxy.setStatus(status);
20098 if(this.afterDragOver){
20100 * An empty function by default, but provided so that you can perform a custom action
20101 * while the dragged item is over the drop target by providing an implementation.
20102 * @param {Roo.dd.DragDrop} target The drop target
20103 * @param {Event} e The event object
20104 * @param {String} id The id of the dragged element
20105 * @method afterDragOver
20107 this.afterDragOver(target, e, id);
20113 * An empty function by default, but provided so that you can perform a custom action
20114 * while the dragged item is over the drop target and optionally cancel the onDragOver.
20115 * @param {Roo.dd.DragDrop} target The drop target
20116 * @param {Event} e The event object
20117 * @param {String} id The id of the dragged element
20118 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20120 beforeDragOver : function(target, e, id){
20125 onDragOut : function(e, id){
20126 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20127 if(this.beforeDragOut(target, e, id) !== false){
20128 if(target.isNotifyTarget){
20129 target.notifyOut(this, e, this.dragData);
20131 this.proxy.reset();
20132 if(this.afterDragOut){
20134 * An empty function by default, but provided so that you can perform a custom action
20135 * after the dragged item is dragged out of the target without dropping.
20136 * @param {Roo.dd.DragDrop} target The drop target
20137 * @param {Event} e The event object
20138 * @param {String} id The id of the dragged element
20139 * @method afterDragOut
20141 this.afterDragOut(target, e, id);
20144 this.cachedTarget = null;
20148 * An empty function by default, but provided so that you can perform a custom action before the dragged
20149 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20150 * @param {Roo.dd.DragDrop} target The drop target
20151 * @param {Event} e The event object
20152 * @param {String} id The id of the dragged element
20153 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20155 beforeDragOut : function(target, e, id){
20160 onDragDrop : function(e, id){
20161 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20162 if(this.beforeDragDrop(target, e, id) !== false){
20163 if(target.isNotifyTarget){
20164 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20165 this.onValidDrop(target, e, id);
20167 this.onInvalidDrop(target, e, id);
20170 this.onValidDrop(target, e, id);
20173 if(this.afterDragDrop){
20175 * An empty function by default, but provided so that you can perform a custom action
20176 * after a valid drag drop has occurred by providing an implementation.
20177 * @param {Roo.dd.DragDrop} target The drop target
20178 * @param {Event} e The event object
20179 * @param {String} id The id of the dropped element
20180 * @method afterDragDrop
20182 this.afterDragDrop(target, e, id);
20185 delete this.cachedTarget;
20189 * An empty function by default, but provided so that you can perform a custom action before the dragged
20190 * item is dropped onto the target and optionally cancel the onDragDrop.
20191 * @param {Roo.dd.DragDrop} target The drop target
20192 * @param {Event} e The event object
20193 * @param {String} id The id of the dragged element
20194 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20196 beforeDragDrop : function(target, e, id){
20201 onValidDrop : function(target, e, id){
20203 if(this.afterValidDrop){
20205 * An empty function by default, but provided so that you can perform a custom action
20206 * after a valid drop has occurred by providing an implementation.
20207 * @param {Object} target The target DD
20208 * @param {Event} e The event object
20209 * @param {String} id The id of the dropped element
20210 * @method afterInvalidDrop
20212 this.afterValidDrop(target, e, id);
20217 getRepairXY : function(e, data){
20218 return this.el.getXY();
20222 onInvalidDrop : function(target, e, id){
20223 this.beforeInvalidDrop(target, e, id);
20224 if(this.cachedTarget){
20225 if(this.cachedTarget.isNotifyTarget){
20226 this.cachedTarget.notifyOut(this, e, this.dragData);
20228 this.cacheTarget = null;
20230 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20232 if(this.afterInvalidDrop){
20234 * An empty function by default, but provided so that you can perform a custom action
20235 * after an invalid drop has occurred by providing an implementation.
20236 * @param {Event} e The event object
20237 * @param {String} id The id of the dropped element
20238 * @method afterInvalidDrop
20240 this.afterInvalidDrop(e, id);
20245 afterRepair : function(){
20247 this.el.highlight(this.hlColor || "c3daf9");
20249 this.dragging = false;
20253 * An empty function by default, but provided so that you can perform a custom action after an invalid
20254 * drop has occurred.
20255 * @param {Roo.dd.DragDrop} target The drop target
20256 * @param {Event} e The event object
20257 * @param {String} id The id of the dragged element
20258 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20260 beforeInvalidDrop : function(target, e, id){
20265 handleMouseDown : function(e){
20266 if(this.dragging) {
20269 var data = this.getDragData(e);
20270 if(data && this.onBeforeDrag(data, e) !== false){
20271 this.dragData = data;
20273 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20278 * An empty function by default, but provided so that you can perform a custom action before the initial
20279 * drag event begins and optionally cancel it.
20280 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20281 * @param {Event} e The event object
20282 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20284 onBeforeDrag : function(data, e){
20289 * An empty function by default, but provided so that you can perform a custom action once the initial
20290 * drag event has begun. The drag cannot be canceled from this function.
20291 * @param {Number} x The x position of the click on the dragged object
20292 * @param {Number} y The y position of the click on the dragged object
20294 onStartDrag : Roo.emptyFn,
20296 // private - YUI override
20297 startDrag : function(x, y){
20298 this.proxy.reset();
20299 this.dragging = true;
20300 this.proxy.update("");
20301 this.onInitDrag(x, y);
20306 onInitDrag : function(x, y){
20307 var clone = this.el.dom.cloneNode(true);
20308 clone.id = Roo.id(); // prevent duplicate ids
20309 this.proxy.update(clone);
20310 this.onStartDrag(x, y);
20315 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20316 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20318 getProxy : function(){
20323 * Hides the drag source's {@link Roo.dd.StatusProxy}
20325 hideProxy : function(){
20327 this.proxy.reset(true);
20328 this.dragging = false;
20332 triggerCacheRefresh : function(){
20333 Roo.dd.DDM.refreshCache(this.groups);
20336 // private - override to prevent hiding
20337 b4EndDrag: function(e) {
20340 // private - override to prevent moving
20341 endDrag : function(e){
20342 this.onEndDrag(this.dragData, e);
20346 onEndDrag : function(data, e){
20349 // private - pin to cursor
20350 autoOffset : function(x, y) {
20351 this.setDelta(-12, -20);
20355 * Ext JS Library 1.1.1
20356 * Copyright(c) 2006-2007, Ext JS, LLC.
20358 * Originally Released Under LGPL - original licence link has changed is not relivant.
20361 * <script type="text/javascript">
20366 * @class Roo.dd.DropTarget
20367 * @extends Roo.dd.DDTarget
20368 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20369 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20371 * @param {String/HTMLElement/Element} el The container element
20372 * @param {Object} config
20374 Roo.dd.DropTarget = function(el, config){
20375 this.el = Roo.get(el);
20377 var listeners = false; ;
20378 if (config && config.listeners) {
20379 listeners= config.listeners;
20380 delete config.listeners;
20382 Roo.apply(this, config);
20384 if(this.containerScroll){
20385 Roo.dd.ScrollManager.register(this.el);
20389 * @scope Roo.dd.DropTarget
20394 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20395 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20396 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20398 * IMPORTANT : it should set this.overClass and this.dropAllowed
20400 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20401 * @param {Event} e The event
20402 * @param {Object} data An object containing arbitrary data supplied by the drag source
20408 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20409 * This method will be called on every mouse movement while the drag source is over the drop target.
20410 * This default implementation simply returns the dropAllowed config value.
20412 * IMPORTANT : it should set this.dropAllowed
20414 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20415 * @param {Event} e The event
20416 * @param {Object} data An object containing arbitrary data supplied by the drag source
20422 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20423 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20424 * overClass (if any) from the drop element.
20426 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20427 * @param {Event} e The event
20428 * @param {Object} data An object containing arbitrary data supplied by the drag source
20434 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20435 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20436 * implementation that does something to process the drop event and returns true so that the drag source's
20437 * repair action does not run.
20439 * IMPORTANT : it should set this.success
20441 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20442 * @param {Event} e The event
20443 * @param {Object} data An object containing arbitrary data supplied by the drag source
20449 Roo.dd.DropTarget.superclass.constructor.call( this,
20451 this.ddGroup || this.group,
20454 listeners : listeners || {}
20462 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20464 * @cfg {String} overClass
20465 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20468 * @cfg {String} ddGroup
20469 * The drag drop group to handle drop events for
20473 * @cfg {String} dropAllowed
20474 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20476 dropAllowed : "x-dd-drop-ok",
20478 * @cfg {String} dropNotAllowed
20479 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20481 dropNotAllowed : "x-dd-drop-nodrop",
20483 * @cfg {boolean} success
20484 * set this after drop listener..
20488 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20489 * if the drop point is valid for over/enter..
20496 isNotifyTarget : true,
20501 notifyEnter : function(dd, e, data)
20504 this.fireEvent('enter', dd, e, data);
20505 if(this.overClass){
20506 this.el.addClass(this.overClass);
20508 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20509 this.valid ? this.dropAllowed : this.dropNotAllowed
20516 notifyOver : function(dd, e, data)
20519 this.fireEvent('over', dd, e, data);
20520 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20521 this.valid ? this.dropAllowed : this.dropNotAllowed
20528 notifyOut : function(dd, e, data)
20530 this.fireEvent('out', dd, e, data);
20531 if(this.overClass){
20532 this.el.removeClass(this.overClass);
20539 notifyDrop : function(dd, e, data)
20541 this.success = false;
20542 this.fireEvent('drop', dd, e, data);
20543 return this.success;
20547 * Ext JS Library 1.1.1
20548 * Copyright(c) 2006-2007, Ext JS, LLC.
20550 * Originally Released Under LGPL - original licence link has changed is not relivant.
20553 * <script type="text/javascript">
20558 * @class Roo.dd.DragZone
20559 * @extends Roo.dd.DragSource
20560 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20561 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20563 * @param {String/HTMLElement/Element} el The container element
20564 * @param {Object} config
20566 Roo.dd.DragZone = function(el, config){
20567 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20568 if(this.containerScroll){
20569 Roo.dd.ScrollManager.register(this.el);
20573 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20575 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20576 * for auto scrolling during drag operations.
20579 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20580 * method after a failed drop (defaults to "c3daf9" - light blue)
20584 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20585 * for a valid target to drag based on the mouse down. Override this method
20586 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20587 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20588 * @param {EventObject} e The mouse down event
20589 * @return {Object} The dragData
20591 getDragData : function(e){
20592 return Roo.dd.Registry.getHandleFromEvent(e);
20596 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20597 * this.dragData.ddel
20598 * @param {Number} x The x position of the click on the dragged object
20599 * @param {Number} y The y position of the click on the dragged object
20600 * @return {Boolean} true to continue the drag, false to cancel
20602 onInitDrag : function(x, y){
20603 this.proxy.update(this.dragData.ddel.cloneNode(true));
20604 this.onStartDrag(x, y);
20609 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20611 afterRepair : function(){
20613 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20615 this.dragging = false;
20619 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20620 * the XY of this.dragData.ddel
20621 * @param {EventObject} e The mouse up event
20622 * @return {Array} The xy location (e.g. [100, 200])
20624 getRepairXY : function(e){
20625 return Roo.Element.fly(this.dragData.ddel).getXY();
20629 * Ext JS Library 1.1.1
20630 * Copyright(c) 2006-2007, Ext JS, LLC.
20632 * Originally Released Under LGPL - original licence link has changed is not relivant.
20635 * <script type="text/javascript">
20638 * @class Roo.dd.DropZone
20639 * @extends Roo.dd.DropTarget
20640 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20641 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20643 * @param {String/HTMLElement/Element} el The container element
20644 * @param {Object} config
20646 Roo.dd.DropZone = function(el, config){
20647 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20650 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20652 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20653 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20654 * provide your own custom lookup.
20655 * @param {Event} e The event
20656 * @return {Object} data The custom data
20658 getTargetFromEvent : function(e){
20659 return Roo.dd.Registry.getTargetFromEvent(e);
20663 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20664 * that it has registered. This method has no default implementation and should be overridden to provide
20665 * node-specific processing if necessary.
20666 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20667 * {@link #getTargetFromEvent} for this node)
20668 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20669 * @param {Event} e The event
20670 * @param {Object} data An object containing arbitrary data supplied by the drag source
20672 onNodeEnter : function(n, dd, e, data){
20677 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20678 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20679 * overridden to provide the proper feedback.
20680 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20681 * {@link #getTargetFromEvent} for this node)
20682 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20683 * @param {Event} e The event
20684 * @param {Object} data An object containing arbitrary data supplied by the drag source
20685 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20686 * underlying {@link Roo.dd.StatusProxy} can be updated
20688 onNodeOver : function(n, dd, e, data){
20689 return this.dropAllowed;
20693 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20694 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20695 * node-specific processing if necessary.
20696 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20697 * {@link #getTargetFromEvent} for this node)
20698 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20699 * @param {Event} e The event
20700 * @param {Object} data An object containing arbitrary data supplied by the drag source
20702 onNodeOut : function(n, dd, e, data){
20707 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20708 * the drop node. The default implementation returns false, so it should be overridden to provide the
20709 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20710 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20711 * {@link #getTargetFromEvent} for this node)
20712 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20713 * @param {Event} e The event
20714 * @param {Object} data An object containing arbitrary data supplied by the drag source
20715 * @return {Boolean} True if the drop was valid, else false
20717 onNodeDrop : function(n, dd, e, data){
20722 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20723 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20724 * it should be overridden to provide the proper feedback if necessary.
20725 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20726 * @param {Event} e The event
20727 * @param {Object} data An object containing arbitrary data supplied by the drag source
20728 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20729 * underlying {@link Roo.dd.StatusProxy} can be updated
20731 onContainerOver : function(dd, e, data){
20732 return this.dropNotAllowed;
20736 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20737 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20738 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20739 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20740 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20741 * @param {Event} e The event
20742 * @param {Object} data An object containing arbitrary data supplied by the drag source
20743 * @return {Boolean} True if the drop was valid, else false
20745 onContainerDrop : function(dd, e, data){
20750 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20751 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20752 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20753 * you should override this method and provide a custom implementation.
20754 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20755 * @param {Event} e The event
20756 * @param {Object} data An object containing arbitrary data supplied by the drag source
20757 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20758 * underlying {@link Roo.dd.StatusProxy} can be updated
20760 notifyEnter : function(dd, e, data){
20761 return this.dropNotAllowed;
20765 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20766 * This method will be called on every mouse movement while the drag source is over the drop zone.
20767 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20768 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20769 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20770 * registered node, it will call {@link #onContainerOver}.
20771 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20772 * @param {Event} e The event
20773 * @param {Object} data An object containing arbitrary data supplied by the drag source
20774 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20775 * underlying {@link Roo.dd.StatusProxy} can be updated
20777 notifyOver : function(dd, e, data){
20778 var n = this.getTargetFromEvent(e);
20779 if(!n){ // not over valid drop target
20780 if(this.lastOverNode){
20781 this.onNodeOut(this.lastOverNode, dd, e, data);
20782 this.lastOverNode = null;
20784 return this.onContainerOver(dd, e, data);
20786 if(this.lastOverNode != n){
20787 if(this.lastOverNode){
20788 this.onNodeOut(this.lastOverNode, dd, e, data);
20790 this.onNodeEnter(n, dd, e, data);
20791 this.lastOverNode = n;
20793 return this.onNodeOver(n, dd, e, data);
20797 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20798 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20799 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20800 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20801 * @param {Event} e The event
20802 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20804 notifyOut : function(dd, e, data){
20805 if(this.lastOverNode){
20806 this.onNodeOut(this.lastOverNode, dd, e, data);
20807 this.lastOverNode = null;
20812 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20813 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20814 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20815 * otherwise it will call {@link #onContainerDrop}.
20816 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20817 * @param {Event} e The event
20818 * @param {Object} data An object containing arbitrary data supplied by the drag source
20819 * @return {Boolean} True if the drop was valid, else false
20821 notifyDrop : function(dd, e, data){
20822 if(this.lastOverNode){
20823 this.onNodeOut(this.lastOverNode, dd, e, data);
20824 this.lastOverNode = null;
20826 var n = this.getTargetFromEvent(e);
20828 this.onNodeDrop(n, dd, e, data) :
20829 this.onContainerDrop(dd, e, data);
20833 triggerCacheRefresh : function(){
20834 Roo.dd.DDM.refreshCache(this.groups);
20838 * Ext JS Library 1.1.1
20839 * Copyright(c) 2006-2007, Ext JS, LLC.
20841 * Originally Released Under LGPL - original licence link has changed is not relivant.
20844 * <script type="text/javascript">
20849 * @class Roo.data.SortTypes
20851 * Defines the default sorting (casting?) comparison functions used when sorting data.
20853 Roo.data.SortTypes = {
20855 * Default sort that does nothing
20856 * @param {Mixed} s The value being converted
20857 * @return {Mixed} The comparison value
20859 none : function(s){
20864 * The regular expression used to strip tags
20868 stripTagsRE : /<\/?[^>]+>/gi,
20871 * Strips all HTML tags to sort on text only
20872 * @param {Mixed} s The value being converted
20873 * @return {String} The comparison value
20875 asText : function(s){
20876 return String(s).replace(this.stripTagsRE, "");
20880 * Strips all HTML tags to sort on text only - Case insensitive
20881 * @param {Mixed} s The value being converted
20882 * @return {String} The comparison value
20884 asUCText : function(s){
20885 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20889 * Case insensitive string
20890 * @param {Mixed} s The value being converted
20891 * @return {String} The comparison value
20893 asUCString : function(s) {
20894 return String(s).toUpperCase();
20899 * @param {Mixed} s The value being converted
20900 * @return {Number} The comparison value
20902 asDate : function(s) {
20906 if(s instanceof Date){
20907 return s.getTime();
20909 return Date.parse(String(s));
20914 * @param {Mixed} s The value being converted
20915 * @return {Float} The comparison value
20917 asFloat : function(s) {
20918 var val = parseFloat(String(s).replace(/,/g, ""));
20919 if(isNaN(val)) val = 0;
20925 * @param {Mixed} s The value being converted
20926 * @return {Number} The comparison value
20928 asInt : function(s) {
20929 var val = parseInt(String(s).replace(/,/g, ""));
20930 if(isNaN(val)) val = 0;
20935 * Ext JS Library 1.1.1
20936 * Copyright(c) 2006-2007, Ext JS, LLC.
20938 * Originally Released Under LGPL - original licence link has changed is not relivant.
20941 * <script type="text/javascript">
20945 * @class Roo.data.Record
20946 * Instances of this class encapsulate both record <em>definition</em> information, and record
20947 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20948 * to access Records cached in an {@link Roo.data.Store} object.<br>
20950 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20951 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20954 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20956 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20957 * {@link #create}. The parameters are the same.
20958 * @param {Array} data An associative Array of data values keyed by the field name.
20959 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20960 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20961 * not specified an integer id is generated.
20963 Roo.data.Record = function(data, id){
20964 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20969 * Generate a constructor for a specific record layout.
20970 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20971 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20972 * Each field definition object may contain the following properties: <ul>
20973 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
20974 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20975 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20976 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20977 * is being used, then this is a string containing the javascript expression to reference the data relative to
20978 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20979 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20980 * this may be omitted.</p></li>
20981 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20982 * <ul><li>auto (Default, implies no conversion)</li>
20987 * <li>date</li></ul></p></li>
20988 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20989 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20990 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20991 * by the Reader into an object that will be stored in the Record. It is passed the
20992 * following parameters:<ul>
20993 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20995 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20997 * <br>usage:<br><pre><code>
20998 var TopicRecord = Roo.data.Record.create(
20999 {name: 'title', mapping: 'topic_title'},
21000 {name: 'author', mapping: 'username'},
21001 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
21002 {name: 'lastPost', mapping: 'post_time', type: 'date'},
21003 {name: 'lastPoster', mapping: 'user2'},
21004 {name: 'excerpt', mapping: 'post_text'}
21007 var myNewRecord = new TopicRecord({
21008 title: 'Do my job please',
21011 lastPost: new Date(),
21012 lastPoster: 'Animal',
21013 excerpt: 'No way dude!'
21015 myStore.add(myNewRecord);
21020 Roo.data.Record.create = function(o){
21021 var f = function(){
21022 f.superclass.constructor.apply(this, arguments);
21024 Roo.extend(f, Roo.data.Record);
21025 var p = f.prototype;
21026 p.fields = new Roo.util.MixedCollection(false, function(field){
21029 for(var i = 0, len = o.length; i < len; i++){
21030 p.fields.add(new Roo.data.Field(o[i]));
21032 f.getField = function(name){
21033 return p.fields.get(name);
21038 Roo.data.Record.AUTO_ID = 1000;
21039 Roo.data.Record.EDIT = 'edit';
21040 Roo.data.Record.REJECT = 'reject';
21041 Roo.data.Record.COMMIT = 'commit';
21043 Roo.data.Record.prototype = {
21045 * Readonly flag - true if this record has been modified.
21054 join : function(store){
21055 this.store = store;
21059 * Set the named field to the specified value.
21060 * @param {String} name The name of the field to set.
21061 * @param {Object} value The value to set the field to.
21063 set : function(name, value){
21064 if(this.data[name] == value){
21068 if(!this.modified){
21069 this.modified = {};
21071 if(typeof this.modified[name] == 'undefined'){
21072 this.modified[name] = this.data[name];
21074 this.data[name] = value;
21075 if(!this.editing && this.store){
21076 this.store.afterEdit(this);
21081 * Get the value of the named field.
21082 * @param {String} name The name of the field to get the value of.
21083 * @return {Object} The value of the field.
21085 get : function(name){
21086 return this.data[name];
21090 beginEdit : function(){
21091 this.editing = true;
21092 this.modified = {};
21096 cancelEdit : function(){
21097 this.editing = false;
21098 delete this.modified;
21102 endEdit : function(){
21103 this.editing = false;
21104 if(this.dirty && this.store){
21105 this.store.afterEdit(this);
21110 * Usually called by the {@link Roo.data.Store} which owns the Record.
21111 * Rejects all changes made to the Record since either creation, or the last commit operation.
21112 * Modified fields are reverted to their original values.
21114 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21115 * of reject operations.
21117 reject : function(){
21118 var m = this.modified;
21120 if(typeof m[n] != "function"){
21121 this.data[n] = m[n];
21124 this.dirty = false;
21125 delete this.modified;
21126 this.editing = false;
21128 this.store.afterReject(this);
21133 * Usually called by the {@link Roo.data.Store} which owns the Record.
21134 * Commits all changes made to the Record since either creation, or the last commit operation.
21136 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21137 * of commit operations.
21139 commit : function(){
21140 this.dirty = false;
21141 delete this.modified;
21142 this.editing = false;
21144 this.store.afterCommit(this);
21149 hasError : function(){
21150 return this.error != null;
21154 clearError : function(){
21159 * Creates a copy of this record.
21160 * @param {String} id (optional) A new record id if you don't want to use this record's id
21163 copy : function(newId) {
21164 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21168 * Ext JS Library 1.1.1
21169 * Copyright(c) 2006-2007, Ext JS, LLC.
21171 * Originally Released Under LGPL - original licence link has changed is not relivant.
21174 * <script type="text/javascript">
21180 * @class Roo.data.Store
21181 * @extends Roo.util.Observable
21182 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21183 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21185 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
21186 * has no knowledge of the format of the data returned by the Proxy.<br>
21188 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21189 * instances from the data object. These records are cached and made available through accessor functions.
21191 * Creates a new Store.
21192 * @param {Object} config A config object containing the objects needed for the Store to access data,
21193 * and read the data into Records.
21195 Roo.data.Store = function(config){
21196 this.data = new Roo.util.MixedCollection(false);
21197 this.data.getKey = function(o){
21200 this.baseParams = {};
21202 this.paramNames = {
21207 "multisort" : "_multisort"
21210 if(config && config.data){
21211 this.inlineData = config.data;
21212 delete config.data;
21215 Roo.apply(this, config);
21217 if(this.reader){ // reader passed
21218 this.reader = Roo.factory(this.reader, Roo.data);
21219 this.reader.xmodule = this.xmodule || false;
21220 if(!this.recordType){
21221 this.recordType = this.reader.recordType;
21223 if(this.reader.onMetaChange){
21224 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21228 if(this.recordType){
21229 this.fields = this.recordType.prototype.fields;
21231 this.modified = [];
21235 * @event datachanged
21236 * Fires when the data cache has changed, and a widget which is using this Store
21237 * as a Record cache should refresh its view.
21238 * @param {Store} this
21240 datachanged : true,
21242 * @event metachange
21243 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21244 * @param {Store} this
21245 * @param {Object} meta The JSON metadata
21250 * Fires when Records have been added to the Store
21251 * @param {Store} this
21252 * @param {Roo.data.Record[]} records The array of Records added
21253 * @param {Number} index The index at which the record(s) were added
21258 * Fires when a Record has been removed from the Store
21259 * @param {Store} this
21260 * @param {Roo.data.Record} record The Record that was removed
21261 * @param {Number} index The index at which the record was removed
21266 * Fires when a Record has been updated
21267 * @param {Store} this
21268 * @param {Roo.data.Record} record The Record that was updated
21269 * @param {String} operation The update operation being performed. Value may be one of:
21271 Roo.data.Record.EDIT
21272 Roo.data.Record.REJECT
21273 Roo.data.Record.COMMIT
21279 * Fires when the data cache has been cleared.
21280 * @param {Store} this
21284 * @event beforeload
21285 * Fires before a request is made for a new data object. If the beforeload handler returns false
21286 * the load action will be canceled.
21287 * @param {Store} this
21288 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21292 * @event beforeloadadd
21293 * Fires after a new set of Records has been loaded.
21294 * @param {Store} this
21295 * @param {Roo.data.Record[]} records The Records that were loaded
21296 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21298 beforeloadadd : true,
21301 * Fires after a new set of Records has been loaded, before they are added to the store.
21302 * @param {Store} this
21303 * @param {Roo.data.Record[]} records The Records that were loaded
21304 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21305 * @params {Object} return from reader
21309 * @event loadexception
21310 * Fires if an exception occurs in the Proxy during loading.
21311 * Called with the signature of the Proxy's "loadexception" event.
21312 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21315 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21316 * @param {Object} load options
21317 * @param {Object} jsonData from your request (normally this contains the Exception)
21319 loadexception : true
21323 this.proxy = Roo.factory(this.proxy, Roo.data);
21324 this.proxy.xmodule = this.xmodule || false;
21325 this.relayEvents(this.proxy, ["loadexception"]);
21327 this.sortToggle = {};
21328 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21330 Roo.data.Store.superclass.constructor.call(this);
21332 if(this.inlineData){
21333 this.loadData(this.inlineData);
21334 delete this.inlineData;
21338 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21340 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21341 * without a remote query - used by combo/forms at present.
21345 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21348 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21351 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21352 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21355 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21356 * on any HTTP request
21359 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21362 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21366 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21367 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21369 remoteSort : false,
21372 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21373 * loaded or when a record is removed. (defaults to false).
21375 pruneModifiedRecords : false,
21378 lastOptions : null,
21381 * Add Records to the Store and fires the add event.
21382 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21384 add : function(records){
21385 records = [].concat(records);
21386 for(var i = 0, len = records.length; i < len; i++){
21387 records[i].join(this);
21389 var index = this.data.length;
21390 this.data.addAll(records);
21391 this.fireEvent("add", this, records, index);
21395 * Remove a Record from the Store and fires the remove event.
21396 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21398 remove : function(record){
21399 var index = this.data.indexOf(record);
21400 this.data.removeAt(index);
21401 if(this.pruneModifiedRecords){
21402 this.modified.remove(record);
21404 this.fireEvent("remove", this, record, index);
21408 * Remove all Records from the Store and fires the clear event.
21410 removeAll : function(){
21412 if(this.pruneModifiedRecords){
21413 this.modified = [];
21415 this.fireEvent("clear", this);
21419 * Inserts Records to the Store at the given index and fires the add event.
21420 * @param {Number} index The start index at which to insert the passed Records.
21421 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21423 insert : function(index, records){
21424 records = [].concat(records);
21425 for(var i = 0, len = records.length; i < len; i++){
21426 this.data.insert(index, records[i]);
21427 records[i].join(this);
21429 this.fireEvent("add", this, records, index);
21433 * Get the index within the cache of the passed Record.
21434 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21435 * @return {Number} The index of the passed Record. Returns -1 if not found.
21437 indexOf : function(record){
21438 return this.data.indexOf(record);
21442 * Get the index within the cache of the Record with the passed id.
21443 * @param {String} id The id of the Record to find.
21444 * @return {Number} The index of the Record. Returns -1 if not found.
21446 indexOfId : function(id){
21447 return this.data.indexOfKey(id);
21451 * Get the Record with the specified id.
21452 * @param {String} id The id of the Record to find.
21453 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21455 getById : function(id){
21456 return this.data.key(id);
21460 * Get the Record at the specified index.
21461 * @param {Number} index The index of the Record to find.
21462 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21464 getAt : function(index){
21465 return this.data.itemAt(index);
21469 * Returns a range of Records between specified indices.
21470 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21471 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21472 * @return {Roo.data.Record[]} An array of Records
21474 getRange : function(start, end){
21475 return this.data.getRange(start, end);
21479 storeOptions : function(o){
21480 o = Roo.apply({}, o);
21483 this.lastOptions = o;
21487 * Loads the Record cache from the configured Proxy using the configured Reader.
21489 * If using remote paging, then the first load call must specify the <em>start</em>
21490 * and <em>limit</em> properties in the options.params property to establish the initial
21491 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21493 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21494 * and this call will return before the new data has been loaded. Perform any post-processing
21495 * in a callback function, or in a "load" event handler.</strong>
21497 * @param {Object} options An object containing properties which control loading options:<ul>
21498 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21499 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21500 * passed the following arguments:<ul>
21501 * <li>r : Roo.data.Record[]</li>
21502 * <li>options: Options object from the load call</li>
21503 * <li>success: Boolean success indicator</li></ul></li>
21504 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21505 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21508 load : function(options){
21509 options = options || {};
21510 if(this.fireEvent("beforeload", this, options) !== false){
21511 this.storeOptions(options);
21512 var p = Roo.apply(options.params || {}, this.baseParams);
21513 // if meta was not loaded from remote source.. try requesting it.
21514 if (!this.reader.metaFromRemote) {
21515 p._requestMeta = 1;
21517 if(this.sortInfo && this.remoteSort){
21518 var pn = this.paramNames;
21519 p[pn["sort"]] = this.sortInfo.field;
21520 p[pn["dir"]] = this.sortInfo.direction;
21522 if (this.multiSort) {
21523 var pn = this.paramNames;
21524 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21527 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21532 * Reloads the Record cache from the configured Proxy using the configured Reader and
21533 * the options from the last load operation performed.
21534 * @param {Object} options (optional) An object containing properties which may override the options
21535 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21536 * the most recently used options are reused).
21538 reload : function(options){
21539 this.load(Roo.applyIf(options||{}, this.lastOptions));
21543 // Called as a callback by the Reader during a load operation.
21544 loadRecords : function(o, options, success){
21545 if(!o || success === false){
21546 if(success !== false){
21547 this.fireEvent("load", this, [], options, o);
21549 if(options.callback){
21550 options.callback.call(options.scope || this, [], options, false);
21554 // if data returned failure - throw an exception.
21555 if (o.success === false) {
21556 // show a message if no listener is registered.
21557 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21558 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21560 // loadmask wil be hooked into this..
21561 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21564 var r = o.records, t = o.totalRecords || r.length;
21566 this.fireEvent("beforeloadadd", this, r, options, o);
21568 if(!options || options.add !== true){
21569 if(this.pruneModifiedRecords){
21570 this.modified = [];
21572 for(var i = 0, len = r.length; i < len; i++){
21576 this.data = this.snapshot;
21577 delete this.snapshot;
21580 this.data.addAll(r);
21581 this.totalLength = t;
21583 this.fireEvent("datachanged", this);
21585 this.totalLength = Math.max(t, this.data.length+r.length);
21588 this.fireEvent("load", this, r, options, o);
21589 if(options.callback){
21590 options.callback.call(options.scope || this, r, options, true);
21596 * Loads data from a passed data block. A Reader which understands the format of the data
21597 * must have been configured in the constructor.
21598 * @param {Object} data The data block from which to read the Records. The format of the data expected
21599 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21600 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21602 loadData : function(o, append){
21603 var r = this.reader.readRecords(o);
21604 this.loadRecords(r, {add: append}, true);
21608 * Gets the number of cached records.
21610 * <em>If using paging, this may not be the total size of the dataset. If the data object
21611 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21612 * the data set size</em>
21614 getCount : function(){
21615 return this.data.length || 0;
21619 * Gets the total number of records in the dataset as returned by the server.
21621 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21622 * the dataset size</em>
21624 getTotalCount : function(){
21625 return this.totalLength || 0;
21629 * Returns the sort state of the Store as an object with two properties:
21631 field {String} The name of the field by which the Records are sorted
21632 direction {String} The sort order, "ASC" or "DESC"
21635 getSortState : function(){
21636 return this.sortInfo;
21640 applySort : function(){
21641 if(this.sortInfo && !this.remoteSort){
21642 var s = this.sortInfo, f = s.field;
21643 var st = this.fields.get(f).sortType;
21644 var fn = function(r1, r2){
21645 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21646 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21648 this.data.sort(s.direction, fn);
21649 if(this.snapshot && this.snapshot != this.data){
21650 this.snapshot.sort(s.direction, fn);
21656 * Sets the default sort column and order to be used by the next load operation.
21657 * @param {String} fieldName The name of the field to sort by.
21658 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21660 setDefaultSort : function(field, dir){
21661 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21665 * Sort the Records.
21666 * If remote sorting is used, the sort is performed on the server, and the cache is
21667 * reloaded. If local sorting is used, the cache is sorted internally.
21668 * @param {String} fieldName The name of the field to sort by.
21669 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21671 sort : function(fieldName, dir){
21672 var f = this.fields.get(fieldName);
21674 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21676 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21677 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21682 this.sortToggle[f.name] = dir;
21683 this.sortInfo = {field: f.name, direction: dir};
21684 if(!this.remoteSort){
21686 this.fireEvent("datachanged", this);
21688 this.load(this.lastOptions);
21693 * Calls the specified function for each of the Records in the cache.
21694 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21695 * Returning <em>false</em> aborts and exits the iteration.
21696 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21698 each : function(fn, scope){
21699 this.data.each(fn, scope);
21703 * Gets all records modified since the last commit. Modified records are persisted across load operations
21704 * (e.g., during paging).
21705 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21707 getModifiedRecords : function(){
21708 return this.modified;
21712 createFilterFn : function(property, value, anyMatch){
21713 if(!value.exec){ // not a regex
21714 value = String(value);
21715 if(value.length == 0){
21718 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21720 return function(r){
21721 return value.test(r.data[property]);
21726 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21727 * @param {String} property A field on your records
21728 * @param {Number} start The record index to start at (defaults to 0)
21729 * @param {Number} end The last record index to include (defaults to length - 1)
21730 * @return {Number} The sum
21732 sum : function(property, start, end){
21733 var rs = this.data.items, v = 0;
21734 start = start || 0;
21735 end = (end || end === 0) ? end : rs.length-1;
21737 for(var i = start; i <= end; i++){
21738 v += (rs[i].data[property] || 0);
21744 * Filter the records by a specified property.
21745 * @param {String} field A field on your records
21746 * @param {String/RegExp} value Either a string that the field
21747 * should start with or a RegExp to test against the field
21748 * @param {Boolean} anyMatch True to match any part not just the beginning
21750 filter : function(property, value, anyMatch){
21751 var fn = this.createFilterFn(property, value, anyMatch);
21752 return fn ? this.filterBy(fn) : this.clearFilter();
21756 * Filter by a function. The specified function will be called with each
21757 * record in this data source. If the function returns true the record is included,
21758 * otherwise it is filtered.
21759 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21760 * @param {Object} scope (optional) The scope of the function (defaults to this)
21762 filterBy : function(fn, scope){
21763 this.snapshot = this.snapshot || this.data;
21764 this.data = this.queryBy(fn, scope||this);
21765 this.fireEvent("datachanged", this);
21769 * Query the records by a specified property.
21770 * @param {String} field A field on your records
21771 * @param {String/RegExp} value Either a string that the field
21772 * should start with or a RegExp to test against the field
21773 * @param {Boolean} anyMatch True to match any part not just the beginning
21774 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21776 query : function(property, value, anyMatch){
21777 var fn = this.createFilterFn(property, value, anyMatch);
21778 return fn ? this.queryBy(fn) : this.data.clone();
21782 * Query by a function. The specified function will be called with each
21783 * record in this data source. If the function returns true the record is included
21785 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21786 * @param {Object} scope (optional) The scope of the function (defaults to this)
21787 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21789 queryBy : function(fn, scope){
21790 var data = this.snapshot || this.data;
21791 return data.filterBy(fn, scope||this);
21795 * Collects unique values for a particular dataIndex from this store.
21796 * @param {String} dataIndex The property to collect
21797 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21798 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21799 * @return {Array} An array of the unique values
21801 collect : function(dataIndex, allowNull, bypassFilter){
21802 var d = (bypassFilter === true && this.snapshot) ?
21803 this.snapshot.items : this.data.items;
21804 var v, sv, r = [], l = {};
21805 for(var i = 0, len = d.length; i < len; i++){
21806 v = d[i].data[dataIndex];
21808 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21817 * Revert to a view of the Record cache with no filtering applied.
21818 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21820 clearFilter : function(suppressEvent){
21821 if(this.snapshot && this.snapshot != this.data){
21822 this.data = this.snapshot;
21823 delete this.snapshot;
21824 if(suppressEvent !== true){
21825 this.fireEvent("datachanged", this);
21831 afterEdit : function(record){
21832 if(this.modified.indexOf(record) == -1){
21833 this.modified.push(record);
21835 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21839 afterReject : function(record){
21840 this.modified.remove(record);
21841 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21845 afterCommit : function(record){
21846 this.modified.remove(record);
21847 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21851 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21852 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21854 commitChanges : function(){
21855 var m = this.modified.slice(0);
21856 this.modified = [];
21857 for(var i = 0, len = m.length; i < len; i++){
21863 * Cancel outstanding changes on all changed records.
21865 rejectChanges : function(){
21866 var m = this.modified.slice(0);
21867 this.modified = [];
21868 for(var i = 0, len = m.length; i < len; i++){
21873 onMetaChange : function(meta, rtype, o){
21874 this.recordType = rtype;
21875 this.fields = rtype.prototype.fields;
21876 delete this.snapshot;
21877 this.sortInfo = meta.sortInfo || this.sortInfo;
21878 this.modified = [];
21879 this.fireEvent('metachange', this, this.reader.meta);
21882 moveIndex : function(data, type)
21884 var index = this.indexOf(data);
21886 var newIndex = index + type;
21890 this.insert(newIndex, data);
21895 * Ext JS Library 1.1.1
21896 * Copyright(c) 2006-2007, Ext JS, LLC.
21898 * Originally Released Under LGPL - original licence link has changed is not relivant.
21901 * <script type="text/javascript">
21905 * @class Roo.data.SimpleStore
21906 * @extends Roo.data.Store
21907 * Small helper class to make creating Stores from Array data easier.
21908 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21909 * @cfg {Array} fields An array of field definition objects, or field name strings.
21910 * @cfg {Array} data The multi-dimensional array of data
21912 * @param {Object} config
21914 Roo.data.SimpleStore = function(config){
21915 Roo.data.SimpleStore.superclass.constructor.call(this, {
21917 reader: new Roo.data.ArrayReader({
21920 Roo.data.Record.create(config.fields)
21922 proxy : new Roo.data.MemoryProxy(config.data)
21926 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21928 * Ext JS Library 1.1.1
21929 * Copyright(c) 2006-2007, Ext JS, LLC.
21931 * Originally Released Under LGPL - original licence link has changed is not relivant.
21934 * <script type="text/javascript">
21939 * @extends Roo.data.Store
21940 * @class Roo.data.JsonStore
21941 * Small helper class to make creating Stores for JSON data easier. <br/>
21943 var store = new Roo.data.JsonStore({
21944 url: 'get-images.php',
21946 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21949 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21950 * JsonReader and HttpProxy (unless inline data is provided).</b>
21951 * @cfg {Array} fields An array of field definition objects, or field name strings.
21953 * @param {Object} config
21955 Roo.data.JsonStore = function(c){
21956 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21957 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21958 reader: new Roo.data.JsonReader(c, c.fields)
21961 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21963 * Ext JS Library 1.1.1
21964 * Copyright(c) 2006-2007, Ext JS, LLC.
21966 * Originally Released Under LGPL - original licence link has changed is not relivant.
21969 * <script type="text/javascript">
21973 Roo.data.Field = function(config){
21974 if(typeof config == "string"){
21975 config = {name: config};
21977 Roo.apply(this, config);
21980 this.type = "auto";
21983 var st = Roo.data.SortTypes;
21984 // named sortTypes are supported, here we look them up
21985 if(typeof this.sortType == "string"){
21986 this.sortType = st[this.sortType];
21989 // set default sortType for strings and dates
21990 if(!this.sortType){
21993 this.sortType = st.asUCString;
21996 this.sortType = st.asDate;
21999 this.sortType = st.none;
22004 var stripRe = /[\$,%]/g;
22006 // prebuilt conversion function for this field, instead of
22007 // switching every time we're reading a value
22009 var cv, dateFormat = this.dateFormat;
22014 cv = function(v){ return v; };
22017 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
22021 return v !== undefined && v !== null && v !== '' ?
22022 parseInt(String(v).replace(stripRe, ""), 10) : '';
22027 return v !== undefined && v !== null && v !== '' ?
22028 parseFloat(String(v).replace(stripRe, ""), 10) : '';
22033 cv = function(v){ return v === true || v === "true" || v == 1; };
22040 if(v instanceof Date){
22044 if(dateFormat == "timestamp"){
22045 return new Date(v*1000);
22047 return Date.parseDate(v, dateFormat);
22049 var parsed = Date.parse(v);
22050 return parsed ? new Date(parsed) : null;
22059 Roo.data.Field.prototype = {
22067 * Ext JS Library 1.1.1
22068 * Copyright(c) 2006-2007, Ext JS, LLC.
22070 * Originally Released Under LGPL - original licence link has changed is not relivant.
22073 * <script type="text/javascript">
22076 // Base class for reading structured data from a data source. This class is intended to be
22077 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
22080 * @class Roo.data.DataReader
22081 * Base class for reading structured data from a data source. This class is intended to be
22082 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
22085 Roo.data.DataReader = function(meta, recordType){
22089 this.recordType = recordType instanceof Array ?
22090 Roo.data.Record.create(recordType) : recordType;
22093 Roo.data.DataReader.prototype = {
22095 * Create an empty record
22096 * @param {Object} data (optional) - overlay some values
22097 * @return {Roo.data.Record} record created.
22099 newRow : function(d) {
22101 this.recordType.prototype.fields.each(function(c) {
22103 case 'int' : da[c.name] = 0; break;
22104 case 'date' : da[c.name] = new Date(); break;
22105 case 'float' : da[c.name] = 0.0; break;
22106 case 'boolean' : da[c.name] = false; break;
22107 default : da[c.name] = ""; break;
22111 return new this.recordType(Roo.apply(da, d));
22116 * Ext JS Library 1.1.1
22117 * Copyright(c) 2006-2007, Ext JS, LLC.
22119 * Originally Released Under LGPL - original licence link has changed is not relivant.
22122 * <script type="text/javascript">
22126 * @class Roo.data.DataProxy
22127 * @extends Roo.data.Observable
22128 * This class is an abstract base class for implementations which provide retrieval of
22129 * unformatted data objects.<br>
22131 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
22132 * (of the appropriate type which knows how to parse the data object) to provide a block of
22133 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
22135 * Custom implementations must implement the load method as described in
22136 * {@link Roo.data.HttpProxy#load}.
22138 Roo.data.DataProxy = function(){
22141 * @event beforeload
22142 * Fires before a network request is made to retrieve a data object.
22143 * @param {Object} This DataProxy object.
22144 * @param {Object} params The params parameter to the load function.
22149 * Fires before the load method's callback is called.
22150 * @param {Object} This DataProxy object.
22151 * @param {Object} o The data object.
22152 * @param {Object} arg The callback argument object passed to the load function.
22156 * @event loadexception
22157 * Fires if an Exception occurs during data retrieval.
22158 * @param {Object} This DataProxy object.
22159 * @param {Object} o The data object.
22160 * @param {Object} arg The callback argument object passed to the load function.
22161 * @param {Object} e The Exception.
22163 loadexception : true
22165 Roo.data.DataProxy.superclass.constructor.call(this);
22168 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22171 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22175 * Ext JS Library 1.1.1
22176 * Copyright(c) 2006-2007, Ext JS, LLC.
22178 * Originally Released Under LGPL - original licence link has changed is not relivant.
22181 * <script type="text/javascript">
22184 * @class Roo.data.MemoryProxy
22185 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22186 * to the Reader when its load method is called.
22188 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22190 Roo.data.MemoryProxy = function(data){
22194 Roo.data.MemoryProxy.superclass.constructor.call(this);
22198 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22200 * Load data from the requested source (in this case an in-memory
22201 * data object passed to the constructor), read the data object into
22202 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22203 * process that block using the passed callback.
22204 * @param {Object} params This parameter is not used by the MemoryProxy class.
22205 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22206 * object into a block of Roo.data.Records.
22207 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22208 * The function must be passed <ul>
22209 * <li>The Record block object</li>
22210 * <li>The "arg" argument from the load function</li>
22211 * <li>A boolean success indicator</li>
22213 * @param {Object} scope The scope in which to call the callback
22214 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22216 load : function(params, reader, callback, scope, arg){
22217 params = params || {};
22220 result = reader.readRecords(this.data);
22222 this.fireEvent("loadexception", this, arg, null, e);
22223 callback.call(scope, null, arg, false);
22226 callback.call(scope, result, arg, true);
22230 update : function(params, records){
22235 * Ext JS Library 1.1.1
22236 * Copyright(c) 2006-2007, Ext JS, LLC.
22238 * Originally Released Under LGPL - original licence link has changed is not relivant.
22241 * <script type="text/javascript">
22244 * @class Roo.data.HttpProxy
22245 * @extends Roo.data.DataProxy
22246 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22247 * configured to reference a certain URL.<br><br>
22249 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22250 * from which the running page was served.<br><br>
22252 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22254 * Be aware that to enable the browser to parse an XML document, the server must set
22255 * the Content-Type header in the HTTP response to "text/xml".
22257 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22258 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22259 * will be used to make the request.
22261 Roo.data.HttpProxy = function(conn){
22262 Roo.data.HttpProxy.superclass.constructor.call(this);
22263 // is conn a conn config or a real conn?
22265 this.useAjax = !conn || !conn.events;
22269 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22270 // thse are take from connection...
22273 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22276 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22277 * extra parameters to each request made by this object. (defaults to undefined)
22280 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22281 * to each request made by this object. (defaults to undefined)
22284 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
22287 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22290 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22296 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22300 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22301 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22302 * a finer-grained basis than the DataProxy events.
22304 getConnection : function(){
22305 return this.useAjax ? Roo.Ajax : this.conn;
22309 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22310 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22311 * process that block using the passed callback.
22312 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22313 * for the request to the remote server.
22314 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22315 * object into a block of Roo.data.Records.
22316 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22317 * The function must be passed <ul>
22318 * <li>The Record block object</li>
22319 * <li>The "arg" argument from the load function</li>
22320 * <li>A boolean success indicator</li>
22322 * @param {Object} scope The scope in which to call the callback
22323 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22325 load : function(params, reader, callback, scope, arg){
22326 if(this.fireEvent("beforeload", this, params) !== false){
22328 params : params || {},
22330 callback : callback,
22335 callback : this.loadResponse,
22339 Roo.applyIf(o, this.conn);
22340 if(this.activeRequest){
22341 Roo.Ajax.abort(this.activeRequest);
22343 this.activeRequest = Roo.Ajax.request(o);
22345 this.conn.request(o);
22348 callback.call(scope||this, null, arg, false);
22353 loadResponse : function(o, success, response){
22354 delete this.activeRequest;
22356 this.fireEvent("loadexception", this, o, response);
22357 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22362 result = o.reader.read(response);
22364 this.fireEvent("loadexception", this, o, response, e);
22365 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22369 this.fireEvent("load", this, o, o.request.arg);
22370 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22374 update : function(dataSet){
22379 updateResponse : function(dataSet){
22384 * Ext JS Library 1.1.1
22385 * Copyright(c) 2006-2007, Ext JS, LLC.
22387 * Originally Released Under LGPL - original licence link has changed is not relivant.
22390 * <script type="text/javascript">
22394 * @class Roo.data.ScriptTagProxy
22395 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22396 * other than the originating domain of the running page.<br><br>
22398 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
22399 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22401 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22402 * source code that is used as the source inside a <script> tag.<br><br>
22404 * In order for the browser to process the returned data, the server must wrap the data object
22405 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22406 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22407 * depending on whether the callback name was passed:
22410 boolean scriptTag = false;
22411 String cb = request.getParameter("callback");
22414 response.setContentType("text/javascript");
22416 response.setContentType("application/x-json");
22418 Writer out = response.getWriter();
22420 out.write(cb + "(");
22422 out.print(dataBlock.toJsonString());
22429 * @param {Object} config A configuration object.
22431 Roo.data.ScriptTagProxy = function(config){
22432 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22433 Roo.apply(this, config);
22434 this.head = document.getElementsByTagName("head")[0];
22437 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22439 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22441 * @cfg {String} url The URL from which to request the data object.
22444 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22448 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22449 * the server the name of the callback function set up by the load call to process the returned data object.
22450 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22451 * javascript output which calls this named function passing the data object as its only parameter.
22453 callbackParam : "callback",
22455 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22456 * name to the request.
22461 * Load data from the configured URL, read the data object into
22462 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22463 * process that block using the passed callback.
22464 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22465 * for the request to the remote server.
22466 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22467 * object into a block of Roo.data.Records.
22468 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22469 * The function must be passed <ul>
22470 * <li>The Record block object</li>
22471 * <li>The "arg" argument from the load function</li>
22472 * <li>A boolean success indicator</li>
22474 * @param {Object} scope The scope in which to call the callback
22475 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22477 load : function(params, reader, callback, scope, arg){
22478 if(this.fireEvent("beforeload", this, params) !== false){
22480 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22482 var url = this.url;
22483 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22485 url += "&_dc=" + (new Date().getTime());
22487 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22490 cb : "stcCallback"+transId,
22491 scriptId : "stcScript"+transId,
22495 callback : callback,
22501 window[trans.cb] = function(o){
22502 conn.handleResponse(o, trans);
22505 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22507 if(this.autoAbort !== false){
22511 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22513 var script = document.createElement("script");
22514 script.setAttribute("src", url);
22515 script.setAttribute("type", "text/javascript");
22516 script.setAttribute("id", trans.scriptId);
22517 this.head.appendChild(script);
22519 this.trans = trans;
22521 callback.call(scope||this, null, arg, false);
22526 isLoading : function(){
22527 return this.trans ? true : false;
22531 * Abort the current server request.
22533 abort : function(){
22534 if(this.isLoading()){
22535 this.destroyTrans(this.trans);
22540 destroyTrans : function(trans, isLoaded){
22541 this.head.removeChild(document.getElementById(trans.scriptId));
22542 clearTimeout(trans.timeoutId);
22544 window[trans.cb] = undefined;
22546 delete window[trans.cb];
22549 // if hasn't been loaded, wait for load to remove it to prevent script error
22550 window[trans.cb] = function(){
22551 window[trans.cb] = undefined;
22553 delete window[trans.cb];
22560 handleResponse : function(o, trans){
22561 this.trans = false;
22562 this.destroyTrans(trans, true);
22565 result = trans.reader.readRecords(o);
22567 this.fireEvent("loadexception", this, o, trans.arg, e);
22568 trans.callback.call(trans.scope||window, null, trans.arg, false);
22571 this.fireEvent("load", this, o, trans.arg);
22572 trans.callback.call(trans.scope||window, result, trans.arg, true);
22576 handleFailure : function(trans){
22577 this.trans = false;
22578 this.destroyTrans(trans, false);
22579 this.fireEvent("loadexception", this, null, trans.arg);
22580 trans.callback.call(trans.scope||window, null, trans.arg, false);
22584 * Ext JS Library 1.1.1
22585 * Copyright(c) 2006-2007, Ext JS, LLC.
22587 * Originally Released Under LGPL - original licence link has changed is not relivant.
22590 * <script type="text/javascript">
22594 * @class Roo.data.JsonReader
22595 * @extends Roo.data.DataReader
22596 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22597 * based on mappings in a provided Roo.data.Record constructor.
22599 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22600 * in the reply previously.
22605 var RecordDef = Roo.data.Record.create([
22606 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22607 {name: 'occupation'} // This field will use "occupation" as the mapping.
22609 var myReader = new Roo.data.JsonReader({
22610 totalProperty: "results", // The property which contains the total dataset size (optional)
22611 root: "rows", // The property which contains an Array of row objects
22612 id: "id" // The property within each row object that provides an ID for the record (optional)
22616 * This would consume a JSON file like this:
22618 { 'results': 2, 'rows': [
22619 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22620 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22623 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22624 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22625 * paged from the remote server.
22626 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22627 * @cfg {String} root name of the property which contains the Array of row objects.
22628 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22629 * @cfg {Array} fields Array of field definition objects
22631 * Create a new JsonReader
22632 * @param {Object} meta Metadata configuration options
22633 * @param {Object} recordType Either an Array of field definition objects,
22634 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22636 Roo.data.JsonReader = function(meta, recordType){
22639 // set some defaults:
22640 Roo.applyIf(meta, {
22641 totalProperty: 'total',
22642 successProperty : 'success',
22647 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22649 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22652 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22653 * Used by Store query builder to append _requestMeta to params.
22656 metaFromRemote : false,
22658 * This method is only used by a DataProxy which has retrieved data from a remote server.
22659 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22660 * @return {Object} data A data block which is used by an Roo.data.Store object as
22661 * a cache of Roo.data.Records.
22663 read : function(response){
22664 var json = response.responseText;
22666 var o = /* eval:var:o */ eval("("+json+")");
22668 throw {message: "JsonReader.read: Json object not found"};
22674 this.metaFromRemote = true;
22675 this.meta = o.metaData;
22676 this.recordType = Roo.data.Record.create(o.metaData.fields);
22677 this.onMetaChange(this.meta, this.recordType, o);
22679 return this.readRecords(o);
22682 // private function a store will implement
22683 onMetaChange : function(meta, recordType, o){
22690 simpleAccess: function(obj, subsc) {
22697 getJsonAccessor: function(){
22699 return function(expr) {
22701 return(re.test(expr))
22702 ? new Function("obj", "return obj." + expr)
22707 return Roo.emptyFn;
22712 * Create a data block containing Roo.data.Records from an XML document.
22713 * @param {Object} o An object which contains an Array of row objects in the property specified
22714 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22715 * which contains the total size of the dataset.
22716 * @return {Object} data A data block which is used by an Roo.data.Store object as
22717 * a cache of Roo.data.Records.
22719 readRecords : function(o){
22721 * After any data loads, the raw JSON data is available for further custom processing.
22725 var s = this.meta, Record = this.recordType,
22726 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
22728 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22730 if(s.totalProperty) {
22731 this.getTotal = this.getJsonAccessor(s.totalProperty);
22733 if(s.successProperty) {
22734 this.getSuccess = this.getJsonAccessor(s.successProperty);
22736 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22738 var g = this.getJsonAccessor(s.id);
22739 this.getId = function(rec) {
22741 return (r === undefined || r === "") ? null : r;
22744 this.getId = function(){return null;};
22747 for(var jj = 0; jj < fl; jj++){
22749 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22750 this.ef[jj] = this.getJsonAccessor(map);
22754 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22755 if(s.totalProperty){
22756 var vt = parseInt(this.getTotal(o), 10);
22761 if(s.successProperty){
22762 var vs = this.getSuccess(o);
22763 if(vs === false || vs === 'false'){
22768 for(var i = 0; i < c; i++){
22771 var id = this.getId(n);
22772 for(var j = 0; j < fl; j++){
22774 var v = this.ef[j](n);
22776 Roo.log('missing convert for ' + f.name);
22780 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22782 var record = new Record(values, id);
22784 records[i] = record;
22790 totalRecords : totalRecords
22795 * Ext JS Library 1.1.1
22796 * Copyright(c) 2006-2007, Ext JS, LLC.
22798 * Originally Released Under LGPL - original licence link has changed is not relivant.
22801 * <script type="text/javascript">
22805 * @class Roo.data.XmlReader
22806 * @extends Roo.data.DataReader
22807 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22808 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22810 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22811 * header in the HTTP response must be set to "text/xml".</em>
22815 var RecordDef = Roo.data.Record.create([
22816 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22817 {name: 'occupation'} // This field will use "occupation" as the mapping.
22819 var myReader = new Roo.data.XmlReader({
22820 totalRecords: "results", // The element which contains the total dataset size (optional)
22821 record: "row", // The repeated element which contains row information
22822 id: "id" // The element within the row that provides an ID for the record (optional)
22826 * This would consume an XML file like this:
22830 <results>2</results>
22833 <name>Bill</name>
22834 <occupation>Gardener</occupation>
22838 <name>Ben</name>
22839 <occupation>Horticulturalist</occupation>
22843 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22844 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22845 * paged from the remote server.
22846 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22847 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22848 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22849 * a record identifier value.
22851 * Create a new XmlReader
22852 * @param {Object} meta Metadata configuration options
22853 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22854 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22855 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22857 Roo.data.XmlReader = function(meta, recordType){
22859 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22861 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22863 * This method is only used by a DataProxy which has retrieved data from a remote server.
22864 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22865 * to contain a method called 'responseXML' that returns an XML document object.
22866 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22867 * a cache of Roo.data.Records.
22869 read : function(response){
22870 var doc = response.responseXML;
22872 throw {message: "XmlReader.read: XML Document not available"};
22874 return this.readRecords(doc);
22878 * Create a data block containing Roo.data.Records from an XML document.
22879 * @param {Object} doc A parsed XML document.
22880 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22881 * a cache of Roo.data.Records.
22883 readRecords : function(doc){
22885 * After any data loads/reads, the raw XML Document is available for further custom processing.
22886 * @type XMLDocument
22888 this.xmlData = doc;
22889 var root = doc.documentElement || doc;
22890 var q = Roo.DomQuery;
22891 var recordType = this.recordType, fields = recordType.prototype.fields;
22892 var sid = this.meta.id;
22893 var totalRecords = 0, success = true;
22894 if(this.meta.totalRecords){
22895 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22898 if(this.meta.success){
22899 var sv = q.selectValue(this.meta.success, root, true);
22900 success = sv !== false && sv !== 'false';
22903 var ns = q.select(this.meta.record, root);
22904 for(var i = 0, len = ns.length; i < len; i++) {
22907 var id = sid ? q.selectValue(sid, n) : undefined;
22908 for(var j = 0, jlen = fields.length; j < jlen; j++){
22909 var f = fields.items[j];
22910 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22912 values[f.name] = v;
22914 var record = new recordType(values, id);
22916 records[records.length] = record;
22922 totalRecords : totalRecords || records.length
22927 * Ext JS Library 1.1.1
22928 * Copyright(c) 2006-2007, Ext JS, LLC.
22930 * Originally Released Under LGPL - original licence link has changed is not relivant.
22933 * <script type="text/javascript">
22937 * @class Roo.data.ArrayReader
22938 * @extends Roo.data.DataReader
22939 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22940 * Each element of that Array represents a row of data fields. The
22941 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22942 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22946 var RecordDef = Roo.data.Record.create([
22947 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22948 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22950 var myReader = new Roo.data.ArrayReader({
22951 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22955 * This would consume an Array like this:
22957 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22959 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22961 * Create a new JsonReader
22962 * @param {Object} meta Metadata configuration options.
22963 * @param {Object} recordType Either an Array of field definition objects
22964 * as specified to {@link Roo.data.Record#create},
22965 * or an {@link Roo.data.Record} object
22966 * created using {@link Roo.data.Record#create}.
22968 Roo.data.ArrayReader = function(meta, recordType){
22969 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22972 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22974 * Create a data block containing Roo.data.Records from an XML document.
22975 * @param {Object} o An Array of row objects which represents the dataset.
22976 * @return {Object} data A data block which is used by an Roo.data.Store object as
22977 * a cache of Roo.data.Records.
22979 readRecords : function(o){
22980 var sid = this.meta ? this.meta.id : null;
22981 var recordType = this.recordType, fields = recordType.prototype.fields;
22984 for(var i = 0; i < root.length; i++){
22987 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22988 for(var j = 0, jlen = fields.length; j < jlen; j++){
22989 var f = fields.items[j];
22990 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22991 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22993 values[f.name] = v;
22995 var record = new recordType(values, id);
22997 records[records.length] = record;
23001 totalRecords : records.length
23006 * Ext JS Library 1.1.1
23007 * Copyright(c) 2006-2007, Ext JS, LLC.
23009 * Originally Released Under LGPL - original licence link has changed is not relivant.
23012 * <script type="text/javascript">
23017 * @class Roo.data.Tree
23018 * @extends Roo.util.Observable
23019 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
23020 * in the tree have most standard DOM functionality.
23022 * @param {Node} root (optional) The root node
23024 Roo.data.Tree = function(root){
23025 this.nodeHash = {};
23027 * The root node for this tree
23032 this.setRootNode(root);
23037 * Fires when a new child node is appended to a node in this tree.
23038 * @param {Tree} tree The owner tree
23039 * @param {Node} parent The parent node
23040 * @param {Node} node The newly appended node
23041 * @param {Number} index The index of the newly appended node
23046 * Fires when a child node is removed from a node in this tree.
23047 * @param {Tree} tree The owner tree
23048 * @param {Node} parent The parent node
23049 * @param {Node} node The child node removed
23054 * Fires when a node is moved to a new location in the tree
23055 * @param {Tree} tree The owner tree
23056 * @param {Node} node The node moved
23057 * @param {Node} oldParent The old parent of this node
23058 * @param {Node} newParent The new parent of this node
23059 * @param {Number} index The index it was moved to
23064 * Fires when a new child node is inserted in a node in this tree.
23065 * @param {Tree} tree The owner tree
23066 * @param {Node} parent The parent node
23067 * @param {Node} node The child node inserted
23068 * @param {Node} refNode The child node the node was inserted before
23072 * @event beforeappend
23073 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
23074 * @param {Tree} tree The owner tree
23075 * @param {Node} parent The parent node
23076 * @param {Node} node The child node to be appended
23078 "beforeappend" : true,
23080 * @event beforeremove
23081 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
23082 * @param {Tree} tree The owner tree
23083 * @param {Node} parent The parent node
23084 * @param {Node} node The child node to be removed
23086 "beforeremove" : true,
23088 * @event beforemove
23089 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
23090 * @param {Tree} tree The owner tree
23091 * @param {Node} node The node being moved
23092 * @param {Node} oldParent The parent of the node
23093 * @param {Node} newParent The new parent the node is moving to
23094 * @param {Number} index The index it is being moved to
23096 "beforemove" : true,
23098 * @event beforeinsert
23099 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
23100 * @param {Tree} tree The owner tree
23101 * @param {Node} parent The parent node
23102 * @param {Node} node The child node to be inserted
23103 * @param {Node} refNode The child node the node is being inserted before
23105 "beforeinsert" : true
23108 Roo.data.Tree.superclass.constructor.call(this);
23111 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
23112 pathSeparator: "/",
23114 proxyNodeEvent : function(){
23115 return this.fireEvent.apply(this, arguments);
23119 * Returns the root node for this tree.
23122 getRootNode : function(){
23127 * Sets the root node for this tree.
23128 * @param {Node} node
23131 setRootNode : function(node){
23133 node.ownerTree = this;
23134 node.isRoot = true;
23135 this.registerNode(node);
23140 * Gets a node in this tree by its id.
23141 * @param {String} id
23144 getNodeById : function(id){
23145 return this.nodeHash[id];
23148 registerNode : function(node){
23149 this.nodeHash[node.id] = node;
23152 unregisterNode : function(node){
23153 delete this.nodeHash[node.id];
23156 toString : function(){
23157 return "[Tree"+(this.id?" "+this.id:"")+"]";
23162 * @class Roo.data.Node
23163 * @extends Roo.util.Observable
23164 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23165 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23167 * @param {Object} attributes The attributes/config for the node
23169 Roo.data.Node = function(attributes){
23171 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23174 this.attributes = attributes || {};
23175 this.leaf = this.attributes.leaf;
23177 * The node id. @type String
23179 this.id = this.attributes.id;
23181 this.id = Roo.id(null, "ynode-");
23182 this.attributes.id = this.id;
23187 * All child nodes of this node. @type Array
23189 this.childNodes = [];
23190 if(!this.childNodes.indexOf){ // indexOf is a must
23191 this.childNodes.indexOf = function(o){
23192 for(var i = 0, len = this.length; i < len; i++){
23201 * The parent node for this node. @type Node
23203 this.parentNode = null;
23205 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23207 this.firstChild = null;
23209 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23211 this.lastChild = null;
23213 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23215 this.previousSibling = null;
23217 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23219 this.nextSibling = null;
23224 * Fires when a new child node is appended
23225 * @param {Tree} tree The owner tree
23226 * @param {Node} this This node
23227 * @param {Node} node The newly appended node
23228 * @param {Number} index The index of the newly appended node
23233 * Fires when a child node is removed
23234 * @param {Tree} tree The owner tree
23235 * @param {Node} this This node
23236 * @param {Node} node The removed node
23241 * Fires when this node is moved to a new location in the tree
23242 * @param {Tree} tree The owner tree
23243 * @param {Node} this This node
23244 * @param {Node} oldParent The old parent of this node
23245 * @param {Node} newParent The new parent of this node
23246 * @param {Number} index The index it was moved to
23251 * Fires when a new child node is inserted.
23252 * @param {Tree} tree The owner tree
23253 * @param {Node} this This node
23254 * @param {Node} node The child node inserted
23255 * @param {Node} refNode The child node the node was inserted before
23259 * @event beforeappend
23260 * Fires before a new child is appended, return false to cancel the append.
23261 * @param {Tree} tree The owner tree
23262 * @param {Node} this This node
23263 * @param {Node} node The child node to be appended
23265 "beforeappend" : true,
23267 * @event beforeremove
23268 * Fires before a child is removed, return false to cancel the remove.
23269 * @param {Tree} tree The owner tree
23270 * @param {Node} this This node
23271 * @param {Node} node The child node to be removed
23273 "beforeremove" : true,
23275 * @event beforemove
23276 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23277 * @param {Tree} tree The owner tree
23278 * @param {Node} this This node
23279 * @param {Node} oldParent The parent of this node
23280 * @param {Node} newParent The new parent this node is moving to
23281 * @param {Number} index The index it is being moved to
23283 "beforemove" : true,
23285 * @event beforeinsert
23286 * Fires before a new child is inserted, return false to cancel the insert.
23287 * @param {Tree} tree The owner tree
23288 * @param {Node} this This node
23289 * @param {Node} node The child node to be inserted
23290 * @param {Node} refNode The child node the node is being inserted before
23292 "beforeinsert" : true
23294 this.listeners = this.attributes.listeners;
23295 Roo.data.Node.superclass.constructor.call(this);
23298 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23299 fireEvent : function(evtName){
23300 // first do standard event for this node
23301 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23304 // then bubble it up to the tree if the event wasn't cancelled
23305 var ot = this.getOwnerTree();
23307 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23315 * Returns true if this node is a leaf
23316 * @return {Boolean}
23318 isLeaf : function(){
23319 return this.leaf === true;
23323 setFirstChild : function(node){
23324 this.firstChild = node;
23328 setLastChild : function(node){
23329 this.lastChild = node;
23334 * Returns true if this node is the last child of its parent
23335 * @return {Boolean}
23337 isLast : function(){
23338 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23342 * Returns true if this node is the first child of its parent
23343 * @return {Boolean}
23345 isFirst : function(){
23346 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23349 hasChildNodes : function(){
23350 return !this.isLeaf() && this.childNodes.length > 0;
23354 * Insert node(s) as the last child node of this node.
23355 * @param {Node/Array} node The node or Array of nodes to append
23356 * @return {Node} The appended node if single append, or null if an array was passed
23358 appendChild : function(node){
23360 if(node instanceof Array){
23362 }else if(arguments.length > 1){
23365 // if passed an array or multiple args do them one by one
23367 for(var i = 0, len = multi.length; i < len; i++) {
23368 this.appendChild(multi[i]);
23371 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23374 var index = this.childNodes.length;
23375 var oldParent = node.parentNode;
23376 // it's a move, make sure we move it cleanly
23378 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23381 oldParent.removeChild(node);
23383 index = this.childNodes.length;
23385 this.setFirstChild(node);
23387 this.childNodes.push(node);
23388 node.parentNode = this;
23389 var ps = this.childNodes[index-1];
23391 node.previousSibling = ps;
23392 ps.nextSibling = node;
23394 node.previousSibling = null;
23396 node.nextSibling = null;
23397 this.setLastChild(node);
23398 node.setOwnerTree(this.getOwnerTree());
23399 this.fireEvent("append", this.ownerTree, this, node, index);
23401 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23408 * Removes a child node from this node.
23409 * @param {Node} node The node to remove
23410 * @return {Node} The removed node
23412 removeChild : function(node){
23413 var index = this.childNodes.indexOf(node);
23417 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23421 // remove it from childNodes collection
23422 this.childNodes.splice(index, 1);
23425 if(node.previousSibling){
23426 node.previousSibling.nextSibling = node.nextSibling;
23428 if(node.nextSibling){
23429 node.nextSibling.previousSibling = node.previousSibling;
23432 // update child refs
23433 if(this.firstChild == node){
23434 this.setFirstChild(node.nextSibling);
23436 if(this.lastChild == node){
23437 this.setLastChild(node.previousSibling);
23440 node.setOwnerTree(null);
23441 // clear any references from the node
23442 node.parentNode = null;
23443 node.previousSibling = null;
23444 node.nextSibling = null;
23445 this.fireEvent("remove", this.ownerTree, this, node);
23450 * Inserts the first node before the second node in this nodes childNodes collection.
23451 * @param {Node} node The node to insert
23452 * @param {Node} refNode The node to insert before (if null the node is appended)
23453 * @return {Node} The inserted node
23455 insertBefore : function(node, refNode){
23456 if(!refNode){ // like standard Dom, refNode can be null for append
23457 return this.appendChild(node);
23460 if(node == refNode){
23464 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23467 var index = this.childNodes.indexOf(refNode);
23468 var oldParent = node.parentNode;
23469 var refIndex = index;
23471 // when moving internally, indexes will change after remove
23472 if(oldParent == this && this.childNodes.indexOf(node) < index){
23476 // it's a move, make sure we move it cleanly
23478 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23481 oldParent.removeChild(node);
23484 this.setFirstChild(node);
23486 this.childNodes.splice(refIndex, 0, node);
23487 node.parentNode = this;
23488 var ps = this.childNodes[refIndex-1];
23490 node.previousSibling = ps;
23491 ps.nextSibling = node;
23493 node.previousSibling = null;
23495 node.nextSibling = refNode;
23496 refNode.previousSibling = node;
23497 node.setOwnerTree(this.getOwnerTree());
23498 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23500 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23506 * Returns the child node at the specified index.
23507 * @param {Number} index
23510 item : function(index){
23511 return this.childNodes[index];
23515 * Replaces one child node in this node with another.
23516 * @param {Node} newChild The replacement node
23517 * @param {Node} oldChild The node to replace
23518 * @return {Node} The replaced node
23520 replaceChild : function(newChild, oldChild){
23521 this.insertBefore(newChild, oldChild);
23522 this.removeChild(oldChild);
23527 * Returns the index of a child node
23528 * @param {Node} node
23529 * @return {Number} The index of the node or -1 if it was not found
23531 indexOf : function(child){
23532 return this.childNodes.indexOf(child);
23536 * Returns the tree this node is in.
23539 getOwnerTree : function(){
23540 // if it doesn't have one, look for one
23541 if(!this.ownerTree){
23545 this.ownerTree = p.ownerTree;
23551 return this.ownerTree;
23555 * Returns depth of this node (the root node has a depth of 0)
23558 getDepth : function(){
23561 while(p.parentNode){
23569 setOwnerTree : function(tree){
23570 // if it's move, we need to update everyone
23571 if(tree != this.ownerTree){
23572 if(this.ownerTree){
23573 this.ownerTree.unregisterNode(this);
23575 this.ownerTree = tree;
23576 var cs = this.childNodes;
23577 for(var i = 0, len = cs.length; i < len; i++) {
23578 cs[i].setOwnerTree(tree);
23581 tree.registerNode(this);
23587 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23588 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23589 * @return {String} The path
23591 getPath : function(attr){
23592 attr = attr || "id";
23593 var p = this.parentNode;
23594 var b = [this.attributes[attr]];
23596 b.unshift(p.attributes[attr]);
23599 var sep = this.getOwnerTree().pathSeparator;
23600 return sep + b.join(sep);
23604 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23605 * function call will be the scope provided or the current node. The arguments to the function
23606 * will be the args provided or the current node. If the function returns false at any point,
23607 * the bubble is stopped.
23608 * @param {Function} fn The function to call
23609 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23610 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23612 bubble : function(fn, scope, args){
23615 if(fn.call(scope || p, args || p) === false){
23623 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23624 * function call will be the scope provided or the current node. The arguments to the function
23625 * will be the args provided or the current node. If the function returns false at any point,
23626 * the cascade is stopped on that branch.
23627 * @param {Function} fn The function to call
23628 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23629 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23631 cascade : function(fn, scope, args){
23632 if(fn.call(scope || this, args || this) !== false){
23633 var cs = this.childNodes;
23634 for(var i = 0, len = cs.length; i < len; i++) {
23635 cs[i].cascade(fn, scope, args);
23641 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23642 * function call will be the scope provided or the current node. The arguments to the function
23643 * will be the args provided or the current node. If the function returns false at any point,
23644 * the iteration stops.
23645 * @param {Function} fn The function to call
23646 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23647 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23649 eachChild : function(fn, scope, args){
23650 var cs = this.childNodes;
23651 for(var i = 0, len = cs.length; i < len; i++) {
23652 if(fn.call(scope || this, args || cs[i]) === false){
23659 * Finds the first child that has the attribute with the specified value.
23660 * @param {String} attribute The attribute name
23661 * @param {Mixed} value The value to search for
23662 * @return {Node} The found child or null if none was found
23664 findChild : function(attribute, value){
23665 var cs = this.childNodes;
23666 for(var i = 0, len = cs.length; i < len; i++) {
23667 if(cs[i].attributes[attribute] == value){
23675 * Finds the first child by a custom function. The child matches if the function passed
23677 * @param {Function} fn
23678 * @param {Object} scope (optional)
23679 * @return {Node} The found child or null if none was found
23681 findChildBy : function(fn, scope){
23682 var cs = this.childNodes;
23683 for(var i = 0, len = cs.length; i < len; i++) {
23684 if(fn.call(scope||cs[i], cs[i]) === true){
23692 * Sorts this nodes children using the supplied sort function
23693 * @param {Function} fn
23694 * @param {Object} scope (optional)
23696 sort : function(fn, scope){
23697 var cs = this.childNodes;
23698 var len = cs.length;
23700 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23702 for(var i = 0; i < len; i++){
23704 n.previousSibling = cs[i-1];
23705 n.nextSibling = cs[i+1];
23707 this.setFirstChild(n);
23710 this.setLastChild(n);
23717 * Returns true if this node is an ancestor (at any point) of the passed node.
23718 * @param {Node} node
23719 * @return {Boolean}
23721 contains : function(node){
23722 return node.isAncestor(this);
23726 * Returns true if the passed node is an ancestor (at any point) of this node.
23727 * @param {Node} node
23728 * @return {Boolean}
23730 isAncestor : function(node){
23731 var p = this.parentNode;
23741 toString : function(){
23742 return "[Node"+(this.id?" "+this.id:"")+"]";
23746 * Ext JS Library 1.1.1
23747 * Copyright(c) 2006-2007, Ext JS, LLC.
23749 * Originally Released Under LGPL - original licence link has changed is not relivant.
23752 * <script type="text/javascript">
23757 * @extends Roo.Element
23758 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23759 * automatic maintaining of shadow/shim positions.
23760 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23761 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23762 * you can pass a string with a CSS class name. False turns off the shadow.
23763 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23764 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23765 * @cfg {String} cls CSS class to add to the element
23766 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23767 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23769 * @param {Object} config An object with config options.
23770 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23773 Roo.Layer = function(config, existingEl){
23774 config = config || {};
23775 var dh = Roo.DomHelper;
23776 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23778 this.dom = Roo.getDom(existingEl);
23781 var o = config.dh || {tag: "div", cls: "x-layer"};
23782 this.dom = dh.append(pel, o);
23785 this.addClass(config.cls);
23787 this.constrain = config.constrain !== false;
23788 this.visibilityMode = Roo.Element.VISIBILITY;
23790 this.id = this.dom.id = config.id;
23792 this.id = Roo.id(this.dom);
23794 this.zindex = config.zindex || this.getZIndex();
23795 this.position("absolute", this.zindex);
23797 this.shadowOffset = config.shadowOffset || 4;
23798 this.shadow = new Roo.Shadow({
23799 offset : this.shadowOffset,
23800 mode : config.shadow
23803 this.shadowOffset = 0;
23805 this.useShim = config.shim !== false && Roo.useShims;
23806 this.useDisplay = config.useDisplay;
23810 var supr = Roo.Element.prototype;
23812 // shims are shared among layer to keep from having 100 iframes
23815 Roo.extend(Roo.Layer, Roo.Element, {
23817 getZIndex : function(){
23818 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23821 getShim : function(){
23828 var shim = shims.shift();
23830 shim = this.createShim();
23831 shim.enableDisplayMode('block');
23832 shim.dom.style.display = 'none';
23833 shim.dom.style.visibility = 'visible';
23835 var pn = this.dom.parentNode;
23836 if(shim.dom.parentNode != pn){
23837 pn.insertBefore(shim.dom, this.dom);
23839 shim.setStyle('z-index', this.getZIndex()-2);
23844 hideShim : function(){
23846 this.shim.setDisplayed(false);
23847 shims.push(this.shim);
23852 disableShadow : function(){
23854 this.shadowDisabled = true;
23855 this.shadow.hide();
23856 this.lastShadowOffset = this.shadowOffset;
23857 this.shadowOffset = 0;
23861 enableShadow : function(show){
23863 this.shadowDisabled = false;
23864 this.shadowOffset = this.lastShadowOffset;
23865 delete this.lastShadowOffset;
23873 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23874 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23875 sync : function(doShow){
23876 var sw = this.shadow;
23877 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23878 var sh = this.getShim();
23880 var w = this.getWidth(),
23881 h = this.getHeight();
23883 var l = this.getLeft(true),
23884 t = this.getTop(true);
23886 if(sw && !this.shadowDisabled){
23887 if(doShow && !sw.isVisible()){
23890 sw.realign(l, t, w, h);
23896 // fit the shim behind the shadow, so it is shimmed too
23897 var a = sw.adjusts, s = sh.dom.style;
23898 s.left = (Math.min(l, l+a.l))+"px";
23899 s.top = (Math.min(t, t+a.t))+"px";
23900 s.width = (w+a.w)+"px";
23901 s.height = (h+a.h)+"px";
23908 sh.setLeftTop(l, t);
23915 destroy : function(){
23918 this.shadow.hide();
23920 this.removeAllListeners();
23921 var pn = this.dom.parentNode;
23923 pn.removeChild(this.dom);
23925 Roo.Element.uncache(this.id);
23928 remove : function(){
23933 beginUpdate : function(){
23934 this.updating = true;
23938 endUpdate : function(){
23939 this.updating = false;
23944 hideUnders : function(negOffset){
23946 this.shadow.hide();
23952 constrainXY : function(){
23953 if(this.constrain){
23954 var vw = Roo.lib.Dom.getViewWidth(),
23955 vh = Roo.lib.Dom.getViewHeight();
23956 var s = Roo.get(document).getScroll();
23958 var xy = this.getXY();
23959 var x = xy[0], y = xy[1];
23960 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23961 // only move it if it needs it
23963 // first validate right/bottom
23964 if((x + w) > vw+s.left){
23965 x = vw - w - this.shadowOffset;
23968 if((y + h) > vh+s.top){
23969 y = vh - h - this.shadowOffset;
23972 // then make sure top/left isn't negative
23983 var ay = this.avoidY;
23984 if(y <= ay && (y+h) >= ay){
23990 supr.setXY.call(this, xy);
23996 isVisible : function(){
23997 return this.visible;
24001 showAction : function(){
24002 this.visible = true; // track visibility to prevent getStyle calls
24003 if(this.useDisplay === true){
24004 this.setDisplayed("");
24005 }else if(this.lastXY){
24006 supr.setXY.call(this, this.lastXY);
24007 }else if(this.lastLT){
24008 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
24013 hideAction : function(){
24014 this.visible = false;
24015 if(this.useDisplay === true){
24016 this.setDisplayed(false);
24018 this.setLeftTop(-10000,-10000);
24022 // overridden Element method
24023 setVisible : function(v, a, d, c, e){
24028 var cb = function(){
24033 }.createDelegate(this);
24034 supr.setVisible.call(this, true, true, d, cb, e);
24037 this.hideUnders(true);
24046 }.createDelegate(this);
24048 supr.setVisible.call(this, v, a, d, cb, e);
24057 storeXY : function(xy){
24058 delete this.lastLT;
24062 storeLeftTop : function(left, top){
24063 delete this.lastXY;
24064 this.lastLT = [left, top];
24068 beforeFx : function(){
24069 this.beforeAction();
24070 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
24074 afterFx : function(){
24075 Roo.Layer.superclass.afterFx.apply(this, arguments);
24076 this.sync(this.isVisible());
24080 beforeAction : function(){
24081 if(!this.updating && this.shadow){
24082 this.shadow.hide();
24086 // overridden Element method
24087 setLeft : function(left){
24088 this.storeLeftTop(left, this.getTop(true));
24089 supr.setLeft.apply(this, arguments);
24093 setTop : function(top){
24094 this.storeLeftTop(this.getLeft(true), top);
24095 supr.setTop.apply(this, arguments);
24099 setLeftTop : function(left, top){
24100 this.storeLeftTop(left, top);
24101 supr.setLeftTop.apply(this, arguments);
24105 setXY : function(xy, a, d, c, e){
24107 this.beforeAction();
24109 var cb = this.createCB(c);
24110 supr.setXY.call(this, xy, a, d, cb, e);
24117 createCB : function(c){
24128 // overridden Element method
24129 setX : function(x, a, d, c, e){
24130 this.setXY([x, this.getY()], a, d, c, e);
24133 // overridden Element method
24134 setY : function(y, a, d, c, e){
24135 this.setXY([this.getX(), y], a, d, c, e);
24138 // overridden Element method
24139 setSize : function(w, h, a, d, c, e){
24140 this.beforeAction();
24141 var cb = this.createCB(c);
24142 supr.setSize.call(this, w, h, a, d, cb, e);
24148 // overridden Element method
24149 setWidth : function(w, a, d, c, e){
24150 this.beforeAction();
24151 var cb = this.createCB(c);
24152 supr.setWidth.call(this, w, a, d, cb, e);
24158 // overridden Element method
24159 setHeight : function(h, a, d, c, e){
24160 this.beforeAction();
24161 var cb = this.createCB(c);
24162 supr.setHeight.call(this, h, a, d, cb, e);
24168 // overridden Element method
24169 setBounds : function(x, y, w, h, a, d, c, e){
24170 this.beforeAction();
24171 var cb = this.createCB(c);
24173 this.storeXY([x, y]);
24174 supr.setXY.call(this, [x, y]);
24175 supr.setSize.call(this, w, h, a, d, cb, e);
24178 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24184 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24185 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24186 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24187 * @param {Number} zindex The new z-index to set
24188 * @return {this} The Layer
24190 setZIndex : function(zindex){
24191 this.zindex = zindex;
24192 this.setStyle("z-index", zindex + 2);
24194 this.shadow.setZIndex(zindex + 1);
24197 this.shim.setStyle("z-index", zindex);
24203 * Ext JS Library 1.1.1
24204 * Copyright(c) 2006-2007, Ext JS, LLC.
24206 * Originally Released Under LGPL - original licence link has changed is not relivant.
24209 * <script type="text/javascript">
24214 * @class Roo.Shadow
24215 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24216 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24217 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24219 * Create a new Shadow
24220 * @param {Object} config The config object
24222 Roo.Shadow = function(config){
24223 Roo.apply(this, config);
24224 if(typeof this.mode != "string"){
24225 this.mode = this.defaultMode;
24227 var o = this.offset, a = {h: 0};
24228 var rad = Math.floor(this.offset/2);
24229 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24235 a.l -= this.offset + rad;
24236 a.t -= this.offset + rad;
24247 a.l -= (this.offset - rad);
24248 a.t -= this.offset + rad;
24250 a.w -= (this.offset - rad)*2;
24261 a.l -= (this.offset - rad);
24262 a.t -= (this.offset - rad);
24264 a.w -= (this.offset + rad + 1);
24265 a.h -= (this.offset + rad);
24274 Roo.Shadow.prototype = {
24276 * @cfg {String} mode
24277 * The shadow display mode. Supports the following options:<br />
24278 * sides: Shadow displays on both sides and bottom only<br />
24279 * frame: Shadow displays equally on all four sides<br />
24280 * drop: Traditional bottom-right drop shadow (default)
24283 * @cfg {String} offset
24284 * The number of pixels to offset the shadow from the element (defaults to 4)
24289 defaultMode: "drop",
24292 * Displays the shadow under the target element
24293 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24295 show : function(target){
24296 target = Roo.get(target);
24298 this.el = Roo.Shadow.Pool.pull();
24299 if(this.el.dom.nextSibling != target.dom){
24300 this.el.insertBefore(target);
24303 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24305 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24308 target.getLeft(true),
24309 target.getTop(true),
24313 this.el.dom.style.display = "block";
24317 * Returns true if the shadow is visible, else false
24319 isVisible : function(){
24320 return this.el ? true : false;
24324 * Direct alignment when values are already available. Show must be called at least once before
24325 * calling this method to ensure it is initialized.
24326 * @param {Number} left The target element left position
24327 * @param {Number} top The target element top position
24328 * @param {Number} width The target element width
24329 * @param {Number} height The target element height
24331 realign : function(l, t, w, h){
24335 var a = this.adjusts, d = this.el.dom, s = d.style;
24337 s.left = (l+a.l)+"px";
24338 s.top = (t+a.t)+"px";
24339 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24341 if(s.width != sws || s.height != shs){
24345 var cn = d.childNodes;
24346 var sww = Math.max(0, (sw-12))+"px";
24347 cn[0].childNodes[1].style.width = sww;
24348 cn[1].childNodes[1].style.width = sww;
24349 cn[2].childNodes[1].style.width = sww;
24350 cn[1].style.height = Math.max(0, (sh-12))+"px";
24356 * Hides this shadow
24360 this.el.dom.style.display = "none";
24361 Roo.Shadow.Pool.push(this.el);
24367 * Adjust the z-index of this shadow
24368 * @param {Number} zindex The new z-index
24370 setZIndex : function(z){
24373 this.el.setStyle("z-index", z);
24378 // Private utility class that manages the internal Shadow cache
24379 Roo.Shadow.Pool = function(){
24381 var markup = Roo.isIE ?
24382 '<div class="x-ie-shadow"></div>' :
24383 '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
24386 var sh = p.shift();
24388 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24389 sh.autoBoxAdjust = false;
24394 push : function(sh){
24400 * Ext JS Library 1.1.1
24401 * Copyright(c) 2006-2007, Ext JS, LLC.
24403 * Originally Released Under LGPL - original licence link has changed is not relivant.
24406 * <script type="text/javascript">
24411 * @class Roo.SplitBar
24412 * @extends Roo.util.Observable
24413 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24417 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24418 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24419 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24420 split.minSize = 100;
24421 split.maxSize = 600;
24422 split.animate = true;
24423 split.on('moved', splitterMoved);
24426 * Create a new SplitBar
24427 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24428 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24429 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24430 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24431 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24432 position of the SplitBar).
24434 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24437 this.el = Roo.get(dragElement, true);
24438 this.el.dom.unselectable = "on";
24440 this.resizingEl = Roo.get(resizingElement, true);
24444 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24445 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24448 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24451 * The minimum size of the resizing element. (Defaults to 0)
24457 * The maximum size of the resizing element. (Defaults to 2000)
24460 this.maxSize = 2000;
24463 * Whether to animate the transition to the new size
24466 this.animate = false;
24469 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24472 this.useShim = false;
24477 if(!existingProxy){
24479 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24481 this.proxy = Roo.get(existingProxy).dom;
24484 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24487 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24490 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24493 this.dragSpecs = {};
24496 * @private The adapter to use to positon and resize elements
24498 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24499 this.adapter.init(this);
24501 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24503 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24504 this.el.addClass("x-splitbar-h");
24507 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24508 this.el.addClass("x-splitbar-v");
24514 * Fires when the splitter is moved (alias for {@link #event-moved})
24515 * @param {Roo.SplitBar} this
24516 * @param {Number} newSize the new width or height
24521 * Fires when the splitter is moved
24522 * @param {Roo.SplitBar} this
24523 * @param {Number} newSize the new width or height
24527 * @event beforeresize
24528 * Fires before the splitter is dragged
24529 * @param {Roo.SplitBar} this
24531 "beforeresize" : true,
24533 "beforeapply" : true
24536 Roo.util.Observable.call(this);
24539 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24540 onStartProxyDrag : function(x, y){
24541 this.fireEvent("beforeresize", this);
24543 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24545 o.enableDisplayMode("block");
24546 // all splitbars share the same overlay
24547 Roo.SplitBar.prototype.overlay = o;
24549 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24550 this.overlay.show();
24551 Roo.get(this.proxy).setDisplayed("block");
24552 var size = this.adapter.getElementSize(this);
24553 this.activeMinSize = this.getMinimumSize();;
24554 this.activeMaxSize = this.getMaximumSize();;
24555 var c1 = size - this.activeMinSize;
24556 var c2 = Math.max(this.activeMaxSize - size, 0);
24557 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24558 this.dd.resetConstraints();
24559 this.dd.setXConstraint(
24560 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24561 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24563 this.dd.setYConstraint(0, 0);
24565 this.dd.resetConstraints();
24566 this.dd.setXConstraint(0, 0);
24567 this.dd.setYConstraint(
24568 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24569 this.placement == Roo.SplitBar.TOP ? c2 : c1
24572 this.dragSpecs.startSize = size;
24573 this.dragSpecs.startPoint = [x, y];
24574 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24578 * @private Called after the drag operation by the DDProxy
24580 onEndProxyDrag : function(e){
24581 Roo.get(this.proxy).setDisplayed(false);
24582 var endPoint = Roo.lib.Event.getXY(e);
24584 this.overlay.hide();
24587 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24588 newSize = this.dragSpecs.startSize +
24589 (this.placement == Roo.SplitBar.LEFT ?
24590 endPoint[0] - this.dragSpecs.startPoint[0] :
24591 this.dragSpecs.startPoint[0] - endPoint[0]
24594 newSize = this.dragSpecs.startSize +
24595 (this.placement == Roo.SplitBar.TOP ?
24596 endPoint[1] - this.dragSpecs.startPoint[1] :
24597 this.dragSpecs.startPoint[1] - endPoint[1]
24600 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24601 if(newSize != this.dragSpecs.startSize){
24602 if(this.fireEvent('beforeapply', this, newSize) !== false){
24603 this.adapter.setElementSize(this, newSize);
24604 this.fireEvent("moved", this, newSize);
24605 this.fireEvent("resize", this, newSize);
24611 * Get the adapter this SplitBar uses
24612 * @return The adapter object
24614 getAdapter : function(){
24615 return this.adapter;
24619 * Set the adapter this SplitBar uses
24620 * @param {Object} adapter A SplitBar adapter object
24622 setAdapter : function(adapter){
24623 this.adapter = adapter;
24624 this.adapter.init(this);
24628 * Gets the minimum size for the resizing element
24629 * @return {Number} The minimum size
24631 getMinimumSize : function(){
24632 return this.minSize;
24636 * Sets the minimum size for the resizing element
24637 * @param {Number} minSize The minimum size
24639 setMinimumSize : function(minSize){
24640 this.minSize = minSize;
24644 * Gets the maximum size for the resizing element
24645 * @return {Number} The maximum size
24647 getMaximumSize : function(){
24648 return this.maxSize;
24652 * Sets the maximum size for the resizing element
24653 * @param {Number} maxSize The maximum size
24655 setMaximumSize : function(maxSize){
24656 this.maxSize = maxSize;
24660 * Sets the initialize size for the resizing element
24661 * @param {Number} size The initial size
24663 setCurrentSize : function(size){
24664 var oldAnimate = this.animate;
24665 this.animate = false;
24666 this.adapter.setElementSize(this, size);
24667 this.animate = oldAnimate;
24671 * Destroy this splitbar.
24672 * @param {Boolean} removeEl True to remove the element
24674 destroy : function(removeEl){
24676 this.shim.remove();
24679 this.proxy.parentNode.removeChild(this.proxy);
24687 * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
24689 Roo.SplitBar.createProxy = function(dir){
24690 var proxy = new Roo.Element(document.createElement("div"));
24691 proxy.unselectable();
24692 var cls = 'x-splitbar-proxy';
24693 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24694 document.body.appendChild(proxy.dom);
24699 * @class Roo.SplitBar.BasicLayoutAdapter
24700 * Default Adapter. It assumes the splitter and resizing element are not positioned
24701 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24703 Roo.SplitBar.BasicLayoutAdapter = function(){
24706 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24707 // do nothing for now
24708 init : function(s){
24712 * Called before drag operations to get the current size of the resizing element.
24713 * @param {Roo.SplitBar} s The SplitBar using this adapter
24715 getElementSize : function(s){
24716 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24717 return s.resizingEl.getWidth();
24719 return s.resizingEl.getHeight();
24724 * Called after drag operations to set the size of the resizing element.
24725 * @param {Roo.SplitBar} s The SplitBar using this adapter
24726 * @param {Number} newSize The new size to set
24727 * @param {Function} onComplete A function to be invoked when resizing is complete
24729 setElementSize : function(s, newSize, onComplete){
24730 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24732 s.resizingEl.setWidth(newSize);
24734 onComplete(s, newSize);
24737 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24742 s.resizingEl.setHeight(newSize);
24744 onComplete(s, newSize);
24747 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24754 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24755 * @extends Roo.SplitBar.BasicLayoutAdapter
24756 * Adapter that moves the splitter element to align with the resized sizing element.
24757 * Used with an absolute positioned SplitBar.
24758 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24759 * document.body, make sure you assign an id to the body element.
24761 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24762 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24763 this.container = Roo.get(container);
24766 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24767 init : function(s){
24768 this.basic.init(s);
24771 getElementSize : function(s){
24772 return this.basic.getElementSize(s);
24775 setElementSize : function(s, newSize, onComplete){
24776 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24779 moveSplitter : function(s){
24780 var yes = Roo.SplitBar;
24781 switch(s.placement){
24783 s.el.setX(s.resizingEl.getRight());
24786 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24789 s.el.setY(s.resizingEl.getBottom());
24792 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24799 * Orientation constant - Create a vertical SplitBar
24803 Roo.SplitBar.VERTICAL = 1;
24806 * Orientation constant - Create a horizontal SplitBar
24810 Roo.SplitBar.HORIZONTAL = 2;
24813 * Placement constant - The resizing element is to the left of the splitter element
24817 Roo.SplitBar.LEFT = 1;
24820 * Placement constant - The resizing element is to the right of the splitter element
24824 Roo.SplitBar.RIGHT = 2;
24827 * Placement constant - The resizing element is positioned above the splitter element
24831 Roo.SplitBar.TOP = 3;
24834 * Placement constant - The resizing element is positioned under splitter element
24838 Roo.SplitBar.BOTTOM = 4;
24841 * Ext JS Library 1.1.1
24842 * Copyright(c) 2006-2007, Ext JS, LLC.
24844 * Originally Released Under LGPL - original licence link has changed is not relivant.
24847 * <script type="text/javascript">
24852 * @extends Roo.util.Observable
24853 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24854 * This class also supports single and multi selection modes. <br>
24855 * Create a data model bound view:
24857 var store = new Roo.data.Store(...);
24859 var view = new Roo.View({
24861 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24863 singleSelect: true,
24864 selectedClass: "ydataview-selected",
24868 // listen for node click?
24869 view.on("click", function(vw, index, node, e){
24870 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24874 dataModel.load("foobar.xml");
24876 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24878 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24879 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24881 * Note: old style constructor is still suported (container, template, config)
24884 * Create a new View
24885 * @param {Object} config The config object
24888 Roo.View = function(config, depreciated_tpl, depreciated_config){
24890 this.parent = false;
24892 if (typeof(depreciated_tpl) == 'undefined') {
24893 // new way.. - universal constructor.
24894 Roo.apply(this, config);
24895 this.el = Roo.get(this.el);
24898 this.el = Roo.get(config);
24899 this.tpl = depreciated_tpl;
24900 Roo.apply(this, depreciated_config);
24902 this.wrapEl = this.el.wrap().wrap();
24903 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24906 if(typeof(this.tpl) == "string"){
24907 this.tpl = new Roo.Template(this.tpl);
24909 // support xtype ctors..
24910 this.tpl = new Roo.factory(this.tpl, Roo);
24914 this.tpl.compile();
24919 * @event beforeclick
24920 * Fires before a click is processed. Returns false to cancel the default action.
24921 * @param {Roo.View} this
24922 * @param {Number} index The index of the target node
24923 * @param {HTMLElement} node The target node
24924 * @param {Roo.EventObject} e The raw event object
24926 "beforeclick" : true,
24929 * Fires when a template node is clicked.
24930 * @param {Roo.View} this
24931 * @param {Number} index The index of the target node
24932 * @param {HTMLElement} node The target node
24933 * @param {Roo.EventObject} e The raw event object
24938 * Fires when a template node is double clicked.
24939 * @param {Roo.View} this
24940 * @param {Number} index The index of the target node
24941 * @param {HTMLElement} node The target node
24942 * @param {Roo.EventObject} e The raw event object
24946 * @event contextmenu
24947 * Fires when a template node is right clicked.
24948 * @param {Roo.View} this
24949 * @param {Number} index The index of the target node
24950 * @param {HTMLElement} node The target node
24951 * @param {Roo.EventObject} e The raw event object
24953 "contextmenu" : true,
24955 * @event selectionchange
24956 * Fires when the selected nodes change.
24957 * @param {Roo.View} this
24958 * @param {Array} selections Array of the selected nodes
24960 "selectionchange" : true,
24963 * @event beforeselect
24964 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24965 * @param {Roo.View} this
24966 * @param {HTMLElement} node The node to be selected
24967 * @param {Array} selections Array of currently selected nodes
24969 "beforeselect" : true,
24971 * @event preparedata
24972 * Fires on every row to render, to allow you to change the data.
24973 * @param {Roo.View} this
24974 * @param {Object} data to be rendered (change this)
24976 "preparedata" : true
24984 "click": this.onClick,
24985 "dblclick": this.onDblClick,
24986 "contextmenu": this.onContextMenu,
24990 this.selections = [];
24992 this.cmp = new Roo.CompositeElementLite([]);
24994 this.store = Roo.factory(this.store, Roo.data);
24995 this.setStore(this.store, true);
24998 if ( this.footer && this.footer.xtype) {
25000 var fctr = this.wrapEl.appendChild(document.createElement("div"));
25002 this.footer.dataSource = this.store;
25003 this.footer.container = fctr;
25004 this.footer = Roo.factory(this.footer, Roo);
25005 fctr.insertFirst(this.el);
25007 // this is a bit insane - as the paging toolbar seems to detach the el..
25008 // dom.parentNode.parentNode.parentNode
25009 // they get detached?
25013 Roo.View.superclass.constructor.call(this);
25018 Roo.extend(Roo.View, Roo.util.Observable, {
25021 * @cfg {Roo.data.Store} store Data store to load data from.
25026 * @cfg {String|Roo.Element} el The container element.
25031 * @cfg {String|Roo.Template} tpl The template used by this View
25035 * @cfg {String} dataName the named area of the template to use as the data area
25036 * Works with domtemplates roo-name="name"
25040 * @cfg {String} selectedClass The css class to add to selected nodes
25042 selectedClass : "x-view-selected",
25044 * @cfg {String} emptyText The empty text to show when nothing is loaded.
25049 * @cfg {String} text to display on mask (default Loading)
25053 * @cfg {Boolean} multiSelect Allow multiple selection
25055 multiSelect : false,
25057 * @cfg {Boolean} singleSelect Allow single selection
25059 singleSelect: false,
25062 * @cfg {Boolean} toggleSelect - selecting
25064 toggleSelect : false,
25067 * @cfg {Boolean} tickable - selecting
25072 * Returns the element this view is bound to.
25073 * @return {Roo.Element}
25075 getEl : function(){
25076 return this.wrapEl;
25082 * Refreshes the view. - called by datachanged on the store. - do not call directly.
25084 refresh : function(){
25085 //Roo.log('refresh');
25088 // if we are using something like 'domtemplate', then
25089 // the what gets used is:
25090 // t.applySubtemplate(NAME, data, wrapping data..)
25091 // the outer template then get' applied with
25092 // the store 'extra data'
25093 // and the body get's added to the
25094 // roo-name="data" node?
25095 // <span class='roo-tpl-{name}'></span> ?????
25099 this.clearSelections();
25100 this.el.update("");
25102 var records = this.store.getRange();
25103 if(records.length < 1) {
25105 // is this valid?? = should it render a template??
25107 this.el.update(this.emptyText);
25111 if (this.dataName) {
25112 this.el.update(t.apply(this.store.meta)); //????
25113 el = this.el.child('.roo-tpl-' + this.dataName);
25116 for(var i = 0, len = records.length; i < len; i++){
25117 var data = this.prepareData(records[i].data, i, records[i]);
25118 this.fireEvent("preparedata", this, data, i, records[i]);
25120 var d = Roo.apply({}, data);
25123 Roo.apply(d, {'roo-id' : Roo.id()});
25127 Roo.each(this.parent.item, function(item){
25128 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
25131 Roo.apply(d, {'roo-data-checked' : 'checked'});
25135 html[html.length] = Roo.util.Format.trim(
25137 t.applySubtemplate(this.dataName, d, this.store.meta) :
25144 el.update(html.join(""));
25145 this.nodes = el.dom.childNodes;
25146 this.updateIndexes(0);
25151 * Function to override to reformat the data that is sent to
25152 * the template for each node.
25153 * DEPRICATED - use the preparedata event handler.
25154 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25155 * a JSON object for an UpdateManager bound view).
25157 prepareData : function(data, index, record)
25159 this.fireEvent("preparedata", this, data, index, record);
25163 onUpdate : function(ds, record){
25164 // Roo.log('on update');
25165 this.clearSelections();
25166 var index = this.store.indexOf(record);
25167 var n = this.nodes[index];
25168 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25169 n.parentNode.removeChild(n);
25170 this.updateIndexes(index, index);
25176 onAdd : function(ds, records, index)
25178 //Roo.log(['on Add', ds, records, index] );
25179 this.clearSelections();
25180 if(this.nodes.length == 0){
25184 var n = this.nodes[index];
25185 for(var i = 0, len = records.length; i < len; i++){
25186 var d = this.prepareData(records[i].data, i, records[i]);
25188 this.tpl.insertBefore(n, d);
25191 this.tpl.append(this.el, d);
25194 this.updateIndexes(index);
25197 onRemove : function(ds, record, index){
25198 // Roo.log('onRemove');
25199 this.clearSelections();
25200 var el = this.dataName ?
25201 this.el.child('.roo-tpl-' + this.dataName) :
25204 el.dom.removeChild(this.nodes[index]);
25205 this.updateIndexes(index);
25209 * Refresh an individual node.
25210 * @param {Number} index
25212 refreshNode : function(index){
25213 this.onUpdate(this.store, this.store.getAt(index));
25216 updateIndexes : function(startIndex, endIndex){
25217 var ns = this.nodes;
25218 startIndex = startIndex || 0;
25219 endIndex = endIndex || ns.length - 1;
25220 for(var i = startIndex; i <= endIndex; i++){
25221 ns[i].nodeIndex = i;
25226 * Changes the data store this view uses and refresh the view.
25227 * @param {Store} store
25229 setStore : function(store, initial){
25230 if(!initial && this.store){
25231 this.store.un("datachanged", this.refresh);
25232 this.store.un("add", this.onAdd);
25233 this.store.un("remove", this.onRemove);
25234 this.store.un("update", this.onUpdate);
25235 this.store.un("clear", this.refresh);
25236 this.store.un("beforeload", this.onBeforeLoad);
25237 this.store.un("load", this.onLoad);
25238 this.store.un("loadexception", this.onLoad);
25242 store.on("datachanged", this.refresh, this);
25243 store.on("add", this.onAdd, this);
25244 store.on("remove", this.onRemove, this);
25245 store.on("update", this.onUpdate, this);
25246 store.on("clear", this.refresh, this);
25247 store.on("beforeload", this.onBeforeLoad, this);
25248 store.on("load", this.onLoad, this);
25249 store.on("loadexception", this.onLoad, this);
25257 * onbeforeLoad - masks the loading area.
25260 onBeforeLoad : function(store,opts)
25262 //Roo.log('onBeforeLoad');
25264 this.el.update("");
25266 this.el.mask(this.mask ? this.mask : "Loading" );
25268 onLoad : function ()
25275 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25276 * @param {HTMLElement} node
25277 * @return {HTMLElement} The template node
25279 findItemFromChild : function(node){
25280 var el = this.dataName ?
25281 this.el.child('.roo-tpl-' + this.dataName,true) :
25284 if(!node || node.parentNode == el){
25287 var p = node.parentNode;
25288 while(p && p != el){
25289 if(p.parentNode == el){
25298 onClick : function(e){
25299 var item = this.findItemFromChild(e.getTarget());
25301 var index = this.indexOf(item);
25302 if(this.onItemClick(item, index, e) !== false){
25303 this.fireEvent("click", this, index, item, e);
25306 this.clearSelections();
25311 onContextMenu : function(e){
25312 var item = this.findItemFromChild(e.getTarget());
25314 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25319 onDblClick : function(e){
25320 var item = this.findItemFromChild(e.getTarget());
25322 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25326 onItemClick : function(item, index, e)
25328 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25331 if (this.toggleSelect) {
25332 var m = this.isSelected(item) ? 'unselect' : 'select';
25335 _t[m](item, true, false);
25338 if(this.multiSelect || this.singleSelect){
25339 if(this.multiSelect && e.shiftKey && this.lastSelection){
25340 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25342 this.select(item, this.multiSelect && e.ctrlKey);
25343 this.lastSelection = item;
25346 if(!this.tickable){
25347 e.preventDefault();
25355 * Get the number of selected nodes.
25358 getSelectionCount : function(){
25359 return this.selections.length;
25363 * Get the currently selected nodes.
25364 * @return {Array} An array of HTMLElements
25366 getSelectedNodes : function(){
25367 return this.selections;
25371 * Get the indexes of the selected nodes.
25374 getSelectedIndexes : function(){
25375 var indexes = [], s = this.selections;
25376 for(var i = 0, len = s.length; i < len; i++){
25377 indexes.push(s[i].nodeIndex);
25383 * Clear all selections
25384 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25386 clearSelections : function(suppressEvent){
25387 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25388 this.cmp.elements = this.selections;
25389 this.cmp.removeClass(this.selectedClass);
25390 this.selections = [];
25391 if(!suppressEvent){
25392 this.fireEvent("selectionchange", this, this.selections);
25398 * Returns true if the passed node is selected
25399 * @param {HTMLElement/Number} node The node or node index
25400 * @return {Boolean}
25402 isSelected : function(node){
25403 var s = this.selections;
25407 node = this.getNode(node);
25408 return s.indexOf(node) !== -1;
25413 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
25414 * @param {Boolean} keepExisting (optional) true to keep existing selections
25415 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25417 select : function(nodeInfo, keepExisting, suppressEvent){
25418 if(nodeInfo instanceof Array){
25420 this.clearSelections(true);
25422 for(var i = 0, len = nodeInfo.length; i < len; i++){
25423 this.select(nodeInfo[i], true, true);
25427 var node = this.getNode(nodeInfo);
25428 if(!node || this.isSelected(node)){
25429 return; // already selected.
25432 this.clearSelections(true);
25435 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25436 Roo.fly(node).addClass(this.selectedClass);
25437 this.selections.push(node);
25438 if(!suppressEvent){
25439 this.fireEvent("selectionchange", this, this.selections);
25447 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
25448 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25449 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25451 unselect : function(nodeInfo, keepExisting, suppressEvent)
25453 if(nodeInfo instanceof Array){
25454 Roo.each(this.selections, function(s) {
25455 this.unselect(s, nodeInfo);
25459 var node = this.getNode(nodeInfo);
25460 if(!node || !this.isSelected(node)){
25461 //Roo.log("not selected");
25462 return; // not selected.
25466 Roo.each(this.selections, function(s) {
25468 Roo.fly(node).removeClass(this.selectedClass);
25475 this.selections= ns;
25476 this.fireEvent("selectionchange", this, this.selections);
25480 * Gets a template node.
25481 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25482 * @return {HTMLElement} The node or null if it wasn't found
25484 getNode : function(nodeInfo){
25485 if(typeof nodeInfo == "string"){
25486 return document.getElementById(nodeInfo);
25487 }else if(typeof nodeInfo == "number"){
25488 return this.nodes[nodeInfo];
25494 * Gets a range template nodes.
25495 * @param {Number} startIndex
25496 * @param {Number} endIndex
25497 * @return {Array} An array of nodes
25499 getNodes : function(start, end){
25500 var ns = this.nodes;
25501 start = start || 0;
25502 end = typeof end == "undefined" ? ns.length - 1 : end;
25505 for(var i = start; i <= end; i++){
25509 for(var i = start; i >= end; i--){
25517 * Finds the index of the passed node
25518 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25519 * @return {Number} The index of the node or -1
25521 indexOf : function(node){
25522 node = this.getNode(node);
25523 if(typeof node.nodeIndex == "number"){
25524 return node.nodeIndex;
25526 var ns = this.nodes;
25527 for(var i = 0, len = ns.length; i < len; i++){
25537 * Ext JS Library 1.1.1
25538 * Copyright(c) 2006-2007, Ext JS, LLC.
25540 * Originally Released Under LGPL - original licence link has changed is not relivant.
25543 * <script type="text/javascript">
25547 * @class Roo.JsonView
25548 * @extends Roo.View
25549 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25551 var view = new Roo.JsonView({
25552 container: "my-element",
25553 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25558 // listen for node click?
25559 view.on("click", function(vw, index, node, e){
25560 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25563 // direct load of JSON data
25564 view.load("foobar.php");
25566 // Example from my blog list
25567 var tpl = new Roo.Template(
25568 '<div class="entry">' +
25569 '<a class="entry-title" href="{link}">{title}</a>' +
25570 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25571 "</div><hr />"
25574 var moreView = new Roo.JsonView({
25575 container : "entry-list",
25579 moreView.on("beforerender", this.sortEntries, this);
25581 url: "/blog/get-posts.php",
25582 params: "allposts=true",
25583 text: "Loading Blog Entries..."
25587 * Note: old code is supported with arguments : (container, template, config)
25591 * Create a new JsonView
25593 * @param {Object} config The config object
25596 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25599 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25601 var um = this.el.getUpdateManager();
25602 um.setRenderer(this);
25603 um.on("update", this.onLoad, this);
25604 um.on("failure", this.onLoadException, this);
25607 * @event beforerender
25608 * Fires before rendering of the downloaded JSON data.
25609 * @param {Roo.JsonView} this
25610 * @param {Object} data The JSON data loaded
25614 * Fires when data is loaded.
25615 * @param {Roo.JsonView} this
25616 * @param {Object} data The JSON data loaded
25617 * @param {Object} response The raw Connect response object
25620 * @event loadexception
25621 * Fires when loading fails.
25622 * @param {Roo.JsonView} this
25623 * @param {Object} response The raw Connect response object
25626 'beforerender' : true,
25628 'loadexception' : true
25631 Roo.extend(Roo.JsonView, Roo.View, {
25633 * @type {String} The root property in the loaded JSON object that contains the data
25638 * Refreshes the view.
25640 refresh : function(){
25641 this.clearSelections();
25642 this.el.update("");
25644 var o = this.jsonData;
25645 if(o && o.length > 0){
25646 for(var i = 0, len = o.length; i < len; i++){
25647 var data = this.prepareData(o[i], i, o);
25648 html[html.length] = this.tpl.apply(data);
25651 html.push(this.emptyText);
25653 this.el.update(html.join(""));
25654 this.nodes = this.el.dom.childNodes;
25655 this.updateIndexes(0);
25659 * Performs an async HTTP request, and loads the JSON from the response. If <i>params</i> are specified it uses POST, otherwise it uses GET.
25660 * @param {Object/String/Function} url The URL for this request, or a function to call to get the URL, or a config object containing any of the following options:
25663 url: "your-url.php",
25664 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25665 callback: yourFunction,
25666 scope: yourObject, //(optional scope)
25669 text: "Loading...",
25674 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25675 * are respectively shorthand for <i>disableCaching</i>, <i>indicatorText</i>, and <i>loadScripts</i> and are used to set their associated property on this UpdateManager instance.
25676 * @param {String/Object} params (optional) The parameters to pass, as either a URL encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
25677 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25678 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
25681 var um = this.el.getUpdateManager();
25682 um.update.apply(um, arguments);
25685 render : function(el, response){
25686 this.clearSelections();
25687 this.el.update("");
25690 o = Roo.util.JSON.decode(response.responseText);
25693 o = o[this.jsonRoot];
25698 * The current JSON data or null
25701 this.beforeRender();
25706 * Get the number of records in the current JSON dataset
25709 getCount : function(){
25710 return this.jsonData ? this.jsonData.length : 0;
25714 * Returns the JSON object for the specified node(s)
25715 * @param {HTMLElement/Array} node The node or an array of nodes
25716 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25717 * you get the JSON object for the node
25719 getNodeData : function(node){
25720 if(node instanceof Array){
25722 for(var i = 0, len = node.length; i < len; i++){
25723 data.push(this.getNodeData(node[i]));
25727 return this.jsonData[this.indexOf(node)] || null;
25730 beforeRender : function(){
25731 this.snapshot = this.jsonData;
25733 this.sort.apply(this, this.sortInfo);
25735 this.fireEvent("beforerender", this, this.jsonData);
25738 onLoad : function(el, o){
25739 this.fireEvent("load", this, this.jsonData, o);
25742 onLoadException : function(el, o){
25743 this.fireEvent("loadexception", this, o);
25747 * Filter the data by a specific property.
25748 * @param {String} property A property on your JSON objects
25749 * @param {String/RegExp} value Either string that the property values
25750 * should start with, or a RegExp to test against the property
25752 filter : function(property, value){
25755 var ss = this.snapshot;
25756 if(typeof value == "string"){
25757 var vlen = value.length;
25759 this.clearFilter();
25762 value = value.toLowerCase();
25763 for(var i = 0, len = ss.length; i < len; i++){
25765 if(o[property].substr(0, vlen).toLowerCase() == value){
25769 } else if(value.exec){ // regex?
25770 for(var i = 0, len = ss.length; i < len; i++){
25772 if(value.test(o[property])){
25779 this.jsonData = data;
25785 * Filter by a function. The passed function will be called with each
25786 * object in the current dataset. If the function returns true the value is kept,
25787 * otherwise it is filtered.
25788 * @param {Function} fn
25789 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25791 filterBy : function(fn, scope){
25794 var ss = this.snapshot;
25795 for(var i = 0, len = ss.length; i < len; i++){
25797 if(fn.call(scope || this, o)){
25801 this.jsonData = data;
25807 * Clears the current filter.
25809 clearFilter : function(){
25810 if(this.snapshot && this.jsonData != this.snapshot){
25811 this.jsonData = this.snapshot;
25818 * Sorts the data for this view and refreshes it.
25819 * @param {String} property A property on your JSON objects to sort on
25820 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25821 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25823 sort : function(property, dir, sortType){
25824 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25827 var dsc = dir && dir.toLowerCase() == "desc";
25828 var f = function(o1, o2){
25829 var v1 = sortType ? sortType(o1[p]) : o1[p];
25830 var v2 = sortType ? sortType(o2[p]) : o2[p];
25833 return dsc ? +1 : -1;
25834 } else if(v1 > v2){
25835 return dsc ? -1 : +1;
25840 this.jsonData.sort(f);
25842 if(this.jsonData != this.snapshot){
25843 this.snapshot.sort(f);
25849 * Ext JS Library 1.1.1
25850 * Copyright(c) 2006-2007, Ext JS, LLC.
25852 * Originally Released Under LGPL - original licence link has changed is not relivant.
25855 * <script type="text/javascript">
25860 * @class Roo.ColorPalette
25861 * @extends Roo.Component
25862 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25863 * Here's an example of typical usage:
25865 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25866 cp.render('my-div');
25868 cp.on('select', function(palette, selColor){
25869 // do something with selColor
25873 * Create a new ColorPalette
25874 * @param {Object} config The config object
25876 Roo.ColorPalette = function(config){
25877 Roo.ColorPalette.superclass.constructor.call(this, config);
25881 * Fires when a color is selected
25882 * @param {ColorPalette} this
25883 * @param {String} color The 6-digit color hex code (without the # symbol)
25889 this.on("select", this.handler, this.scope, true);
25892 Roo.extend(Roo.ColorPalette, Roo.Component, {
25894 * @cfg {String} itemCls
25895 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25897 itemCls : "x-color-palette",
25899 * @cfg {String} value
25900 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25901 * the hex codes are case-sensitive.
25904 clickEvent:'click',
25906 ctype: "Roo.ColorPalette",
25909 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25911 allowReselect : false,
25914 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25915 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25916 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25917 * of colors with the width setting until the box is symmetrical.</p>
25918 * <p>You can override individual colors if needed:</p>
25920 var cp = new Roo.ColorPalette();
25921 cp.colors[0] = "FF0000"; // change the first box to red
25924 Or you can provide a custom array of your own for complete control:
25926 var cp = new Roo.ColorPalette();
25927 cp.colors = ["000000", "993300", "333300"];
25932 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25933 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25934 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25935 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25936 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25940 onRender : function(container, position){
25941 var t = new Roo.MasterTemplate(
25942 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25944 var c = this.colors;
25945 for(var i = 0, len = c.length; i < len; i++){
25948 var el = document.createElement("div");
25949 el.className = this.itemCls;
25951 container.dom.insertBefore(el, position);
25952 this.el = Roo.get(el);
25953 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25954 if(this.clickEvent != 'click'){
25955 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25960 afterRender : function(){
25961 Roo.ColorPalette.superclass.afterRender.call(this);
25963 var s = this.value;
25970 handleClick : function(e, t){
25971 e.preventDefault();
25972 if(!this.disabled){
25973 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25974 this.select(c.toUpperCase());
25979 * Selects the specified color in the palette (fires the select event)
25980 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25982 select : function(color){
25983 color = color.replace("#", "");
25984 if(color != this.value || this.allowReselect){
25987 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25989 el.child("a.color-"+color).addClass("x-color-palette-sel");
25990 this.value = color;
25991 this.fireEvent("select", this, color);
25996 * Ext JS Library 1.1.1
25997 * Copyright(c) 2006-2007, Ext JS, LLC.
25999 * Originally Released Under LGPL - original licence link has changed is not relivant.
26002 * <script type="text/javascript">
26006 * @class Roo.DatePicker
26007 * @extends Roo.Component
26008 * Simple date picker class.
26010 * Create a new DatePicker
26011 * @param {Object} config The config object
26013 Roo.DatePicker = function(config){
26014 Roo.DatePicker.superclass.constructor.call(this, config);
26016 this.value = config && config.value ?
26017 config.value.clearTime() : new Date().clearTime();
26022 * Fires when a date is selected
26023 * @param {DatePicker} this
26024 * @param {Date} date The selected date
26028 * @event monthchange
26029 * Fires when the displayed month changes
26030 * @param {DatePicker} this
26031 * @param {Date} date The selected month
26033 'monthchange': true
26037 this.on("select", this.handler, this.scope || this);
26039 // build the disabledDatesRE
26040 if(!this.disabledDatesRE && this.disabledDates){
26041 var dd = this.disabledDates;
26043 for(var i = 0; i < dd.length; i++){
26045 if(i != dd.length-1) re += "|";
26047 this.disabledDatesRE = new RegExp(re + ")");
26051 Roo.extend(Roo.DatePicker, Roo.Component, {
26053 * @cfg {String} todayText
26054 * The text to display on the button that selects the current date (defaults to "Today")
26056 todayText : "Today",
26058 * @cfg {String} okText
26059 * The text to display on the ok button
26061 okText : " OK ", //   to give the user extra clicking room
26063 * @cfg {String} cancelText
26064 * The text to display on the cancel button
26066 cancelText : "Cancel",
26068 * @cfg {String} todayTip
26069 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
26071 todayTip : "{0} (Spacebar)",
26073 * @cfg {Date} minDate
26074 * Minimum allowable date (JavaScript date object, defaults to null)
26078 * @cfg {Date} maxDate
26079 * Maximum allowable date (JavaScript date object, defaults to null)
26083 * @cfg {String} minText
26084 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
26086 minText : "This date is before the minimum date",
26088 * @cfg {String} maxText
26089 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
26091 maxText : "This date is after the maximum date",
26093 * @cfg {String} format
26094 * The default date format string which can be overriden for localization support. The format must be
26095 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
26099 * @cfg {Array} disabledDays
26100 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
26102 disabledDays : null,
26104 * @cfg {String} disabledDaysText
26105 * The tooltip to display when the date falls on a disabled day (defaults to "")
26107 disabledDaysText : "",
26109 * @cfg {RegExp} disabledDatesRE
26110 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
26112 disabledDatesRE : null,
26114 * @cfg {String} disabledDatesText
26115 * The tooltip text to display when the date falls on a disabled date (defaults to "")
26117 disabledDatesText : "",
26119 * @cfg {Boolean} constrainToViewport
26120 * True to constrain the date picker to the viewport (defaults to true)
26122 constrainToViewport : true,
26124 * @cfg {Array} monthNames
26125 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
26127 monthNames : Date.monthNames,
26129 * @cfg {Array} dayNames
26130 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
26132 dayNames : Date.dayNames,
26134 * @cfg {String} nextText
26135 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
26137 nextText: 'Next Month (Control+Right)',
26139 * @cfg {String} prevText
26140 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
26142 prevText: 'Previous Month (Control+Left)',
26144 * @cfg {String} monthYearText
26145 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
26147 monthYearText: 'Choose a month (Control+Up/Down to move years)',
26149 * @cfg {Number} startDay
26150 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
26154 * @cfg {Bool} showClear
26155 * Show a clear button (usefull for date form elements that can be blank.)
26161 * Sets the value of the date field
26162 * @param {Date} value The date to set
26164 setValue : function(value){
26165 var old = this.value;
26167 if (typeof(value) == 'string') {
26169 value = Date.parseDate(value, this.format);
26172 value = new Date();
26175 this.value = value.clearTime(true);
26177 this.update(this.value);
26182 * Gets the current selected value of the date field
26183 * @return {Date} The selected date
26185 getValue : function(){
26190 focus : function(){
26192 this.update(this.activeDate);
26197 onRender : function(container, position){
26200 '<table cellspacing="0">',
26201 '<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'"> </a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'"> </a></td></tr>',
26202 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26203 var dn = this.dayNames;
26204 for(var i = 0; i < 7; i++){
26205 var d = this.startDay+i;
26209 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26211 m[m.length] = "</tr></thead><tbody><tr>";
26212 for(var i = 0; i < 42; i++) {
26213 if(i % 7 == 0 && i != 0){
26214 m[m.length] = "</tr><tr>";
26216 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26218 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26219 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26221 var el = document.createElement("div");
26222 el.className = "x-date-picker";
26223 el.innerHTML = m.join("");
26225 container.dom.insertBefore(el, position);
26227 this.el = Roo.get(el);
26228 this.eventEl = Roo.get(el.firstChild);
26230 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26231 handler: this.showPrevMonth,
26233 preventDefault:true,
26237 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26238 handler: this.showNextMonth,
26240 preventDefault:true,
26244 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26246 this.monthPicker = this.el.down('div.x-date-mp');
26247 this.monthPicker.enableDisplayMode('block');
26249 var kn = new Roo.KeyNav(this.eventEl, {
26250 "left" : function(e){
26252 this.showPrevMonth() :
26253 this.update(this.activeDate.add("d", -1));
26256 "right" : function(e){
26258 this.showNextMonth() :
26259 this.update(this.activeDate.add("d", 1));
26262 "up" : function(e){
26264 this.showNextYear() :
26265 this.update(this.activeDate.add("d", -7));
26268 "down" : function(e){
26270 this.showPrevYear() :
26271 this.update(this.activeDate.add("d", 7));
26274 "pageUp" : function(e){
26275 this.showNextMonth();
26278 "pageDown" : function(e){
26279 this.showPrevMonth();
26282 "enter" : function(e){
26283 e.stopPropagation();
26290 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26292 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26294 this.el.unselectable();
26296 this.cells = this.el.select("table.x-date-inner tbody td");
26297 this.textNodes = this.el.query("table.x-date-inner tbody span");
26299 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26301 tooltip: this.monthYearText
26304 this.mbtn.on('click', this.showMonthPicker, this);
26305 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26308 var today = (new Date()).dateFormat(this.format);
26310 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26311 if (this.showClear) {
26312 baseTb.add( new Roo.Toolbar.Fill());
26315 text: String.format(this.todayText, today),
26316 tooltip: String.format(this.todayTip, today),
26317 handler: this.selectToday,
26321 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26324 if (this.showClear) {
26326 baseTb.add( new Roo.Toolbar.Fill());
26329 cls: 'x-btn-icon x-btn-clear',
26330 handler: function() {
26332 this.fireEvent("select", this, '');
26342 this.update(this.value);
26345 createMonthPicker : function(){
26346 if(!this.monthPicker.dom.firstChild){
26347 var buf = ['<table border="0" cellspacing="0">'];
26348 for(var i = 0; i < 6; i++){
26350 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26351 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26353 '<td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-prev"></a></td><td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-next"></a></td></tr>' :
26354 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26358 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26360 '</button><button type="button" class="x-date-mp-cancel">',
26362 '</button></td></tr>',
26365 this.monthPicker.update(buf.join(''));
26366 this.monthPicker.on('click', this.onMonthClick, this);
26367 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26369 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26370 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26372 this.mpMonths.each(function(m, a, i){
26375 m.dom.xmonth = 5 + Math.round(i * .5);
26377 m.dom.xmonth = Math.round((i-1) * .5);
26383 showMonthPicker : function(){
26384 this.createMonthPicker();
26385 var size = this.el.getSize();
26386 this.monthPicker.setSize(size);
26387 this.monthPicker.child('table').setSize(size);
26389 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26390 this.updateMPMonth(this.mpSelMonth);
26391 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26392 this.updateMPYear(this.mpSelYear);
26394 this.monthPicker.slideIn('t', {duration:.2});
26397 updateMPYear : function(y){
26399 var ys = this.mpYears.elements;
26400 for(var i = 1; i <= 10; i++){
26401 var td = ys[i-1], y2;
26403 y2 = y + Math.round(i * .5);
26404 td.firstChild.innerHTML = y2;
26407 y2 = y - (5-Math.round(i * .5));
26408 td.firstChild.innerHTML = y2;
26411 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26415 updateMPMonth : function(sm){
26416 this.mpMonths.each(function(m, a, i){
26417 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26421 selectMPMonth: function(m){
26425 onMonthClick : function(e, t){
26427 var el = new Roo.Element(t), pn;
26428 if(el.is('button.x-date-mp-cancel')){
26429 this.hideMonthPicker();
26431 else if(el.is('button.x-date-mp-ok')){
26432 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26433 this.hideMonthPicker();
26435 else if(pn = el.up('td.x-date-mp-month', 2)){
26436 this.mpMonths.removeClass('x-date-mp-sel');
26437 pn.addClass('x-date-mp-sel');
26438 this.mpSelMonth = pn.dom.xmonth;
26440 else if(pn = el.up('td.x-date-mp-year', 2)){
26441 this.mpYears.removeClass('x-date-mp-sel');
26442 pn.addClass('x-date-mp-sel');
26443 this.mpSelYear = pn.dom.xyear;
26445 else if(el.is('a.x-date-mp-prev')){
26446 this.updateMPYear(this.mpyear-10);
26448 else if(el.is('a.x-date-mp-next')){
26449 this.updateMPYear(this.mpyear+10);
26453 onMonthDblClick : function(e, t){
26455 var el = new Roo.Element(t), pn;
26456 if(pn = el.up('td.x-date-mp-month', 2)){
26457 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26458 this.hideMonthPicker();
26460 else if(pn = el.up('td.x-date-mp-year', 2)){
26461 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26462 this.hideMonthPicker();
26466 hideMonthPicker : function(disableAnim){
26467 if(this.monthPicker){
26468 if(disableAnim === true){
26469 this.monthPicker.hide();
26471 this.monthPicker.slideOut('t', {duration:.2});
26477 showPrevMonth : function(e){
26478 this.update(this.activeDate.add("mo", -1));
26482 showNextMonth : function(e){
26483 this.update(this.activeDate.add("mo", 1));
26487 showPrevYear : function(){
26488 this.update(this.activeDate.add("y", -1));
26492 showNextYear : function(){
26493 this.update(this.activeDate.add("y", 1));
26497 handleMouseWheel : function(e){
26498 var delta = e.getWheelDelta();
26500 this.showPrevMonth();
26502 } else if(delta < 0){
26503 this.showNextMonth();
26509 handleDateClick : function(e, t){
26511 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26512 this.setValue(new Date(t.dateValue));
26513 this.fireEvent("select", this, this.value);
26518 selectToday : function(){
26519 this.setValue(new Date().clearTime());
26520 this.fireEvent("select", this, this.value);
26524 update : function(date)
26526 var vd = this.activeDate;
26527 this.activeDate = date;
26529 var t = date.getTime();
26530 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26531 this.cells.removeClass("x-date-selected");
26532 this.cells.each(function(c){
26533 if(c.dom.firstChild.dateValue == t){
26534 c.addClass("x-date-selected");
26535 setTimeout(function(){
26536 try{c.dom.firstChild.focus();}catch(e){}
26545 var days = date.getDaysInMonth();
26546 var firstOfMonth = date.getFirstDateOfMonth();
26547 var startingPos = firstOfMonth.getDay()-this.startDay;
26549 if(startingPos <= this.startDay){
26553 var pm = date.add("mo", -1);
26554 var prevStart = pm.getDaysInMonth()-startingPos;
26556 var cells = this.cells.elements;
26557 var textEls = this.textNodes;
26558 days += startingPos;
26560 // convert everything to numbers so it's fast
26561 var day = 86400000;
26562 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26563 var today = new Date().clearTime().getTime();
26564 var sel = date.clearTime().getTime();
26565 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26566 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26567 var ddMatch = this.disabledDatesRE;
26568 var ddText = this.disabledDatesText;
26569 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26570 var ddaysText = this.disabledDaysText;
26571 var format = this.format;
26573 var setCellClass = function(cal, cell){
26575 var t = d.getTime();
26576 cell.firstChild.dateValue = t;
26578 cell.className += " x-date-today";
26579 cell.title = cal.todayText;
26582 cell.className += " x-date-selected";
26583 setTimeout(function(){
26584 try{cell.firstChild.focus();}catch(e){}
26589 cell.className = " x-date-disabled";
26590 cell.title = cal.minText;
26594 cell.className = " x-date-disabled";
26595 cell.title = cal.maxText;
26599 if(ddays.indexOf(d.getDay()) != -1){
26600 cell.title = ddaysText;
26601 cell.className = " x-date-disabled";
26604 if(ddMatch && format){
26605 var fvalue = d.dateFormat(format);
26606 if(ddMatch.test(fvalue)){
26607 cell.title = ddText.replace("%0", fvalue);
26608 cell.className = " x-date-disabled";
26614 for(; i < startingPos; i++) {
26615 textEls[i].innerHTML = (++prevStart);
26616 d.setDate(d.getDate()+1);
26617 cells[i].className = "x-date-prevday";
26618 setCellClass(this, cells[i]);
26620 for(; i < days; i++){
26621 intDay = i - startingPos + 1;
26622 textEls[i].innerHTML = (intDay);
26623 d.setDate(d.getDate()+1);
26624 cells[i].className = "x-date-active";
26625 setCellClass(this, cells[i]);
26628 for(; i < 42; i++) {
26629 textEls[i].innerHTML = (++extraDays);
26630 d.setDate(d.getDate()+1);
26631 cells[i].className = "x-date-nextday";
26632 setCellClass(this, cells[i]);
26635 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26636 this.fireEvent('monthchange', this, date);
26638 if(!this.internalRender){
26639 var main = this.el.dom.firstChild;
26640 var w = main.offsetWidth;
26641 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26642 Roo.fly(main).setWidth(w);
26643 this.internalRender = true;
26644 // opera does not respect the auto grow header center column
26645 // then, after it gets a width opera refuses to recalculate
26646 // without a second pass
26647 if(Roo.isOpera && !this.secondPass){
26648 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26649 this.secondPass = true;
26650 this.update.defer(10, this, [date]);
26658 * Ext JS Library 1.1.1
26659 * Copyright(c) 2006-2007, Ext JS, LLC.
26661 * Originally Released Under LGPL - original licence link has changed is not relivant.
26664 * <script type="text/javascript">
26667 * @class Roo.TabPanel
26668 * @extends Roo.util.Observable
26669 * A lightweight tab container.
26673 // basic tabs 1, built from existing content
26674 var tabs = new Roo.TabPanel("tabs1");
26675 tabs.addTab("script", "View Script");
26676 tabs.addTab("markup", "View Markup");
26677 tabs.activate("script");
26679 // more advanced tabs, built from javascript
26680 var jtabs = new Roo.TabPanel("jtabs");
26681 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26683 // set up the UpdateManager
26684 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26685 var updater = tab2.getUpdateManager();
26686 updater.setDefaultUrl("ajax1.htm");
26687 tab2.on('activate', updater.refresh, updater, true);
26689 // Use setUrl for Ajax loading
26690 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26691 tab3.setUrl("ajax2.htm", null, true);
26694 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26697 jtabs.activate("jtabs-1");
26700 * Create a new TabPanel.
26701 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26702 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26704 Roo.TabPanel = function(container, config){
26706 * The container element for this TabPanel.
26707 * @type Roo.Element
26709 this.el = Roo.get(container, true);
26711 if(typeof config == "boolean"){
26712 this.tabPosition = config ? "bottom" : "top";
26714 Roo.apply(this, config);
26717 if(this.tabPosition == "bottom"){
26718 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26719 this.el.addClass("x-tabs-bottom");
26721 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26722 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26723 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26725 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26727 if(this.tabPosition != "bottom"){
26728 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26729 * @type Roo.Element
26731 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26732 this.el.addClass("x-tabs-top");
26736 this.bodyEl.setStyle("position", "relative");
26738 this.active = null;
26739 this.activateDelegate = this.activate.createDelegate(this);
26744 * Fires when the active tab changes
26745 * @param {Roo.TabPanel} this
26746 * @param {Roo.TabPanelItem} activePanel The new active tab
26750 * @event beforetabchange
26751 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26752 * @param {Roo.TabPanel} this
26753 * @param {Object} e Set cancel to true on this object to cancel the tab change
26754 * @param {Roo.TabPanelItem} tab The tab being changed to
26756 "beforetabchange" : true
26759 Roo.EventManager.onWindowResize(this.onResize, this);
26760 this.cpad = this.el.getPadding("lr");
26761 this.hiddenCount = 0;
26764 // toolbar on the tabbar support...
26765 if (this.toolbar) {
26766 var tcfg = this.toolbar;
26767 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26768 this.toolbar = new Roo.Toolbar(tcfg);
26769 if (Roo.isSafari) {
26770 var tbl = tcfg.container.child('table', true);
26771 tbl.setAttribute('width', '100%');
26778 Roo.TabPanel.superclass.constructor.call(this);
26781 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26783 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26785 tabPosition : "top",
26787 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26789 currentTabWidth : 0,
26791 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26795 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26799 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26801 preferredTabWidth : 175,
26803 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26805 resizeTabs : false,
26807 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26809 monitorResize : true,
26811 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26816 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26817 * @param {String} id The id of the div to use <b>or create</b>
26818 * @param {String} text The text for the tab
26819 * @param {String} content (optional) Content to put in the TabPanelItem body
26820 * @param {Boolean} closable (optional) True to create a close icon on the tab
26821 * @return {Roo.TabPanelItem} The created TabPanelItem
26823 addTab : function(id, text, content, closable){
26824 var item = new Roo.TabPanelItem(this, id, text, closable);
26825 this.addTabItem(item);
26827 item.setContent(content);
26833 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26834 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26835 * @return {Roo.TabPanelItem}
26837 getTab : function(id){
26838 return this.items[id];
26842 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26843 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26845 hideTab : function(id){
26846 var t = this.items[id];
26849 this.hiddenCount++;
26850 this.autoSizeTabs();
26855 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26856 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26858 unhideTab : function(id){
26859 var t = this.items[id];
26861 t.setHidden(false);
26862 this.hiddenCount--;
26863 this.autoSizeTabs();
26868 * Adds an existing {@link Roo.TabPanelItem}.
26869 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26871 addTabItem : function(item){
26872 this.items[item.id] = item;
26873 this.items.push(item);
26874 if(this.resizeTabs){
26875 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26876 this.autoSizeTabs();
26883 * Removes a {@link Roo.TabPanelItem}.
26884 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26886 removeTab : function(id){
26887 var items = this.items;
26888 var tab = items[id];
26889 if(!tab) { return; }
26890 var index = items.indexOf(tab);
26891 if(this.active == tab && items.length > 1){
26892 var newTab = this.getNextAvailable(index);
26897 this.stripEl.dom.removeChild(tab.pnode.dom);
26898 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26899 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26901 items.splice(index, 1);
26902 delete this.items[tab.id];
26903 tab.fireEvent("close", tab);
26904 tab.purgeListeners();
26905 this.autoSizeTabs();
26908 getNextAvailable : function(start){
26909 var items = this.items;
26911 // look for a next tab that will slide over to
26912 // replace the one being removed
26913 while(index < items.length){
26914 var item = items[++index];
26915 if(item && !item.isHidden()){
26919 // if one isn't found select the previous tab (on the left)
26922 var item = items[--index];
26923 if(item && !item.isHidden()){
26931 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26932 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26934 disableTab : function(id){
26935 var tab = this.items[id];
26936 if(tab && this.active != tab){
26942 * Enables a {@link Roo.TabPanelItem} that is disabled.
26943 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26945 enableTab : function(id){
26946 var tab = this.items[id];
26951 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26952 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26953 * @return {Roo.TabPanelItem} The TabPanelItem.
26955 activate : function(id){
26956 var tab = this.items[id];
26960 if(tab == this.active || tab.disabled){
26964 this.fireEvent("beforetabchange", this, e, tab);
26965 if(e.cancel !== true && !tab.disabled){
26967 this.active.hide();
26969 this.active = this.items[id];
26970 this.active.show();
26971 this.fireEvent("tabchange", this, this.active);
26977 * Gets the active {@link Roo.TabPanelItem}.
26978 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26980 getActiveTab : function(){
26981 return this.active;
26985 * Updates the tab body element to fit the height of the container element
26986 * for overflow scrolling
26987 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26989 syncHeight : function(targetHeight){
26990 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26991 var bm = this.bodyEl.getMargins();
26992 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26993 this.bodyEl.setHeight(newHeight);
26997 onResize : function(){
26998 if(this.monitorResize){
26999 this.autoSizeTabs();
27004 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
27006 beginUpdate : function(){
27007 this.updating = true;
27011 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
27013 endUpdate : function(){
27014 this.updating = false;
27015 this.autoSizeTabs();
27019 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
27021 autoSizeTabs : function(){
27022 var count = this.items.length;
27023 var vcount = count - this.hiddenCount;
27024 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
27025 var w = Math.max(this.el.getWidth() - this.cpad, 10);
27026 var availWidth = Math.floor(w / vcount);
27027 var b = this.stripBody;
27028 if(b.getWidth() > w){
27029 var tabs = this.items;
27030 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
27031 if(availWidth < this.minTabWidth){
27032 /*if(!this.sleft){ // incomplete scrolling code
27033 this.createScrollButtons();
27036 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
27039 if(this.currentTabWidth < this.preferredTabWidth){
27040 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
27046 * Returns the number of tabs in this TabPanel.
27049 getCount : function(){
27050 return this.items.length;
27054 * Resizes all the tabs to the passed width
27055 * @param {Number} The new width
27057 setTabWidth : function(width){
27058 this.currentTabWidth = width;
27059 for(var i = 0, len = this.items.length; i < len; i++) {
27060 if(!this.items[i].isHidden())this.items[i].setWidth(width);
27065 * Destroys this TabPanel
27066 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
27068 destroy : function(removeEl){
27069 Roo.EventManager.removeResizeListener(this.onResize, this);
27070 for(var i = 0, len = this.items.length; i < len; i++){
27071 this.items[i].purgeListeners();
27073 if(removeEl === true){
27074 this.el.update("");
27081 * @class Roo.TabPanelItem
27082 * @extends Roo.util.Observable
27083 * Represents an individual item (tab plus body) in a TabPanel.
27084 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
27085 * @param {String} id The id of this TabPanelItem
27086 * @param {String} text The text for the tab of this TabPanelItem
27087 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
27089 Roo.TabPanelItem = function(tabPanel, id, text, closable){
27091 * The {@link Roo.TabPanel} this TabPanelItem belongs to
27092 * @type Roo.TabPanel
27094 this.tabPanel = tabPanel;
27096 * The id for this TabPanelItem
27101 this.disabled = false;
27105 this.loaded = false;
27106 this.closable = closable;
27109 * The body element for this TabPanelItem.
27110 * @type Roo.Element
27112 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
27113 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
27114 this.bodyEl.setStyle("display", "block");
27115 this.bodyEl.setStyle("zoom", "1");
27118 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
27120 this.el = Roo.get(els.el, true);
27121 this.inner = Roo.get(els.inner, true);
27122 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
27123 this.pnode = Roo.get(els.el.parentNode, true);
27124 this.el.on("mousedown", this.onTabMouseDown, this);
27125 this.el.on("click", this.onTabClick, this);
27128 var c = Roo.get(els.close, true);
27129 c.dom.title = this.closeText;
27130 c.addClassOnOver("close-over");
27131 c.on("click", this.closeClick, this);
27137 * Fires when this tab becomes the active tab.
27138 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27139 * @param {Roo.TabPanelItem} this
27143 * @event beforeclose
27144 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
27145 * @param {Roo.TabPanelItem} this
27146 * @param {Object} e Set cancel to true on this object to cancel the close.
27148 "beforeclose": true,
27151 * Fires when this tab is closed.
27152 * @param {Roo.TabPanelItem} this
27156 * @event deactivate
27157 * Fires when this tab is no longer the active tab.
27158 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27159 * @param {Roo.TabPanelItem} this
27161 "deactivate" : true
27163 this.hidden = false;
27165 Roo.TabPanelItem.superclass.constructor.call(this);
27168 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27169 purgeListeners : function(){
27170 Roo.util.Observable.prototype.purgeListeners.call(this);
27171 this.el.removeAllListeners();
27174 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27177 this.pnode.addClass("on");
27180 this.tabPanel.stripWrap.repaint();
27182 this.fireEvent("activate", this.tabPanel, this);
27186 * Returns true if this tab is the active tab.
27187 * @return {Boolean}
27189 isActive : function(){
27190 return this.tabPanel.getActiveTab() == this;
27194 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27197 this.pnode.removeClass("on");
27199 this.fireEvent("deactivate", this.tabPanel, this);
27202 hideAction : function(){
27203 this.bodyEl.hide();
27204 this.bodyEl.setStyle("position", "absolute");
27205 this.bodyEl.setLeft("-20000px");
27206 this.bodyEl.setTop("-20000px");
27209 showAction : function(){
27210 this.bodyEl.setStyle("position", "relative");
27211 this.bodyEl.setTop("");
27212 this.bodyEl.setLeft("");
27213 this.bodyEl.show();
27217 * Set the tooltip for the tab.
27218 * @param {String} tooltip The tab's tooltip
27220 setTooltip : function(text){
27221 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27222 this.textEl.dom.qtip = text;
27223 this.textEl.dom.removeAttribute('title');
27225 this.textEl.dom.title = text;
27229 onTabClick : function(e){
27230 e.preventDefault();
27231 this.tabPanel.activate(this.id);
27234 onTabMouseDown : function(e){
27235 e.preventDefault();
27236 this.tabPanel.activate(this.id);
27239 getWidth : function(){
27240 return this.inner.getWidth();
27243 setWidth : function(width){
27244 var iwidth = width - this.pnode.getPadding("lr");
27245 this.inner.setWidth(iwidth);
27246 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27247 this.pnode.setWidth(width);
27251 * Show or hide the tab
27252 * @param {Boolean} hidden True to hide or false to show.
27254 setHidden : function(hidden){
27255 this.hidden = hidden;
27256 this.pnode.setStyle("display", hidden ? "none" : "");
27260 * Returns true if this tab is "hidden"
27261 * @return {Boolean}
27263 isHidden : function(){
27264 return this.hidden;
27268 * Returns the text for this tab
27271 getText : function(){
27275 autoSize : function(){
27276 //this.el.beginMeasure();
27277 this.textEl.setWidth(1);
27279 * #2804 [new] Tabs in Roojs
27280 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
27282 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
27283 //this.el.endMeasure();
27287 * Sets the text for the tab (Note: this also sets the tooltip text)
27288 * @param {String} text The tab's text and tooltip
27290 setText : function(text){
27292 this.textEl.update(text);
27293 this.setTooltip(text);
27294 if(!this.tabPanel.resizeTabs){
27299 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27301 activate : function(){
27302 this.tabPanel.activate(this.id);
27306 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27308 disable : function(){
27309 if(this.tabPanel.active != this){
27310 this.disabled = true;
27311 this.pnode.addClass("disabled");
27316 * Enables this TabPanelItem if it was previously disabled.
27318 enable : function(){
27319 this.disabled = false;
27320 this.pnode.removeClass("disabled");
27324 * Sets the content for this TabPanelItem.
27325 * @param {String} content The content
27326 * @param {Boolean} loadScripts true to look for and load scripts
27328 setContent : function(content, loadScripts){
27329 this.bodyEl.update(content, loadScripts);
27333 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27334 * @return {Roo.UpdateManager} The UpdateManager
27336 getUpdateManager : function(){
27337 return this.bodyEl.getUpdateManager();
27341 * Set a URL to be used to load the content for this TabPanelItem.
27342 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27343 * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
27344 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
27345 * @return {Roo.UpdateManager} The UpdateManager
27347 setUrl : function(url, params, loadOnce){
27348 if(this.refreshDelegate){
27349 this.un('activate', this.refreshDelegate);
27351 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27352 this.on("activate", this.refreshDelegate);
27353 return this.bodyEl.getUpdateManager();
27357 _handleRefresh : function(url, params, loadOnce){
27358 if(!loadOnce || !this.loaded){
27359 var updater = this.bodyEl.getUpdateManager();
27360 updater.update(url, params, this._setLoaded.createDelegate(this));
27365 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27366 * Will fail silently if the setUrl method has not been called.
27367 * This does not activate the panel, just updates its content.
27369 refresh : function(){
27370 if(this.refreshDelegate){
27371 this.loaded = false;
27372 this.refreshDelegate();
27377 _setLoaded : function(){
27378 this.loaded = true;
27382 closeClick : function(e){
27385 this.fireEvent("beforeclose", this, o);
27386 if(o.cancel !== true){
27387 this.tabPanel.removeTab(this.id);
27391 * The text displayed in the tooltip for the close icon.
27394 closeText : "Close this tab"
27398 Roo.TabPanel.prototype.createStrip = function(container){
27399 var strip = document.createElement("div");
27400 strip.className = "x-tabs-wrap";
27401 container.appendChild(strip);
27405 Roo.TabPanel.prototype.createStripList = function(strip){
27406 // div wrapper for retard IE
27407 // returns the "tr" element.
27408 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27409 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27410 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27411 return strip.firstChild.firstChild.firstChild.firstChild;
27414 Roo.TabPanel.prototype.createBody = function(container){
27415 var body = document.createElement("div");
27416 Roo.id(body, "tab-body");
27417 Roo.fly(body).addClass("x-tabs-body");
27418 container.appendChild(body);
27422 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27423 var body = Roo.getDom(id);
27425 body = document.createElement("div");
27428 Roo.fly(body).addClass("x-tabs-item-body");
27429 bodyEl.insertBefore(body, bodyEl.firstChild);
27433 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27434 var td = document.createElement("td");
27435 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27436 //stripEl.appendChild(td);
27438 td.className = "x-tabs-closable";
27439 if(!this.closeTpl){
27440 this.closeTpl = new Roo.Template(
27441 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27442 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27443 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27446 var el = this.closeTpl.overwrite(td, {"text": text});
27447 var close = el.getElementsByTagName("div")[0];
27448 var inner = el.getElementsByTagName("em")[0];
27449 return {"el": el, "close": close, "inner": inner};
27452 this.tabTpl = new Roo.Template(
27453 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27454 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27457 var el = this.tabTpl.overwrite(td, {"text": text});
27458 var inner = el.getElementsByTagName("em")[0];
27459 return {"el": el, "inner": inner};
27463 * Ext JS Library 1.1.1
27464 * Copyright(c) 2006-2007, Ext JS, LLC.
27466 * Originally Released Under LGPL - original licence link has changed is not relivant.
27469 * <script type="text/javascript">
27473 * @class Roo.Button
27474 * @extends Roo.util.Observable
27475 * Simple Button class
27476 * @cfg {String} text The button text
27477 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27478 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27479 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27480 * @cfg {Object} scope The scope of the handler
27481 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27482 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27483 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27484 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27485 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27486 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27487 applies if enableToggle = true)
27488 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27489 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27490 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27492 * Create a new button
27493 * @param {Object} config The config object
27495 Roo.Button = function(renderTo, config)
27499 renderTo = config.renderTo || false;
27502 Roo.apply(this, config);
27506 * Fires when this button is clicked
27507 * @param {Button} this
27508 * @param {EventObject} e The click event
27513 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27514 * @param {Button} this
27515 * @param {Boolean} pressed
27520 * Fires when the mouse hovers over the button
27521 * @param {Button} this
27522 * @param {Event} e The event object
27524 'mouseover' : true,
27527 * Fires when the mouse exits the button
27528 * @param {Button} this
27529 * @param {Event} e The event object
27534 * Fires when the button is rendered
27535 * @param {Button} this
27540 this.menu = Roo.menu.MenuMgr.get(this.menu);
27542 // register listeners first!! - so render can be captured..
27543 Roo.util.Observable.call(this);
27545 this.render(renderTo);
27551 Roo.extend(Roo.Button, Roo.util.Observable, {
27557 * Read-only. True if this button is hidden
27562 * Read-only. True if this button is disabled
27567 * Read-only. True if this button is pressed (only if enableToggle = true)
27573 * @cfg {Number} tabIndex
27574 * The DOM tabIndex for this button (defaults to undefined)
27576 tabIndex : undefined,
27579 * @cfg {Boolean} enableToggle
27580 * True to enable pressed/not pressed toggling (defaults to false)
27582 enableToggle: false,
27584 * @cfg {Mixed} menu
27585 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27589 * @cfg {String} menuAlign
27590 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27592 menuAlign : "tl-bl?",
27595 * @cfg {String} iconCls
27596 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27598 iconCls : undefined,
27600 * @cfg {String} type
27601 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27606 menuClassTarget: 'tr',
27609 * @cfg {String} clickEvent
27610 * The type of event to map to the button's event handler (defaults to 'click')
27612 clickEvent : 'click',
27615 * @cfg {Boolean} handleMouseEvents
27616 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27618 handleMouseEvents : true,
27621 * @cfg {String} tooltipType
27622 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27624 tooltipType : 'qtip',
27627 * @cfg {String} cls
27628 * A CSS class to apply to the button's main element.
27632 * @cfg {Roo.Template} template (Optional)
27633 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27634 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27635 * require code modifications if required elements (e.g. a button) aren't present.
27639 render : function(renderTo){
27641 if(this.hideParent){
27642 this.parentEl = Roo.get(renderTo);
27644 if(!this.dhconfig){
27645 if(!this.template){
27646 if(!Roo.Button.buttonTemplate){
27647 // hideous table template
27648 Roo.Button.buttonTemplate = new Roo.Template(
27649 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27650 '<td class="x-btn-left"><i> </i></td><td class="x-btn-center"><em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td><td class="x-btn-right"><i> </i></td>',
27651 "</tr></tbody></table>");
27653 this.template = Roo.Button.buttonTemplate;
27655 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27656 var btnEl = btn.child("button:first");
27657 btnEl.on('focus', this.onFocus, this);
27658 btnEl.on('blur', this.onBlur, this);
27660 btn.addClass(this.cls);
27663 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27666 btnEl.addClass(this.iconCls);
27668 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27671 if(this.tabIndex !== undefined){
27672 btnEl.dom.tabIndex = this.tabIndex;
27675 if(typeof this.tooltip == 'object'){
27676 Roo.QuickTips.tips(Roo.apply({
27680 btnEl.dom[this.tooltipType] = this.tooltip;
27684 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27688 this.el.dom.id = this.el.id = this.id;
27691 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27692 this.menu.on("show", this.onMenuShow, this);
27693 this.menu.on("hide", this.onMenuHide, this);
27695 btn.addClass("x-btn");
27696 if(Roo.isIE && !Roo.isIE7){
27697 this.autoWidth.defer(1, this);
27701 if(this.handleMouseEvents){
27702 btn.on("mouseover", this.onMouseOver, this);
27703 btn.on("mouseout", this.onMouseOut, this);
27704 btn.on("mousedown", this.onMouseDown, this);
27706 btn.on(this.clickEvent, this.onClick, this);
27707 //btn.on("mouseup", this.onMouseUp, this);
27714 Roo.ButtonToggleMgr.register(this);
27716 this.el.addClass("x-btn-pressed");
27719 var repeater = new Roo.util.ClickRepeater(btn,
27720 typeof this.repeat == "object" ? this.repeat : {}
27722 repeater.on("click", this.onClick, this);
27725 this.fireEvent('render', this);
27729 * Returns the button's underlying element
27730 * @return {Roo.Element} The element
27732 getEl : function(){
27737 * Destroys this Button and removes any listeners.
27739 destroy : function(){
27740 Roo.ButtonToggleMgr.unregister(this);
27741 this.el.removeAllListeners();
27742 this.purgeListeners();
27747 autoWidth : function(){
27749 this.el.setWidth("auto");
27750 if(Roo.isIE7 && Roo.isStrict){
27751 var ib = this.el.child('button');
27752 if(ib && ib.getWidth() > 20){
27754 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27759 this.el.beginMeasure();
27761 if(this.el.getWidth() < this.minWidth){
27762 this.el.setWidth(this.minWidth);
27765 this.el.endMeasure();
27772 * Assigns this button's click handler
27773 * @param {Function} handler The function to call when the button is clicked
27774 * @param {Object} scope (optional) Scope for the function passed in
27776 setHandler : function(handler, scope){
27777 this.handler = handler;
27778 this.scope = scope;
27782 * Sets this button's text
27783 * @param {String} text The button text
27785 setText : function(text){
27788 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27794 * Gets the text for this button
27795 * @return {String} The button text
27797 getText : function(){
27805 this.hidden = false;
27807 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27815 this.hidden = true;
27817 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27822 * Convenience function for boolean show/hide
27823 * @param {Boolean} visible True to show, false to hide
27825 setVisible: function(visible){
27834 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27835 * @param {Boolean} state (optional) Force a particular state
27837 toggle : function(state){
27838 state = state === undefined ? !this.pressed : state;
27839 if(state != this.pressed){
27841 this.el.addClass("x-btn-pressed");
27842 this.pressed = true;
27843 this.fireEvent("toggle", this, true);
27845 this.el.removeClass("x-btn-pressed");
27846 this.pressed = false;
27847 this.fireEvent("toggle", this, false);
27849 if(this.toggleHandler){
27850 this.toggleHandler.call(this.scope || this, this, state);
27858 focus : function(){
27859 this.el.child('button:first').focus();
27863 * Disable this button
27865 disable : function(){
27867 this.el.addClass("x-btn-disabled");
27869 this.disabled = true;
27873 * Enable this button
27875 enable : function(){
27877 this.el.removeClass("x-btn-disabled");
27879 this.disabled = false;
27883 * Convenience function for boolean enable/disable
27884 * @param {Boolean} enabled True to enable, false to disable
27886 setDisabled : function(v){
27887 this[v !== true ? "enable" : "disable"]();
27891 onClick : function(e)
27894 e.preventDefault();
27899 if(!this.disabled){
27900 if(this.enableToggle){
27903 if(this.menu && !this.menu.isVisible()){
27904 this.menu.show(this.el, this.menuAlign);
27906 this.fireEvent("click", this, e);
27908 this.el.removeClass("x-btn-over");
27909 this.handler.call(this.scope || this, this, e);
27914 onMouseOver : function(e){
27915 if(!this.disabled){
27916 this.el.addClass("x-btn-over");
27917 this.fireEvent('mouseover', this, e);
27921 onMouseOut : function(e){
27922 if(!e.within(this.el, true)){
27923 this.el.removeClass("x-btn-over");
27924 this.fireEvent('mouseout', this, e);
27928 onFocus : function(e){
27929 if(!this.disabled){
27930 this.el.addClass("x-btn-focus");
27934 onBlur : function(e){
27935 this.el.removeClass("x-btn-focus");
27938 onMouseDown : function(e){
27939 if(!this.disabled && e.button == 0){
27940 this.el.addClass("x-btn-click");
27941 Roo.get(document).on('mouseup', this.onMouseUp, this);
27945 onMouseUp : function(e){
27947 this.el.removeClass("x-btn-click");
27948 Roo.get(document).un('mouseup', this.onMouseUp, this);
27952 onMenuShow : function(e){
27953 this.el.addClass("x-btn-menu-active");
27956 onMenuHide : function(e){
27957 this.el.removeClass("x-btn-menu-active");
27961 // Private utility class used by Button
27962 Roo.ButtonToggleMgr = function(){
27965 function toggleGroup(btn, state){
27967 var g = groups[btn.toggleGroup];
27968 for(var i = 0, l = g.length; i < l; i++){
27970 g[i].toggle(false);
27977 register : function(btn){
27978 if(!btn.toggleGroup){
27981 var g = groups[btn.toggleGroup];
27983 g = groups[btn.toggleGroup] = [];
27986 btn.on("toggle", toggleGroup);
27989 unregister : function(btn){
27990 if(!btn.toggleGroup){
27993 var g = groups[btn.toggleGroup];
27996 btn.un("toggle", toggleGroup);
28002 * Ext JS Library 1.1.1
28003 * Copyright(c) 2006-2007, Ext JS, LLC.
28005 * Originally Released Under LGPL - original licence link has changed is not relivant.
28008 * <script type="text/javascript">
28012 * @class Roo.SplitButton
28013 * @extends Roo.Button
28014 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
28015 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
28016 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
28017 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
28018 * @cfg {String} arrowTooltip The title attribute of the arrow
28020 * Create a new menu button
28021 * @param {String/HTMLElement/Element} renderTo The element to append the button to
28022 * @param {Object} config The config object
28024 Roo.SplitButton = function(renderTo, config){
28025 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
28027 * @event arrowclick
28028 * Fires when this button's arrow is clicked
28029 * @param {SplitButton} this
28030 * @param {EventObject} e The click event
28032 this.addEvents({"arrowclick":true});
28035 Roo.extend(Roo.SplitButton, Roo.Button, {
28036 render : function(renderTo){
28037 // this is one sweet looking template!
28038 var tpl = new Roo.Template(
28039 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
28040 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
28041 '<tr><td class="x-btn-left"><i> </i></td><td class="x-btn-center"><button class="x-btn-text" type="{1}">{0}</button></td></tr>',
28042 "</tbody></table></td><td>",
28043 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
28044 '<tr><td class="x-btn-center"><button class="x-btn-menu-arrow-el" type="button"> </button></td><td class="x-btn-right"><i> </i></td></tr>',
28045 "</tbody></table></td></tr></table>"
28047 var btn = tpl.append(renderTo, [this.text, this.type], true);
28048 var btnEl = btn.child("button");
28050 btn.addClass(this.cls);
28053 btnEl.setStyle('background-image', 'url(' +this.icon +')');
28056 btnEl.addClass(this.iconCls);
28058 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
28062 if(this.handleMouseEvents){
28063 btn.on("mouseover", this.onMouseOver, this);
28064 btn.on("mouseout", this.onMouseOut, this);
28065 btn.on("mousedown", this.onMouseDown, this);
28066 btn.on("mouseup", this.onMouseUp, this);
28068 btn.on(this.clickEvent, this.onClick, this);
28070 if(typeof this.tooltip == 'object'){
28071 Roo.QuickTips.tips(Roo.apply({
28075 btnEl.dom[this.tooltipType] = this.tooltip;
28078 if(this.arrowTooltip){
28079 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
28088 this.el.addClass("x-btn-pressed");
28090 if(Roo.isIE && !Roo.isIE7){
28091 this.autoWidth.defer(1, this);
28096 this.menu.on("show", this.onMenuShow, this);
28097 this.menu.on("hide", this.onMenuHide, this);
28099 this.fireEvent('render', this);
28103 autoWidth : function(){
28105 var tbl = this.el.child("table:first");
28106 var tbl2 = this.el.child("table:last");
28107 this.el.setWidth("auto");
28108 tbl.setWidth("auto");
28109 if(Roo.isIE7 && Roo.isStrict){
28110 var ib = this.el.child('button:first');
28111 if(ib && ib.getWidth() > 20){
28113 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
28118 this.el.beginMeasure();
28120 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
28121 tbl.setWidth(this.minWidth-tbl2.getWidth());
28124 this.el.endMeasure();
28127 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
28131 * Sets this button's click handler
28132 * @param {Function} handler The function to call when the button is clicked
28133 * @param {Object} scope (optional) Scope for the function passed above
28135 setHandler : function(handler, scope){
28136 this.handler = handler;
28137 this.scope = scope;
28141 * Sets this button's arrow click handler
28142 * @param {Function} handler The function to call when the arrow is clicked
28143 * @param {Object} scope (optional) Scope for the function passed above
28145 setArrowHandler : function(handler, scope){
28146 this.arrowHandler = handler;
28147 this.scope = scope;
28153 focus : function(){
28155 this.el.child("button:first").focus();
28160 onClick : function(e){
28161 e.preventDefault();
28162 if(!this.disabled){
28163 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28164 if(this.menu && !this.menu.isVisible()){
28165 this.menu.show(this.el, this.menuAlign);
28167 this.fireEvent("arrowclick", this, e);
28168 if(this.arrowHandler){
28169 this.arrowHandler.call(this.scope || this, this, e);
28172 this.fireEvent("click", this, e);
28174 this.handler.call(this.scope || this, this, e);
28180 onMouseDown : function(e){
28181 if(!this.disabled){
28182 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28186 onMouseUp : function(e){
28187 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28192 // backwards compat
28193 Roo.MenuButton = Roo.SplitButton;/*
28195 * Ext JS Library 1.1.1
28196 * Copyright(c) 2006-2007, Ext JS, LLC.
28198 * Originally Released Under LGPL - original licence link has changed is not relivant.
28201 * <script type="text/javascript">
28205 * @class Roo.Toolbar
28206 * Basic Toolbar class.
28208 * Creates a new Toolbar
28209 * @param {Object} container The config object
28211 Roo.Toolbar = function(container, buttons, config)
28213 /// old consturctor format still supported..
28214 if(container instanceof Array){ // omit the container for later rendering
28215 buttons = container;
28219 if (typeof(container) == 'object' && container.xtype) {
28220 config = container;
28221 container = config.container;
28222 buttons = config.buttons || []; // not really - use items!!
28225 if (config && config.items) {
28226 xitems = config.items;
28227 delete config.items;
28229 Roo.apply(this, config);
28230 this.buttons = buttons;
28233 this.render(container);
28235 this.xitems = xitems;
28236 Roo.each(xitems, function(b) {
28242 Roo.Toolbar.prototype = {
28244 * @cfg {Array} items
28245 * array of button configs or elements to add (will be converted to a MixedCollection)
28249 * @cfg {String/HTMLElement/Element} container
28250 * The id or element that will contain the toolbar
28253 render : function(ct){
28254 this.el = Roo.get(ct);
28256 this.el.addClass(this.cls);
28258 // using a table allows for vertical alignment
28259 // 100% width is needed by Safari...
28260 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28261 this.tr = this.el.child("tr", true);
28263 this.items = new Roo.util.MixedCollection(false, function(o){
28264 return o.id || ("item" + (++autoId));
28267 this.add.apply(this, this.buttons);
28268 delete this.buttons;
28273 * Adds element(s) to the toolbar -- this function takes a variable number of
28274 * arguments of mixed type and adds them to the toolbar.
28275 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28277 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28278 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28279 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28280 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28281 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28282 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28283 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28284 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28285 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28287 * @param {Mixed} arg2
28288 * @param {Mixed} etc.
28291 var a = arguments, l = a.length;
28292 for(var i = 0; i < l; i++){
28297 _add : function(el) {
28300 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28303 if (el.applyTo){ // some kind of form field
28304 return this.addField(el);
28306 if (el.render){ // some kind of Toolbar.Item
28307 return this.addItem(el);
28309 if (typeof el == "string"){ // string
28310 if(el == "separator" || el == "-"){
28311 return this.addSeparator();
28314 return this.addSpacer();
28317 return this.addFill();
28319 return this.addText(el);
28322 if(el.tagName){ // element
28323 return this.addElement(el);
28325 if(typeof el == "object"){ // must be button config?
28326 return this.addButton(el);
28328 // and now what?!?!
28334 * Add an Xtype element
28335 * @param {Object} xtype Xtype Object
28336 * @return {Object} created Object
28338 addxtype : function(e){
28339 return this.add(e);
28343 * Returns the Element for this toolbar.
28344 * @return {Roo.Element}
28346 getEl : function(){
28352 * @return {Roo.Toolbar.Item} The separator item
28354 addSeparator : function(){
28355 return this.addItem(new Roo.Toolbar.Separator());
28359 * Adds a spacer element
28360 * @return {Roo.Toolbar.Spacer} The spacer item
28362 addSpacer : function(){
28363 return this.addItem(new Roo.Toolbar.Spacer());
28367 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28368 * @return {Roo.Toolbar.Fill} The fill item
28370 addFill : function(){
28371 return this.addItem(new Roo.Toolbar.Fill());
28375 * Adds any standard HTML element to the toolbar
28376 * @param {String/HTMLElement/Element} el The element or id of the element to add
28377 * @return {Roo.Toolbar.Item} The element's item
28379 addElement : function(el){
28380 return this.addItem(new Roo.Toolbar.Item(el));
28383 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28384 * @type Roo.util.MixedCollection
28389 * Adds any Toolbar.Item or subclass
28390 * @param {Roo.Toolbar.Item} item
28391 * @return {Roo.Toolbar.Item} The item
28393 addItem : function(item){
28394 var td = this.nextBlock();
28396 this.items.add(item);
28401 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28402 * @param {Object/Array} config A button config or array of configs
28403 * @return {Roo.Toolbar.Button/Array}
28405 addButton : function(config){
28406 if(config instanceof Array){
28408 for(var i = 0, len = config.length; i < len; i++) {
28409 buttons.push(this.addButton(config[i]));
28414 if(!(config instanceof Roo.Toolbar.Button)){
28416 new Roo.Toolbar.SplitButton(config) :
28417 new Roo.Toolbar.Button(config);
28419 var td = this.nextBlock();
28426 * Adds text to the toolbar
28427 * @param {String} text The text to add
28428 * @return {Roo.Toolbar.Item} The element's item
28430 addText : function(text){
28431 return this.addItem(new Roo.Toolbar.TextItem(text));
28435 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28436 * @param {Number} index The index where the item is to be inserted
28437 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28438 * @return {Roo.Toolbar.Button/Item}
28440 insertButton : function(index, item){
28441 if(item instanceof Array){
28443 for(var i = 0, len = item.length; i < len; i++) {
28444 buttons.push(this.insertButton(index + i, item[i]));
28448 if (!(item instanceof Roo.Toolbar.Button)){
28449 item = new Roo.Toolbar.Button(item);
28451 var td = document.createElement("td");
28452 this.tr.insertBefore(td, this.tr.childNodes[index]);
28454 this.items.insert(index, item);
28459 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28460 * @param {Object} config
28461 * @return {Roo.Toolbar.Item} The element's item
28463 addDom : function(config, returnEl){
28464 var td = this.nextBlock();
28465 Roo.DomHelper.overwrite(td, config);
28466 var ti = new Roo.Toolbar.Item(td.firstChild);
28468 this.items.add(ti);
28473 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28474 * @type Roo.util.MixedCollection
28479 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28480 * Note: the field should not have been rendered yet. For a field that has already been
28481 * rendered, use {@link #addElement}.
28482 * @param {Roo.form.Field} field
28483 * @return {Roo.ToolbarItem}
28487 addField : function(field) {
28488 if (!this.fields) {
28490 this.fields = new Roo.util.MixedCollection(false, function(o){
28491 return o.id || ("item" + (++autoId));
28496 var td = this.nextBlock();
28498 var ti = new Roo.Toolbar.Item(td.firstChild);
28500 this.items.add(ti);
28501 this.fields.add(field);
28512 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28513 this.el.child('div').hide();
28521 this.el.child('div').show();
28525 nextBlock : function(){
28526 var td = document.createElement("td");
28527 this.tr.appendChild(td);
28532 destroy : function(){
28533 if(this.items){ // rendered?
28534 Roo.destroy.apply(Roo, this.items.items);
28536 if(this.fields){ // rendered?
28537 Roo.destroy.apply(Roo, this.fields.items);
28539 Roo.Element.uncache(this.el, this.tr);
28544 * @class Roo.Toolbar.Item
28545 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28547 * Creates a new Item
28548 * @param {HTMLElement} el
28550 Roo.Toolbar.Item = function(el){
28552 if (typeof (el.xtype) != 'undefined') {
28557 this.el = Roo.getDom(el);
28558 this.id = Roo.id(this.el);
28559 this.hidden = false;
28564 * Fires when the button is rendered
28565 * @param {Button} this
28569 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
28571 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
28572 //Roo.Toolbar.Item.prototype = {
28575 * Get this item's HTML Element
28576 * @return {HTMLElement}
28578 getEl : function(){
28583 render : function(td){
28586 td.appendChild(this.el);
28588 this.fireEvent('render', this);
28592 * Removes and destroys this item.
28594 destroy : function(){
28595 this.td.parentNode.removeChild(this.td);
28602 this.hidden = false;
28603 this.td.style.display = "";
28610 this.hidden = true;
28611 this.td.style.display = "none";
28615 * Convenience function for boolean show/hide.
28616 * @param {Boolean} visible true to show/false to hide
28618 setVisible: function(visible){
28627 * Try to focus this item.
28629 focus : function(){
28630 Roo.fly(this.el).focus();
28634 * Disables this item.
28636 disable : function(){
28637 Roo.fly(this.td).addClass("x-item-disabled");
28638 this.disabled = true;
28639 this.el.disabled = true;
28643 * Enables this item.
28645 enable : function(){
28646 Roo.fly(this.td).removeClass("x-item-disabled");
28647 this.disabled = false;
28648 this.el.disabled = false;
28654 * @class Roo.Toolbar.Separator
28655 * @extends Roo.Toolbar.Item
28656 * A simple toolbar separator class
28658 * Creates a new Separator
28660 Roo.Toolbar.Separator = function(cfg){
28662 var s = document.createElement("span");
28663 s.className = "ytb-sep";
28668 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
28670 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28671 enable:Roo.emptyFn,
28672 disable:Roo.emptyFn,
28677 * @class Roo.Toolbar.Spacer
28678 * @extends Roo.Toolbar.Item
28679 * A simple element that adds extra horizontal space to a toolbar.
28681 * Creates a new Spacer
28683 Roo.Toolbar.Spacer = function(cfg){
28684 var s = document.createElement("div");
28685 s.className = "ytb-spacer";
28689 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
28691 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28692 enable:Roo.emptyFn,
28693 disable:Roo.emptyFn,
28698 * @class Roo.Toolbar.Fill
28699 * @extends Roo.Toolbar.Spacer
28700 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28702 * Creates a new Spacer
28704 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28706 render : function(td){
28707 td.style.width = '100%';
28708 Roo.Toolbar.Fill.superclass.render.call(this, td);
28713 * @class Roo.Toolbar.TextItem
28714 * @extends Roo.Toolbar.Item
28715 * A simple class that renders text directly into a toolbar.
28717 * Creates a new TextItem
28718 * @param {String} text
28720 Roo.Toolbar.TextItem = function(cfg){
28721 var text = cfg || "";
28722 if (typeof(cfg) == 'object') {
28723 text = cfg.text || "";
28727 var s = document.createElement("span");
28728 s.className = "ytb-text";
28729 s.innerHTML = text;
28734 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
28736 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28739 enable:Roo.emptyFn,
28740 disable:Roo.emptyFn,
28745 * @class Roo.Toolbar.Button
28746 * @extends Roo.Button
28747 * A button that renders into a toolbar.
28749 * Creates a new Button
28750 * @param {Object} config A standard {@link Roo.Button} config object
28752 Roo.Toolbar.Button = function(config){
28753 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28755 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28756 render : function(td){
28758 Roo.Toolbar.Button.superclass.render.call(this, td);
28762 * Removes and destroys this button
28764 destroy : function(){
28765 Roo.Toolbar.Button.superclass.destroy.call(this);
28766 this.td.parentNode.removeChild(this.td);
28770 * Shows this button
28773 this.hidden = false;
28774 this.td.style.display = "";
28778 * Hides this button
28781 this.hidden = true;
28782 this.td.style.display = "none";
28786 * Disables this item
28788 disable : function(){
28789 Roo.fly(this.td).addClass("x-item-disabled");
28790 this.disabled = true;
28794 * Enables this item
28796 enable : function(){
28797 Roo.fly(this.td).removeClass("x-item-disabled");
28798 this.disabled = false;
28801 // backwards compat
28802 Roo.ToolbarButton = Roo.Toolbar.Button;
28805 * @class Roo.Toolbar.SplitButton
28806 * @extends Roo.SplitButton
28807 * A menu button that renders into a toolbar.
28809 * Creates a new SplitButton
28810 * @param {Object} config A standard {@link Roo.SplitButton} config object
28812 Roo.Toolbar.SplitButton = function(config){
28813 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28815 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28816 render : function(td){
28818 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28822 * Removes and destroys this button
28824 destroy : function(){
28825 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28826 this.td.parentNode.removeChild(this.td);
28830 * Shows this button
28833 this.hidden = false;
28834 this.td.style.display = "";
28838 * Hides this button
28841 this.hidden = true;
28842 this.td.style.display = "none";
28846 // backwards compat
28847 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28849 * Ext JS Library 1.1.1
28850 * Copyright(c) 2006-2007, Ext JS, LLC.
28852 * Originally Released Under LGPL - original licence link has changed is not relivant.
28855 * <script type="text/javascript">
28859 * @class Roo.PagingToolbar
28860 * @extends Roo.Toolbar
28861 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28863 * Create a new PagingToolbar
28864 * @param {Object} config The config object
28866 Roo.PagingToolbar = function(el, ds, config)
28868 // old args format still supported... - xtype is prefered..
28869 if (typeof(el) == 'object' && el.xtype) {
28870 // created from xtype...
28872 ds = el.dataSource;
28873 el = config.container;
28876 if (config.items) {
28877 items = config.items;
28881 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28884 this.renderButtons(this.el);
28887 // supprot items array.
28889 Roo.each(items, function(e) {
28890 this.add(Roo.factory(e));
28895 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28897 * @cfg {Roo.data.Store} dataSource
28898 * The underlying data store providing the paged data
28901 * @cfg {String/HTMLElement/Element} container
28902 * container The id or element that will contain the toolbar
28905 * @cfg {Boolean} displayInfo
28906 * True to display the displayMsg (defaults to false)
28909 * @cfg {Number} pageSize
28910 * The number of records to display per page (defaults to 20)
28914 * @cfg {String} displayMsg
28915 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28917 displayMsg : 'Displaying {0} - {1} of {2}',
28919 * @cfg {String} emptyMsg
28920 * The message to display when no records are found (defaults to "No data to display")
28922 emptyMsg : 'No data to display',
28924 * Customizable piece of the default paging text (defaults to "Page")
28927 beforePageText : "Page",
28929 * Customizable piece of the default paging text (defaults to "of %0")
28932 afterPageText : "of {0}",
28934 * Customizable piece of the default paging text (defaults to "First Page")
28937 firstText : "First Page",
28939 * Customizable piece of the default paging text (defaults to "Previous Page")
28942 prevText : "Previous Page",
28944 * Customizable piece of the default paging text (defaults to "Next Page")
28947 nextText : "Next Page",
28949 * Customizable piece of the default paging text (defaults to "Last Page")
28952 lastText : "Last Page",
28954 * Customizable piece of the default paging text (defaults to "Refresh")
28957 refreshText : "Refresh",
28960 renderButtons : function(el){
28961 Roo.PagingToolbar.superclass.render.call(this, el);
28962 this.first = this.addButton({
28963 tooltip: this.firstText,
28964 cls: "x-btn-icon x-grid-page-first",
28966 handler: this.onClick.createDelegate(this, ["first"])
28968 this.prev = this.addButton({
28969 tooltip: this.prevText,
28970 cls: "x-btn-icon x-grid-page-prev",
28972 handler: this.onClick.createDelegate(this, ["prev"])
28974 //this.addSeparator();
28975 this.add(this.beforePageText);
28976 this.field = Roo.get(this.addDom({
28981 cls: "x-grid-page-number"
28983 this.field.on("keydown", this.onPagingKeydown, this);
28984 this.field.on("focus", function(){this.dom.select();});
28985 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28986 this.field.setHeight(18);
28987 //this.addSeparator();
28988 this.next = this.addButton({
28989 tooltip: this.nextText,
28990 cls: "x-btn-icon x-grid-page-next",
28992 handler: this.onClick.createDelegate(this, ["next"])
28994 this.last = this.addButton({
28995 tooltip: this.lastText,
28996 cls: "x-btn-icon x-grid-page-last",
28998 handler: this.onClick.createDelegate(this, ["last"])
29000 //this.addSeparator();
29001 this.loading = this.addButton({
29002 tooltip: this.refreshText,
29003 cls: "x-btn-icon x-grid-loading",
29004 handler: this.onClick.createDelegate(this, ["refresh"])
29007 if(this.displayInfo){
29008 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
29013 updateInfo : function(){
29014 if(this.displayEl){
29015 var count = this.ds.getCount();
29016 var msg = count == 0 ?
29020 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
29022 this.displayEl.update(msg);
29027 onLoad : function(ds, r, o){
29028 this.cursor = o.params ? o.params.start : 0;
29029 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
29031 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
29032 this.field.dom.value = ap;
29033 this.first.setDisabled(ap == 1);
29034 this.prev.setDisabled(ap == 1);
29035 this.next.setDisabled(ap == ps);
29036 this.last.setDisabled(ap == ps);
29037 this.loading.enable();
29042 getPageData : function(){
29043 var total = this.ds.getTotalCount();
29046 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
29047 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
29052 onLoadError : function(){
29053 this.loading.enable();
29057 onPagingKeydown : function(e){
29058 var k = e.getKey();
29059 var d = this.getPageData();
29061 var v = this.field.dom.value, pageNum;
29062 if(!v || isNaN(pageNum = parseInt(v, 10))){
29063 this.field.dom.value = d.activePage;
29066 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
29067 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29070 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
29072 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
29073 this.field.dom.value = pageNum;
29074 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
29077 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29079 var v = this.field.dom.value, pageNum;
29080 var increment = (e.shiftKey) ? 10 : 1;
29081 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29083 if(!v || isNaN(pageNum = parseInt(v, 10))) {
29084 this.field.dom.value = d.activePage;
29087 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
29089 this.field.dom.value = parseInt(v, 10) + increment;
29090 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
29091 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29098 beforeLoad : function(){
29100 this.loading.disable();
29105 onClick : function(which){
29109 ds.load({params:{start: 0, limit: this.pageSize}});
29112 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
29115 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
29118 var total = ds.getTotalCount();
29119 var extra = total % this.pageSize;
29120 var lastStart = extra ? (total - extra) : total-this.pageSize;
29121 ds.load({params:{start: lastStart, limit: this.pageSize}});
29124 ds.load({params:{start: this.cursor, limit: this.pageSize}});
29130 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
29131 * @param {Roo.data.Store} store The data store to unbind
29133 unbind : function(ds){
29134 ds.un("beforeload", this.beforeLoad, this);
29135 ds.un("load", this.onLoad, this);
29136 ds.un("loadexception", this.onLoadError, this);
29137 ds.un("remove", this.updateInfo, this);
29138 ds.un("add", this.updateInfo, this);
29139 this.ds = undefined;
29143 * Binds the paging toolbar to the specified {@link Roo.data.Store}
29144 * @param {Roo.data.Store} store The data store to bind
29146 bind : function(ds){
29147 ds.on("beforeload", this.beforeLoad, this);
29148 ds.on("load", this.onLoad, this);
29149 ds.on("loadexception", this.onLoadError, this);
29150 ds.on("remove", this.updateInfo, this);
29151 ds.on("add", this.updateInfo, this);
29156 * Ext JS Library 1.1.1
29157 * Copyright(c) 2006-2007, Ext JS, LLC.
29159 * Originally Released Under LGPL - original licence link has changed is not relivant.
29162 * <script type="text/javascript">
29166 * @class Roo.Resizable
29167 * @extends Roo.util.Observable
29168 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
29169 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
29170 * the textarea in a div and set "resizeChild" to true (or to the id of the element), <b>or</b> set wrap:true in your config and
29171 * the element will be wrapped for you automatically.</p>
29172 * <p>Here is the list of valid resize handles:</p>
29175 ------ -------------------
29184 'hd' horizontal drag
29187 * <p>Here's an example showing the creation of a typical Resizable:</p>
29189 var resizer = new Roo.Resizable("element-id", {
29197 resizer.on("resize", myHandler);
29199 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29200 * resizer.east.setDisplayed(false);</p>
29201 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29202 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29203 * resize operation's new size (defaults to [0, 0])
29204 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29205 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29206 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29207 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29208 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29209 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29210 * @cfg {Number} width The width of the element in pixels (defaults to null)
29211 * @cfg {Number} height The height of the element in pixels (defaults to null)
29212 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29213 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29214 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29215 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29216 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29217 * in favor of the handles config option (defaults to false)
29218 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29219 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29220 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29221 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29222 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29223 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29224 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29225 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29226 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29227 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29228 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29230 * Create a new resizable component
29231 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29232 * @param {Object} config configuration options
29234 Roo.Resizable = function(el, config)
29236 this.el = Roo.get(el);
29238 if(config && config.wrap){
29239 config.resizeChild = this.el;
29240 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29241 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29242 this.el.setStyle("overflow", "hidden");
29243 this.el.setPositioning(config.resizeChild.getPositioning());
29244 config.resizeChild.clearPositioning();
29245 if(!config.width || !config.height){
29246 var csize = config.resizeChild.getSize();
29247 this.el.setSize(csize.width, csize.height);
29249 if(config.pinned && !config.adjustments){
29250 config.adjustments = "auto";
29254 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29255 this.proxy.unselectable();
29256 this.proxy.enableDisplayMode('block');
29258 Roo.apply(this, config);
29261 this.disableTrackOver = true;
29262 this.el.addClass("x-resizable-pinned");
29264 // if the element isn't positioned, make it relative
29265 var position = this.el.getStyle("position");
29266 if(position != "absolute" && position != "fixed"){
29267 this.el.setStyle("position", "relative");
29269 if(!this.handles){ // no handles passed, must be legacy style
29270 this.handles = 's,e,se';
29271 if(this.multiDirectional){
29272 this.handles += ',n,w';
29275 if(this.handles == "all"){
29276 this.handles = "n s e w ne nw se sw";
29278 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29279 var ps = Roo.Resizable.positions;
29280 for(var i = 0, len = hs.length; i < len; i++){
29281 if(hs[i] && ps[hs[i]]){
29282 var pos = ps[hs[i]];
29283 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29287 this.corner = this.southeast;
29289 // updateBox = the box can move..
29290 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29291 this.updateBox = true;
29294 this.activeHandle = null;
29296 if(this.resizeChild){
29297 if(typeof this.resizeChild == "boolean"){
29298 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29300 this.resizeChild = Roo.get(this.resizeChild, true);
29304 if(this.adjustments == "auto"){
29305 var rc = this.resizeChild;
29306 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29307 if(rc && (hw || hn)){
29308 rc.position("relative");
29309 rc.setLeft(hw ? hw.el.getWidth() : 0);
29310 rc.setTop(hn ? hn.el.getHeight() : 0);
29312 this.adjustments = [
29313 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29314 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29318 if(this.draggable){
29319 this.dd = this.dynamic ?
29320 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29321 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29327 * @event beforeresize
29328 * Fired before resize is allowed. Set enabled to false to cancel resize.
29329 * @param {Roo.Resizable} this
29330 * @param {Roo.EventObject} e The mousedown event
29332 "beforeresize" : true,
29335 * Fired a resizing.
29336 * @param {Roo.Resizable} this
29337 * @param {Number} x The new x position
29338 * @param {Number} y The new y position
29339 * @param {Number} w The new w width
29340 * @param {Number} h The new h hight
29341 * @param {Roo.EventObject} e The mouseup event
29346 * Fired after a resize.
29347 * @param {Roo.Resizable} this
29348 * @param {Number} width The new width
29349 * @param {Number} height The new height
29350 * @param {Roo.EventObject} e The mouseup event
29355 if(this.width !== null && this.height !== null){
29356 this.resizeTo(this.width, this.height);
29358 this.updateChildSize();
29361 this.el.dom.style.zoom = 1;
29363 Roo.Resizable.superclass.constructor.call(this);
29366 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29367 resizeChild : false,
29368 adjustments : [0, 0],
29378 multiDirectional : false,
29379 disableTrackOver : false,
29380 easing : 'easeOutStrong',
29381 widthIncrement : 0,
29382 heightIncrement : 0,
29386 preserveRatio : false,
29387 transparent: false,
29393 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29395 constrainTo: undefined,
29397 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29399 resizeRegion: undefined,
29403 * Perform a manual resize
29404 * @param {Number} width
29405 * @param {Number} height
29407 resizeTo : function(width, height){
29408 this.el.setSize(width, height);
29409 this.updateChildSize();
29410 this.fireEvent("resize", this, width, height, null);
29414 startSizing : function(e, handle){
29415 this.fireEvent("beforeresize", this, e);
29416 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29419 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29420 this.overlay.unselectable();
29421 this.overlay.enableDisplayMode("block");
29422 this.overlay.on("mousemove", this.onMouseMove, this);
29423 this.overlay.on("mouseup", this.onMouseUp, this);
29425 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29427 this.resizing = true;
29428 this.startBox = this.el.getBox();
29429 this.startPoint = e.getXY();
29430 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29431 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29433 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29434 this.overlay.show();
29436 if(this.constrainTo) {
29437 var ct = Roo.get(this.constrainTo);
29438 this.resizeRegion = ct.getRegion().adjust(
29439 ct.getFrameWidth('t'),
29440 ct.getFrameWidth('l'),
29441 -ct.getFrameWidth('b'),
29442 -ct.getFrameWidth('r')
29446 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29448 this.proxy.setBox(this.startBox);
29450 this.proxy.setStyle('visibility', 'visible');
29456 onMouseDown : function(handle, e){
29459 this.activeHandle = handle;
29460 this.startSizing(e, handle);
29465 onMouseUp : function(e){
29466 var size = this.resizeElement();
29467 this.resizing = false;
29469 this.overlay.hide();
29471 this.fireEvent("resize", this, size.width, size.height, e);
29475 updateChildSize : function(){
29477 if(this.resizeChild){
29479 var child = this.resizeChild;
29480 var adj = this.adjustments;
29481 if(el.dom.offsetWidth){
29482 var b = el.getSize(true);
29483 child.setSize(b.width+adj[0], b.height+adj[1]);
29485 // Second call here for IE
29486 // The first call enables instant resizing and
29487 // the second call corrects scroll bars if they
29490 setTimeout(function(){
29491 if(el.dom.offsetWidth){
29492 var b = el.getSize(true);
29493 child.setSize(b.width+adj[0], b.height+adj[1]);
29501 snap : function(value, inc, min){
29502 if(!inc || !value) return value;
29503 var newValue = value;
29504 var m = value % inc;
29507 newValue = value + (inc-m);
29509 newValue = value - m;
29512 return Math.max(min, newValue);
29516 resizeElement : function(){
29517 var box = this.proxy.getBox();
29518 if(this.updateBox){
29519 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29521 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29523 this.updateChildSize();
29531 constrain : function(v, diff, m, mx){
29534 }else if(v - diff > mx){
29541 onMouseMove : function(e){
29544 try{// try catch so if something goes wrong the user doesn't get hung
29546 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29550 //var curXY = this.startPoint;
29551 var curSize = this.curSize || this.startBox;
29552 var x = this.startBox.x, y = this.startBox.y;
29553 var ox = x, oy = y;
29554 var w = curSize.width, h = curSize.height;
29555 var ow = w, oh = h;
29556 var mw = this.minWidth, mh = this.minHeight;
29557 var mxw = this.maxWidth, mxh = this.maxHeight;
29558 var wi = this.widthIncrement;
29559 var hi = this.heightIncrement;
29561 var eventXY = e.getXY();
29562 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29563 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29565 var pos = this.activeHandle.position;
29570 w = Math.min(Math.max(mw, w), mxw);
29575 h = Math.min(Math.max(mh, h), mxh);
29580 w = Math.min(Math.max(mw, w), mxw);
29581 h = Math.min(Math.max(mh, h), mxh);
29584 diffY = this.constrain(h, diffY, mh, mxh);
29591 var adiffX = Math.abs(diffX);
29592 var sub = (adiffX % wi); // how much
29593 if (sub > (wi/2)) { // far enough to snap
29594 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29596 // remove difference..
29597 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29601 x = Math.max(this.minX, x);
29604 diffX = this.constrain(w, diffX, mw, mxw);
29610 w = Math.min(Math.max(mw, w), mxw);
29611 diffY = this.constrain(h, diffY, mh, mxh);
29616 diffX = this.constrain(w, diffX, mw, mxw);
29617 diffY = this.constrain(h, diffY, mh, mxh);
29624 diffX = this.constrain(w, diffX, mw, mxw);
29626 h = Math.min(Math.max(mh, h), mxh);
29632 var sw = this.snap(w, wi, mw);
29633 var sh = this.snap(h, hi, mh);
29634 if(sw != w || sh != h){
29657 if(this.preserveRatio){
29662 h = Math.min(Math.max(mh, h), mxh);
29667 w = Math.min(Math.max(mw, w), mxw);
29672 w = Math.min(Math.max(mw, w), mxw);
29678 w = Math.min(Math.max(mw, w), mxw);
29684 h = Math.min(Math.max(mh, h), mxh);
29692 h = Math.min(Math.max(mh, h), mxh);
29702 h = Math.min(Math.max(mh, h), mxh);
29710 if (pos == 'hdrag') {
29713 this.proxy.setBounds(x, y, w, h);
29715 this.resizeElement();
29719 this.fireEvent("resizing", this, x, y, w, h, e);
29723 handleOver : function(){
29725 this.el.addClass("x-resizable-over");
29730 handleOut : function(){
29731 if(!this.resizing){
29732 this.el.removeClass("x-resizable-over");
29737 * Returns the element this component is bound to.
29738 * @return {Roo.Element}
29740 getEl : function(){
29745 * Returns the resizeChild element (or null).
29746 * @return {Roo.Element}
29748 getResizeChild : function(){
29749 return this.resizeChild;
29751 groupHandler : function()
29756 * Destroys this resizable. If the element was wrapped and
29757 * removeEl is not true then the element remains.
29758 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29760 destroy : function(removeEl){
29761 this.proxy.remove();
29763 this.overlay.removeAllListeners();
29764 this.overlay.remove();
29766 var ps = Roo.Resizable.positions;
29768 if(typeof ps[k] != "function" && this[ps[k]]){
29769 var h = this[ps[k]];
29770 h.el.removeAllListeners();
29775 this.el.update("");
29782 // hash to map config positions to true positions
29783 Roo.Resizable.positions = {
29784 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29789 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29791 // only initialize the template if resizable is used
29792 var tpl = Roo.DomHelper.createTemplate(
29793 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29796 Roo.Resizable.Handle.prototype.tpl = tpl;
29798 this.position = pos;
29800 // show north drag fro topdra
29801 var handlepos = pos == 'hdrag' ? 'north' : pos;
29803 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29804 if (pos == 'hdrag') {
29805 this.el.setStyle('cursor', 'pointer');
29807 this.el.unselectable();
29809 this.el.setOpacity(0);
29811 this.el.on("mousedown", this.onMouseDown, this);
29812 if(!disableTrackOver){
29813 this.el.on("mouseover", this.onMouseOver, this);
29814 this.el.on("mouseout", this.onMouseOut, this);
29819 Roo.Resizable.Handle.prototype = {
29820 afterResize : function(rz){
29825 onMouseDown : function(e){
29826 this.rz.onMouseDown(this, e);
29829 onMouseOver : function(e){
29830 this.rz.handleOver(this, e);
29833 onMouseOut : function(e){
29834 this.rz.handleOut(this, e);
29838 * Ext JS Library 1.1.1
29839 * Copyright(c) 2006-2007, Ext JS, LLC.
29841 * Originally Released Under LGPL - original licence link has changed is not relivant.
29844 * <script type="text/javascript">
29848 * @class Roo.Editor
29849 * @extends Roo.Component
29850 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29852 * Create a new Editor
29853 * @param {Roo.form.Field} field The Field object (or descendant)
29854 * @param {Object} config The config object
29856 Roo.Editor = function(field, config){
29857 Roo.Editor.superclass.constructor.call(this, config);
29858 this.field = field;
29861 * @event beforestartedit
29862 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29863 * false from the handler of this event.
29864 * @param {Editor} this
29865 * @param {Roo.Element} boundEl The underlying element bound to this editor
29866 * @param {Mixed} value The field value being set
29868 "beforestartedit" : true,
29871 * Fires when this editor is displayed
29872 * @param {Roo.Element} boundEl The underlying element bound to this editor
29873 * @param {Mixed} value The starting field value
29875 "startedit" : true,
29877 * @event beforecomplete
29878 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29879 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29880 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29881 * event will not fire since no edit actually occurred.
29882 * @param {Editor} this
29883 * @param {Mixed} value The current field value
29884 * @param {Mixed} startValue The original field value
29886 "beforecomplete" : true,
29889 * Fires after editing is complete and any changed value has been written to the underlying field.
29890 * @param {Editor} this
29891 * @param {Mixed} value The current field value
29892 * @param {Mixed} startValue The original field value
29896 * @event specialkey
29897 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29898 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29899 * @param {Roo.form.Field} this
29900 * @param {Roo.EventObject} e The event object
29902 "specialkey" : true
29906 Roo.extend(Roo.Editor, Roo.Component, {
29908 * @cfg {Boolean/String} autosize
29909 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29910 * or "height" to adopt the height only (defaults to false)
29913 * @cfg {Boolean} revertInvalid
29914 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29915 * validation fails (defaults to true)
29918 * @cfg {Boolean} ignoreNoChange
29919 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29920 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29921 * will never be ignored.
29924 * @cfg {Boolean} hideEl
29925 * False to keep the bound element visible while the editor is displayed (defaults to true)
29928 * @cfg {Mixed} value
29929 * The data value of the underlying field (defaults to "")
29933 * @cfg {String} alignment
29934 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29938 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29939 * for bottom-right shadow (defaults to "frame")
29943 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29947 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29949 completeOnEnter : false,
29951 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29953 cancelOnEsc : false,
29955 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29960 onRender : function(ct, position){
29961 this.el = new Roo.Layer({
29962 shadow: this.shadow,
29968 constrain: this.constrain
29970 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29971 if(this.field.msgTarget != 'title'){
29972 this.field.msgTarget = 'qtip';
29974 this.field.render(this.el);
29976 this.field.el.dom.setAttribute('autocomplete', 'off');
29978 this.field.on("specialkey", this.onSpecialKey, this);
29979 if(this.swallowKeys){
29980 this.field.el.swallowEvent(['keydown','keypress']);
29983 this.field.on("blur", this.onBlur, this);
29984 if(this.field.grow){
29985 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29989 onSpecialKey : function(field, e)
29991 //Roo.log('editor onSpecialKey');
29992 if(this.completeOnEnter && e.getKey() == e.ENTER){
29994 this.completeEdit();
29997 // do not fire special key otherwise it might hide close the editor...
29998 if(e.getKey() == e.ENTER){
30001 if(this.cancelOnEsc && e.getKey() == e.ESC){
30005 this.fireEvent('specialkey', field, e);
30010 * Starts the editing process and shows the editor.
30011 * @param {String/HTMLElement/Element} el The element to edit
30012 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
30013 * to the innerHTML of el.
30015 startEdit : function(el, value){
30017 this.completeEdit();
30019 this.boundEl = Roo.get(el);
30020 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
30021 if(!this.rendered){
30022 this.render(this.parentEl || document.body);
30024 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
30027 this.startValue = v;
30028 this.field.setValue(v);
30030 var sz = this.boundEl.getSize();
30031 switch(this.autoSize){
30033 this.setSize(sz.width, "");
30036 this.setSize("", sz.height);
30039 this.setSize(sz.width, sz.height);
30042 this.el.alignTo(this.boundEl, this.alignment);
30043 this.editing = true;
30045 Roo.QuickTips.disable();
30051 * Sets the height and width of this editor.
30052 * @param {Number} width The new width
30053 * @param {Number} height The new height
30055 setSize : function(w, h){
30056 this.field.setSize(w, h);
30063 * Realigns the editor to the bound field based on the current alignment config value.
30065 realign : function(){
30066 this.el.alignTo(this.boundEl, this.alignment);
30070 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
30071 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
30073 completeEdit : function(remainVisible){
30077 var v = this.getValue();
30078 if(this.revertInvalid !== false && !this.field.isValid()){
30079 v = this.startValue;
30080 this.cancelEdit(true);
30082 if(String(v) === String(this.startValue) && this.ignoreNoChange){
30083 this.editing = false;
30087 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
30088 this.editing = false;
30089 if(this.updateEl && this.boundEl){
30090 this.boundEl.update(v);
30092 if(remainVisible !== true){
30095 this.fireEvent("complete", this, v, this.startValue);
30100 onShow : function(){
30102 if(this.hideEl !== false){
30103 this.boundEl.hide();
30106 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
30107 this.fixIEFocus = true;
30108 this.deferredFocus.defer(50, this);
30110 this.field.focus();
30112 this.fireEvent("startedit", this.boundEl, this.startValue);
30115 deferredFocus : function(){
30117 this.field.focus();
30122 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
30123 * reverted to the original starting value.
30124 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
30125 * cancel (defaults to false)
30127 cancelEdit : function(remainVisible){
30129 this.setValue(this.startValue);
30130 if(remainVisible !== true){
30137 onBlur : function(){
30138 if(this.allowBlur !== true && this.editing){
30139 this.completeEdit();
30144 onHide : function(){
30146 this.completeEdit();
30150 if(this.field.collapse){
30151 this.field.collapse();
30154 if(this.hideEl !== false){
30155 this.boundEl.show();
30158 Roo.QuickTips.enable();
30163 * Sets the data value of the editor
30164 * @param {Mixed} value Any valid value supported by the underlying field
30166 setValue : function(v){
30167 this.field.setValue(v);
30171 * Gets the data value of the editor
30172 * @return {Mixed} The data value
30174 getValue : function(){
30175 return this.field.getValue();
30179 * Ext JS Library 1.1.1
30180 * Copyright(c) 2006-2007, Ext JS, LLC.
30182 * Originally Released Under LGPL - original licence link has changed is not relivant.
30185 * <script type="text/javascript">
30189 * @class Roo.BasicDialog
30190 * @extends Roo.util.Observable
30191 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
30193 var dlg = new Roo.BasicDialog("my-dlg", {
30202 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30203 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30204 dlg.addButton('Cancel', dlg.hide, dlg);
30207 <b>A Dialog should always be a direct child of the body element.</b>
30208 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30209 * @cfg {String} title Default text to display in the title bar (defaults to null)
30210 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30211 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30212 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30213 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30214 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30215 * (defaults to null with no animation)
30216 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30217 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30218 * property for valid values (defaults to 'all')
30219 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30220 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30221 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30222 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30223 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30224 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30225 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30226 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30227 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30228 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30229 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30230 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30231 * draggable = true (defaults to false)
30232 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30233 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30234 * shadow (defaults to false)
30235 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30236 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30237 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30238 * @cfg {Array} buttons Array of buttons
30239 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30241 * Create a new BasicDialog.
30242 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30243 * @param {Object} config Configuration options
30245 Roo.BasicDialog = function(el, config){
30246 this.el = Roo.get(el);
30247 var dh = Roo.DomHelper;
30248 if(!this.el && config && config.autoCreate){
30249 if(typeof config.autoCreate == "object"){
30250 if(!config.autoCreate.id){
30251 config.autoCreate.id = el;
30253 this.el = dh.append(document.body,
30254 config.autoCreate, true);
30256 this.el = dh.append(document.body,
30257 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30261 el.setDisplayed(true);
30262 el.hide = this.hideAction;
30264 el.addClass("x-dlg");
30266 Roo.apply(this, config);
30268 this.proxy = el.createProxy("x-dlg-proxy");
30269 this.proxy.hide = this.hideAction;
30270 this.proxy.setOpacity(.5);
30274 el.setWidth(config.width);
30277 el.setHeight(config.height);
30279 this.size = el.getSize();
30280 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30281 this.xy = [config.x,config.y];
30283 this.xy = el.getCenterXY(true);
30285 /** The header element @type Roo.Element */
30286 this.header = el.child("> .x-dlg-hd");
30287 /** The body element @type Roo.Element */
30288 this.body = el.child("> .x-dlg-bd");
30289 /** The footer element @type Roo.Element */
30290 this.footer = el.child("> .x-dlg-ft");
30293 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30296 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30299 this.header.unselectable();
30301 this.header.update(this.title);
30303 // this element allows the dialog to be focused for keyboard event
30304 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30305 this.focusEl.swallowEvent("click", true);
30307 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30309 // wrap the body and footer for special rendering
30310 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30312 this.bwrap.dom.appendChild(this.footer.dom);
30315 this.bg = this.el.createChild({
30316 tag: "div", cls:"x-dlg-bg",
30317 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30319 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30322 if(this.autoScroll !== false && !this.autoTabs){
30323 this.body.setStyle("overflow", "auto");
30326 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30328 if(this.closable !== false){
30329 this.el.addClass("x-dlg-closable");
30330 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30331 this.close.on("click", this.closeClick, this);
30332 this.close.addClassOnOver("x-dlg-close-over");
30334 if(this.collapsible !== false){
30335 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30336 this.collapseBtn.on("click", this.collapseClick, this);
30337 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30338 this.header.on("dblclick", this.collapseClick, this);
30340 if(this.resizable !== false){
30341 this.el.addClass("x-dlg-resizable");
30342 this.resizer = new Roo.Resizable(el, {
30343 minWidth: this.minWidth || 80,
30344 minHeight:this.minHeight || 80,
30345 handles: this.resizeHandles || "all",
30348 this.resizer.on("beforeresize", this.beforeResize, this);
30349 this.resizer.on("resize", this.onResize, this);
30351 if(this.draggable !== false){
30352 el.addClass("x-dlg-draggable");
30353 if (!this.proxyDrag) {
30354 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30357 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30359 dd.setHandleElId(this.header.id);
30360 dd.endDrag = this.endMove.createDelegate(this);
30361 dd.startDrag = this.startMove.createDelegate(this);
30362 dd.onDrag = this.onDrag.createDelegate(this);
30367 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30368 this.mask.enableDisplayMode("block");
30370 this.el.addClass("x-dlg-modal");
30373 this.shadow = new Roo.Shadow({
30374 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30375 offset : this.shadowOffset
30378 this.shadowOffset = 0;
30380 if(Roo.useShims && this.shim !== false){
30381 this.shim = this.el.createShim();
30382 this.shim.hide = this.hideAction;
30390 if (this.buttons) {
30391 var bts= this.buttons;
30393 Roo.each(bts, function(b) {
30402 * Fires when a key is pressed
30403 * @param {Roo.BasicDialog} this
30404 * @param {Roo.EventObject} e
30409 * Fires when this dialog is moved by the user.
30410 * @param {Roo.BasicDialog} this
30411 * @param {Number} x The new page X
30412 * @param {Number} y The new page Y
30417 * Fires when this dialog is resized by the user.
30418 * @param {Roo.BasicDialog} this
30419 * @param {Number} width The new width
30420 * @param {Number} height The new height
30424 * @event beforehide
30425 * Fires before this dialog is hidden.
30426 * @param {Roo.BasicDialog} this
30428 "beforehide" : true,
30431 * Fires when this dialog is hidden.
30432 * @param {Roo.BasicDialog} this
30436 * @event beforeshow
30437 * Fires before this dialog is shown.
30438 * @param {Roo.BasicDialog} this
30440 "beforeshow" : true,
30443 * Fires when this dialog is shown.
30444 * @param {Roo.BasicDialog} this
30448 el.on("keydown", this.onKeyDown, this);
30449 el.on("mousedown", this.toFront, this);
30450 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30452 Roo.DialogManager.register(this);
30453 Roo.BasicDialog.superclass.constructor.call(this);
30456 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30457 shadowOffset: Roo.isIE ? 6 : 5,
30460 minButtonWidth: 75,
30461 defaultButton: null,
30462 buttonAlign: "right",
30467 * Sets the dialog title text
30468 * @param {String} text The title text to display
30469 * @return {Roo.BasicDialog} this
30471 setTitle : function(text){
30472 this.header.update(text);
30477 closeClick : function(){
30482 collapseClick : function(){
30483 this[this.collapsed ? "expand" : "collapse"]();
30487 * Collapses the dialog to its minimized state (only the title bar is visible).
30488 * Equivalent to the user clicking the collapse dialog button.
30490 collapse : function(){
30491 if(!this.collapsed){
30492 this.collapsed = true;
30493 this.el.addClass("x-dlg-collapsed");
30494 this.restoreHeight = this.el.getHeight();
30495 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30500 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30501 * clicking the expand dialog button.
30503 expand : function(){
30504 if(this.collapsed){
30505 this.collapsed = false;
30506 this.el.removeClass("x-dlg-collapsed");
30507 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30512 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30513 * @return {Roo.TabPanel} The tabs component
30515 initTabs : function(){
30516 var tabs = this.getTabs();
30517 while(tabs.getTab(0)){
30520 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30522 tabs.addTab(Roo.id(dom), dom.title);
30530 beforeResize : function(){
30531 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30535 onResize : function(){
30536 this.refreshSize();
30537 this.syncBodyHeight();
30538 this.adjustAssets();
30540 this.fireEvent("resize", this, this.size.width, this.size.height);
30544 onKeyDown : function(e){
30545 if(this.isVisible()){
30546 this.fireEvent("keydown", this, e);
30551 * Resizes the dialog.
30552 * @param {Number} width
30553 * @param {Number} height
30554 * @return {Roo.BasicDialog} this
30556 resizeTo : function(width, height){
30557 this.el.setSize(width, height);
30558 this.size = {width: width, height: height};
30559 this.syncBodyHeight();
30560 if(this.fixedcenter){
30563 if(this.isVisible()){
30564 this.constrainXY();
30565 this.adjustAssets();
30567 this.fireEvent("resize", this, width, height);
30573 * Resizes the dialog to fit the specified content size.
30574 * @param {Number} width
30575 * @param {Number} height
30576 * @return {Roo.BasicDialog} this
30578 setContentSize : function(w, h){
30579 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30580 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30581 //if(!this.el.isBorderBox()){
30582 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30583 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30586 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30587 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30589 this.resizeTo(w, h);
30594 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30595 * executed in response to a particular key being pressed while the dialog is active.
30596 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30597 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30598 * @param {Function} fn The function to call
30599 * @param {Object} scope (optional) The scope of the function
30600 * @return {Roo.BasicDialog} this
30602 addKeyListener : function(key, fn, scope){
30603 var keyCode, shift, ctrl, alt;
30604 if(typeof key == "object" && !(key instanceof Array)){
30605 keyCode = key["key"];
30606 shift = key["shift"];
30607 ctrl = key["ctrl"];
30612 var handler = function(dlg, e){
30613 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30614 var k = e.getKey();
30615 if(keyCode instanceof Array){
30616 for(var i = 0, len = keyCode.length; i < len; i++){
30617 if(keyCode[i] == k){
30618 fn.call(scope || window, dlg, k, e);
30624 fn.call(scope || window, dlg, k, e);
30629 this.on("keydown", handler);
30634 * Returns the TabPanel component (creates it if it doesn't exist).
30635 * Note: If you wish to simply check for the existence of tabs without creating them,
30636 * check for a null 'tabs' property.
30637 * @return {Roo.TabPanel} The tabs component
30639 getTabs : function(){
30641 this.el.addClass("x-dlg-auto-tabs");
30642 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30643 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30649 * Adds a button to the footer section of the dialog.
30650 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30651 * object or a valid Roo.DomHelper element config
30652 * @param {Function} handler The function called when the button is clicked
30653 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30654 * @return {Roo.Button} The new button
30656 addButton : function(config, handler, scope){
30657 var dh = Roo.DomHelper;
30659 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30661 if(!this.btnContainer){
30662 var tb = this.footer.createChild({
30664 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30665 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30667 this.btnContainer = tb.firstChild.firstChild.firstChild;
30672 minWidth: this.minButtonWidth,
30675 if(typeof config == "string"){
30676 bconfig.text = config;
30679 bconfig.dhconfig = config;
30681 Roo.apply(bconfig, config);
30685 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30686 bconfig.position = Math.max(0, bconfig.position);
30687 fc = this.btnContainer.childNodes[bconfig.position];
30690 var btn = new Roo.Button(
30692 this.btnContainer.insertBefore(document.createElement("td"),fc)
30693 : this.btnContainer.appendChild(document.createElement("td")),
30694 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30697 this.syncBodyHeight();
30700 * Array of all the buttons that have been added to this dialog via addButton
30705 this.buttons.push(btn);
30710 * Sets the default button to be focused when the dialog is displayed.
30711 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30712 * @return {Roo.BasicDialog} this
30714 setDefaultButton : function(btn){
30715 this.defaultButton = btn;
30720 getHeaderFooterHeight : function(safe){
30723 height += this.header.getHeight();
30726 var fm = this.footer.getMargins();
30727 height += (this.footer.getHeight()+fm.top+fm.bottom);
30729 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30730 height += this.centerBg.getPadding("tb");
30735 syncBodyHeight : function()
30737 var bd = this.body, // the text
30738 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30740 var height = this.size.height - this.getHeaderFooterHeight(false);
30741 bd.setHeight(height-bd.getMargins("tb"));
30742 var hh = this.header.getHeight();
30743 var h = this.size.height-hh;
30746 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30747 bw.setHeight(h-cb.getPadding("tb"));
30749 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30750 bd.setWidth(bw.getWidth(true));
30752 this.tabs.syncHeight();
30754 this.tabs.el.repaint();
30760 * Restores the previous state of the dialog if Roo.state is configured.
30761 * @return {Roo.BasicDialog} this
30763 restoreState : function(){
30764 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30765 if(box && box.width){
30766 this.xy = [box.x, box.y];
30767 this.resizeTo(box.width, box.height);
30773 beforeShow : function(){
30775 if(this.fixedcenter){
30776 this.xy = this.el.getCenterXY(true);
30779 Roo.get(document.body).addClass("x-body-masked");
30780 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30783 this.constrainXY();
30787 animShow : function(){
30788 var b = Roo.get(this.animateTarget).getBox();
30789 this.proxy.setSize(b.width, b.height);
30790 this.proxy.setLocation(b.x, b.y);
30792 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30793 true, .35, this.showEl.createDelegate(this));
30797 * Shows the dialog.
30798 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30799 * @return {Roo.BasicDialog} this
30801 show : function(animateTarget){
30802 if (this.fireEvent("beforeshow", this) === false){
30805 if(this.syncHeightBeforeShow){
30806 this.syncBodyHeight();
30807 }else if(this.firstShow){
30808 this.firstShow = false;
30809 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30811 this.animateTarget = animateTarget || this.animateTarget;
30812 if(!this.el.isVisible()){
30814 if(this.animateTarget && Roo.get(this.animateTarget)){
30824 showEl : function(){
30826 this.el.setXY(this.xy);
30828 this.adjustAssets(true);
30831 // IE peekaboo bug - fix found by Dave Fenwick
30835 this.fireEvent("show", this);
30839 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30840 * dialog itself will receive focus.
30842 focus : function(){
30843 if(this.defaultButton){
30844 this.defaultButton.focus();
30846 this.focusEl.focus();
30851 constrainXY : function(){
30852 if(this.constraintoviewport !== false){
30853 if(!this.viewSize){
30854 if(this.container){
30855 var s = this.container.getSize();
30856 this.viewSize = [s.width, s.height];
30858 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30861 var s = Roo.get(this.container||document).getScroll();
30863 var x = this.xy[0], y = this.xy[1];
30864 var w = this.size.width, h = this.size.height;
30865 var vw = this.viewSize[0], vh = this.viewSize[1];
30866 // only move it if it needs it
30868 // first validate right/bottom
30869 if(x + w > vw+s.left){
30873 if(y + h > vh+s.top){
30877 // then make sure top/left isn't negative
30889 if(this.isVisible()){
30890 this.el.setLocation(x, y);
30891 this.adjustAssets();
30898 onDrag : function(){
30899 if(!this.proxyDrag){
30900 this.xy = this.el.getXY();
30901 this.adjustAssets();
30906 adjustAssets : function(doShow){
30907 var x = this.xy[0], y = this.xy[1];
30908 var w = this.size.width, h = this.size.height;
30909 if(doShow === true){
30911 this.shadow.show(this.el);
30917 if(this.shadow && this.shadow.isVisible()){
30918 this.shadow.show(this.el);
30920 if(this.shim && this.shim.isVisible()){
30921 this.shim.setBounds(x, y, w, h);
30926 adjustViewport : function(w, h){
30928 w = Roo.lib.Dom.getViewWidth();
30929 h = Roo.lib.Dom.getViewHeight();
30932 this.viewSize = [w, h];
30933 if(this.modal && this.mask.isVisible()){
30934 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30935 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30937 if(this.isVisible()){
30938 this.constrainXY();
30943 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30944 * shadow, proxy, mask, etc.) Also removes all event listeners.
30945 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30947 destroy : function(removeEl){
30948 if(this.isVisible()){
30949 this.animateTarget = null;
30952 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30954 this.tabs.destroy(removeEl);
30967 for(var i = 0, len = this.buttons.length; i < len; i++){
30968 this.buttons[i].destroy();
30971 this.el.removeAllListeners();
30972 if(removeEl === true){
30973 this.el.update("");
30976 Roo.DialogManager.unregister(this);
30980 startMove : function(){
30981 if(this.proxyDrag){
30984 if(this.constraintoviewport !== false){
30985 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30990 endMove : function(){
30991 if(!this.proxyDrag){
30992 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30994 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30997 this.refreshSize();
30998 this.adjustAssets();
31000 this.fireEvent("move", this, this.xy[0], this.xy[1]);
31004 * Brings this dialog to the front of any other visible dialogs
31005 * @return {Roo.BasicDialog} this
31007 toFront : function(){
31008 Roo.DialogManager.bringToFront(this);
31013 * Sends this dialog to the back (under) of any other visible dialogs
31014 * @return {Roo.BasicDialog} this
31016 toBack : function(){
31017 Roo.DialogManager.sendToBack(this);
31022 * Centers this dialog in the viewport
31023 * @return {Roo.BasicDialog} this
31025 center : function(){
31026 var xy = this.el.getCenterXY(true);
31027 this.moveTo(xy[0], xy[1]);
31032 * Moves the dialog's top-left corner to the specified point
31033 * @param {Number} x
31034 * @param {Number} y
31035 * @return {Roo.BasicDialog} this
31037 moveTo : function(x, y){
31039 if(this.isVisible()){
31040 this.el.setXY(this.xy);
31041 this.adjustAssets();
31047 * Aligns the dialog to the specified element
31048 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31049 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
31050 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31051 * @return {Roo.BasicDialog} this
31053 alignTo : function(element, position, offsets){
31054 this.xy = this.el.getAlignToXY(element, position, offsets);
31055 if(this.isVisible()){
31056 this.el.setXY(this.xy);
31057 this.adjustAssets();
31063 * Anchors an element to another element and realigns it when the window is resized.
31064 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31065 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
31066 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31067 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
31068 * is a number, it is used as the buffer delay (defaults to 50ms).
31069 * @return {Roo.BasicDialog} this
31071 anchorTo : function(el, alignment, offsets, monitorScroll){
31072 var action = function(){
31073 this.alignTo(el, alignment, offsets);
31075 Roo.EventManager.onWindowResize(action, this);
31076 var tm = typeof monitorScroll;
31077 if(tm != 'undefined'){
31078 Roo.EventManager.on(window, 'scroll', action, this,
31079 {buffer: tm == 'number' ? monitorScroll : 50});
31086 * Returns true if the dialog is visible
31087 * @return {Boolean}
31089 isVisible : function(){
31090 return this.el.isVisible();
31094 animHide : function(callback){
31095 var b = Roo.get(this.animateTarget).getBox();
31097 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
31099 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
31100 this.hideEl.createDelegate(this, [callback]));
31104 * Hides the dialog.
31105 * @param {Function} callback (optional) Function to call when the dialog is hidden
31106 * @return {Roo.BasicDialog} this
31108 hide : function(callback){
31109 if (this.fireEvent("beforehide", this) === false){
31113 this.shadow.hide();
31118 // sometimes animateTarget seems to get set.. causing problems...
31119 // this just double checks..
31120 if(this.animateTarget && Roo.get(this.animateTarget)) {
31121 this.animHide(callback);
31124 this.hideEl(callback);
31130 hideEl : function(callback){
31134 Roo.get(document.body).removeClass("x-body-masked");
31136 this.fireEvent("hide", this);
31137 if(typeof callback == "function"){
31143 hideAction : function(){
31144 this.setLeft("-10000px");
31145 this.setTop("-10000px");
31146 this.setStyle("visibility", "hidden");
31150 refreshSize : function(){
31151 this.size = this.el.getSize();
31152 this.xy = this.el.getXY();
31153 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
31157 // z-index is managed by the DialogManager and may be overwritten at any time
31158 setZIndex : function(index){
31160 this.mask.setStyle("z-index", index);
31163 this.shim.setStyle("z-index", ++index);
31166 this.shadow.setZIndex(++index);
31168 this.el.setStyle("z-index", ++index);
31170 this.proxy.setStyle("z-index", ++index);
31173 this.resizer.proxy.setStyle("z-index", ++index);
31176 this.lastZIndex = index;
31180 * Returns the element for this dialog
31181 * @return {Roo.Element} The underlying dialog Element
31183 getEl : function(){
31189 * @class Roo.DialogManager
31190 * Provides global access to BasicDialogs that have been created and
31191 * support for z-indexing (layering) multiple open dialogs.
31193 Roo.DialogManager = function(){
31195 var accessList = [];
31199 var sortDialogs = function(d1, d2){
31200 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31204 var orderDialogs = function(){
31205 accessList.sort(sortDialogs);
31206 var seed = Roo.DialogManager.zseed;
31207 for(var i = 0, len = accessList.length; i < len; i++){
31208 var dlg = accessList[i];
31210 dlg.setZIndex(seed + (i*10));
31217 * The starting z-index for BasicDialogs (defaults to 9000)
31218 * @type Number The z-index value
31223 register : function(dlg){
31224 list[dlg.id] = dlg;
31225 accessList.push(dlg);
31229 unregister : function(dlg){
31230 delete list[dlg.id];
31233 if(!accessList.indexOf){
31234 for( i = 0, len = accessList.length; i < len; i++){
31235 if(accessList[i] == dlg){
31236 accessList.splice(i, 1);
31241 i = accessList.indexOf(dlg);
31243 accessList.splice(i, 1);
31249 * Gets a registered dialog by id
31250 * @param {String/Object} id The id of the dialog or a dialog
31251 * @return {Roo.BasicDialog} this
31253 get : function(id){
31254 return typeof id == "object" ? id : list[id];
31258 * Brings the specified dialog to the front
31259 * @param {String/Object} dlg The id of the dialog or a dialog
31260 * @return {Roo.BasicDialog} this
31262 bringToFront : function(dlg){
31263 dlg = this.get(dlg);
31266 dlg._lastAccess = new Date().getTime();
31273 * Sends the specified dialog to the back
31274 * @param {String/Object} dlg The id of the dialog or a dialog
31275 * @return {Roo.BasicDialog} this
31277 sendToBack : function(dlg){
31278 dlg = this.get(dlg);
31279 dlg._lastAccess = -(new Date().getTime());
31285 * Hides all dialogs
31287 hideAll : function(){
31288 for(var id in list){
31289 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31298 * @class Roo.LayoutDialog
31299 * @extends Roo.BasicDialog
31300 * Dialog which provides adjustments for working with a layout in a Dialog.
31301 * Add your necessary layout config options to the dialog's config.<br>
31302 * Example usage (including a nested layout):
31305 dialog = new Roo.LayoutDialog("download-dlg", {
31314 // layout config merges with the dialog config
31316 tabPosition: "top",
31317 alwaysShowTabs: true
31320 dialog.addKeyListener(27, dialog.hide, dialog);
31321 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31322 dialog.addButton("Build It!", this.getDownload, this);
31324 // we can even add nested layouts
31325 var innerLayout = new Roo.BorderLayout("dl-inner", {
31335 innerLayout.beginUpdate();
31336 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31337 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31338 innerLayout.endUpdate(true);
31340 var layout = dialog.getLayout();
31341 layout.beginUpdate();
31342 layout.add("center", new Roo.ContentPanel("standard-panel",
31343 {title: "Download the Source", fitToFrame:true}));
31344 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31345 {title: "Build your own roo.js"}));
31346 layout.getRegion("center").showPanel(sp);
31347 layout.endUpdate();
31351 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31352 * @param {Object} config configuration options
31354 Roo.LayoutDialog = function(el, cfg){
31357 if (typeof(cfg) == 'undefined') {
31358 config = Roo.apply({}, el);
31359 // not sure why we use documentElement here.. - it should always be body.
31360 // IE7 borks horribly if we use documentElement.
31361 // webkit also does not like documentElement - it creates a body element...
31362 el = Roo.get( document.body || document.documentElement ).createChild();
31363 //config.autoCreate = true;
31367 config.autoTabs = false;
31368 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31369 this.body.setStyle({overflow:"hidden", position:"relative"});
31370 this.layout = new Roo.BorderLayout(this.body.dom, config);
31371 this.layout.monitorWindowResize = false;
31372 this.el.addClass("x-dlg-auto-layout");
31373 // fix case when center region overwrites center function
31374 this.center = Roo.BasicDialog.prototype.center;
31375 this.on("show", this.layout.layout, this.layout, true);
31376 if (config.items) {
31377 var xitems = config.items;
31378 delete config.items;
31379 Roo.each(xitems, this.addxtype, this);
31384 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31386 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31389 endUpdate : function(){
31390 this.layout.endUpdate();
31394 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31397 beginUpdate : function(){
31398 this.layout.beginUpdate();
31402 * Get the BorderLayout for this dialog
31403 * @return {Roo.BorderLayout}
31405 getLayout : function(){
31406 return this.layout;
31409 showEl : function(){
31410 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31412 this.layout.layout();
31417 // Use the syncHeightBeforeShow config option to control this automatically
31418 syncBodyHeight : function(){
31419 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31420 if(this.layout){this.layout.layout();}
31424 * Add an xtype element (actually adds to the layout.)
31425 * @return {Object} xdata xtype object data.
31428 addxtype : function(c) {
31429 return this.layout.addxtype(c);
31433 * Ext JS Library 1.1.1
31434 * Copyright(c) 2006-2007, Ext JS, LLC.
31436 * Originally Released Under LGPL - original licence link has changed is not relivant.
31439 * <script type="text/javascript">
31443 * @class Roo.MessageBox
31444 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31448 Roo.Msg.alert('Status', 'Changes saved successfully.');
31450 // Prompt for user data:
31451 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31453 // process text value...
31457 // Show a dialog using config options:
31459 title:'Save Changes?',
31460 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31461 buttons: Roo.Msg.YESNOCANCEL,
31468 Roo.MessageBox = function(){
31469 var dlg, opt, mask, waitTimer;
31470 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31471 var buttons, activeTextEl, bwidth;
31474 var handleButton = function(button){
31476 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31480 var handleHide = function(){
31481 if(opt && opt.cls){
31482 dlg.el.removeClass(opt.cls);
31485 Roo.TaskMgr.stop(waitTimer);
31491 var updateButtons = function(b){
31494 buttons["ok"].hide();
31495 buttons["cancel"].hide();
31496 buttons["yes"].hide();
31497 buttons["no"].hide();
31498 dlg.footer.dom.style.display = 'none';
31501 dlg.footer.dom.style.display = '';
31502 for(var k in buttons){
31503 if(typeof buttons[k] != "function"){
31506 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31507 width += buttons[k].el.getWidth()+15;
31517 var handleEsc = function(d, k, e){
31518 if(opt && opt.closable !== false){
31528 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31529 * @return {Roo.BasicDialog} The BasicDialog element
31531 getDialog : function(){
31533 dlg = new Roo.BasicDialog("x-msg-box", {
31538 constraintoviewport:false,
31540 collapsible : false,
31543 width:400, height:100,
31544 buttonAlign:"center",
31545 closeClick : function(){
31546 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31547 handleButton("no");
31549 handleButton("cancel");
31553 dlg.on("hide", handleHide);
31555 dlg.addKeyListener(27, handleEsc);
31557 var bt = this.buttonText;
31558 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31559 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31560 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31561 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31562 bodyEl = dlg.body.createChild({
31564 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" /><textarea class="roo-mb-textarea"></textarea><div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
31566 msgEl = bodyEl.dom.firstChild;
31567 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31568 textboxEl.enableDisplayMode();
31569 textboxEl.addKeyListener([10,13], function(){
31570 if(dlg.isVisible() && opt && opt.buttons){
31571 if(opt.buttons.ok){
31572 handleButton("ok");
31573 }else if(opt.buttons.yes){
31574 handleButton("yes");
31578 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31579 textareaEl.enableDisplayMode();
31580 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31581 progressEl.enableDisplayMode();
31582 var pf = progressEl.dom.firstChild;
31584 pp = Roo.get(pf.firstChild);
31585 pp.setHeight(pf.offsetHeight);
31593 * Updates the message box body text
31594 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31595 * the XHTML-compliant non-breaking space character '&#160;')
31596 * @return {Roo.MessageBox} This message box
31598 updateText : function(text){
31599 if(!dlg.isVisible() && !opt.width){
31600 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31602 msgEl.innerHTML = text || ' ';
31604 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31605 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31607 Math.min(opt.width || cw , this.maxWidth),
31608 Math.max(opt.minWidth || this.minWidth, bwidth)
31611 activeTextEl.setWidth(w);
31613 if(dlg.isVisible()){
31614 dlg.fixedcenter = false;
31616 // to big, make it scroll. = But as usual stupid IE does not support
31619 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31620 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31621 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31623 bodyEl.dom.style.height = '';
31624 bodyEl.dom.style.overflowY = '';
31627 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31629 bodyEl.dom.style.overflowX = '';
31632 dlg.setContentSize(w, bodyEl.getHeight());
31633 if(dlg.isVisible()){
31634 dlg.fixedcenter = true;
31640 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31641 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31642 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31643 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31644 * @return {Roo.MessageBox} This message box
31646 updateProgress : function(value, text){
31648 this.updateText(text);
31650 if (pp) { // weird bug on my firefox - for some reason this is not defined
31651 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31657 * Returns true if the message box is currently displayed
31658 * @return {Boolean} True if the message box is visible, else false
31660 isVisible : function(){
31661 return dlg && dlg.isVisible();
31665 * Hides the message box if it is displayed
31668 if(this.isVisible()){
31674 * Displays a new message box, or reinitializes an existing message box, based on the config options
31675 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31676 * The following config object properties are supported:
31678 Property Type Description
31679 ---------- --------------- ------------------------------------------------------------------------------------
31680 animEl String/Element An id or Element from which the message box should animate as it opens and
31681 closes (defaults to undefined)
31682 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31683 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31684 closable Boolean False to hide the top-right close button (defaults to true). Note that
31685 progress and wait dialogs will ignore this property and always hide the
31686 close button as they can only be closed programmatically.
31687 cls String A custom CSS class to apply to the message box element
31688 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31689 displayed (defaults to 75)
31690 fn Function A callback function to execute after closing the dialog. The arguments to the
31691 function will be btn (the name of the button that was clicked, if applicable,
31692 e.g. "ok"), and text (the value of the active text field, if applicable).
31693 Progress and wait dialogs will ignore this option since they do not respond to
31694 user actions and can only be closed programmatically, so any required function
31695 should be called by the same code after it closes the dialog.
31696 icon String A CSS class that provides a background image to be used as an icon for
31697 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31698 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31699 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31700 modal Boolean False to allow user interaction with the page while the message box is
31701 displayed (defaults to true)
31702 msg String A string that will replace the existing message box body text (defaults
31703 to the XHTML-compliant non-breaking space character ' ')
31704 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31705 progress Boolean True to display a progress bar (defaults to false)
31706 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31707 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31708 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31709 title String The title text
31710 value String The string value to set into the active textbox element if displayed
31711 wait Boolean True to display a progress bar (defaults to false)
31712 width Number The width of the dialog in pixels
31719 msg: 'Please enter your address:',
31721 buttons: Roo.MessageBox.OKCANCEL,
31724 animEl: 'addAddressBtn'
31727 * @param {Object} config Configuration options
31728 * @return {Roo.MessageBox} This message box
31730 show : function(options)
31733 // this causes nightmares if you show one dialog after another
31734 // especially on callbacks..
31736 if(this.isVisible()){
31739 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31740 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31741 Roo.log("New Dialog Message:" + options.msg )
31742 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31743 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31746 var d = this.getDialog();
31748 d.setTitle(opt.title || " ");
31749 d.close.setDisplayed(opt.closable !== false);
31750 activeTextEl = textboxEl;
31751 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31756 textareaEl.setHeight(typeof opt.multiline == "number" ?
31757 opt.multiline : this.defaultTextHeight);
31758 activeTextEl = textareaEl;
31767 progressEl.setDisplayed(opt.progress === true);
31768 this.updateProgress(0);
31769 activeTextEl.dom.value = opt.value || "";
31771 dlg.setDefaultButton(activeTextEl);
31773 var bs = opt.buttons;
31776 db = buttons["ok"];
31777 }else if(bs && bs.yes){
31778 db = buttons["yes"];
31780 dlg.setDefaultButton(db);
31782 bwidth = updateButtons(opt.buttons);
31783 this.updateText(opt.msg);
31785 d.el.addClass(opt.cls);
31787 d.proxyDrag = opt.proxyDrag === true;
31788 d.modal = opt.modal !== false;
31789 d.mask = opt.modal !== false ? mask : false;
31790 if(!d.isVisible()){
31791 // force it to the end of the z-index stack so it gets a cursor in FF
31792 document.body.appendChild(dlg.el.dom);
31793 d.animateTarget = null;
31794 d.show(options.animEl);
31800 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31801 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31802 * and closing the message box when the process is complete.
31803 * @param {String} title The title bar text
31804 * @param {String} msg The message box body text
31805 * @return {Roo.MessageBox} This message box
31807 progress : function(title, msg){
31814 minWidth: this.minProgressWidth,
31821 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31822 * If a callback function is passed it will be called after the user clicks the button, and the
31823 * id of the button that was clicked will be passed as the only parameter to the callback
31824 * (could also be the top-right close button).
31825 * @param {String} title The title bar text
31826 * @param {String} msg The message box body text
31827 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31828 * @param {Object} scope (optional) The scope of the callback function
31829 * @return {Roo.MessageBox} This message box
31831 alert : function(title, msg, fn, scope){
31844 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31845 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31846 * You are responsible for closing the message box when the process is complete.
31847 * @param {String} msg The message box body text
31848 * @param {String} title (optional) The title bar text
31849 * @return {Roo.MessageBox} This message box
31851 wait : function(msg, title){
31862 waitTimer = Roo.TaskMgr.start({
31864 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31872 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31873 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31874 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31875 * @param {String} title The title bar text
31876 * @param {String} msg The message box body text
31877 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31878 * @param {Object} scope (optional) The scope of the callback function
31879 * @return {Roo.MessageBox} This message box
31881 confirm : function(title, msg, fn, scope){
31885 buttons: this.YESNO,
31894 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31895 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31896 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31897 * (could also be the top-right close button) and the text that was entered will be passed as the two
31898 * parameters to the callback.
31899 * @param {String} title The title bar text
31900 * @param {String} msg The message box body text
31901 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31902 * @param {Object} scope (optional) The scope of the callback function
31903 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31904 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31905 * @return {Roo.MessageBox} This message box
31907 prompt : function(title, msg, fn, scope, multiline){
31911 buttons: this.OKCANCEL,
31916 multiline: multiline,
31923 * Button config that displays a single OK button
31928 * Button config that displays Yes and No buttons
31931 YESNO : {yes:true, no:true},
31933 * Button config that displays OK and Cancel buttons
31936 OKCANCEL : {ok:true, cancel:true},
31938 * Button config that displays Yes, No and Cancel buttons
31941 YESNOCANCEL : {yes:true, no:true, cancel:true},
31944 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31947 defaultTextHeight : 75,
31949 * The maximum width in pixels of the message box (defaults to 600)
31954 * The minimum width in pixels of the message box (defaults to 100)
31959 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31960 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31963 minProgressWidth : 250,
31965 * An object containing the default button text strings that can be overriden for localized language support.
31966 * Supported properties are: ok, cancel, yes and no.
31967 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31980 * Shorthand for {@link Roo.MessageBox}
31982 Roo.Msg = Roo.MessageBox;/*
31984 * Ext JS Library 1.1.1
31985 * Copyright(c) 2006-2007, Ext JS, LLC.
31987 * Originally Released Under LGPL - original licence link has changed is not relivant.
31990 * <script type="text/javascript">
31993 * @class Roo.QuickTips
31994 * Provides attractive and customizable tooltips for any element.
31997 Roo.QuickTips = function(){
31998 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31999 var ce, bd, xy, dd;
32000 var visible = false, disabled = true, inited = false;
32001 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
32003 var onOver = function(e){
32007 var t = e.getTarget();
32008 if(!t || t.nodeType !== 1 || t == document || t == document.body){
32011 if(ce && t == ce.el){
32012 clearTimeout(hideProc);
32015 if(t && tagEls[t.id]){
32016 tagEls[t.id].el = t;
32017 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
32020 var ttp, et = Roo.fly(t);
32021 var ns = cfg.namespace;
32022 if(tm.interceptTitles && t.title){
32025 t.removeAttribute("title");
32026 e.preventDefault();
32028 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
32031 showProc = show.defer(tm.showDelay, tm, [{
32034 width: et.getAttributeNS(ns, cfg.width),
32035 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
32036 title: et.getAttributeNS(ns, cfg.title),
32037 cls: et.getAttributeNS(ns, cfg.cls)
32042 var onOut = function(e){
32043 clearTimeout(showProc);
32044 var t = e.getTarget();
32045 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
32046 hideProc = setTimeout(hide, tm.hideDelay);
32050 var onMove = function(e){
32056 if(tm.trackMouse && ce){
32061 var onDown = function(e){
32062 clearTimeout(showProc);
32063 clearTimeout(hideProc);
32065 if(tm.hideOnClick){
32068 tm.enable.defer(100, tm);
32073 var getPad = function(){
32074 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
32077 var show = function(o){
32081 clearTimeout(dismissProc);
32083 if(removeCls){ // in case manually hidden
32084 el.removeClass(removeCls);
32088 el.addClass(ce.cls);
32089 removeCls = ce.cls;
32092 tipTitle.update(ce.title);
32095 tipTitle.update('');
32098 el.dom.style.width = tm.maxWidth+'px';
32099 //tipBody.dom.style.width = '';
32100 tipBodyText.update(o.text);
32101 var p = getPad(), w = ce.width;
32103 var td = tipBodyText.dom;
32104 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
32105 if(aw > tm.maxWidth){
32107 }else if(aw < tm.minWidth){
32113 //tipBody.setWidth(w);
32114 el.setWidth(parseInt(w, 10) + p);
32115 if(ce.autoHide === false){
32116 close.setDisplayed(true);
32121 close.setDisplayed(false);
32127 el.avoidY = xy[1]-18;
32132 el.setStyle("visibility", "visible");
32133 el.fadeIn({callback: afterShow});
32139 var afterShow = function(){
32143 if(tm.autoDismiss && ce.autoHide !== false){
32144 dismissProc = setTimeout(hide, tm.autoDismissDelay);
32149 var hide = function(noanim){
32150 clearTimeout(dismissProc);
32151 clearTimeout(hideProc);
32153 if(el.isVisible()){
32155 if(noanim !== true && tm.animate){
32156 el.fadeOut({callback: afterHide});
32163 var afterHide = function(){
32166 el.removeClass(removeCls);
32173 * @cfg {Number} minWidth
32174 * The minimum width of the quick tip (defaults to 40)
32178 * @cfg {Number} maxWidth
32179 * The maximum width of the quick tip (defaults to 300)
32183 * @cfg {Boolean} interceptTitles
32184 * True to automatically use the element's DOM title value if available (defaults to false)
32186 interceptTitles : false,
32188 * @cfg {Boolean} trackMouse
32189 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
32191 trackMouse : false,
32193 * @cfg {Boolean} hideOnClick
32194 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32196 hideOnClick : true,
32198 * @cfg {Number} showDelay
32199 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32203 * @cfg {Number} hideDelay
32204 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32208 * @cfg {Boolean} autoHide
32209 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32210 * Used in conjunction with hideDelay.
32215 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32216 * (defaults to true). Used in conjunction with autoDismissDelay.
32218 autoDismiss : true,
32221 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32223 autoDismissDelay : 5000,
32225 * @cfg {Boolean} animate
32226 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32231 * @cfg {String} title
32232 * Title text to display (defaults to ''). This can be any valid HTML markup.
32236 * @cfg {String} text
32237 * Body text to display (defaults to ''). This can be any valid HTML markup.
32241 * @cfg {String} cls
32242 * A CSS class to apply to the base quick tip element (defaults to '').
32246 * @cfg {Number} width
32247 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32248 * minWidth or maxWidth.
32253 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32254 * or display QuickTips in a page.
32257 tm = Roo.QuickTips;
32258 cfg = tm.tagConfig;
32260 if(!Roo.isReady){ // allow calling of init() before onReady
32261 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32264 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32265 el.fxDefaults = {stopFx: true};
32266 // maximum custom styling
32267 //el.update('<div class="x-tip-top-left"><div class="x-tip-top-right"><div class="x-tip-top"></div></div></div><div class="x-tip-bd-left"><div class="x-tip-bd-right"><div class="x-tip-bd"><div class="x-tip-close"></div><h3></h3><div class="x-tip-bd-inner"></div><div class="x-clear"></div></div></div></div><div class="x-tip-ft-left"><div class="x-tip-ft-right"><div class="x-tip-ft"></div></div></div>');
32268 el.update('<div class="x-tip-bd"><div class="x-tip-close"></div><h3></h3><div class="x-tip-bd-inner"></div><div class="x-clear"></div></div>');
32269 tipTitle = el.child('h3');
32270 tipTitle.enableDisplayMode("block");
32271 tipBody = el.child('div.x-tip-bd');
32272 tipBodyText = el.child('div.x-tip-bd-inner');
32273 //bdLeft = el.child('div.x-tip-bd-left');
32274 //bdRight = el.child('div.x-tip-bd-right');
32275 close = el.child('div.x-tip-close');
32276 close.enableDisplayMode("block");
32277 close.on("click", hide);
32278 var d = Roo.get(document);
32279 d.on("mousedown", onDown);
32280 d.on("mouseover", onOver);
32281 d.on("mouseout", onOut);
32282 d.on("mousemove", onMove);
32283 esc = d.addKeyListener(27, hide);
32286 dd = el.initDD("default", null, {
32287 onDrag : function(){
32291 dd.setHandleElId(tipTitle.id);
32300 * Configures a new quick tip instance and assigns it to a target element. The following config options
32303 Property Type Description
32304 ---------- --------------------- ------------------------------------------------------------------------
32305 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32307 * @param {Object} config The config object
32309 register : function(config){
32310 var cs = config instanceof Array ? config : arguments;
32311 for(var i = 0, len = cs.length; i < len; i++) {
32313 var target = c.target;
32315 if(target instanceof Array){
32316 for(var j = 0, jlen = target.length; j < jlen; j++){
32317 tagEls[target[j]] = c;
32320 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32327 * Removes this quick tip from its element and destroys it.
32328 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32330 unregister : function(el){
32331 delete tagEls[Roo.id(el)];
32335 * Enable this quick tip.
32337 enable : function(){
32338 if(inited && disabled){
32340 if(locks.length < 1){
32347 * Disable this quick tip.
32349 disable : function(){
32351 clearTimeout(showProc);
32352 clearTimeout(hideProc);
32353 clearTimeout(dismissProc);
32361 * Returns true if the quick tip is enabled, else false.
32363 isEnabled : function(){
32370 attribute : "qtip",
32380 // backwards compat
32381 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32383 * Ext JS Library 1.1.1
32384 * Copyright(c) 2006-2007, Ext JS, LLC.
32386 * Originally Released Under LGPL - original licence link has changed is not relivant.
32389 * <script type="text/javascript">
32394 * @class Roo.tree.TreePanel
32395 * @extends Roo.data.Tree
32397 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32398 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32399 * @cfg {Boolean} enableDD true to enable drag and drop
32400 * @cfg {Boolean} enableDrag true to enable just drag
32401 * @cfg {Boolean} enableDrop true to enable just drop
32402 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32403 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32404 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32405 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32406 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32407 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32408 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32409 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32410 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32411 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32412 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32413 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32414 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32415 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32416 * @cfg {Function} renderer DEPRECATED - use TreeLoader:create event / Sets the rendering (formatting) function for the nodes. to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
32417 * @cfg {Function} rendererTip DEPRECATED - use TreeLoader:create event / Sets the rendering (formatting) function for the nodes hovertip to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
32420 * @param {String/HTMLElement/Element} el The container element
32421 * @param {Object} config
32423 Roo.tree.TreePanel = function(el, config){
32425 var loader = false;
32427 root = config.root;
32428 delete config.root;
32430 if (config.loader) {
32431 loader = config.loader;
32432 delete config.loader;
32435 Roo.apply(this, config);
32436 Roo.tree.TreePanel.superclass.constructor.call(this);
32437 this.el = Roo.get(el);
32438 this.el.addClass('x-tree');
32439 //console.log(root);
32441 this.setRootNode( Roo.factory(root, Roo.tree));
32444 this.loader = Roo.factory(loader, Roo.tree);
32447 * Read-only. The id of the container element becomes this TreePanel's id.
32449 this.id = this.el.id;
32452 * @event beforeload
32453 * Fires before a node is loaded, return false to cancel
32454 * @param {Node} node The node being loaded
32456 "beforeload" : true,
32459 * Fires when a node is loaded
32460 * @param {Node} node The node that was loaded
32464 * @event textchange
32465 * Fires when the text for a node is changed
32466 * @param {Node} node The node
32467 * @param {String} text The new text
32468 * @param {String} oldText The old text
32470 "textchange" : true,
32472 * @event beforeexpand
32473 * Fires before a node is expanded, return false to cancel.
32474 * @param {Node} node The node
32475 * @param {Boolean} deep
32476 * @param {Boolean} anim
32478 "beforeexpand" : true,
32480 * @event beforecollapse
32481 * Fires before a node is collapsed, return false to cancel.
32482 * @param {Node} node The node
32483 * @param {Boolean} deep
32484 * @param {Boolean} anim
32486 "beforecollapse" : true,
32489 * Fires when a node is expanded
32490 * @param {Node} node The node
32494 * @event disabledchange
32495 * Fires when the disabled status of a node changes
32496 * @param {Node} node The node
32497 * @param {Boolean} disabled
32499 "disabledchange" : true,
32502 * Fires when a node is collapsed
32503 * @param {Node} node The node
32507 * @event beforeclick
32508 * Fires before click processing on a node. Return false to cancel the default action.
32509 * @param {Node} node The node
32510 * @param {Roo.EventObject} e The event object
32512 "beforeclick":true,
32514 * @event checkchange
32515 * Fires when a node with a checkbox's checked property changes
32516 * @param {Node} this This node
32517 * @param {Boolean} checked
32519 "checkchange":true,
32522 * Fires when a node is clicked
32523 * @param {Node} node The node
32524 * @param {Roo.EventObject} e The event object
32529 * Fires when a node is double clicked
32530 * @param {Node} node The node
32531 * @param {Roo.EventObject} e The event object
32535 * @event contextmenu
32536 * Fires when a node is right clicked
32537 * @param {Node} node The node
32538 * @param {Roo.EventObject} e The event object
32540 "contextmenu":true,
32542 * @event beforechildrenrendered
32543 * Fires right before the child nodes for a node are rendered
32544 * @param {Node} node The node
32546 "beforechildrenrendered":true,
32549 * Fires when a node starts being dragged
32550 * @param {Roo.tree.TreePanel} this
32551 * @param {Roo.tree.TreeNode} node
32552 * @param {event} e The raw browser event
32554 "startdrag" : true,
32557 * Fires when a drag operation is complete
32558 * @param {Roo.tree.TreePanel} this
32559 * @param {Roo.tree.TreeNode} node
32560 * @param {event} e The raw browser event
32565 * Fires when a dragged node is dropped on a valid DD target
32566 * @param {Roo.tree.TreePanel} this
32567 * @param {Roo.tree.TreeNode} node
32568 * @param {DD} dd The dd it was dropped on
32569 * @param {event} e The raw browser event
32573 * @event beforenodedrop
32574 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32575 * passed to handlers has the following properties:<br />
32576 * <ul style="padding:5px;padding-left:16px;">
32577 * <li>tree - The TreePanel</li>
32578 * <li>target - The node being targeted for the drop</li>
32579 * <li>data - The drag data from the drag source</li>
32580 * <li>point - The point of the drop - append, above or below</li>
32581 * <li>source - The drag source</li>
32582 * <li>rawEvent - Raw mouse event</li>
32583 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32584 * to be inserted by setting them on this object.</li>
32585 * <li>cancel - Set this to true to cancel the drop.</li>
32587 * @param {Object} dropEvent
32589 "beforenodedrop" : true,
32592 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32593 * passed to handlers has the following properties:<br />
32594 * <ul style="padding:5px;padding-left:16px;">
32595 * <li>tree - The TreePanel</li>
32596 * <li>target - The node being targeted for the drop</li>
32597 * <li>data - The drag data from the drag source</li>
32598 * <li>point - The point of the drop - append, above or below</li>
32599 * <li>source - The drag source</li>
32600 * <li>rawEvent - Raw mouse event</li>
32601 * <li>dropNode - Dropped node(s).</li>
32603 * @param {Object} dropEvent
32607 * @event nodedragover
32608 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32609 * passed to handlers has the following properties:<br />
32610 * <ul style="padding:5px;padding-left:16px;">
32611 * <li>tree - The TreePanel</li>
32612 * <li>target - The node being targeted for the drop</li>
32613 * <li>data - The drag data from the drag source</li>
32614 * <li>point - The point of the drop - append, above or below</li>
32615 * <li>source - The drag source</li>
32616 * <li>rawEvent - Raw mouse event</li>
32617 * <li>dropNode - Drop node(s) provided by the source.</li>
32618 * <li>cancel - Set this to true to signal drop not allowed.</li>
32620 * @param {Object} dragOverEvent
32622 "nodedragover" : true
32625 if(this.singleExpand){
32626 this.on("beforeexpand", this.restrictExpand, this);
32629 this.editor.tree = this;
32630 this.editor = Roo.factory(this.editor, Roo.tree);
32633 if (this.selModel) {
32634 this.selModel = Roo.factory(this.selModel, Roo.tree);
32638 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32639 rootVisible : true,
32640 animate: Roo.enableFx,
32643 hlDrop : Roo.enableFx,
32647 rendererTip: false,
32649 restrictExpand : function(node){
32650 var p = node.parentNode;
32652 if(p.expandedChild && p.expandedChild.parentNode == p){
32653 p.expandedChild.collapse();
32655 p.expandedChild = node;
32659 // private override
32660 setRootNode : function(node){
32661 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32662 if(!this.rootVisible){
32663 node.ui = new Roo.tree.RootTreeNodeUI(node);
32669 * Returns the container element for this TreePanel
32671 getEl : function(){
32676 * Returns the default TreeLoader for this TreePanel
32678 getLoader : function(){
32679 return this.loader;
32685 expandAll : function(){
32686 this.root.expand(true);
32690 * Collapse all nodes
32692 collapseAll : function(){
32693 this.root.collapse(true);
32697 * Returns the selection model used by this TreePanel
32699 getSelectionModel : function(){
32700 if(!this.selModel){
32701 this.selModel = new Roo.tree.DefaultSelectionModel();
32703 return this.selModel;
32707 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32708 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32709 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32712 getChecked : function(a, startNode){
32713 startNode = startNode || this.root;
32715 var f = function(){
32716 if(this.attributes.checked){
32717 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32720 startNode.cascade(f);
32725 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32726 * @param {String} path
32727 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32728 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32729 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32731 expandPath : function(path, attr, callback){
32732 attr = attr || "id";
32733 var keys = path.split(this.pathSeparator);
32734 var curNode = this.root;
32735 if(curNode.attributes[attr] != keys[1]){ // invalid root
32737 callback(false, null);
32742 var f = function(){
32743 if(++index == keys.length){
32745 callback(true, curNode);
32749 var c = curNode.findChild(attr, keys[index]);
32752 callback(false, curNode);
32757 c.expand(false, false, f);
32759 curNode.expand(false, false, f);
32763 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32764 * @param {String} path
32765 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32766 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32767 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32769 selectPath : function(path, attr, callback){
32770 attr = attr || "id";
32771 var keys = path.split(this.pathSeparator);
32772 var v = keys.pop();
32773 if(keys.length > 0){
32774 var f = function(success, node){
32775 if(success && node){
32776 var n = node.findChild(attr, v);
32782 }else if(callback){
32783 callback(false, n);
32787 callback(false, n);
32791 this.expandPath(keys.join(this.pathSeparator), attr, f);
32793 this.root.select();
32795 callback(true, this.root);
32800 getTreeEl : function(){
32805 * Trigger rendering of this TreePanel
32807 render : function(){
32808 if (this.innerCt) {
32809 return this; // stop it rendering more than once!!
32812 this.innerCt = this.el.createChild({tag:"ul",
32813 cls:"x-tree-root-ct " +
32814 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32816 if(this.containerScroll){
32817 Roo.dd.ScrollManager.register(this.el);
32819 if((this.enableDD || this.enableDrop) && !this.dropZone){
32821 * The dropZone used by this tree if drop is enabled
32822 * @type Roo.tree.TreeDropZone
32824 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32825 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32828 if((this.enableDD || this.enableDrag) && !this.dragZone){
32830 * The dragZone used by this tree if drag is enabled
32831 * @type Roo.tree.TreeDragZone
32833 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32834 ddGroup: this.ddGroup || "TreeDD",
32835 scroll: this.ddScroll
32838 this.getSelectionModel().init(this);
32840 Roo.log("ROOT not set in tree");
32843 this.root.render();
32844 if(!this.rootVisible){
32845 this.root.renderChildren();
32851 * Ext JS Library 1.1.1
32852 * Copyright(c) 2006-2007, Ext JS, LLC.
32854 * Originally Released Under LGPL - original licence link has changed is not relivant.
32857 * <script type="text/javascript">
32862 * @class Roo.tree.DefaultSelectionModel
32863 * @extends Roo.util.Observable
32864 * The default single selection for a TreePanel.
32865 * @param {Object} cfg Configuration
32867 Roo.tree.DefaultSelectionModel = function(cfg){
32868 this.selNode = null;
32874 * @event selectionchange
32875 * Fires when the selected node changes
32876 * @param {DefaultSelectionModel} this
32877 * @param {TreeNode} node the new selection
32879 "selectionchange" : true,
32882 * @event beforeselect
32883 * Fires before the selected node changes, return false to cancel the change
32884 * @param {DefaultSelectionModel} this
32885 * @param {TreeNode} node the new selection
32886 * @param {TreeNode} node the old selection
32888 "beforeselect" : true
32891 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32894 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32895 init : function(tree){
32897 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32898 tree.on("click", this.onNodeClick, this);
32901 onNodeClick : function(node, e){
32902 if (e.ctrlKey && this.selNode == node) {
32903 this.unselect(node);
32911 * @param {TreeNode} node The node to select
32912 * @return {TreeNode} The selected node
32914 select : function(node){
32915 var last = this.selNode;
32916 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32918 last.ui.onSelectedChange(false);
32920 this.selNode = node;
32921 node.ui.onSelectedChange(true);
32922 this.fireEvent("selectionchange", this, node, last);
32929 * @param {TreeNode} node The node to unselect
32931 unselect : function(node){
32932 if(this.selNode == node){
32933 this.clearSelections();
32938 * Clear all selections
32940 clearSelections : function(){
32941 var n = this.selNode;
32943 n.ui.onSelectedChange(false);
32944 this.selNode = null;
32945 this.fireEvent("selectionchange", this, null);
32951 * Get the selected node
32952 * @return {TreeNode} The selected node
32954 getSelectedNode : function(){
32955 return this.selNode;
32959 * Returns true if the node is selected
32960 * @param {TreeNode} node The node to check
32961 * @return {Boolean}
32963 isSelected : function(node){
32964 return this.selNode == node;
32968 * Selects the node above the selected node in the tree, intelligently walking the nodes
32969 * @return TreeNode The new selection
32971 selectPrevious : function(){
32972 var s = this.selNode || this.lastSelNode;
32976 var ps = s.previousSibling;
32978 if(!ps.isExpanded() || ps.childNodes.length < 1){
32979 return this.select(ps);
32981 var lc = ps.lastChild;
32982 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32985 return this.select(lc);
32987 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32988 return this.select(s.parentNode);
32994 * Selects the node above the selected node in the tree, intelligently walking the nodes
32995 * @return TreeNode The new selection
32997 selectNext : function(){
32998 var s = this.selNode || this.lastSelNode;
33002 if(s.firstChild && s.isExpanded()){
33003 return this.select(s.firstChild);
33004 }else if(s.nextSibling){
33005 return this.select(s.nextSibling);
33006 }else if(s.parentNode){
33008 s.parentNode.bubble(function(){
33009 if(this.nextSibling){
33010 newS = this.getOwnerTree().selModel.select(this.nextSibling);
33019 onKeyDown : function(e){
33020 var s = this.selNode || this.lastSelNode;
33021 // undesirable, but required
33026 var k = e.getKey();
33034 this.selectPrevious();
33037 e.preventDefault();
33038 if(s.hasChildNodes()){
33039 if(!s.isExpanded()){
33041 }else if(s.firstChild){
33042 this.select(s.firstChild, e);
33047 e.preventDefault();
33048 if(s.hasChildNodes() && s.isExpanded()){
33050 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
33051 this.select(s.parentNode, e);
33059 * @class Roo.tree.MultiSelectionModel
33060 * @extends Roo.util.Observable
33061 * Multi selection for a TreePanel.
33062 * @param {Object} cfg Configuration
33064 Roo.tree.MultiSelectionModel = function(){
33065 this.selNodes = [];
33069 * @event selectionchange
33070 * Fires when the selected nodes change
33071 * @param {MultiSelectionModel} this
33072 * @param {Array} nodes Array of the selected nodes
33074 "selectionchange" : true
33076 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
33080 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
33081 init : function(tree){
33083 tree.getTreeEl().on("keydown", this.onKeyDown, this);
33084 tree.on("click", this.onNodeClick, this);
33087 onNodeClick : function(node, e){
33088 this.select(node, e, e.ctrlKey);
33093 * @param {TreeNode} node The node to select
33094 * @param {EventObject} e (optional) An event associated with the selection
33095 * @param {Boolean} keepExisting True to retain existing selections
33096 * @return {TreeNode} The selected node
33098 select : function(node, e, keepExisting){
33099 if(keepExisting !== true){
33100 this.clearSelections(true);
33102 if(this.isSelected(node)){
33103 this.lastSelNode = node;
33106 this.selNodes.push(node);
33107 this.selMap[node.id] = node;
33108 this.lastSelNode = node;
33109 node.ui.onSelectedChange(true);
33110 this.fireEvent("selectionchange", this, this.selNodes);
33116 * @param {TreeNode} node The node to unselect
33118 unselect : function(node){
33119 if(this.selMap[node.id]){
33120 node.ui.onSelectedChange(false);
33121 var sn = this.selNodes;
33124 index = sn.indexOf(node);
33126 for(var i = 0, len = sn.length; i < len; i++){
33134 this.selNodes.splice(index, 1);
33136 delete this.selMap[node.id];
33137 this.fireEvent("selectionchange", this, this.selNodes);
33142 * Clear all selections
33144 clearSelections : function(suppressEvent){
33145 var sn = this.selNodes;
33147 for(var i = 0, len = sn.length; i < len; i++){
33148 sn[i].ui.onSelectedChange(false);
33150 this.selNodes = [];
33152 if(suppressEvent !== true){
33153 this.fireEvent("selectionchange", this, this.selNodes);
33159 * Returns true if the node is selected
33160 * @param {TreeNode} node The node to check
33161 * @return {Boolean}
33163 isSelected : function(node){
33164 return this.selMap[node.id] ? true : false;
33168 * Returns an array of the selected nodes
33171 getSelectedNodes : function(){
33172 return this.selNodes;
33175 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
33177 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
33179 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
33182 * Ext JS Library 1.1.1
33183 * Copyright(c) 2006-2007, Ext JS, LLC.
33185 * Originally Released Under LGPL - original licence link has changed is not relivant.
33188 * <script type="text/javascript">
33192 * @class Roo.tree.TreeNode
33193 * @extends Roo.data.Node
33194 * @cfg {String} text The text for this node
33195 * @cfg {Boolean} expanded true to start the node expanded
33196 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33197 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33198 * @cfg {Boolean} disabled true to start the node disabled
33199 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33200 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33201 * @cfg {String} cls A css class to be added to the node
33202 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33203 * @cfg {String} href URL of the link used for the node (defaults to #)
33204 * @cfg {String} hrefTarget target frame for the link
33205 * @cfg {String} qtip An Ext QuickTip for the node
33206 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33207 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33208 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33209 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33210 * (defaults to undefined with no checkbox rendered)
33212 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33214 Roo.tree.TreeNode = function(attributes){
33215 attributes = attributes || {};
33216 if(typeof attributes == "string"){
33217 attributes = {text: attributes};
33219 this.childrenRendered = false;
33220 this.rendered = false;
33221 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33222 this.expanded = attributes.expanded === true;
33223 this.isTarget = attributes.isTarget !== false;
33224 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33225 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33228 * Read-only. The text for this node. To change it use setText().
33231 this.text = attributes.text;
33233 * True if this node is disabled.
33236 this.disabled = attributes.disabled === true;
33240 * @event textchange
33241 * Fires when the text for this node is changed
33242 * @param {Node} this This node
33243 * @param {String} text The new text
33244 * @param {String} oldText The old text
33246 "textchange" : true,
33248 * @event beforeexpand
33249 * Fires before this node is expanded, return false to cancel.
33250 * @param {Node} this This node
33251 * @param {Boolean} deep
33252 * @param {Boolean} anim
33254 "beforeexpand" : true,
33256 * @event beforecollapse
33257 * Fires before this node is collapsed, return false to cancel.
33258 * @param {Node} this This node
33259 * @param {Boolean} deep
33260 * @param {Boolean} anim
33262 "beforecollapse" : true,
33265 * Fires when this node is expanded
33266 * @param {Node} this This node
33270 * @event disabledchange
33271 * Fires when the disabled status of this node changes
33272 * @param {Node} this This node
33273 * @param {Boolean} disabled
33275 "disabledchange" : true,
33278 * Fires when this node is collapsed
33279 * @param {Node} this This node
33283 * @event beforeclick
33284 * Fires before click processing. Return false to cancel the default action.
33285 * @param {Node} this This node
33286 * @param {Roo.EventObject} e The event object
33288 "beforeclick":true,
33290 * @event checkchange
33291 * Fires when a node with a checkbox's checked property changes
33292 * @param {Node} this This node
33293 * @param {Boolean} checked
33295 "checkchange":true,
33298 * Fires when this node is clicked
33299 * @param {Node} this This node
33300 * @param {Roo.EventObject} e The event object
33305 * Fires when this node is double clicked
33306 * @param {Node} this This node
33307 * @param {Roo.EventObject} e The event object
33311 * @event contextmenu
33312 * Fires when this node is right clicked
33313 * @param {Node} this This node
33314 * @param {Roo.EventObject} e The event object
33316 "contextmenu":true,
33318 * @event beforechildrenrendered
33319 * Fires right before the child nodes for this node are rendered
33320 * @param {Node} this This node
33322 "beforechildrenrendered":true
33325 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33328 * Read-only. The UI for this node
33331 this.ui = new uiClass(this);
33333 // finally support items[]
33334 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33339 Roo.each(this.attributes.items, function(c) {
33340 this.appendChild(Roo.factory(c,Roo.Tree));
33342 delete this.attributes.items;
33347 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33348 preventHScroll: true,
33350 * Returns true if this node is expanded
33351 * @return {Boolean}
33353 isExpanded : function(){
33354 return this.expanded;
33358 * Returns the UI object for this node
33359 * @return {TreeNodeUI}
33361 getUI : function(){
33365 // private override
33366 setFirstChild : function(node){
33367 var of = this.firstChild;
33368 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33369 if(this.childrenRendered && of && node != of){
33370 of.renderIndent(true, true);
33373 this.renderIndent(true, true);
33377 // private override
33378 setLastChild : function(node){
33379 var ol = this.lastChild;
33380 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33381 if(this.childrenRendered && ol && node != ol){
33382 ol.renderIndent(true, true);
33385 this.renderIndent(true, true);
33389 // these methods are overridden to provide lazy rendering support
33390 // private override
33391 appendChild : function()
33393 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33394 if(node && this.childrenRendered){
33397 this.ui.updateExpandIcon();
33401 // private override
33402 removeChild : function(node){
33403 this.ownerTree.getSelectionModel().unselect(node);
33404 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33405 // if it's been rendered remove dom node
33406 if(this.childrenRendered){
33409 if(this.childNodes.length < 1){
33410 this.collapse(false, false);
33412 this.ui.updateExpandIcon();
33414 if(!this.firstChild) {
33415 this.childrenRendered = false;
33420 // private override
33421 insertBefore : function(node, refNode){
33422 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33423 if(newNode && refNode && this.childrenRendered){
33426 this.ui.updateExpandIcon();
33431 * Sets the text for this node
33432 * @param {String} text
33434 setText : function(text){
33435 var oldText = this.text;
33437 this.attributes.text = text;
33438 if(this.rendered){ // event without subscribing
33439 this.ui.onTextChange(this, text, oldText);
33441 this.fireEvent("textchange", this, text, oldText);
33445 * Triggers selection of this node
33447 select : function(){
33448 this.getOwnerTree().getSelectionModel().select(this);
33452 * Triggers deselection of this node
33454 unselect : function(){
33455 this.getOwnerTree().getSelectionModel().unselect(this);
33459 * Returns true if this node is selected
33460 * @return {Boolean}
33462 isSelected : function(){
33463 return this.getOwnerTree().getSelectionModel().isSelected(this);
33467 * Expand this node.
33468 * @param {Boolean} deep (optional) True to expand all children as well
33469 * @param {Boolean} anim (optional) false to cancel the default animation
33470 * @param {Function} callback (optional) A callback to be called when
33471 * expanding this node completes (does not wait for deep expand to complete).
33472 * Called with 1 parameter, this node.
33474 expand : function(deep, anim, callback){
33475 if(!this.expanded){
33476 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33479 if(!this.childrenRendered){
33480 this.renderChildren();
33482 this.expanded = true;
33483 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33484 this.ui.animExpand(function(){
33485 this.fireEvent("expand", this);
33486 if(typeof callback == "function"){
33490 this.expandChildNodes(true);
33492 }.createDelegate(this));
33496 this.fireEvent("expand", this);
33497 if(typeof callback == "function"){
33502 if(typeof callback == "function"){
33507 this.expandChildNodes(true);
33511 isHiddenRoot : function(){
33512 return this.isRoot && !this.getOwnerTree().rootVisible;
33516 * Collapse this node.
33517 * @param {Boolean} deep (optional) True to collapse all children as well
33518 * @param {Boolean} anim (optional) false to cancel the default animation
33520 collapse : function(deep, anim){
33521 if(this.expanded && !this.isHiddenRoot()){
33522 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33525 this.expanded = false;
33526 if((this.getOwnerTree().animate && anim !== false) || anim){
33527 this.ui.animCollapse(function(){
33528 this.fireEvent("collapse", this);
33530 this.collapseChildNodes(true);
33532 }.createDelegate(this));
33535 this.ui.collapse();
33536 this.fireEvent("collapse", this);
33540 var cs = this.childNodes;
33541 for(var i = 0, len = cs.length; i < len; i++) {
33542 cs[i].collapse(true, false);
33548 delayedExpand : function(delay){
33549 if(!this.expandProcId){
33550 this.expandProcId = this.expand.defer(delay, this);
33555 cancelExpand : function(){
33556 if(this.expandProcId){
33557 clearTimeout(this.expandProcId);
33559 this.expandProcId = false;
33563 * Toggles expanded/collapsed state of the node
33565 toggle : function(){
33574 * Ensures all parent nodes are expanded
33576 ensureVisible : function(callback){
33577 var tree = this.getOwnerTree();
33578 tree.expandPath(this.parentNode.getPath(), false, function(){
33579 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33580 Roo.callback(callback);
33581 }.createDelegate(this));
33585 * Expand all child nodes
33586 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33588 expandChildNodes : function(deep){
33589 var cs = this.childNodes;
33590 for(var i = 0, len = cs.length; i < len; i++) {
33591 cs[i].expand(deep);
33596 * Collapse all child nodes
33597 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33599 collapseChildNodes : function(deep){
33600 var cs = this.childNodes;
33601 for(var i = 0, len = cs.length; i < len; i++) {
33602 cs[i].collapse(deep);
33607 * Disables this node
33609 disable : function(){
33610 this.disabled = true;
33612 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33613 this.ui.onDisableChange(this, true);
33615 this.fireEvent("disabledchange", this, true);
33619 * Enables this node
33621 enable : function(){
33622 this.disabled = false;
33623 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33624 this.ui.onDisableChange(this, false);
33626 this.fireEvent("disabledchange", this, false);
33630 renderChildren : function(suppressEvent){
33631 if(suppressEvent !== false){
33632 this.fireEvent("beforechildrenrendered", this);
33634 var cs = this.childNodes;
33635 for(var i = 0, len = cs.length; i < len; i++){
33636 cs[i].render(true);
33638 this.childrenRendered = true;
33642 sort : function(fn, scope){
33643 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33644 if(this.childrenRendered){
33645 var cs = this.childNodes;
33646 for(var i = 0, len = cs.length; i < len; i++){
33647 cs[i].render(true);
33653 render : function(bulkRender){
33654 this.ui.render(bulkRender);
33655 if(!this.rendered){
33656 this.rendered = true;
33658 this.expanded = false;
33659 this.expand(false, false);
33665 renderIndent : function(deep, refresh){
33667 this.ui.childIndent = null;
33669 this.ui.renderIndent();
33670 if(deep === true && this.childrenRendered){
33671 var cs = this.childNodes;
33672 for(var i = 0, len = cs.length; i < len; i++){
33673 cs[i].renderIndent(true, refresh);
33679 * Ext JS Library 1.1.1
33680 * Copyright(c) 2006-2007, Ext JS, LLC.
33682 * Originally Released Under LGPL - original licence link has changed is not relivant.
33685 * <script type="text/javascript">
33689 * @class Roo.tree.AsyncTreeNode
33690 * @extends Roo.tree.TreeNode
33691 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33693 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33695 Roo.tree.AsyncTreeNode = function(config){
33696 this.loaded = false;
33697 this.loading = false;
33698 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33700 * @event beforeload
33701 * Fires before this node is loaded, return false to cancel
33702 * @param {Node} this This node
33704 this.addEvents({'beforeload':true, 'load': true});
33707 * Fires when this node is loaded
33708 * @param {Node} this This node
33711 * The loader used by this node (defaults to using the tree's defined loader)
33716 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33717 expand : function(deep, anim, callback){
33718 if(this.loading){ // if an async load is already running, waiting til it's done
33720 var f = function(){
33721 if(!this.loading){ // done loading
33722 clearInterval(timer);
33723 this.expand(deep, anim, callback);
33725 }.createDelegate(this);
33726 timer = setInterval(f, 200);
33730 if(this.fireEvent("beforeload", this) === false){
33733 this.loading = true;
33734 this.ui.beforeLoad(this);
33735 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33737 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33741 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33745 * Returns true if this node is currently loading
33746 * @return {Boolean}
33748 isLoading : function(){
33749 return this.loading;
33752 loadComplete : function(deep, anim, callback){
33753 this.loading = false;
33754 this.loaded = true;
33755 this.ui.afterLoad(this);
33756 this.fireEvent("load", this);
33757 this.expand(deep, anim, callback);
33761 * Returns true if this node has been loaded
33762 * @return {Boolean}
33764 isLoaded : function(){
33765 return this.loaded;
33768 hasChildNodes : function(){
33769 if(!this.isLeaf() && !this.loaded){
33772 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33777 * Trigger a reload for this node
33778 * @param {Function} callback
33780 reload : function(callback){
33781 this.collapse(false, false);
33782 while(this.firstChild){
33783 this.removeChild(this.firstChild);
33785 this.childrenRendered = false;
33786 this.loaded = false;
33787 if(this.isHiddenRoot()){
33788 this.expanded = false;
33790 this.expand(false, false, callback);
33794 * Ext JS Library 1.1.1
33795 * Copyright(c) 2006-2007, Ext JS, LLC.
33797 * Originally Released Under LGPL - original licence link has changed is not relivant.
33800 * <script type="text/javascript">
33804 * @class Roo.tree.TreeNodeUI
33806 * @param {Object} node The node to render
33807 * The TreeNode UI implementation is separate from the
33808 * tree implementation. Unless you are customizing the tree UI,
33809 * you should never have to use this directly.
33811 Roo.tree.TreeNodeUI = function(node){
33813 this.rendered = false;
33814 this.animating = false;
33815 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33818 Roo.tree.TreeNodeUI.prototype = {
33819 removeChild : function(node){
33821 this.ctNode.removeChild(node.ui.getEl());
33825 beforeLoad : function(){
33826 this.addClass("x-tree-node-loading");
33829 afterLoad : function(){
33830 this.removeClass("x-tree-node-loading");
33833 onTextChange : function(node, text, oldText){
33835 this.textNode.innerHTML = text;
33839 onDisableChange : function(node, state){
33840 this.disabled = state;
33842 this.addClass("x-tree-node-disabled");
33844 this.removeClass("x-tree-node-disabled");
33848 onSelectedChange : function(state){
33851 this.addClass("x-tree-selected");
33854 this.removeClass("x-tree-selected");
33858 onMove : function(tree, node, oldParent, newParent, index, refNode){
33859 this.childIndent = null;
33861 var targetNode = newParent.ui.getContainer();
33862 if(!targetNode){//target not rendered
33863 this.holder = document.createElement("div");
33864 this.holder.appendChild(this.wrap);
33867 var insertBefore = refNode ? refNode.ui.getEl() : null;
33869 targetNode.insertBefore(this.wrap, insertBefore);
33871 targetNode.appendChild(this.wrap);
33873 this.node.renderIndent(true);
33877 addClass : function(cls){
33879 Roo.fly(this.elNode).addClass(cls);
33883 removeClass : function(cls){
33885 Roo.fly(this.elNode).removeClass(cls);
33889 remove : function(){
33891 this.holder = document.createElement("div");
33892 this.holder.appendChild(this.wrap);
33896 fireEvent : function(){
33897 return this.node.fireEvent.apply(this.node, arguments);
33900 initEvents : function(){
33901 this.node.on("move", this.onMove, this);
33902 var E = Roo.EventManager;
33903 var a = this.anchor;
33905 var el = Roo.fly(a, '_treeui');
33907 if(Roo.isOpera){ // opera render bug ignores the CSS
33908 el.setStyle("text-decoration", "none");
33911 el.on("click", this.onClick, this);
33912 el.on("dblclick", this.onDblClick, this);
33915 Roo.EventManager.on(this.checkbox,
33916 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33919 el.on("contextmenu", this.onContextMenu, this);
33921 var icon = Roo.fly(this.iconNode);
33922 icon.on("click", this.onClick, this);
33923 icon.on("dblclick", this.onDblClick, this);
33924 icon.on("contextmenu", this.onContextMenu, this);
33925 E.on(this.ecNode, "click", this.ecClick, this, true);
33927 if(this.node.disabled){
33928 this.addClass("x-tree-node-disabled");
33930 if(this.node.hidden){
33931 this.addClass("x-tree-node-disabled");
33933 var ot = this.node.getOwnerTree();
33934 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33935 if(dd && (!this.node.isRoot || ot.rootVisible)){
33936 Roo.dd.Registry.register(this.elNode, {
33938 handles: this.getDDHandles(),
33944 getDDHandles : function(){
33945 return [this.iconNode, this.textNode];
33950 this.wrap.style.display = "none";
33956 this.wrap.style.display = "";
33960 onContextMenu : function(e){
33961 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33962 e.preventDefault();
33964 this.fireEvent("contextmenu", this.node, e);
33968 onClick : function(e){
33973 if(this.fireEvent("beforeclick", this.node, e) !== false){
33974 if(!this.disabled && this.node.attributes.href){
33975 this.fireEvent("click", this.node, e);
33978 e.preventDefault();
33983 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33984 this.node.toggle();
33987 this.fireEvent("click", this.node, e);
33993 onDblClick : function(e){
33994 e.preventDefault();
33999 this.toggleCheck();
34001 if(!this.animating && this.node.hasChildNodes()){
34002 this.node.toggle();
34004 this.fireEvent("dblclick", this.node, e);
34007 onCheckChange : function(){
34008 var checked = this.checkbox.checked;
34009 this.node.attributes.checked = checked;
34010 this.fireEvent('checkchange', this.node, checked);
34013 ecClick : function(e){
34014 if(!this.animating && this.node.hasChildNodes()){
34015 this.node.toggle();
34019 startDrop : function(){
34020 this.dropping = true;
34023 // delayed drop so the click event doesn't get fired on a drop
34024 endDrop : function(){
34025 setTimeout(function(){
34026 this.dropping = false;
34027 }.createDelegate(this), 50);
34030 expand : function(){
34031 this.updateExpandIcon();
34032 this.ctNode.style.display = "";
34035 focus : function(){
34036 if(!this.node.preventHScroll){
34037 try{this.anchor.focus();
34039 }else if(!Roo.isIE){
34041 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
34042 var l = noscroll.scrollLeft;
34043 this.anchor.focus();
34044 noscroll.scrollLeft = l;
34049 toggleCheck : function(value){
34050 var cb = this.checkbox;
34052 cb.checked = (value === undefined ? !cb.checked : value);
34058 this.anchor.blur();
34062 animExpand : function(callback){
34063 var ct = Roo.get(this.ctNode);
34065 if(!this.node.hasChildNodes()){
34066 this.updateExpandIcon();
34067 this.ctNode.style.display = "";
34068 Roo.callback(callback);
34071 this.animating = true;
34072 this.updateExpandIcon();
34075 callback : function(){
34076 this.animating = false;
34077 Roo.callback(callback);
34080 duration: this.node.ownerTree.duration || .25
34084 highlight : function(){
34085 var tree = this.node.getOwnerTree();
34086 Roo.fly(this.wrap).highlight(
34087 tree.hlColor || "C3DAF9",
34088 {endColor: tree.hlBaseColor}
34092 collapse : function(){
34093 this.updateExpandIcon();
34094 this.ctNode.style.display = "none";
34097 animCollapse : function(callback){
34098 var ct = Roo.get(this.ctNode);
34099 ct.enableDisplayMode('block');
34102 this.animating = true;
34103 this.updateExpandIcon();
34106 callback : function(){
34107 this.animating = false;
34108 Roo.callback(callback);
34111 duration: this.node.ownerTree.duration || .25
34115 getContainer : function(){
34116 return this.ctNode;
34119 getEl : function(){
34123 appendDDGhost : function(ghostNode){
34124 ghostNode.appendChild(this.elNode.cloneNode(true));
34127 getDDRepairXY : function(){
34128 return Roo.lib.Dom.getXY(this.iconNode);
34131 onRender : function(){
34135 render : function(bulkRender){
34136 var n = this.node, a = n.attributes;
34137 var targetNode = n.parentNode ?
34138 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
34140 if(!this.rendered){
34141 this.rendered = true;
34143 this.renderElements(n, a, targetNode, bulkRender);
34146 if(this.textNode.setAttributeNS){
34147 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
34149 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
34152 this.textNode.setAttribute("ext:qtip", a.qtip);
34154 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
34157 }else if(a.qtipCfg){
34158 a.qtipCfg.target = Roo.id(this.textNode);
34159 Roo.QuickTips.register(a.qtipCfg);
34162 if(!this.node.expanded){
34163 this.updateExpandIcon();
34166 if(bulkRender === true) {
34167 targetNode.appendChild(this.wrap);
34172 renderElements : function(n, a, targetNode, bulkRender)
34174 // add some indent caching, this helps performance when rendering a large tree
34175 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34176 var t = n.getOwnerTree();
34177 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
34178 if (typeof(n.attributes.html) != 'undefined') {
34179 txt = n.attributes.html;
34181 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
34182 var cb = typeof a.checked == 'boolean';
34183 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34184 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
34185 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
34186 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
34187 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
34188 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
34189 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
34190 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
34191 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
34192 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34195 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34196 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34197 n.nextSibling.ui.getEl(), buf.join(""));
34199 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34202 this.elNode = this.wrap.childNodes[0];
34203 this.ctNode = this.wrap.childNodes[1];
34204 var cs = this.elNode.childNodes;
34205 this.indentNode = cs[0];
34206 this.ecNode = cs[1];
34207 this.iconNode = cs[2];
34210 this.checkbox = cs[3];
34213 this.anchor = cs[index];
34214 this.textNode = cs[index].firstChild;
34217 getAnchor : function(){
34218 return this.anchor;
34221 getTextEl : function(){
34222 return this.textNode;
34225 getIconEl : function(){
34226 return this.iconNode;
34229 isChecked : function(){
34230 return this.checkbox ? this.checkbox.checked : false;
34233 updateExpandIcon : function(){
34235 var n = this.node, c1, c2;
34236 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34237 var hasChild = n.hasChildNodes();
34241 c1 = "x-tree-node-collapsed";
34242 c2 = "x-tree-node-expanded";
34245 c1 = "x-tree-node-expanded";
34246 c2 = "x-tree-node-collapsed";
34249 this.removeClass("x-tree-node-leaf");
34250 this.wasLeaf = false;
34252 if(this.c1 != c1 || this.c2 != c2){
34253 Roo.fly(this.elNode).replaceClass(c1, c2);
34254 this.c1 = c1; this.c2 = c2;
34257 // this changes non-leafs into leafs if they have no children.
34258 // it's not very rational behaviour..
34260 if(!this.wasLeaf && this.node.leaf){
34261 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34264 this.wasLeaf = true;
34267 var ecc = "x-tree-ec-icon "+cls;
34268 if(this.ecc != ecc){
34269 this.ecNode.className = ecc;
34275 getChildIndent : function(){
34276 if(!this.childIndent){
34280 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34282 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34284 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34289 this.childIndent = buf.join("");
34291 return this.childIndent;
34294 renderIndent : function(){
34297 var p = this.node.parentNode;
34299 indent = p.ui.getChildIndent();
34301 if(this.indentMarkup != indent){ // don't rerender if not required
34302 this.indentNode.innerHTML = indent;
34303 this.indentMarkup = indent;
34305 this.updateExpandIcon();
34310 Roo.tree.RootTreeNodeUI = function(){
34311 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34313 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34314 render : function(){
34315 if(!this.rendered){
34316 var targetNode = this.node.ownerTree.innerCt.dom;
34317 this.node.expanded = true;
34318 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34319 this.wrap = this.ctNode = targetNode.firstChild;
34322 collapse : function(){
34324 expand : function(){
34328 * Ext JS Library 1.1.1
34329 * Copyright(c) 2006-2007, Ext JS, LLC.
34331 * Originally Released Under LGPL - original licence link has changed is not relivant.
34334 * <script type="text/javascript">
34337 * @class Roo.tree.TreeLoader
34338 * @extends Roo.util.Observable
34339 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34340 * nodes from a specified URL. The response must be a javascript Array definition
34341 * who's elements are node definition objects. eg:
34346 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34347 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34354 * The old style respose with just an array is still supported, but not recommended.
34357 * A server request is sent, and child nodes are loaded only when a node is expanded.
34358 * The loading node's id is passed to the server under the parameter name "node" to
34359 * enable the server to produce the correct child nodes.
34361 * To pass extra parameters, an event handler may be attached to the "beforeload"
34362 * event, and the parameters specified in the TreeLoader's baseParams property:
34364 myTreeLoader.on("beforeload", function(treeLoader, node) {
34365 this.baseParams.category = node.attributes.category;
34368 * This would pass an HTTP parameter called "category" to the server containing
34369 * the value of the Node's "category" attribute.
34371 * Creates a new Treeloader.
34372 * @param {Object} config A config object containing config properties.
34374 Roo.tree.TreeLoader = function(config){
34375 this.baseParams = {};
34376 this.requestMethod = "POST";
34377 Roo.apply(this, config);
34382 * @event beforeload
34383 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34384 * @param {Object} This TreeLoader object.
34385 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34386 * @param {Object} callback The callback function specified in the {@link #load} call.
34391 * Fires when the node has been successfuly loaded.
34392 * @param {Object} This TreeLoader object.
34393 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34394 * @param {Object} response The response object containing the data from the server.
34398 * @event loadexception
34399 * Fires if the network request failed.
34400 * @param {Object} This TreeLoader object.
34401 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34402 * @param {Object} response The response object containing the data from the server.
34404 loadexception : true,
34407 * Fires before a node is created, enabling you to return custom Node types
34408 * @param {Object} This TreeLoader object.
34409 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34414 Roo.tree.TreeLoader.superclass.constructor.call(this);
34417 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34419 * @cfg {String} dataUrl The URL from which to request a Json string which
34420 * specifies an array of node definition object representing the child nodes
34424 * @cfg {String} requestMethod either GET or POST
34425 * defaults to POST (due to BC)
34429 * @cfg {Object} baseParams (optional) An object containing properties which
34430 * specify HTTP parameters to be passed to each request for child nodes.
34433 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34434 * created by this loader. If the attributes sent by the server have an attribute in this object,
34435 * they take priority.
34438 * @cfg {Object} uiProviders (optional) An object containing properties which
34440 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34441 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34442 * <i>uiProvider</i> attribute of a returned child node is a string rather
34443 * than a reference to a TreeNodeUI implementation, this that string value
34444 * is used as a property name in the uiProviders object. You can define the provider named
34445 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34450 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34451 * child nodes before loading.
34453 clearOnLoad : true,
34456 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34457 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34458 * Grid query { data : [ .....] }
34463 * @cfg {String} queryParam (optional)
34464 * Name of the query as it will be passed on the querystring (defaults to 'node')
34465 * eg. the request will be ?node=[id]
34472 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34473 * This is called automatically when a node is expanded, but may be used to reload
34474 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34475 * @param {Roo.tree.TreeNode} node
34476 * @param {Function} callback
34478 load : function(node, callback){
34479 if(this.clearOnLoad){
34480 while(node.firstChild){
34481 node.removeChild(node.firstChild);
34484 if(node.attributes.children){ // preloaded json children
34485 var cs = node.attributes.children;
34486 for(var i = 0, len = cs.length; i < len; i++){
34487 node.appendChild(this.createNode(cs[i]));
34489 if(typeof callback == "function"){
34492 }else if(this.dataUrl){
34493 this.requestData(node, callback);
34497 getParams: function(node){
34498 var buf = [], bp = this.baseParams;
34499 for(var key in bp){
34500 if(typeof bp[key] != "function"){
34501 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34504 var n = this.queryParam === false ? 'node' : this.queryParam;
34505 buf.push(n + "=", encodeURIComponent(node.id));
34506 return buf.join("");
34509 requestData : function(node, callback){
34510 if(this.fireEvent("beforeload", this, node, callback) !== false){
34511 this.transId = Roo.Ajax.request({
34512 method:this.requestMethod,
34513 url: this.dataUrl||this.url,
34514 success: this.handleResponse,
34515 failure: this.handleFailure,
34517 argument: {callback: callback, node: node},
34518 params: this.getParams(node)
34521 // if the load is cancelled, make sure we notify
34522 // the node that we are done
34523 if(typeof callback == "function"){
34529 isLoading : function(){
34530 return this.transId ? true : false;
34533 abort : function(){
34534 if(this.isLoading()){
34535 Roo.Ajax.abort(this.transId);
34540 createNode : function(attr)
34542 // apply baseAttrs, nice idea Corey!
34543 if(this.baseAttrs){
34544 Roo.applyIf(attr, this.baseAttrs);
34546 if(this.applyLoader !== false){
34547 attr.loader = this;
34549 // uiProvider = depreciated..
34551 if(typeof(attr.uiProvider) == 'string'){
34552 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34553 /** eval:var:attr */ eval(attr.uiProvider);
34555 if(typeof(this.uiProviders['default']) != 'undefined') {
34556 attr.uiProvider = this.uiProviders['default'];
34559 this.fireEvent('create', this, attr);
34561 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34563 new Roo.tree.TreeNode(attr) :
34564 new Roo.tree.AsyncTreeNode(attr));
34567 processResponse : function(response, node, callback)
34569 var json = response.responseText;
34572 var o = Roo.decode(json);
34574 if (this.root === false && typeof(o.success) != undefined) {
34575 this.root = 'data'; // the default behaviour for list like data..
34578 if (this.root !== false && !o.success) {
34579 // it's a failure condition.
34580 var a = response.argument;
34581 this.fireEvent("loadexception", this, a.node, response);
34582 Roo.log("Load failed - should have a handler really");
34588 if (this.root !== false) {
34592 for(var i = 0, len = o.length; i < len; i++){
34593 var n = this.createNode(o[i]);
34595 node.appendChild(n);
34598 if(typeof callback == "function"){
34599 callback(this, node);
34602 this.handleFailure(response);
34606 handleResponse : function(response){
34607 this.transId = false;
34608 var a = response.argument;
34609 this.processResponse(response, a.node, a.callback);
34610 this.fireEvent("load", this, a.node, response);
34613 handleFailure : function(response)
34615 // should handle failure better..
34616 this.transId = false;
34617 var a = response.argument;
34618 this.fireEvent("loadexception", this, a.node, response);
34619 if(typeof a.callback == "function"){
34620 a.callback(this, a.node);
34625 * Ext JS Library 1.1.1
34626 * Copyright(c) 2006-2007, Ext JS, LLC.
34628 * Originally Released Under LGPL - original licence link has changed is not relivant.
34631 * <script type="text/javascript">
34635 * @class Roo.tree.TreeFilter
34636 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34637 * @param {TreePanel} tree
34638 * @param {Object} config (optional)
34640 Roo.tree.TreeFilter = function(tree, config){
34642 this.filtered = {};
34643 Roo.apply(this, config);
34646 Roo.tree.TreeFilter.prototype = {
34653 * Filter the data by a specific attribute.
34654 * @param {String/RegExp} value Either string that the attribute value
34655 * should start with or a RegExp to test against the attribute
34656 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34657 * @param {TreeNode} startNode (optional) The node to start the filter at.
34659 filter : function(value, attr, startNode){
34660 attr = attr || "text";
34662 if(typeof value == "string"){
34663 var vlen = value.length;
34664 // auto clear empty filter
34665 if(vlen == 0 && this.clearBlank){
34669 value = value.toLowerCase();
34671 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34673 }else if(value.exec){ // regex?
34675 return value.test(n.attributes[attr]);
34678 throw 'Illegal filter type, must be string or regex';
34680 this.filterBy(f, null, startNode);
34684 * Filter by a function. The passed function will be called with each
34685 * node in the tree (or from the startNode). If the function returns true, the node is kept
34686 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34687 * @param {Function} fn The filter function
34688 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34690 filterBy : function(fn, scope, startNode){
34691 startNode = startNode || this.tree.root;
34692 if(this.autoClear){
34695 var af = this.filtered, rv = this.reverse;
34696 var f = function(n){
34697 if(n == startNode){
34703 var m = fn.call(scope || n, n);
34711 startNode.cascade(f);
34714 if(typeof id != "function"){
34716 if(n && n.parentNode){
34717 n.parentNode.removeChild(n);
34725 * Clears the current filter. Note: with the "remove" option
34726 * set a filter cannot be cleared.
34728 clear : function(){
34730 var af = this.filtered;
34732 if(typeof id != "function"){
34739 this.filtered = {};
34744 * Ext JS Library 1.1.1
34745 * Copyright(c) 2006-2007, Ext JS, LLC.
34747 * Originally Released Under LGPL - original licence link has changed is not relivant.
34750 * <script type="text/javascript">
34755 * @class Roo.tree.TreeSorter
34756 * Provides sorting of nodes in a TreePanel
34758 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34759 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34760 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34761 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34762 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34763 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34765 * @param {TreePanel} tree
34766 * @param {Object} config
34768 Roo.tree.TreeSorter = function(tree, config){
34769 Roo.apply(this, config);
34770 tree.on("beforechildrenrendered", this.doSort, this);
34771 tree.on("append", this.updateSort, this);
34772 tree.on("insert", this.updateSort, this);
34774 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34775 var p = this.property || "text";
34776 var sortType = this.sortType;
34777 var fs = this.folderSort;
34778 var cs = this.caseSensitive === true;
34779 var leafAttr = this.leafAttr || 'leaf';
34781 this.sortFn = function(n1, n2){
34783 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34786 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34790 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34791 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34793 return dsc ? +1 : -1;
34795 return dsc ? -1 : +1;
34802 Roo.tree.TreeSorter.prototype = {
34803 doSort : function(node){
34804 node.sort(this.sortFn);
34807 compareNodes : function(n1, n2){
34808 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34811 updateSort : function(tree, node){
34812 if(node.childrenRendered){
34813 this.doSort.defer(1, this, [node]);
34818 * Ext JS Library 1.1.1
34819 * Copyright(c) 2006-2007, Ext JS, LLC.
34821 * Originally Released Under LGPL - original licence link has changed is not relivant.
34824 * <script type="text/javascript">
34827 if(Roo.dd.DropZone){
34829 Roo.tree.TreeDropZone = function(tree, config){
34830 this.allowParentInsert = false;
34831 this.allowContainerDrop = false;
34832 this.appendOnly = false;
34833 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34835 this.lastInsertClass = "x-tree-no-status";
34836 this.dragOverData = {};
34839 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34840 ddGroup : "TreeDD",
34843 expandDelay : 1000,
34845 expandNode : function(node){
34846 if(node.hasChildNodes() && !node.isExpanded()){
34847 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34851 queueExpand : function(node){
34852 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34855 cancelExpand : function(){
34856 if(this.expandProcId){
34857 clearTimeout(this.expandProcId);
34858 this.expandProcId = false;
34862 isValidDropPoint : function(n, pt, dd, e, data){
34863 if(!n || !data){ return false; }
34864 var targetNode = n.node;
34865 var dropNode = data.node;
34866 // default drop rules
34867 if(!(targetNode && targetNode.isTarget && pt)){
34870 if(pt == "append" && targetNode.allowChildren === false){
34873 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34876 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34879 // reuse the object
34880 var overEvent = this.dragOverData;
34881 overEvent.tree = this.tree;
34882 overEvent.target = targetNode;
34883 overEvent.data = data;
34884 overEvent.point = pt;
34885 overEvent.source = dd;
34886 overEvent.rawEvent = e;
34887 overEvent.dropNode = dropNode;
34888 overEvent.cancel = false;
34889 var result = this.tree.fireEvent("nodedragover", overEvent);
34890 return overEvent.cancel === false && result !== false;
34893 getDropPoint : function(e, n, dd)
34897 return tn.allowChildren !== false ? "append" : false; // always append for root
34899 var dragEl = n.ddel;
34900 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34901 var y = Roo.lib.Event.getPageY(e);
34902 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34904 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34905 var noAppend = tn.allowChildren === false;
34906 if(this.appendOnly || tn.parentNode.allowChildren === false){
34907 return noAppend ? false : "append";
34909 var noBelow = false;
34910 if(!this.allowParentInsert){
34911 noBelow = tn.hasChildNodes() && tn.isExpanded();
34913 var q = (b - t) / (noAppend ? 2 : 3);
34914 if(y >= t && y < (t + q)){
34916 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34923 onNodeEnter : function(n, dd, e, data)
34925 this.cancelExpand();
34928 onNodeOver : function(n, dd, e, data)
34931 var pt = this.getDropPoint(e, n, dd);
34934 // auto node expand check
34935 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34936 this.queueExpand(node);
34937 }else if(pt != "append"){
34938 this.cancelExpand();
34941 // set the insert point style on the target node
34942 var returnCls = this.dropNotAllowed;
34943 if(this.isValidDropPoint(n, pt, dd, e, data)){
34948 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34949 cls = "x-tree-drag-insert-above";
34950 }else if(pt == "below"){
34951 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34952 cls = "x-tree-drag-insert-below";
34954 returnCls = "x-tree-drop-ok-append";
34955 cls = "x-tree-drag-append";
34957 if(this.lastInsertClass != cls){
34958 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34959 this.lastInsertClass = cls;
34966 onNodeOut : function(n, dd, e, data){
34968 this.cancelExpand();
34969 this.removeDropIndicators(n);
34972 onNodeDrop : function(n, dd, e, data){
34973 var point = this.getDropPoint(e, n, dd);
34974 var targetNode = n.node;
34975 targetNode.ui.startDrop();
34976 if(!this.isValidDropPoint(n, point, dd, e, data)){
34977 targetNode.ui.endDrop();
34980 // first try to find the drop node
34981 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34984 target: targetNode,
34989 dropNode: dropNode,
34992 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34993 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34994 targetNode.ui.endDrop();
34997 // allow target changing
34998 targetNode = dropEvent.target;
34999 if(point == "append" && !targetNode.isExpanded()){
35000 targetNode.expand(false, null, function(){
35001 this.completeDrop(dropEvent);
35002 }.createDelegate(this));
35004 this.completeDrop(dropEvent);
35009 completeDrop : function(de){
35010 var ns = de.dropNode, p = de.point, t = de.target;
35011 if(!(ns instanceof Array)){
35015 for(var i = 0, len = ns.length; i < len; i++){
35018 t.parentNode.insertBefore(n, t);
35019 }else if(p == "below"){
35020 t.parentNode.insertBefore(n, t.nextSibling);
35026 if(this.tree.hlDrop){
35030 this.tree.fireEvent("nodedrop", de);
35033 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
35034 if(this.tree.hlDrop){
35035 dropNode.ui.focus();
35036 dropNode.ui.highlight();
35038 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
35041 getTree : function(){
35045 removeDropIndicators : function(n){
35048 Roo.fly(el).removeClass([
35049 "x-tree-drag-insert-above",
35050 "x-tree-drag-insert-below",
35051 "x-tree-drag-append"]);
35052 this.lastInsertClass = "_noclass";
35056 beforeDragDrop : function(target, e, id){
35057 this.cancelExpand();
35061 afterRepair : function(data){
35062 if(data && Roo.enableFx){
35063 data.node.ui.highlight();
35073 * Ext JS Library 1.1.1
35074 * Copyright(c) 2006-2007, Ext JS, LLC.
35076 * Originally Released Under LGPL - original licence link has changed is not relivant.
35079 * <script type="text/javascript">
35083 if(Roo.dd.DragZone){
35084 Roo.tree.TreeDragZone = function(tree, config){
35085 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
35089 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
35090 ddGroup : "TreeDD",
35092 onBeforeDrag : function(data, e){
35094 return n && n.draggable && !n.disabled;
35098 onInitDrag : function(e){
35099 var data = this.dragData;
35100 this.tree.getSelectionModel().select(data.node);
35101 this.proxy.update("");
35102 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
35103 this.tree.fireEvent("startdrag", this.tree, data.node, e);
35106 getRepairXY : function(e, data){
35107 return data.node.ui.getDDRepairXY();
35110 onEndDrag : function(data, e){
35111 this.tree.fireEvent("enddrag", this.tree, data.node, e);
35116 onValidDrop : function(dd, e, id){
35117 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
35121 beforeInvalidDrop : function(e, id){
35122 // this scrolls the original position back into view
35123 var sm = this.tree.getSelectionModel();
35124 sm.clearSelections();
35125 sm.select(this.dragData.node);
35130 * Ext JS Library 1.1.1
35131 * Copyright(c) 2006-2007, Ext JS, LLC.
35133 * Originally Released Under LGPL - original licence link has changed is not relivant.
35136 * <script type="text/javascript">
35139 * @class Roo.tree.TreeEditor
35140 * @extends Roo.Editor
35141 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
35142 * as the editor field.
35144 * @param {Object} config (used to be the tree panel.)
35145 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
35147 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
35148 * @cfg {Roo.form.TextField|Object} field The field configuration
35152 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
35155 if (oldconfig) { // old style..
35156 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
35159 tree = config.tree;
35160 config.field = config.field || {};
35161 config.field.xtype = 'TextField';
35162 field = Roo.factory(config.field, Roo.form);
35164 config = config || {};
35169 * @event beforenodeedit
35170 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
35171 * false from the handler of this event.
35172 * @param {Editor} this
35173 * @param {Roo.tree.Node} node
35175 "beforenodeedit" : true
35179 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
35183 tree.on('beforeclick', this.beforeNodeClick, this);
35184 tree.getTreeEl().on('mousedown', this.hide, this);
35185 this.on('complete', this.updateNode, this);
35186 this.on('beforestartedit', this.fitToTree, this);
35187 this.on('startedit', this.bindScroll, this, {delay:10});
35188 this.on('specialkey', this.onSpecialKey, this);
35191 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
35193 * @cfg {String} alignment
35194 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35200 * @cfg {Boolean} hideEl
35201 * True to hide the bound element while the editor is displayed (defaults to false)
35205 * @cfg {String} cls
35206 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35208 cls: "x-small-editor x-tree-editor",
35210 * @cfg {Boolean} shim
35211 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35217 * @cfg {Number} maxWidth
35218 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35219 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35220 * scroll and client offsets into account prior to each edit.
35227 fitToTree : function(ed, el){
35228 var td = this.tree.getTreeEl().dom, nd = el.dom;
35229 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35230 td.scrollLeft = nd.offsetLeft;
35234 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35235 this.setSize(w, '');
35237 return this.fireEvent('beforenodeedit', this, this.editNode);
35242 triggerEdit : function(node){
35243 this.completeEdit();
35244 this.editNode = node;
35245 this.startEdit(node.ui.textNode, node.text);
35249 bindScroll : function(){
35250 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35254 beforeNodeClick : function(node, e){
35255 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35256 this.lastClick = new Date();
35257 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35259 this.triggerEdit(node);
35266 updateNode : function(ed, value){
35267 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35268 this.editNode.setText(value);
35272 onHide : function(){
35273 Roo.tree.TreeEditor.superclass.onHide.call(this);
35275 this.editNode.ui.focus();
35280 onSpecialKey : function(field, e){
35281 var k = e.getKey();
35285 }else if(k == e.ENTER && !e.hasModifier()){
35287 this.completeEdit();
35290 });//<Script type="text/javascript">
35293 * Ext JS Library 1.1.1
35294 * Copyright(c) 2006-2007, Ext JS, LLC.
35296 * Originally Released Under LGPL - original licence link has changed is not relivant.
35299 * <script type="text/javascript">
35303 * Not documented??? - probably should be...
35306 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35307 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35309 renderElements : function(n, a, targetNode, bulkRender){
35310 //consel.log("renderElements?");
35311 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35313 var t = n.getOwnerTree();
35314 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35316 var cols = t.columns;
35317 var bw = t.borderWidth;
35319 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35320 var cb = typeof a.checked == "boolean";
35321 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35322 var colcls = 'x-t-' + tid + '-c0';
35324 '<li class="x-tree-node">',
35327 '<div class="x-tree-node-el ', a.cls,'">',
35329 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35332 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35333 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35334 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35335 (a.icon ? ' x-tree-node-inline-icon' : ''),
35336 (a.iconCls ? ' '+a.iconCls : ''),
35337 '" unselectable="on" />',
35338 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35339 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35341 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35342 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35343 '<span unselectable="on" qtip="' + tx + '">',
35347 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35348 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35350 for(var i = 1, len = cols.length; i < len; i++){
35352 colcls = 'x-t-' + tid + '-c' +i;
35353 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35354 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35355 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35361 '<div class="x-clear"></div></div>',
35362 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35365 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35366 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35367 n.nextSibling.ui.getEl(), buf.join(""));
35369 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35371 var el = this.wrap.firstChild;
35373 this.elNode = el.firstChild;
35374 this.ranchor = el.childNodes[1];
35375 this.ctNode = this.wrap.childNodes[1];
35376 var cs = el.firstChild.childNodes;
35377 this.indentNode = cs[0];
35378 this.ecNode = cs[1];
35379 this.iconNode = cs[2];
35382 this.checkbox = cs[3];
35385 this.anchor = cs[index];
35387 this.textNode = cs[index].firstChild;
35389 //el.on("click", this.onClick, this);
35390 //el.on("dblclick", this.onDblClick, this);
35393 // console.log(this);
35395 initEvents : function(){
35396 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35399 var a = this.ranchor;
35401 var el = Roo.get(a);
35403 if(Roo.isOpera){ // opera render bug ignores the CSS
35404 el.setStyle("text-decoration", "none");
35407 el.on("click", this.onClick, this);
35408 el.on("dblclick", this.onDblClick, this);
35409 el.on("contextmenu", this.onContextMenu, this);
35413 /*onSelectedChange : function(state){
35416 this.addClass("x-tree-selected");
35419 this.removeClass("x-tree-selected");
35422 addClass : function(cls){
35424 Roo.fly(this.elRow).addClass(cls);
35430 removeClass : function(cls){
35432 Roo.fly(this.elRow).removeClass(cls);
35438 });//<Script type="text/javascript">
35442 * Ext JS Library 1.1.1
35443 * Copyright(c) 2006-2007, Ext JS, LLC.
35445 * Originally Released Under LGPL - original licence link has changed is not relivant.
35448 * <script type="text/javascript">
35453 * @class Roo.tree.ColumnTree
35454 * @extends Roo.data.TreePanel
35455 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35456 * @cfg {int} borderWidth compined right/left border allowance
35458 * @param {String/HTMLElement/Element} el The container element
35459 * @param {Object} config
35461 Roo.tree.ColumnTree = function(el, config)
35463 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35467 * Fire this event on a container when it resizes
35468 * @param {int} w Width
35469 * @param {int} h Height
35473 this.on('resize', this.onResize, this);
35476 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35480 borderWidth: Roo.isBorderBox ? 0 : 2,
35483 render : function(){
35484 // add the header.....
35486 Roo.tree.ColumnTree.superclass.render.apply(this);
35488 this.el.addClass('x-column-tree');
35490 this.headers = this.el.createChild(
35491 {cls:'x-tree-headers'},this.innerCt.dom);
35493 var cols = this.columns, c;
35494 var totalWidth = 0;
35496 var len = cols.length;
35497 for(var i = 0; i < len; i++){
35499 totalWidth += c.width;
35500 this.headEls.push(this.headers.createChild({
35501 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35503 cls:'x-tree-hd-text',
35506 style:'width:'+(c.width-this.borderWidth)+'px;'
35509 this.headers.createChild({cls:'x-clear'});
35510 // prevent floats from wrapping when clipped
35511 this.headers.setWidth(totalWidth);
35512 //this.innerCt.setWidth(totalWidth);
35513 this.innerCt.setStyle({ overflow: 'auto' });
35514 this.onResize(this.width, this.height);
35518 onResize : function(w,h)
35523 this.innerCt.setWidth(this.width);
35524 this.innerCt.setHeight(this.height-20);
35527 var cols = this.columns, c;
35528 var totalWidth = 0;
35530 var len = cols.length;
35531 for(var i = 0; i < len; i++){
35533 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35534 // it's the expander..
35535 expEl = this.headEls[i];
35538 totalWidth += c.width;
35542 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35544 this.headers.setWidth(w-20);
35553 * Ext JS Library 1.1.1
35554 * Copyright(c) 2006-2007, Ext JS, LLC.
35556 * Originally Released Under LGPL - original licence link has changed is not relivant.
35559 * <script type="text/javascript">
35563 * @class Roo.menu.Menu
35564 * @extends Roo.util.Observable
35565 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35566 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35568 * Creates a new Menu
35569 * @param {Object} config Configuration options
35571 Roo.menu.Menu = function(config){
35572 Roo.apply(this, config);
35573 this.id = this.id || Roo.id();
35576 * @event beforeshow
35577 * Fires before this menu is displayed
35578 * @param {Roo.menu.Menu} this
35582 * @event beforehide
35583 * Fires before this menu is hidden
35584 * @param {Roo.menu.Menu} this
35589 * Fires after this menu is displayed
35590 * @param {Roo.menu.Menu} this
35595 * Fires after this menu is hidden
35596 * @param {Roo.menu.Menu} this
35601 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35602 * @param {Roo.menu.Menu} this
35603 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35604 * @param {Roo.EventObject} e
35609 * Fires when the mouse is hovering over this menu
35610 * @param {Roo.menu.Menu} this
35611 * @param {Roo.EventObject} e
35612 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35617 * Fires when the mouse exits this menu
35618 * @param {Roo.menu.Menu} this
35619 * @param {Roo.EventObject} e
35620 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35625 * Fires when a menu item contained in this menu is clicked
35626 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35627 * @param {Roo.EventObject} e
35631 if (this.registerMenu) {
35632 Roo.menu.MenuMgr.register(this);
35635 var mis = this.items;
35636 this.items = new Roo.util.MixedCollection();
35638 this.add.apply(this, mis);
35642 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35644 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35648 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35649 * for bottom-right shadow (defaults to "sides")
35653 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35654 * this menu (defaults to "tl-tr?")
35656 subMenuAlign : "tl-tr?",
35658 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35659 * relative to its element of origin (defaults to "tl-bl?")
35661 defaultAlign : "tl-bl?",
35663 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35665 allowOtherMenus : false,
35667 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35669 registerMenu : true,
35674 render : function(){
35678 var el = this.el = new Roo.Layer({
35680 shadow:this.shadow,
35682 parentEl: this.parentEl || document.body,
35686 this.keyNav = new Roo.menu.MenuNav(this);
35689 el.addClass("x-menu-plain");
35692 el.addClass(this.cls);
35694 // generic focus element
35695 this.focusEl = el.createChild({
35696 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35698 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35699 //disabling touch- as it's causing issues ..
35700 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35701 ul.on('click' , this.onClick, this);
35704 ul.on("mouseover", this.onMouseOver, this);
35705 ul.on("mouseout", this.onMouseOut, this);
35706 this.items.each(function(item){
35711 var li = document.createElement("li");
35712 li.className = "x-menu-list-item";
35713 ul.dom.appendChild(li);
35714 item.render(li, this);
35721 autoWidth : function(){
35722 var el = this.el, ul = this.ul;
35726 var w = this.width;
35729 }else if(Roo.isIE){
35730 el.setWidth(this.minWidth);
35731 var t = el.dom.offsetWidth; // force recalc
35732 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35737 delayAutoWidth : function(){
35740 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35742 this.awTask.delay(20);
35747 findTargetItem : function(e){
35748 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35749 if(t && t.menuItemId){
35750 return this.items.get(t.menuItemId);
35755 onClick : function(e){
35756 Roo.log("menu.onClick");
35757 var t = this.findTargetItem(e);
35762 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35763 if(t == this.activeItem && t.shouldDeactivate(e)){
35764 this.activeItem.deactivate();
35765 delete this.activeItem;
35769 this.setActiveItem(t, true);
35777 this.fireEvent("click", this, t, e);
35781 setActiveItem : function(item, autoExpand){
35782 if(item != this.activeItem){
35783 if(this.activeItem){
35784 this.activeItem.deactivate();
35786 this.activeItem = item;
35787 item.activate(autoExpand);
35788 }else if(autoExpand){
35794 tryActivate : function(start, step){
35795 var items = this.items;
35796 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35797 var item = items.get(i);
35798 if(!item.disabled && item.canActivate){
35799 this.setActiveItem(item, false);
35807 onMouseOver : function(e){
35809 if(t = this.findTargetItem(e)){
35810 if(t.canActivate && !t.disabled){
35811 this.setActiveItem(t, true);
35814 this.fireEvent("mouseover", this, e, t);
35818 onMouseOut : function(e){
35820 if(t = this.findTargetItem(e)){
35821 if(t == this.activeItem && t.shouldDeactivate(e)){
35822 this.activeItem.deactivate();
35823 delete this.activeItem;
35826 this.fireEvent("mouseout", this, e, t);
35830 * Read-only. Returns true if the menu is currently displayed, else false.
35833 isVisible : function(){
35834 return this.el && !this.hidden;
35838 * Displays this menu relative to another element
35839 * @param {String/HTMLElement/Roo.Element} element The element to align to
35840 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35841 * the element (defaults to this.defaultAlign)
35842 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35844 show : function(el, pos, parentMenu){
35845 this.parentMenu = parentMenu;
35849 this.fireEvent("beforeshow", this);
35850 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35854 * Displays this menu at a specific xy position
35855 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35856 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35858 showAt : function(xy, parentMenu, /* private: */_e){
35859 this.parentMenu = parentMenu;
35864 this.fireEvent("beforeshow", this);
35865 xy = this.el.adjustForConstraints(xy);
35869 this.hidden = false;
35871 this.fireEvent("show", this);
35874 focus : function(){
35876 this.doFocus.defer(50, this);
35880 doFocus : function(){
35882 this.focusEl.focus();
35887 * Hides this menu and optionally all parent menus
35888 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35890 hide : function(deep){
35891 if(this.el && this.isVisible()){
35892 this.fireEvent("beforehide", this);
35893 if(this.activeItem){
35894 this.activeItem.deactivate();
35895 this.activeItem = null;
35898 this.hidden = true;
35899 this.fireEvent("hide", this);
35901 if(deep === true && this.parentMenu){
35902 this.parentMenu.hide(true);
35907 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35908 * Any of the following are valid:
35910 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35911 * <li>An HTMLElement object which will be converted to a menu item</li>
35912 * <li>A menu item config object that will be created as a new menu item</li>
35913 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35914 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35919 var menu = new Roo.menu.Menu();
35921 // Create a menu item to add by reference
35922 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35924 // Add a bunch of items at once using different methods.
35925 // Only the last item added will be returned.
35926 var item = menu.add(
35927 menuItem, // add existing item by ref
35928 'Dynamic Item', // new TextItem
35929 '-', // new separator
35930 { text: 'Config Item' } // new item by config
35933 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35934 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35937 var a = arguments, l = a.length, item;
35938 for(var i = 0; i < l; i++){
35940 if ((typeof(el) == "object") && el.xtype && el.xns) {
35941 el = Roo.factory(el, Roo.menu);
35944 if(el.render){ // some kind of Item
35945 item = this.addItem(el);
35946 }else if(typeof el == "string"){ // string
35947 if(el == "separator" || el == "-"){
35948 item = this.addSeparator();
35950 item = this.addText(el);
35952 }else if(el.tagName || el.el){ // element
35953 item = this.addElement(el);
35954 }else if(typeof el == "object"){ // must be menu item config?
35955 item = this.addMenuItem(el);
35962 * Returns this menu's underlying {@link Roo.Element} object
35963 * @return {Roo.Element} The element
35965 getEl : function(){
35973 * Adds a separator bar to the menu
35974 * @return {Roo.menu.Item} The menu item that was added
35976 addSeparator : function(){
35977 return this.addItem(new Roo.menu.Separator());
35981 * Adds an {@link Roo.Element} object to the menu
35982 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35983 * @return {Roo.menu.Item} The menu item that was added
35985 addElement : function(el){
35986 return this.addItem(new Roo.menu.BaseItem(el));
35990 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35991 * @param {Roo.menu.Item} item The menu item to add
35992 * @return {Roo.menu.Item} The menu item that was added
35994 addItem : function(item){
35995 this.items.add(item);
35997 var li = document.createElement("li");
35998 li.className = "x-menu-list-item";
35999 this.ul.dom.appendChild(li);
36000 item.render(li, this);
36001 this.delayAutoWidth();
36007 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
36008 * @param {Object} config A MenuItem config object
36009 * @return {Roo.menu.Item} The menu item that was added
36011 addMenuItem : function(config){
36012 if(!(config instanceof Roo.menu.Item)){
36013 if(typeof config.checked == "boolean"){ // must be check menu item config?
36014 config = new Roo.menu.CheckItem(config);
36016 config = new Roo.menu.Item(config);
36019 return this.addItem(config);
36023 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
36024 * @param {String} text The text to display in the menu item
36025 * @return {Roo.menu.Item} The menu item that was added
36027 addText : function(text){
36028 return this.addItem(new Roo.menu.TextItem({ text : text }));
36032 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
36033 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
36034 * @param {Roo.menu.Item} item The menu item to add
36035 * @return {Roo.menu.Item} The menu item that was added
36037 insert : function(index, item){
36038 this.items.insert(index, item);
36040 var li = document.createElement("li");
36041 li.className = "x-menu-list-item";
36042 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
36043 item.render(li, this);
36044 this.delayAutoWidth();
36050 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
36051 * @param {Roo.menu.Item} item The menu item to remove
36053 remove : function(item){
36054 this.items.removeKey(item.id);
36059 * Removes and destroys all items in the menu
36061 removeAll : function(){
36063 while(f = this.items.first()){
36069 // MenuNav is a private utility class used internally by the Menu
36070 Roo.menu.MenuNav = function(menu){
36071 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
36072 this.scope = this.menu = menu;
36075 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
36076 doRelay : function(e, h){
36077 var k = e.getKey();
36078 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
36079 this.menu.tryActivate(0, 1);
36082 return h.call(this.scope || this, e, this.menu);
36085 up : function(e, m){
36086 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
36087 m.tryActivate(m.items.length-1, -1);
36091 down : function(e, m){
36092 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
36093 m.tryActivate(0, 1);
36097 right : function(e, m){
36099 m.activeItem.expandMenu(true);
36103 left : function(e, m){
36105 if(m.parentMenu && m.parentMenu.activeItem){
36106 m.parentMenu.activeItem.activate();
36110 enter : function(e, m){
36112 e.stopPropagation();
36113 m.activeItem.onClick(e);
36114 m.fireEvent("click", this, m.activeItem);
36120 * Ext JS Library 1.1.1
36121 * Copyright(c) 2006-2007, Ext JS, LLC.
36123 * Originally Released Under LGPL - original licence link has changed is not relivant.
36126 * <script type="text/javascript">
36130 * @class Roo.menu.MenuMgr
36131 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
36134 Roo.menu.MenuMgr = function(){
36135 var menus, active, groups = {}, attached = false, lastShow = new Date();
36137 // private - called when first menu is created
36140 active = new Roo.util.MixedCollection();
36141 Roo.get(document).addKeyListener(27, function(){
36142 if(active.length > 0){
36149 function hideAll(){
36150 if(active && active.length > 0){
36151 var c = active.clone();
36152 c.each(function(m){
36159 function onHide(m){
36161 if(active.length < 1){
36162 Roo.get(document).un("mousedown", onMouseDown);
36168 function onShow(m){
36169 var last = active.last();
36170 lastShow = new Date();
36173 Roo.get(document).on("mousedown", onMouseDown);
36177 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
36178 m.parentMenu.activeChild = m;
36179 }else if(last && last.isVisible()){
36180 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
36185 function onBeforeHide(m){
36187 m.activeChild.hide();
36189 if(m.autoHideTimer){
36190 clearTimeout(m.autoHideTimer);
36191 delete m.autoHideTimer;
36196 function onBeforeShow(m){
36197 var pm = m.parentMenu;
36198 if(!pm && !m.allowOtherMenus){
36200 }else if(pm && pm.activeChild && active != m){
36201 pm.activeChild.hide();
36206 function onMouseDown(e){
36207 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36213 function onBeforeCheck(mi, state){
36215 var g = groups[mi.group];
36216 for(var i = 0, l = g.length; i < l; i++){
36218 g[i].setChecked(false);
36227 * Hides all menus that are currently visible
36229 hideAll : function(){
36234 register : function(menu){
36238 menus[menu.id] = menu;
36239 menu.on("beforehide", onBeforeHide);
36240 menu.on("hide", onHide);
36241 menu.on("beforeshow", onBeforeShow);
36242 menu.on("show", onShow);
36243 var g = menu.group;
36244 if(g && menu.events["checkchange"]){
36248 groups[g].push(menu);
36249 menu.on("checkchange", onCheck);
36254 * Returns a {@link Roo.menu.Menu} object
36255 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36256 * be used to generate and return a new Menu instance.
36258 get : function(menu){
36259 if(typeof menu == "string"){ // menu id
36260 return menus[menu];
36261 }else if(menu.events){ // menu instance
36263 }else if(typeof menu.length == 'number'){ // array of menu items?
36264 return new Roo.menu.Menu({items:menu});
36265 }else{ // otherwise, must be a config
36266 return new Roo.menu.Menu(menu);
36271 unregister : function(menu){
36272 delete menus[menu.id];
36273 menu.un("beforehide", onBeforeHide);
36274 menu.un("hide", onHide);
36275 menu.un("beforeshow", onBeforeShow);
36276 menu.un("show", onShow);
36277 var g = menu.group;
36278 if(g && menu.events["checkchange"]){
36279 groups[g].remove(menu);
36280 menu.un("checkchange", onCheck);
36285 registerCheckable : function(menuItem){
36286 var g = menuItem.group;
36291 groups[g].push(menuItem);
36292 menuItem.on("beforecheckchange", onBeforeCheck);
36297 unregisterCheckable : function(menuItem){
36298 var g = menuItem.group;
36300 groups[g].remove(menuItem);
36301 menuItem.un("beforecheckchange", onBeforeCheck);
36307 * Ext JS Library 1.1.1
36308 * Copyright(c) 2006-2007, Ext JS, LLC.
36310 * Originally Released Under LGPL - original licence link has changed is not relivant.
36313 * <script type="text/javascript">
36318 * @class Roo.menu.BaseItem
36319 * @extends Roo.Component
36320 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36321 * management and base configuration options shared by all menu components.
36323 * Creates a new BaseItem
36324 * @param {Object} config Configuration options
36326 Roo.menu.BaseItem = function(config){
36327 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36332 * Fires when this item is clicked
36333 * @param {Roo.menu.BaseItem} this
36334 * @param {Roo.EventObject} e
36339 * Fires when this item is activated
36340 * @param {Roo.menu.BaseItem} this
36344 * @event deactivate
36345 * Fires when this item is deactivated
36346 * @param {Roo.menu.BaseItem} this
36352 this.on("click", this.handler, this.scope, true);
36356 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36358 * @cfg {Function} handler
36359 * A function that will handle the click event of this menu item (defaults to undefined)
36362 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36364 canActivate : false,
36367 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36372 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36374 activeClass : "x-menu-item-active",
36376 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36378 hideOnClick : true,
36380 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36385 ctype: "Roo.menu.BaseItem",
36388 actionMode : "container",
36391 render : function(container, parentMenu){
36392 this.parentMenu = parentMenu;
36393 Roo.menu.BaseItem.superclass.render.call(this, container);
36394 this.container.menuItemId = this.id;
36398 onRender : function(container, position){
36399 this.el = Roo.get(this.el);
36400 container.dom.appendChild(this.el.dom);
36404 onClick : function(e){
36405 if(!this.disabled && this.fireEvent("click", this, e) !== false
36406 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36407 this.handleClick(e);
36414 activate : function(){
36418 var li = this.container;
36419 li.addClass(this.activeClass);
36420 this.region = li.getRegion().adjust(2, 2, -2, -2);
36421 this.fireEvent("activate", this);
36426 deactivate : function(){
36427 this.container.removeClass(this.activeClass);
36428 this.fireEvent("deactivate", this);
36432 shouldDeactivate : function(e){
36433 return !this.region || !this.region.contains(e.getPoint());
36437 handleClick : function(e){
36438 if(this.hideOnClick){
36439 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36444 expandMenu : function(autoActivate){
36449 hideMenu : function(){
36454 * Ext JS Library 1.1.1
36455 * Copyright(c) 2006-2007, Ext JS, LLC.
36457 * Originally Released Under LGPL - original licence link has changed is not relivant.
36460 * <script type="text/javascript">
36464 * @class Roo.menu.Adapter
36465 * @extends Roo.menu.BaseItem
36466 * 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.
36467 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36469 * Creates a new Adapter
36470 * @param {Object} config Configuration options
36472 Roo.menu.Adapter = function(component, config){
36473 Roo.menu.Adapter.superclass.constructor.call(this, config);
36474 this.component = component;
36476 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36478 canActivate : true,
36481 onRender : function(container, position){
36482 this.component.render(container);
36483 this.el = this.component.getEl();
36487 activate : function(){
36491 this.component.focus();
36492 this.fireEvent("activate", this);
36497 deactivate : function(){
36498 this.fireEvent("deactivate", this);
36502 disable : function(){
36503 this.component.disable();
36504 Roo.menu.Adapter.superclass.disable.call(this);
36508 enable : function(){
36509 this.component.enable();
36510 Roo.menu.Adapter.superclass.enable.call(this);
36514 * Ext JS Library 1.1.1
36515 * Copyright(c) 2006-2007, Ext JS, LLC.
36517 * Originally Released Under LGPL - original licence link has changed is not relivant.
36520 * <script type="text/javascript">
36524 * @class Roo.menu.TextItem
36525 * @extends Roo.menu.BaseItem
36526 * Adds a static text string to a menu, usually used as either a heading or group separator.
36527 * Note: old style constructor with text is still supported.
36530 * Creates a new TextItem
36531 * @param {Object} cfg Configuration
36533 Roo.menu.TextItem = function(cfg){
36534 if (typeof(cfg) == 'string') {
36537 Roo.apply(this,cfg);
36540 Roo.menu.TextItem.superclass.constructor.call(this);
36543 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36545 * @cfg {Boolean} text Text to show on item.
36550 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36552 hideOnClick : false,
36554 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36556 itemCls : "x-menu-text",
36559 onRender : function(){
36560 var s = document.createElement("span");
36561 s.className = this.itemCls;
36562 s.innerHTML = this.text;
36564 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36568 * Ext JS Library 1.1.1
36569 * Copyright(c) 2006-2007, Ext JS, LLC.
36571 * Originally Released Under LGPL - original licence link has changed is not relivant.
36574 * <script type="text/javascript">
36578 * @class Roo.menu.Separator
36579 * @extends Roo.menu.BaseItem
36580 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36581 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36583 * @param {Object} config Configuration options
36585 Roo.menu.Separator = function(config){
36586 Roo.menu.Separator.superclass.constructor.call(this, config);
36589 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36591 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36593 itemCls : "x-menu-sep",
36595 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36597 hideOnClick : false,
36600 onRender : function(li){
36601 var s = document.createElement("span");
36602 s.className = this.itemCls;
36603 s.innerHTML = " ";
36605 li.addClass("x-menu-sep-li");
36606 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36610 * Ext JS Library 1.1.1
36611 * Copyright(c) 2006-2007, Ext JS, LLC.
36613 * Originally Released Under LGPL - original licence link has changed is not relivant.
36616 * <script type="text/javascript">
36619 * @class Roo.menu.Item
36620 * @extends Roo.menu.BaseItem
36621 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36622 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36623 * activation and click handling.
36625 * Creates a new Item
36626 * @param {Object} config Configuration options
36628 Roo.menu.Item = function(config){
36629 Roo.menu.Item.superclass.constructor.call(this, config);
36631 this.menu = Roo.menu.MenuMgr.get(this.menu);
36634 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36637 * @cfg {String} text
36638 * The text to show on the menu item.
36642 * @cfg {String} HTML to render in menu
36643 * The text to show on the menu item (HTML version).
36647 * @cfg {String} icon
36648 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36652 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36654 itemCls : "x-menu-item",
36656 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36658 canActivate : true,
36660 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36663 // doc'd in BaseItem
36667 ctype: "Roo.menu.Item",
36670 onRender : function(container, position){
36671 var el = document.createElement("a");
36672 el.hideFocus = true;
36673 el.unselectable = "on";
36674 el.href = this.href || "#";
36675 if(this.hrefTarget){
36676 el.target = this.hrefTarget;
36678 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36680 var html = this.html.length ? this.html : String.format('{0}',this.text);
36682 el.innerHTML = String.format(
36683 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36684 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36686 Roo.menu.Item.superclass.onRender.call(this, container, position);
36690 * Sets the text to display in this menu item
36691 * @param {String} text The text to display
36692 * @param {Boolean} isHTML true to indicate text is pure html.
36694 setText : function(text, isHTML){
36702 var html = this.html.length ? this.html : String.format('{0}',this.text);
36704 this.el.update(String.format(
36705 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36706 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36707 this.parentMenu.autoWidth();
36712 handleClick : function(e){
36713 if(!this.href){ // if no link defined, stop the event automatically
36716 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36720 activate : function(autoExpand){
36721 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36731 shouldDeactivate : function(e){
36732 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36733 if(this.menu && this.menu.isVisible()){
36734 return !this.menu.getEl().getRegion().contains(e.getPoint());
36742 deactivate : function(){
36743 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36748 expandMenu : function(autoActivate){
36749 if(!this.disabled && this.menu){
36750 clearTimeout(this.hideTimer);
36751 delete this.hideTimer;
36752 if(!this.menu.isVisible() && !this.showTimer){
36753 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36754 }else if (this.menu.isVisible() && autoActivate){
36755 this.menu.tryActivate(0, 1);
36761 deferExpand : function(autoActivate){
36762 delete this.showTimer;
36763 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36765 this.menu.tryActivate(0, 1);
36770 hideMenu : function(){
36771 clearTimeout(this.showTimer);
36772 delete this.showTimer;
36773 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36774 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36779 deferHide : function(){
36780 delete this.hideTimer;
36785 * Ext JS Library 1.1.1
36786 * Copyright(c) 2006-2007, Ext JS, LLC.
36788 * Originally Released Under LGPL - original licence link has changed is not relivant.
36791 * <script type="text/javascript">
36795 * @class Roo.menu.CheckItem
36796 * @extends Roo.menu.Item
36797 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36799 * Creates a new CheckItem
36800 * @param {Object} config Configuration options
36802 Roo.menu.CheckItem = function(config){
36803 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36806 * @event beforecheckchange
36807 * Fires before the checked value is set, providing an opportunity to cancel if needed
36808 * @param {Roo.menu.CheckItem} this
36809 * @param {Boolean} checked The new checked value that will be set
36811 "beforecheckchange" : true,
36813 * @event checkchange
36814 * Fires after the checked value has been set
36815 * @param {Roo.menu.CheckItem} this
36816 * @param {Boolean} checked The checked value that was set
36818 "checkchange" : true
36820 if(this.checkHandler){
36821 this.on('checkchange', this.checkHandler, this.scope);
36824 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36826 * @cfg {String} group
36827 * All check items with the same group name will automatically be grouped into a single-select
36828 * radio button group (defaults to '')
36831 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36833 itemCls : "x-menu-item x-menu-check-item",
36835 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36837 groupClass : "x-menu-group-item",
36840 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36841 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36842 * initialized with checked = true will be rendered as checked.
36847 ctype: "Roo.menu.CheckItem",
36850 onRender : function(c){
36851 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36853 this.el.addClass(this.groupClass);
36855 Roo.menu.MenuMgr.registerCheckable(this);
36857 this.checked = false;
36858 this.setChecked(true, true);
36863 destroy : function(){
36865 Roo.menu.MenuMgr.unregisterCheckable(this);
36867 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36871 * Set the checked state of this item
36872 * @param {Boolean} checked The new checked value
36873 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36875 setChecked : function(state, suppressEvent){
36876 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36877 if(this.container){
36878 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36880 this.checked = state;
36881 if(suppressEvent !== true){
36882 this.fireEvent("checkchange", this, state);
36888 handleClick : function(e){
36889 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36890 this.setChecked(!this.checked);
36892 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36896 * Ext JS Library 1.1.1
36897 * Copyright(c) 2006-2007, Ext JS, LLC.
36899 * Originally Released Under LGPL - original licence link has changed is not relivant.
36902 * <script type="text/javascript">
36906 * @class Roo.menu.DateItem
36907 * @extends Roo.menu.Adapter
36908 * A menu item that wraps the {@link Roo.DatPicker} component.
36910 * Creates a new DateItem
36911 * @param {Object} config Configuration options
36913 Roo.menu.DateItem = function(config){
36914 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36915 /** The Roo.DatePicker object @type Roo.DatePicker */
36916 this.picker = this.component;
36917 this.addEvents({select: true});
36919 this.picker.on("render", function(picker){
36920 picker.getEl().swallowEvent("click");
36921 picker.container.addClass("x-menu-date-item");
36924 this.picker.on("select", this.onSelect, this);
36927 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36929 onSelect : function(picker, date){
36930 this.fireEvent("select", this, date, picker);
36931 Roo.menu.DateItem.superclass.handleClick.call(this);
36935 * Ext JS Library 1.1.1
36936 * Copyright(c) 2006-2007, Ext JS, LLC.
36938 * Originally Released Under LGPL - original licence link has changed is not relivant.
36941 * <script type="text/javascript">
36945 * @class Roo.menu.ColorItem
36946 * @extends Roo.menu.Adapter
36947 * A menu item that wraps the {@link Roo.ColorPalette} component.
36949 * Creates a new ColorItem
36950 * @param {Object} config Configuration options
36952 Roo.menu.ColorItem = function(config){
36953 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36954 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36955 this.palette = this.component;
36956 this.relayEvents(this.palette, ["select"]);
36957 if(this.selectHandler){
36958 this.on('select', this.selectHandler, this.scope);
36961 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36963 * Ext JS Library 1.1.1
36964 * Copyright(c) 2006-2007, Ext JS, LLC.
36966 * Originally Released Under LGPL - original licence link has changed is not relivant.
36969 * <script type="text/javascript">
36974 * @class Roo.menu.DateMenu
36975 * @extends Roo.menu.Menu
36976 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36978 * Creates a new DateMenu
36979 * @param {Object} config Configuration options
36981 Roo.menu.DateMenu = function(config){
36982 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36984 var di = new Roo.menu.DateItem(config);
36987 * The {@link Roo.DatePicker} instance for this DateMenu
36990 this.picker = di.picker;
36993 * @param {DatePicker} picker
36994 * @param {Date} date
36996 this.relayEvents(di, ["select"]);
36997 this.on('beforeshow', function(){
36999 this.picker.hideMonthPicker(false);
37003 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
37007 * Ext JS Library 1.1.1
37008 * Copyright(c) 2006-2007, Ext JS, LLC.
37010 * Originally Released Under LGPL - original licence link has changed is not relivant.
37013 * <script type="text/javascript">
37018 * @class Roo.menu.ColorMenu
37019 * @extends Roo.menu.Menu
37020 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
37022 * Creates a new ColorMenu
37023 * @param {Object} config Configuration options
37025 Roo.menu.ColorMenu = function(config){
37026 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
37028 var ci = new Roo.menu.ColorItem(config);
37031 * The {@link Roo.ColorPalette} instance for this ColorMenu
37032 * @type ColorPalette
37034 this.palette = ci.palette;
37037 * @param {ColorPalette} palette
37038 * @param {String} color
37040 this.relayEvents(ci, ["select"]);
37042 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
37044 * Ext JS Library 1.1.1
37045 * Copyright(c) 2006-2007, Ext JS, LLC.
37047 * Originally Released Under LGPL - original licence link has changed is not relivant.
37050 * <script type="text/javascript">
37054 * @class Roo.form.Field
37055 * @extends Roo.BoxComponent
37056 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
37058 * Creates a new Field
37059 * @param {Object} config Configuration options
37061 Roo.form.Field = function(config){
37062 Roo.form.Field.superclass.constructor.call(this, config);
37065 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
37067 * @cfg {String} fieldLabel Label to use when rendering a form.
37070 * @cfg {String} qtip Mouse over tip
37074 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
37076 invalidClass : "x-form-invalid",
37078 * @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")
37080 invalidText : "The value in this field is invalid",
37082 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
37084 focusClass : "x-form-focus",
37086 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
37087 automatic validation (defaults to "keyup").
37089 validationEvent : "keyup",
37091 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
37093 validateOnBlur : true,
37095 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
37097 validationDelay : 250,
37099 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37100 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
37102 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
37104 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
37106 fieldClass : "x-form-field",
37108 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
37111 ----------- ----------------------------------------------------------------------
37112 qtip Display a quick tip when the user hovers over the field
37113 title Display a default browser title attribute popup
37114 under Add a block div beneath the field containing the error text
37115 side Add an error icon to the right of the field with a popup on hover
37116 [element id] Add the error text directly to the innerHTML of the specified element
37119 msgTarget : 'qtip',
37121 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
37126 * @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.
37131 * @cfg {Boolean} disabled True to disable the field (defaults to false).
37136 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
37138 inputType : undefined,
37141 * @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).
37143 tabIndex : undefined,
37146 isFormField : true,
37151 * @property {Roo.Element} fieldEl
37152 * Element Containing the rendered Field (with label etc.)
37155 * @cfg {Mixed} value A value to initialize this field with.
37160 * @cfg {String} name The field's HTML name attribute.
37163 * @cfg {String} cls A CSS class to apply to the field's underlying element.
37167 initComponent : function(){
37168 Roo.form.Field.superclass.initComponent.call(this);
37172 * Fires when this field receives input focus.
37173 * @param {Roo.form.Field} this
37178 * Fires when this field loses input focus.
37179 * @param {Roo.form.Field} this
37183 * @event specialkey
37184 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
37185 * {@link Roo.EventObject#getKey} to determine which key was pressed.
37186 * @param {Roo.form.Field} this
37187 * @param {Roo.EventObject} e The event object
37192 * Fires just before the field blurs if the field value has changed.
37193 * @param {Roo.form.Field} this
37194 * @param {Mixed} newValue The new value
37195 * @param {Mixed} oldValue The original value
37200 * Fires after the field has been marked as invalid.
37201 * @param {Roo.form.Field} this
37202 * @param {String} msg The validation message
37207 * Fires after the field has been validated with no errors.
37208 * @param {Roo.form.Field} this
37213 * Fires after the key up
37214 * @param {Roo.form.Field} this
37215 * @param {Roo.EventObject} e The event Object
37222 * Returns the name attribute of the field if available
37223 * @return {String} name The field name
37225 getName: function(){
37226 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37230 onRender : function(ct, position){
37231 Roo.form.Field.superclass.onRender.call(this, ct, position);
37233 var cfg = this.getAutoCreate();
37235 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37237 if (!cfg.name.length) {
37240 if(this.inputType){
37241 cfg.type = this.inputType;
37243 this.el = ct.createChild(cfg, position);
37245 var type = this.el.dom.type;
37247 if(type == 'password'){
37250 this.el.addClass('x-form-'+type);
37253 this.el.dom.readOnly = true;
37255 if(this.tabIndex !== undefined){
37256 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37259 this.el.addClass([this.fieldClass, this.cls]);
37264 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37265 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37266 * @return {Roo.form.Field} this
37268 applyTo : function(target){
37269 this.allowDomMove = false;
37270 this.el = Roo.get(target);
37271 this.render(this.el.dom.parentNode);
37276 initValue : function(){
37277 if(this.value !== undefined){
37278 this.setValue(this.value);
37279 }else if(this.el.dom.value.length > 0){
37280 this.setValue(this.el.dom.value);
37285 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37287 isDirty : function() {
37288 if(this.disabled) {
37291 return String(this.getValue()) !== String(this.originalValue);
37295 afterRender : function(){
37296 Roo.form.Field.superclass.afterRender.call(this);
37301 fireKey : function(e){
37302 //Roo.log('field ' + e.getKey());
37303 if(e.isNavKeyPress()){
37304 this.fireEvent("specialkey", this, e);
37309 * Resets the current field value to the originally loaded value and clears any validation messages
37311 reset : function(){
37312 this.setValue(this.resetValue);
37313 this.clearInvalid();
37317 initEvents : function(){
37318 // safari killled keypress - so keydown is now used..
37319 this.el.on("keydown" , this.fireKey, this);
37320 this.el.on("focus", this.onFocus, this);
37321 this.el.on("blur", this.onBlur, this);
37322 this.el.relayEvent('keyup', this);
37324 // reference to original value for reset
37325 this.originalValue = this.getValue();
37326 this.resetValue = this.getValue();
37330 onFocus : function(){
37331 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37332 this.el.addClass(this.focusClass);
37334 if(!this.hasFocus){
37335 this.hasFocus = true;
37336 this.startValue = this.getValue();
37337 this.fireEvent("focus", this);
37341 beforeBlur : Roo.emptyFn,
37344 onBlur : function(){
37346 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37347 this.el.removeClass(this.focusClass);
37349 this.hasFocus = false;
37350 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37353 var v = this.getValue();
37354 if(String(v) !== String(this.startValue)){
37355 this.fireEvent('change', this, v, this.startValue);
37357 this.fireEvent("blur", this);
37361 * Returns whether or not the field value is currently valid
37362 * @param {Boolean} preventMark True to disable marking the field invalid
37363 * @return {Boolean} True if the value is valid, else false
37365 isValid : function(preventMark){
37369 var restore = this.preventMark;
37370 this.preventMark = preventMark === true;
37371 var v = this.validateValue(this.processValue(this.getRawValue()));
37372 this.preventMark = restore;
37377 * Validates the field value
37378 * @return {Boolean} True if the value is valid, else false
37380 validate : function(){
37381 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37382 this.clearInvalid();
37388 processValue : function(value){
37393 // Subclasses should provide the validation implementation by overriding this
37394 validateValue : function(value){
37399 * Mark this field as invalid
37400 * @param {String} msg The validation message
37402 markInvalid : function(msg){
37403 if(!this.rendered || this.preventMark){ // not rendered
37407 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37409 obj.el.addClass(this.invalidClass);
37410 msg = msg || this.invalidText;
37411 switch(this.msgTarget){
37413 obj.el.dom.qtip = msg;
37414 obj.el.dom.qclass = 'x-form-invalid-tip';
37415 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37416 Roo.QuickTips.enable();
37420 this.el.dom.title = msg;
37424 var elp = this.el.findParent('.x-form-element', 5, true);
37425 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37426 this.errorEl.setWidth(elp.getWidth(true)-20);
37428 this.errorEl.update(msg);
37429 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37432 if(!this.errorIcon){
37433 var elp = this.el.findParent('.x-form-element', 5, true);
37434 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37436 this.alignErrorIcon();
37437 this.errorIcon.dom.qtip = msg;
37438 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37439 this.errorIcon.show();
37440 this.on('resize', this.alignErrorIcon, this);
37443 var t = Roo.getDom(this.msgTarget);
37445 t.style.display = this.msgDisplay;
37448 this.fireEvent('invalid', this, msg);
37452 alignErrorIcon : function(){
37453 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37457 * Clear any invalid styles/messages for this field
37459 clearInvalid : function(){
37460 if(!this.rendered || this.preventMark){ // not rendered
37463 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37465 obj.el.removeClass(this.invalidClass);
37466 switch(this.msgTarget){
37468 obj.el.dom.qtip = '';
37471 this.el.dom.title = '';
37475 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37479 if(this.errorIcon){
37480 this.errorIcon.dom.qtip = '';
37481 this.errorIcon.hide();
37482 this.un('resize', this.alignErrorIcon, this);
37486 var t = Roo.getDom(this.msgTarget);
37488 t.style.display = 'none';
37491 this.fireEvent('valid', this);
37495 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37496 * @return {Mixed} value The field value
37498 getRawValue : function(){
37499 var v = this.el.getValue();
37505 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37506 * @return {Mixed} value The field value
37508 getValue : function(){
37509 var v = this.el.getValue();
37515 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37516 * @param {Mixed} value The value to set
37518 setRawValue : function(v){
37519 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37523 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37524 * @param {Mixed} value The value to set
37526 setValue : function(v){
37529 this.el.dom.value = (v === null || v === undefined ? '' : v);
37534 adjustSize : function(w, h){
37535 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37536 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37540 adjustWidth : function(tag, w){
37541 tag = tag.toLowerCase();
37542 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37543 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37544 if(tag == 'input'){
37547 if(tag == 'textarea'){
37550 }else if(Roo.isOpera){
37551 if(tag == 'input'){
37554 if(tag == 'textarea'){
37564 // anything other than normal should be considered experimental
37565 Roo.form.Field.msgFx = {
37567 show: function(msgEl, f){
37568 msgEl.setDisplayed('block');
37571 hide : function(msgEl, f){
37572 msgEl.setDisplayed(false).update('');
37577 show: function(msgEl, f){
37578 msgEl.slideIn('t', {stopFx:true});
37581 hide : function(msgEl, f){
37582 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37587 show: function(msgEl, f){
37588 msgEl.fixDisplay();
37589 msgEl.alignTo(f.el, 'tl-tr');
37590 msgEl.slideIn('l', {stopFx:true});
37593 hide : function(msgEl, f){
37594 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37599 * Ext JS Library 1.1.1
37600 * Copyright(c) 2006-2007, Ext JS, LLC.
37602 * Originally Released Under LGPL - original licence link has changed is not relivant.
37605 * <script type="text/javascript">
37610 * @class Roo.form.TextField
37611 * @extends Roo.form.Field
37612 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37613 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37615 * Creates a new TextField
37616 * @param {Object} config Configuration options
37618 Roo.form.TextField = function(config){
37619 Roo.form.TextField.superclass.constructor.call(this, config);
37623 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37624 * according to the default logic, but this event provides a hook for the developer to apply additional
37625 * logic at runtime to resize the field if needed.
37626 * @param {Roo.form.Field} this This text field
37627 * @param {Number} width The new field width
37633 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37635 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37639 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37643 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37647 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37651 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37655 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37657 disableKeyFilter : false,
37659 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37663 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37667 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37669 maxLength : Number.MAX_VALUE,
37671 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37673 minLengthText : "The minimum length for this field is {0}",
37675 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37677 maxLengthText : "The maximum length for this field is {0}",
37679 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37681 selectOnFocus : false,
37683 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37685 blankText : "This field is required",
37687 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37688 * If available, this function will be called only after the basic validators all return true, and will be passed the
37689 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37693 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37694 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37695 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37699 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37703 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37709 initEvents : function()
37711 if (this.emptyText) {
37712 this.el.attr('placeholder', this.emptyText);
37715 Roo.form.TextField.superclass.initEvents.call(this);
37716 if(this.validationEvent == 'keyup'){
37717 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37718 this.el.on('keyup', this.filterValidation, this);
37720 else if(this.validationEvent !== false){
37721 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37724 if(this.selectOnFocus){
37725 this.on("focus", this.preFocus, this);
37728 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37729 this.el.on("keypress", this.filterKeys, this);
37732 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37733 this.el.on("click", this.autoSize, this);
37735 if(this.el.is('input[type=password]') && Roo.isSafari){
37736 this.el.on('keydown', this.SafariOnKeyDown, this);
37740 processValue : function(value){
37741 if(this.stripCharsRe){
37742 var newValue = value.replace(this.stripCharsRe, '');
37743 if(newValue !== value){
37744 this.setRawValue(newValue);
37751 filterValidation : function(e){
37752 if(!e.isNavKeyPress()){
37753 this.validationTask.delay(this.validationDelay);
37758 onKeyUp : function(e){
37759 if(!e.isNavKeyPress()){
37765 * Resets the current field value to the originally-loaded value and clears any validation messages.
37768 reset : function(){
37769 Roo.form.TextField.superclass.reset.call(this);
37775 preFocus : function(){
37777 if(this.selectOnFocus){
37778 this.el.dom.select();
37784 filterKeys : function(e){
37785 var k = e.getKey();
37786 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37789 var c = e.getCharCode(), cc = String.fromCharCode(c);
37790 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37793 if(!this.maskRe.test(cc)){
37798 setValue : function(v){
37800 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37806 * Validates a value according to the field's validation rules and marks the field as invalid
37807 * if the validation fails
37808 * @param {Mixed} value The value to validate
37809 * @return {Boolean} True if the value is valid, else false
37811 validateValue : function(value){
37812 if(value.length < 1) { // if it's blank
37813 if(this.allowBlank){
37814 this.clearInvalid();
37817 this.markInvalid(this.blankText);
37821 if(value.length < this.minLength){
37822 this.markInvalid(String.format(this.minLengthText, this.minLength));
37825 if(value.length > this.maxLength){
37826 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37830 var vt = Roo.form.VTypes;
37831 if(!vt[this.vtype](value, this)){
37832 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37836 if(typeof this.validator == "function"){
37837 var msg = this.validator(value);
37839 this.markInvalid(msg);
37843 if(this.regex && !this.regex.test(value)){
37844 this.markInvalid(this.regexText);
37851 * Selects text in this field
37852 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37853 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37855 selectText : function(start, end){
37856 var v = this.getRawValue();
37858 start = start === undefined ? 0 : start;
37859 end = end === undefined ? v.length : end;
37860 var d = this.el.dom;
37861 if(d.setSelectionRange){
37862 d.setSelectionRange(start, end);
37863 }else if(d.createTextRange){
37864 var range = d.createTextRange();
37865 range.moveStart("character", start);
37866 range.moveEnd("character", v.length-end);
37873 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37874 * This only takes effect if grow = true, and fires the autosize event.
37876 autoSize : function(){
37877 if(!this.grow || !this.rendered){
37881 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37884 var v = el.dom.value;
37885 var d = document.createElement('div');
37886 d.appendChild(document.createTextNode(v));
37890 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37891 this.el.setWidth(w);
37892 this.fireEvent("autosize", this, w);
37896 SafariOnKeyDown : function(event)
37898 // this is a workaround for a password hang bug on chrome/ webkit.
37900 var isSelectAll = false;
37902 if(this.el.dom.selectionEnd > 0){
37903 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37905 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37906 event.preventDefault();
37911 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
37913 event.preventDefault();
37914 // this is very hacky as keydown always get's upper case.
37916 var cc = String.fromCharCode(event.getCharCode());
37919 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37927 * Ext JS Library 1.1.1
37928 * Copyright(c) 2006-2007, Ext JS, LLC.
37930 * Originally Released Under LGPL - original licence link has changed is not relivant.
37933 * <script type="text/javascript">
37937 * @class Roo.form.Hidden
37938 * @extends Roo.form.TextField
37939 * Simple Hidden element used on forms
37941 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37944 * Creates a new Hidden form element.
37945 * @param {Object} config Configuration options
37950 // easy hidden field...
37951 Roo.form.Hidden = function(config){
37952 Roo.form.Hidden.superclass.constructor.call(this, config);
37955 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37957 inputType: 'hidden',
37960 labelSeparator: '',
37962 itemCls : 'x-form-item-display-none'
37970 * Ext JS Library 1.1.1
37971 * Copyright(c) 2006-2007, Ext JS, LLC.
37973 * Originally Released Under LGPL - original licence link has changed is not relivant.
37976 * <script type="text/javascript">
37980 * @class Roo.form.TriggerField
37981 * @extends Roo.form.TextField
37982 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37983 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37984 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37985 * for which you can provide a custom implementation. For example:
37987 var trigger = new Roo.form.TriggerField();
37988 trigger.onTriggerClick = myTriggerFn;
37989 trigger.applyTo('my-field');
37992 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37993 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37994 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37995 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37997 * Create a new TriggerField.
37998 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37999 * to the base TextField)
38001 Roo.form.TriggerField = function(config){
38002 this.mimicing = false;
38003 Roo.form.TriggerField.superclass.constructor.call(this, config);
38006 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
38008 * @cfg {String} triggerClass A CSS class to apply to the trigger
38011 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38012 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
38014 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
38016 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
38020 /** @cfg {Boolean} grow @hide */
38021 /** @cfg {Number} growMin @hide */
38022 /** @cfg {Number} growMax @hide */
38028 autoSize: Roo.emptyFn,
38032 deferHeight : true,
38035 actionMode : 'wrap',
38037 onResize : function(w, h){
38038 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
38039 if(typeof w == 'number'){
38040 var x = w - this.trigger.getWidth();
38041 this.el.setWidth(this.adjustWidth('input', x));
38042 this.trigger.setStyle('left', x+'px');
38047 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38050 getResizeEl : function(){
38055 getPositionEl : function(){
38060 alignErrorIcon : function(){
38061 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
38065 onRender : function(ct, position){
38066 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
38067 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
38068 this.trigger = this.wrap.createChild(this.triggerConfig ||
38069 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
38070 if(this.hideTrigger){
38071 this.trigger.setDisplayed(false);
38073 this.initTrigger();
38075 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
38080 initTrigger : function(){
38081 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
38082 this.trigger.addClassOnOver('x-form-trigger-over');
38083 this.trigger.addClassOnClick('x-form-trigger-click');
38087 onDestroy : function(){
38089 this.trigger.removeAllListeners();
38090 this.trigger.remove();
38093 this.wrap.remove();
38095 Roo.form.TriggerField.superclass.onDestroy.call(this);
38099 onFocus : function(){
38100 Roo.form.TriggerField.superclass.onFocus.call(this);
38101 if(!this.mimicing){
38102 this.wrap.addClass('x-trigger-wrap-focus');
38103 this.mimicing = true;
38104 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
38105 if(this.monitorTab){
38106 this.el.on("keydown", this.checkTab, this);
38112 checkTab : function(e){
38113 if(e.getKey() == e.TAB){
38114 this.triggerBlur();
38119 onBlur : function(){
38124 mimicBlur : function(e, t){
38125 if(!this.wrap.contains(t) && this.validateBlur()){
38126 this.triggerBlur();
38131 triggerBlur : function(){
38132 this.mimicing = false;
38133 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
38134 if(this.monitorTab){
38135 this.el.un("keydown", this.checkTab, this);
38137 this.wrap.removeClass('x-trigger-wrap-focus');
38138 Roo.form.TriggerField.superclass.onBlur.call(this);
38142 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
38143 validateBlur : function(e, t){
38148 onDisable : function(){
38149 Roo.form.TriggerField.superclass.onDisable.call(this);
38151 this.wrap.addClass('x-item-disabled');
38156 onEnable : function(){
38157 Roo.form.TriggerField.superclass.onEnable.call(this);
38159 this.wrap.removeClass('x-item-disabled');
38164 onShow : function(){
38165 var ae = this.getActionEl();
38168 ae.dom.style.display = '';
38169 ae.dom.style.visibility = 'visible';
38175 onHide : function(){
38176 var ae = this.getActionEl();
38177 ae.dom.style.display = 'none';
38181 * The function that should handle the trigger's click event. This method does nothing by default until overridden
38182 * by an implementing function.
38184 * @param {EventObject} e
38186 onTriggerClick : Roo.emptyFn
38189 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
38190 // to be extended by an implementing class. For an example of implementing this class, see the custom
38191 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
38192 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
38193 initComponent : function(){
38194 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
38196 this.triggerConfig = {
38197 tag:'span', cls:'x-form-twin-triggers', cn:[
38198 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38199 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38203 getTrigger : function(index){
38204 return this.triggers[index];
38207 initTrigger : function(){
38208 var ts = this.trigger.select('.x-form-trigger', true);
38209 this.wrap.setStyle('overflow', 'hidden');
38210 var triggerField = this;
38211 ts.each(function(t, all, index){
38212 t.hide = function(){
38213 var w = triggerField.wrap.getWidth();
38214 this.dom.style.display = 'none';
38215 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38217 t.show = function(){
38218 var w = triggerField.wrap.getWidth();
38219 this.dom.style.display = '';
38220 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38222 var triggerIndex = 'Trigger'+(index+1);
38224 if(this['hide'+triggerIndex]){
38225 t.dom.style.display = 'none';
38227 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38228 t.addClassOnOver('x-form-trigger-over');
38229 t.addClassOnClick('x-form-trigger-click');
38231 this.triggers = ts.elements;
38234 onTrigger1Click : Roo.emptyFn,
38235 onTrigger2Click : Roo.emptyFn
38238 * Ext JS Library 1.1.1
38239 * Copyright(c) 2006-2007, Ext JS, LLC.
38241 * Originally Released Under LGPL - original licence link has changed is not relivant.
38244 * <script type="text/javascript">
38248 * @class Roo.form.TextArea
38249 * @extends Roo.form.TextField
38250 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38251 * support for auto-sizing.
38253 * Creates a new TextArea
38254 * @param {Object} config Configuration options
38256 Roo.form.TextArea = function(config){
38257 Roo.form.TextArea.superclass.constructor.call(this, config);
38258 // these are provided exchanges for backwards compat
38259 // minHeight/maxHeight were replaced by growMin/growMax to be
38260 // compatible with TextField growing config values
38261 if(this.minHeight !== undefined){
38262 this.growMin = this.minHeight;
38264 if(this.maxHeight !== undefined){
38265 this.growMax = this.maxHeight;
38269 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38271 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38275 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38279 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38280 * in the field (equivalent to setting overflow: hidden, defaults to false)
38282 preventScrollbars: false,
38284 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38285 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38289 onRender : function(ct, position){
38291 this.defaultAutoCreate = {
38293 style:"width:300px;height:60px;",
38294 autocomplete: "new-password"
38297 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38299 this.textSizeEl = Roo.DomHelper.append(document.body, {
38300 tag: "pre", cls: "x-form-grow-sizer"
38302 if(this.preventScrollbars){
38303 this.el.setStyle("overflow", "hidden");
38305 this.el.setHeight(this.growMin);
38309 onDestroy : function(){
38310 if(this.textSizeEl){
38311 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38313 Roo.form.TextArea.superclass.onDestroy.call(this);
38317 onKeyUp : function(e){
38318 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38324 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38325 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38327 autoSize : function(){
38328 if(!this.grow || !this.textSizeEl){
38332 var v = el.dom.value;
38333 var ts = this.textSizeEl;
38336 ts.appendChild(document.createTextNode(v));
38339 Roo.fly(ts).setWidth(this.el.getWidth());
38341 v = "  ";
38344 v = v.replace(/\n/g, '<p> </p>');
38346 v += " \n ";
38349 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38350 if(h != this.lastHeight){
38351 this.lastHeight = h;
38352 this.el.setHeight(h);
38353 this.fireEvent("autosize", this, h);
38358 * Ext JS Library 1.1.1
38359 * Copyright(c) 2006-2007, Ext JS, LLC.
38361 * Originally Released Under LGPL - original licence link has changed is not relivant.
38364 * <script type="text/javascript">
38369 * @class Roo.form.NumberField
38370 * @extends Roo.form.TextField
38371 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38373 * Creates a new NumberField
38374 * @param {Object} config Configuration options
38376 Roo.form.NumberField = function(config){
38377 Roo.form.NumberField.superclass.constructor.call(this, config);
38380 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38382 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38384 fieldClass: "x-form-field x-form-num-field",
38386 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38388 allowDecimals : true,
38390 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38392 decimalSeparator : ".",
38394 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38396 decimalPrecision : 2,
38398 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38400 allowNegative : true,
38402 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38404 minValue : Number.NEGATIVE_INFINITY,
38406 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38408 maxValue : Number.MAX_VALUE,
38410 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38412 minText : "The minimum value for this field is {0}",
38414 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38416 maxText : "The maximum value for this field is {0}",
38418 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38419 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38421 nanText : "{0} is not a valid number",
38424 initEvents : function(){
38425 Roo.form.NumberField.superclass.initEvents.call(this);
38426 var allowed = "0123456789";
38427 if(this.allowDecimals){
38428 allowed += this.decimalSeparator;
38430 if(this.allowNegative){
38433 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38434 var keyPress = function(e){
38435 var k = e.getKey();
38436 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38439 var c = e.getCharCode();
38440 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38444 this.el.on("keypress", keyPress, this);
38448 validateValue : function(value){
38449 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38452 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38455 var num = this.parseValue(value);
38457 this.markInvalid(String.format(this.nanText, value));
38460 if(num < this.minValue){
38461 this.markInvalid(String.format(this.minText, this.minValue));
38464 if(num > this.maxValue){
38465 this.markInvalid(String.format(this.maxText, this.maxValue));
38471 getValue : function(){
38472 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38476 parseValue : function(value){
38477 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38478 return isNaN(value) ? '' : value;
38482 fixPrecision : function(value){
38483 var nan = isNaN(value);
38484 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38485 return nan ? '' : value;
38487 return parseFloat(value).toFixed(this.decimalPrecision);
38490 setValue : function(v){
38491 v = this.fixPrecision(v);
38492 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38496 decimalPrecisionFcn : function(v){
38497 return Math.floor(v);
38500 beforeBlur : function(){
38501 var v = this.parseValue(this.getRawValue());
38508 * Ext JS Library 1.1.1
38509 * Copyright(c) 2006-2007, Ext JS, LLC.
38511 * Originally Released Under LGPL - original licence link has changed is not relivant.
38514 * <script type="text/javascript">
38518 * @class Roo.form.DateField
38519 * @extends Roo.form.TriggerField
38520 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38522 * Create a new DateField
38523 * @param {Object} config
38525 Roo.form.DateField = function(config){
38526 Roo.form.DateField.superclass.constructor.call(this, config);
38532 * Fires when a date is selected
38533 * @param {Roo.form.DateField} combo This combo box
38534 * @param {Date} date The date selected
38541 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38542 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38543 this.ddMatch = null;
38544 if(this.disabledDates){
38545 var dd = this.disabledDates;
38547 for(var i = 0; i < dd.length; i++){
38549 if(i != dd.length-1) re += "|";
38551 this.ddMatch = new RegExp(re + ")");
38555 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38557 * @cfg {String} format
38558 * The default date format string which can be overriden for localization support. The format must be
38559 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38563 * @cfg {String} altFormats
38564 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38565 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38567 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38569 * @cfg {Array} disabledDays
38570 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38572 disabledDays : null,
38574 * @cfg {String} disabledDaysText
38575 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38577 disabledDaysText : "Disabled",
38579 * @cfg {Array} disabledDates
38580 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38581 * expression so they are very powerful. Some examples:
38583 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38584 * <li>["03/08", "09/16"] would disable those days for every year</li>
38585 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38586 * <li>["03/../2006"] would disable every day in March 2006</li>
38587 * <li>["^03"] would disable every day in every March</li>
38589 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38590 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38592 disabledDates : null,
38594 * @cfg {String} disabledDatesText
38595 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38597 disabledDatesText : "Disabled",
38599 * @cfg {Date/String} minValue
38600 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38601 * valid format (defaults to null).
38605 * @cfg {Date/String} maxValue
38606 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38607 * valid format (defaults to null).
38611 * @cfg {String} minText
38612 * The error text to display when the date in the cell is before minValue (defaults to
38613 * 'The date in this field must be after {minValue}').
38615 minText : "The date in this field must be equal to or after {0}",
38617 * @cfg {String} maxText
38618 * The error text to display when the date in the cell is after maxValue (defaults to
38619 * 'The date in this field must be before {maxValue}').
38621 maxText : "The date in this field must be equal to or before {0}",
38623 * @cfg {String} invalidText
38624 * The error text to display when the date in the field is invalid (defaults to
38625 * '{value} is not a valid date - it must be in the format {format}').
38627 invalidText : "{0} is not a valid date - it must be in the format {1}",
38629 * @cfg {String} triggerClass
38630 * An additional CSS class used to style the trigger button. The trigger will always get the
38631 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38632 * which displays a calendar icon).
38634 triggerClass : 'x-form-date-trigger',
38638 * @cfg {Boolean} useIso
38639 * if enabled, then the date field will use a hidden field to store the
38640 * real value as iso formated date. default (false)
38644 * @cfg {String/Object} autoCreate
38645 * A DomHelper element spec, or true for a default element spec (defaults to
38646 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38649 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38652 hiddenField: false,
38654 onRender : function(ct, position)
38656 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38658 //this.el.dom.removeAttribute('name');
38659 Roo.log("Changing name?");
38660 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38661 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38663 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38664 // prevent input submission
38665 this.hiddenName = this.name;
38672 validateValue : function(value)
38674 value = this.formatDate(value);
38675 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38676 Roo.log('super failed');
38679 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38682 var svalue = value;
38683 value = this.parseDate(value);
38685 Roo.log('parse date failed' + svalue);
38686 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38689 var time = value.getTime();
38690 if(this.minValue && time < this.minValue.getTime()){
38691 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38694 if(this.maxValue && time > this.maxValue.getTime()){
38695 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38698 if(this.disabledDays){
38699 var day = value.getDay();
38700 for(var i = 0; i < this.disabledDays.length; i++) {
38701 if(day === this.disabledDays[i]){
38702 this.markInvalid(this.disabledDaysText);
38707 var fvalue = this.formatDate(value);
38708 if(this.ddMatch && this.ddMatch.test(fvalue)){
38709 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38716 // Provides logic to override the default TriggerField.validateBlur which just returns true
38717 validateBlur : function(){
38718 return !this.menu || !this.menu.isVisible();
38721 getName: function()
38723 // returns hidden if it's set..
38724 if (!this.rendered) {return ''};
38725 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38730 * Returns the current date value of the date field.
38731 * @return {Date} The date value
38733 getValue : function(){
38735 return this.hiddenField ?
38736 this.hiddenField.value :
38737 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38741 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38742 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38743 * (the default format used is "m/d/y").
38746 //All of these calls set the same date value (May 4, 2006)
38748 //Pass a date object:
38749 var dt = new Date('5/4/06');
38750 dateField.setValue(dt);
38752 //Pass a date string (default format):
38753 dateField.setValue('5/4/06');
38755 //Pass a date string (custom format):
38756 dateField.format = 'Y-m-d';
38757 dateField.setValue('2006-5-4');
38759 * @param {String/Date} date The date or valid date string
38761 setValue : function(date){
38762 if (this.hiddenField) {
38763 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38765 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38766 // make sure the value field is always stored as a date..
38767 this.value = this.parseDate(date);
38773 parseDate : function(value){
38774 if(!value || value instanceof Date){
38777 var v = Date.parseDate(value, this.format);
38778 if (!v && this.useIso) {
38779 v = Date.parseDate(value, 'Y-m-d');
38781 if(!v && this.altFormats){
38782 if(!this.altFormatsArray){
38783 this.altFormatsArray = this.altFormats.split("|");
38785 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38786 v = Date.parseDate(value, this.altFormatsArray[i]);
38793 formatDate : function(date, fmt){
38794 return (!date || !(date instanceof Date)) ?
38795 date : date.dateFormat(fmt || this.format);
38800 select: function(m, d){
38803 this.fireEvent('select', this, d);
38805 show : function(){ // retain focus styling
38809 this.focus.defer(10, this);
38810 var ml = this.menuListeners;
38811 this.menu.un("select", ml.select, this);
38812 this.menu.un("show", ml.show, this);
38813 this.menu.un("hide", ml.hide, this);
38818 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38819 onTriggerClick : function(){
38823 if(this.menu == null){
38824 this.menu = new Roo.menu.DateMenu();
38826 Roo.apply(this.menu.picker, {
38827 showClear: this.allowBlank,
38828 minDate : this.minValue,
38829 maxDate : this.maxValue,
38830 disabledDatesRE : this.ddMatch,
38831 disabledDatesText : this.disabledDatesText,
38832 disabledDays : this.disabledDays,
38833 disabledDaysText : this.disabledDaysText,
38834 format : this.useIso ? 'Y-m-d' : this.format,
38835 minText : String.format(this.minText, this.formatDate(this.minValue)),
38836 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38838 this.menu.on(Roo.apply({}, this.menuListeners, {
38841 this.menu.picker.setValue(this.getValue() || new Date());
38842 this.menu.show(this.el, "tl-bl?");
38845 beforeBlur : function(){
38846 var v = this.parseDate(this.getRawValue());
38856 isDirty : function() {
38857 if(this.disabled) {
38861 if(typeof(this.startValue) === 'undefined'){
38865 return String(this.getValue()) !== String(this.startValue);
38870 * Ext JS Library 1.1.1
38871 * Copyright(c) 2006-2007, Ext JS, LLC.
38873 * Originally Released Under LGPL - original licence link has changed is not relivant.
38876 * <script type="text/javascript">
38880 * @class Roo.form.MonthField
38881 * @extends Roo.form.TriggerField
38882 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38884 * Create a new MonthField
38885 * @param {Object} config
38887 Roo.form.MonthField = function(config){
38889 Roo.form.MonthField.superclass.constructor.call(this, config);
38895 * Fires when a date is selected
38896 * @param {Roo.form.MonthFieeld} combo This combo box
38897 * @param {Date} date The date selected
38904 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38905 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38906 this.ddMatch = null;
38907 if(this.disabledDates){
38908 var dd = this.disabledDates;
38910 for(var i = 0; i < dd.length; i++){
38912 if(i != dd.length-1) re += "|";
38914 this.ddMatch = new RegExp(re + ")");
38918 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38920 * @cfg {String} format
38921 * The default date format string which can be overriden for localization support. The format must be
38922 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38926 * @cfg {String} altFormats
38927 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38928 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38930 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38932 * @cfg {Array} disabledDays
38933 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38935 disabledDays : [0,1,2,3,4,5,6],
38937 * @cfg {String} disabledDaysText
38938 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38940 disabledDaysText : "Disabled",
38942 * @cfg {Array} disabledDates
38943 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38944 * expression so they are very powerful. Some examples:
38946 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38947 * <li>["03/08", "09/16"] would disable those days for every year</li>
38948 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38949 * <li>["03/../2006"] would disable every day in March 2006</li>
38950 * <li>["^03"] would disable every day in every March</li>
38952 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38953 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38955 disabledDates : null,
38957 * @cfg {String} disabledDatesText
38958 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38960 disabledDatesText : "Disabled",
38962 * @cfg {Date/String} minValue
38963 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38964 * valid format (defaults to null).
38968 * @cfg {Date/String} maxValue
38969 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38970 * valid format (defaults to null).
38974 * @cfg {String} minText
38975 * The error text to display when the date in the cell is before minValue (defaults to
38976 * 'The date in this field must be after {minValue}').
38978 minText : "The date in this field must be equal to or after {0}",
38980 * @cfg {String} maxTextf
38981 * The error text to display when the date in the cell is after maxValue (defaults to
38982 * 'The date in this field must be before {maxValue}').
38984 maxText : "The date in this field must be equal to or before {0}",
38986 * @cfg {String} invalidText
38987 * The error text to display when the date in the field is invalid (defaults to
38988 * '{value} is not a valid date - it must be in the format {format}').
38990 invalidText : "{0} is not a valid date - it must be in the format {1}",
38992 * @cfg {String} triggerClass
38993 * An additional CSS class used to style the trigger button. The trigger will always get the
38994 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38995 * which displays a calendar icon).
38997 triggerClass : 'x-form-date-trigger',
39001 * @cfg {Boolean} useIso
39002 * if enabled, then the date field will use a hidden field to store the
39003 * real value as iso formated date. default (true)
39007 * @cfg {String/Object} autoCreate
39008 * A DomHelper element spec, or true for a default element spec (defaults to
39009 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
39012 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
39015 hiddenField: false,
39017 hideMonthPicker : false,
39019 onRender : function(ct, position)
39021 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
39023 this.el.dom.removeAttribute('name');
39024 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
39026 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
39027 // prevent input submission
39028 this.hiddenName = this.name;
39035 validateValue : function(value)
39037 value = this.formatDate(value);
39038 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
39041 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39044 var svalue = value;
39045 value = this.parseDate(value);
39047 this.markInvalid(String.format(this.invalidText, svalue, this.format));
39050 var time = value.getTime();
39051 if(this.minValue && time < this.minValue.getTime()){
39052 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
39055 if(this.maxValue && time > this.maxValue.getTime()){
39056 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
39059 /*if(this.disabledDays){
39060 var day = value.getDay();
39061 for(var i = 0; i < this.disabledDays.length; i++) {
39062 if(day === this.disabledDays[i]){
39063 this.markInvalid(this.disabledDaysText);
39069 var fvalue = this.formatDate(value);
39070 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
39071 this.markInvalid(String.format(this.disabledDatesText, fvalue));
39079 // Provides logic to override the default TriggerField.validateBlur which just returns true
39080 validateBlur : function(){
39081 return !this.menu || !this.menu.isVisible();
39085 * Returns the current date value of the date field.
39086 * @return {Date} The date value
39088 getValue : function(){
39092 return this.hiddenField ?
39093 this.hiddenField.value :
39094 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
39098 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
39099 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
39100 * (the default format used is "m/d/y").
39103 //All of these calls set the same date value (May 4, 2006)
39105 //Pass a date object:
39106 var dt = new Date('5/4/06');
39107 monthField.setValue(dt);
39109 //Pass a date string (default format):
39110 monthField.setValue('5/4/06');
39112 //Pass a date string (custom format):
39113 monthField.format = 'Y-m-d';
39114 monthField.setValue('2006-5-4');
39116 * @param {String/Date} date The date or valid date string
39118 setValue : function(date){
39119 Roo.log('month setValue' + date);
39120 // can only be first of month..
39122 var val = this.parseDate(date);
39124 if (this.hiddenField) {
39125 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
39127 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
39128 this.value = this.parseDate(date);
39132 parseDate : function(value){
39133 if(!value || value instanceof Date){
39134 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
39137 var v = Date.parseDate(value, this.format);
39138 if (!v && this.useIso) {
39139 v = Date.parseDate(value, 'Y-m-d');
39143 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
39147 if(!v && this.altFormats){
39148 if(!this.altFormatsArray){
39149 this.altFormatsArray = this.altFormats.split("|");
39151 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
39152 v = Date.parseDate(value, this.altFormatsArray[i]);
39159 formatDate : function(date, fmt){
39160 return (!date || !(date instanceof Date)) ?
39161 date : date.dateFormat(fmt || this.format);
39166 select: function(m, d){
39168 this.fireEvent('select', this, d);
39170 show : function(){ // retain focus styling
39174 this.focus.defer(10, this);
39175 var ml = this.menuListeners;
39176 this.menu.un("select", ml.select, this);
39177 this.menu.un("show", ml.show, this);
39178 this.menu.un("hide", ml.hide, this);
39182 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
39183 onTriggerClick : function(){
39187 if(this.menu == null){
39188 this.menu = new Roo.menu.DateMenu();
39192 Roo.apply(this.menu.picker, {
39194 showClear: this.allowBlank,
39195 minDate : this.minValue,
39196 maxDate : this.maxValue,
39197 disabledDatesRE : this.ddMatch,
39198 disabledDatesText : this.disabledDatesText,
39200 format : this.useIso ? 'Y-m-d' : this.format,
39201 minText : String.format(this.minText, this.formatDate(this.minValue)),
39202 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39205 this.menu.on(Roo.apply({}, this.menuListeners, {
39213 // hide month picker get's called when we called by 'before hide';
39215 var ignorehide = true;
39216 p.hideMonthPicker = function(disableAnim){
39220 if(this.monthPicker){
39221 Roo.log("hideMonthPicker called");
39222 if(disableAnim === true){
39223 this.monthPicker.hide();
39225 this.monthPicker.slideOut('t', {duration:.2});
39226 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39227 p.fireEvent("select", this, this.value);
39233 Roo.log('picker set value');
39234 Roo.log(this.getValue());
39235 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39236 m.show(this.el, 'tl-bl?');
39237 ignorehide = false;
39238 // this will trigger hideMonthPicker..
39241 // hidden the day picker
39242 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39248 p.showMonthPicker.defer(100, p);
39254 beforeBlur : function(){
39255 var v = this.parseDate(this.getRawValue());
39261 /** @cfg {Boolean} grow @hide */
39262 /** @cfg {Number} growMin @hide */
39263 /** @cfg {Number} growMax @hide */
39270 * Ext JS Library 1.1.1
39271 * Copyright(c) 2006-2007, Ext JS, LLC.
39273 * Originally Released Under LGPL - original licence link has changed is not relivant.
39276 * <script type="text/javascript">
39281 * @class Roo.form.ComboBox
39282 * @extends Roo.form.TriggerField
39283 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39285 * Create a new ComboBox.
39286 * @param {Object} config Configuration options
39288 Roo.form.ComboBox = function(config){
39289 Roo.form.ComboBox.superclass.constructor.call(this, config);
39293 * Fires when the dropdown list is expanded
39294 * @param {Roo.form.ComboBox} combo This combo box
39299 * Fires when the dropdown list is collapsed
39300 * @param {Roo.form.ComboBox} combo This combo box
39304 * @event beforeselect
39305 * Fires before a list item is selected. Return false to cancel the selection.
39306 * @param {Roo.form.ComboBox} combo This combo box
39307 * @param {Roo.data.Record} record The data record returned from the underlying store
39308 * @param {Number} index The index of the selected item in the dropdown list
39310 'beforeselect' : true,
39313 * Fires when a list item is selected
39314 * @param {Roo.form.ComboBox} combo This combo box
39315 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39316 * @param {Number} index The index of the selected item in the dropdown list
39320 * @event beforequery
39321 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39322 * The event object passed has these properties:
39323 * @param {Roo.form.ComboBox} combo This combo box
39324 * @param {String} query The query
39325 * @param {Boolean} forceAll true to force "all" query
39326 * @param {Boolean} cancel true to cancel the query
39327 * @param {Object} e The query event object
39329 'beforequery': true,
39332 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39333 * @param {Roo.form.ComboBox} combo This combo box
39338 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39339 * @param {Roo.form.ComboBox} combo This combo box
39340 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39346 if(this.transform){
39347 this.allowDomMove = false;
39348 var s = Roo.getDom(this.transform);
39349 if(!this.hiddenName){
39350 this.hiddenName = s.name;
39353 this.mode = 'local';
39354 var d = [], opts = s.options;
39355 for(var i = 0, len = opts.length;i < len; i++){
39357 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39359 this.value = value;
39361 d.push([value, o.text]);
39363 this.store = new Roo.data.SimpleStore({
39365 fields: ['value', 'text'],
39368 this.valueField = 'value';
39369 this.displayField = 'text';
39371 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39372 if(!this.lazyRender){
39373 this.target = true;
39374 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39375 s.parentNode.removeChild(s); // remove it
39376 this.render(this.el.parentNode);
39378 s.parentNode.removeChild(s); // remove it
39383 this.store = Roo.factory(this.store, Roo.data);
39386 this.selectedIndex = -1;
39387 if(this.mode == 'local'){
39388 if(config.queryDelay === undefined){
39389 this.queryDelay = 10;
39391 if(config.minChars === undefined){
39397 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39399 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39402 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39403 * rendering into an Roo.Editor, defaults to false)
39406 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39407 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39410 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39413 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39414 * the dropdown list (defaults to undefined, with no header element)
39418 * @cfg {String/Roo.Template} tpl The template to use to render the output
39422 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39424 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39426 listWidth: undefined,
39428 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39429 * mode = 'remote' or 'text' if mode = 'local')
39431 displayField: undefined,
39433 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39434 * mode = 'remote' or 'value' if mode = 'local').
39435 * Note: use of a valueField requires the user make a selection
39436 * in order for a value to be mapped.
39438 valueField: undefined,
39442 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39443 * field's data value (defaults to the underlying DOM element's name)
39445 hiddenName: undefined,
39447 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39451 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39453 selectedClass: 'x-combo-selected',
39455 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39456 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39457 * which displays a downward arrow icon).
39459 triggerClass : 'x-form-arrow-trigger',
39461 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39465 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39466 * anchor positions (defaults to 'tl-bl')
39468 listAlign: 'tl-bl?',
39470 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39474 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39475 * query specified by the allQuery config option (defaults to 'query')
39477 triggerAction: 'query',
39479 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39480 * (defaults to 4, does not apply if editable = false)
39484 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39485 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39489 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39490 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39494 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39495 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39499 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39500 * when editable = true (defaults to false)
39502 selectOnFocus:false,
39504 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39506 queryParam: 'query',
39508 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39509 * when mode = 'remote' (defaults to 'Loading...')
39511 loadingText: 'Loading...',
39513 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39517 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39521 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39522 * traditional select (defaults to true)
39526 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39530 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39534 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39535 * listWidth has a higher value)
39539 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39540 * allow the user to set arbitrary text into the field (defaults to false)
39542 forceSelection:false,
39544 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39545 * if typeAhead = true (defaults to 250)
39547 typeAheadDelay : 250,
39549 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39550 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39552 valueNotFoundText : undefined,
39554 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39556 blockFocus : false,
39559 * @cfg {Boolean} disableClear Disable showing of clear button.
39561 disableClear : false,
39563 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39565 alwaysQuery : false,
39571 // element that contains real text value.. (when hidden is used..)
39574 onRender : function(ct, position){
39575 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39576 if(this.hiddenName){
39577 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39579 this.hiddenField.value =
39580 this.hiddenValue !== undefined ? this.hiddenValue :
39581 this.value !== undefined ? this.value : '';
39583 // prevent input submission
39584 this.el.dom.removeAttribute('name');
39589 this.el.dom.setAttribute('autocomplete', 'off');
39592 var cls = 'x-combo-list';
39594 this.list = new Roo.Layer({
39595 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39598 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39599 this.list.setWidth(lw);
39600 this.list.swallowEvent('mousewheel');
39601 this.assetHeight = 0;
39604 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39605 this.assetHeight += this.header.getHeight();
39608 this.innerList = this.list.createChild({cls:cls+'-inner'});
39609 this.innerList.on('mouseover', this.onViewOver, this);
39610 this.innerList.on('mousemove', this.onViewMove, this);
39611 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39613 if(this.allowBlank && !this.pageSize && !this.disableClear){
39614 this.footer = this.list.createChild({cls:cls+'-ft'});
39615 this.pageTb = new Roo.Toolbar(this.footer);
39619 this.footer = this.list.createChild({cls:cls+'-ft'});
39620 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39621 {pageSize: this.pageSize});
39625 if (this.pageTb && this.allowBlank && !this.disableClear) {
39627 this.pageTb.add(new Roo.Toolbar.Fill(), {
39628 cls: 'x-btn-icon x-btn-clear',
39630 handler: function()
39633 _this.clearValue();
39634 _this.onSelect(false, -1);
39639 this.assetHeight += this.footer.getHeight();
39644 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39647 this.view = new Roo.View(this.innerList, this.tpl, {
39648 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39651 this.view.on('click', this.onViewClick, this);
39653 this.store.on('beforeload', this.onBeforeLoad, this);
39654 this.store.on('load', this.onLoad, this);
39655 this.store.on('loadexception', this.onLoadException, this);
39657 if(this.resizable){
39658 this.resizer = new Roo.Resizable(this.list, {
39659 pinned:true, handles:'se'
39661 this.resizer.on('resize', function(r, w, h){
39662 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39663 this.listWidth = w;
39664 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39665 this.restrictHeight();
39667 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39669 if(!this.editable){
39670 this.editable = true;
39671 this.setEditable(false);
39675 if (typeof(this.events.add.listeners) != 'undefined') {
39677 this.addicon = this.wrap.createChild(
39678 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39680 this.addicon.on('click', function(e) {
39681 this.fireEvent('add', this);
39684 if (typeof(this.events.edit.listeners) != 'undefined') {
39686 this.editicon = this.wrap.createChild(
39687 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39688 if (this.addicon) {
39689 this.editicon.setStyle('margin-left', '40px');
39691 this.editicon.on('click', function(e) {
39693 // we fire even if inothing is selected..
39694 this.fireEvent('edit', this, this.lastData );
39704 initEvents : function(){
39705 Roo.form.ComboBox.superclass.initEvents.call(this);
39707 this.keyNav = new Roo.KeyNav(this.el, {
39708 "up" : function(e){
39709 this.inKeyMode = true;
39713 "down" : function(e){
39714 if(!this.isExpanded()){
39715 this.onTriggerClick();
39717 this.inKeyMode = true;
39722 "enter" : function(e){
39723 this.onViewClick();
39727 "esc" : function(e){
39731 "tab" : function(e){
39732 this.onViewClick(false);
39733 this.fireEvent("specialkey", this, e);
39739 doRelay : function(foo, bar, hname){
39740 if(hname == 'down' || this.scope.isExpanded()){
39741 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39748 this.queryDelay = Math.max(this.queryDelay || 10,
39749 this.mode == 'local' ? 10 : 250);
39750 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39751 if(this.typeAhead){
39752 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39754 if(this.editable !== false){
39755 this.el.on("keyup", this.onKeyUp, this);
39757 if(this.forceSelection){
39758 this.on('blur', this.doForce, this);
39762 onDestroy : function(){
39764 this.view.setStore(null);
39765 this.view.el.removeAllListeners();
39766 this.view.el.remove();
39767 this.view.purgeListeners();
39770 this.list.destroy();
39773 this.store.un('beforeload', this.onBeforeLoad, this);
39774 this.store.un('load', this.onLoad, this);
39775 this.store.un('loadexception', this.onLoadException, this);
39777 Roo.form.ComboBox.superclass.onDestroy.call(this);
39781 fireKey : function(e){
39782 if(e.isNavKeyPress() && !this.list.isVisible()){
39783 this.fireEvent("specialkey", this, e);
39788 onResize: function(w, h){
39789 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39791 if(typeof w != 'number'){
39792 // we do not handle it!?!?
39795 var tw = this.trigger.getWidth();
39796 tw += this.addicon ? this.addicon.getWidth() : 0;
39797 tw += this.editicon ? this.editicon.getWidth() : 0;
39799 this.el.setWidth( this.adjustWidth('input', x));
39801 this.trigger.setStyle('left', x+'px');
39803 if(this.list && this.listWidth === undefined){
39804 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39805 this.list.setWidth(lw);
39806 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39814 * Allow or prevent the user from directly editing the field text. If false is passed,
39815 * the user will only be able to select from the items defined in the dropdown list. This method
39816 * is the runtime equivalent of setting the 'editable' config option at config time.
39817 * @param {Boolean} value True to allow the user to directly edit the field text
39819 setEditable : function(value){
39820 if(value == this.editable){
39823 this.editable = value;
39825 this.el.dom.setAttribute('readOnly', true);
39826 this.el.on('mousedown', this.onTriggerClick, this);
39827 this.el.addClass('x-combo-noedit');
39829 this.el.dom.setAttribute('readOnly', false);
39830 this.el.un('mousedown', this.onTriggerClick, this);
39831 this.el.removeClass('x-combo-noedit');
39836 onBeforeLoad : function(){
39837 if(!this.hasFocus){
39840 this.innerList.update(this.loadingText ?
39841 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39842 this.restrictHeight();
39843 this.selectedIndex = -1;
39847 onLoad : function(){
39848 if(!this.hasFocus){
39851 if(this.store.getCount() > 0){
39853 this.restrictHeight();
39854 if(this.lastQuery == this.allQuery){
39856 this.el.dom.select();
39858 if(!this.selectByValue(this.value, true)){
39859 this.select(0, true);
39863 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39864 this.taTask.delay(this.typeAheadDelay);
39868 this.onEmptyResults();
39873 onLoadException : function()
39876 Roo.log(this.store.reader.jsonData);
39877 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39878 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39884 onTypeAhead : function(){
39885 if(this.store.getCount() > 0){
39886 var r = this.store.getAt(0);
39887 var newValue = r.data[this.displayField];
39888 var len = newValue.length;
39889 var selStart = this.getRawValue().length;
39890 if(selStart != len){
39891 this.setRawValue(newValue);
39892 this.selectText(selStart, newValue.length);
39898 onSelect : function(record, index){
39899 if(this.fireEvent('beforeselect', this, record, index) !== false){
39900 this.setFromData(index > -1 ? record.data : false);
39902 this.fireEvent('select', this, record, index);
39907 * Returns the currently selected field value or empty string if no value is set.
39908 * @return {String} value The selected value
39910 getValue : function(){
39911 if(this.valueField){
39912 return typeof this.value != 'undefined' ? this.value : '';
39914 return Roo.form.ComboBox.superclass.getValue.call(this);
39918 * Clears any text/value currently set in the field
39920 clearValue : function(){
39921 if(this.hiddenField){
39922 this.hiddenField.value = '';
39925 this.setRawValue('');
39926 this.lastSelectionText = '';
39931 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39932 * will be displayed in the field. If the value does not match the data value of an existing item,
39933 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39934 * Otherwise the field will be blank (although the value will still be set).
39935 * @param {String} value The value to match
39937 setValue : function(v){
39939 if(this.valueField){
39940 var r = this.findRecord(this.valueField, v);
39942 text = r.data[this.displayField];
39943 }else if(this.valueNotFoundText !== undefined){
39944 text = this.valueNotFoundText;
39947 this.lastSelectionText = text;
39948 if(this.hiddenField){
39949 this.hiddenField.value = v;
39951 Roo.form.ComboBox.superclass.setValue.call(this, text);
39955 * @property {Object} the last set data for the element
39960 * Sets the value of the field based on a object which is related to the record format for the store.
39961 * @param {Object} value the value to set as. or false on reset?
39963 setFromData : function(o){
39964 var dv = ''; // display value
39965 var vv = ''; // value value..
39967 if (this.displayField) {
39968 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39970 // this is an error condition!!!
39971 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39974 if(this.valueField){
39975 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39977 if(this.hiddenField){
39978 this.hiddenField.value = vv;
39980 this.lastSelectionText = dv;
39981 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39985 // no hidden field.. - we store the value in 'value', but still display
39986 // display field!!!!
39987 this.lastSelectionText = dv;
39988 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39994 reset : function(){
39995 // overridden so that last data is reset..
39996 this.setValue(this.resetValue);
39997 this.clearInvalid();
39998 this.lastData = false;
40000 this.view.clearSelections();
40004 findRecord : function(prop, value){
40006 if(this.store.getCount() > 0){
40007 this.store.each(function(r){
40008 if(r.data[prop] == value){
40018 getName: function()
40020 // returns hidden if it's set..
40021 if (!this.rendered) {return ''};
40022 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40026 onViewMove : function(e, t){
40027 this.inKeyMode = false;
40031 onViewOver : function(e, t){
40032 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
40035 var item = this.view.findItemFromChild(t);
40037 var index = this.view.indexOf(item);
40038 this.select(index, false);
40043 onViewClick : function(doFocus)
40045 var index = this.view.getSelectedIndexes()[0];
40046 var r = this.store.getAt(index);
40048 this.onSelect(r, index);
40050 if(doFocus !== false && !this.blockFocus){
40056 restrictHeight : function(){
40057 this.innerList.dom.style.height = '';
40058 var inner = this.innerList.dom;
40059 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
40060 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
40061 this.list.beginUpdate();
40062 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
40063 this.list.alignTo(this.el, this.listAlign);
40064 this.list.endUpdate();
40068 onEmptyResults : function(){
40073 * Returns true if the dropdown list is expanded, else false.
40075 isExpanded : function(){
40076 return this.list.isVisible();
40080 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
40081 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40082 * @param {String} value The data value of the item to select
40083 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40084 * selected item if it is not currently in view (defaults to true)
40085 * @return {Boolean} True if the value matched an item in the list, else false
40087 selectByValue : function(v, scrollIntoView){
40088 if(v !== undefined && v !== null){
40089 var r = this.findRecord(this.valueField || this.displayField, v);
40091 this.select(this.store.indexOf(r), scrollIntoView);
40099 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
40100 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40101 * @param {Number} index The zero-based index of the list item to select
40102 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40103 * selected item if it is not currently in view (defaults to true)
40105 select : function(index, scrollIntoView){
40106 this.selectedIndex = index;
40107 this.view.select(index);
40108 if(scrollIntoView !== false){
40109 var el = this.view.getNode(index);
40111 this.innerList.scrollChildIntoView(el, false);
40117 selectNext : function(){
40118 var ct = this.store.getCount();
40120 if(this.selectedIndex == -1){
40122 }else if(this.selectedIndex < ct-1){
40123 this.select(this.selectedIndex+1);
40129 selectPrev : function(){
40130 var ct = this.store.getCount();
40132 if(this.selectedIndex == -1){
40134 }else if(this.selectedIndex != 0){
40135 this.select(this.selectedIndex-1);
40141 onKeyUp : function(e){
40142 if(this.editable !== false && !e.isSpecialKey()){
40143 this.lastKey = e.getKey();
40144 this.dqTask.delay(this.queryDelay);
40149 validateBlur : function(){
40150 return !this.list || !this.list.isVisible();
40154 initQuery : function(){
40155 this.doQuery(this.getRawValue());
40159 doForce : function(){
40160 if(this.el.dom.value.length > 0){
40161 this.el.dom.value =
40162 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
40168 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
40169 * query allowing the query action to be canceled if needed.
40170 * @param {String} query The SQL query to execute
40171 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
40172 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
40173 * saved in the current store (defaults to false)
40175 doQuery : function(q, forceAll){
40176 if(q === undefined || q === null){
40181 forceAll: forceAll,
40185 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
40189 forceAll = qe.forceAll;
40190 if(forceAll === true || (q.length >= this.minChars)){
40191 if(this.lastQuery != q || this.alwaysQuery){
40192 this.lastQuery = q;
40193 if(this.mode == 'local'){
40194 this.selectedIndex = -1;
40196 this.store.clearFilter();
40198 this.store.filter(this.displayField, q);
40202 this.store.baseParams[this.queryParam] = q;
40204 params: this.getParams(q)
40209 this.selectedIndex = -1;
40216 getParams : function(q){
40218 //p[this.queryParam] = q;
40221 p.limit = this.pageSize;
40227 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40229 collapse : function(){
40230 if(!this.isExpanded()){
40234 Roo.get(document).un('mousedown', this.collapseIf, this);
40235 Roo.get(document).un('mousewheel', this.collapseIf, this);
40236 if (!this.editable) {
40237 Roo.get(document).un('keydown', this.listKeyPress, this);
40239 this.fireEvent('collapse', this);
40243 collapseIf : function(e){
40244 if(!e.within(this.wrap) && !e.within(this.list)){
40250 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40252 expand : function(){
40253 if(this.isExpanded() || !this.hasFocus){
40256 this.list.alignTo(this.el, this.listAlign);
40258 Roo.get(document).on('mousedown', this.collapseIf, this);
40259 Roo.get(document).on('mousewheel', this.collapseIf, this);
40260 if (!this.editable) {
40261 Roo.get(document).on('keydown', this.listKeyPress, this);
40264 this.fireEvent('expand', this);
40268 // Implements the default empty TriggerField.onTriggerClick function
40269 onTriggerClick : function(){
40273 if(this.isExpanded()){
40275 if (!this.blockFocus) {
40280 this.hasFocus = true;
40281 if(this.triggerAction == 'all') {
40282 this.doQuery(this.allQuery, true);
40284 this.doQuery(this.getRawValue());
40286 if (!this.blockFocus) {
40291 listKeyPress : function(e)
40293 //Roo.log('listkeypress');
40294 // scroll to first matching element based on key pres..
40295 if (e.isSpecialKey()) {
40298 var k = String.fromCharCode(e.getKey()).toUpperCase();
40301 var csel = this.view.getSelectedNodes();
40302 var cselitem = false;
40304 var ix = this.view.indexOf(csel[0]);
40305 cselitem = this.store.getAt(ix);
40306 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40312 this.store.each(function(v) {
40314 // start at existing selection.
40315 if (cselitem.id == v.id) {
40321 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40322 match = this.store.indexOf(v);
40327 if (match === false) {
40328 return true; // no more action?
40331 this.view.select(match);
40332 var sn = Roo.get(this.view.getSelectedNodes()[0])
40333 sn.scrollIntoView(sn.dom.parentNode, false);
40337 * @cfg {Boolean} grow
40341 * @cfg {Number} growMin
40345 * @cfg {Number} growMax
40353 * Copyright(c) 2010-2012, Roo J Solutions Limited
40360 * @class Roo.form.ComboBoxArray
40361 * @extends Roo.form.TextField
40362 * A facebook style adder... for lists of email / people / countries etc...
40363 * pick multiple items from a combo box, and shows each one.
40365 * Fred [x] Brian [x] [Pick another |v]
40368 * For this to work: it needs various extra information
40369 * - normal combo problay has
40371 * + displayField, valueField
40373 * For our purpose...
40376 * If we change from 'extends' to wrapping...
40383 * Create a new ComboBoxArray.
40384 * @param {Object} config Configuration options
40388 Roo.form.ComboBoxArray = function(config)
40392 * @event beforeremove
40393 * Fires before 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
40397 'beforeremove' : true,
40400 * Fires when remove the value from the list
40401 * @param {Roo.form.ComboBoxArray} _self This combo box array
40402 * @param {Roo.form.ComboBoxArray.Item} item removed item
40409 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40411 this.items = new Roo.util.MixedCollection(false);
40413 // construct the child combo...
40423 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40426 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40431 // behavies liek a hiddne field
40432 inputType: 'hidden',
40434 * @cfg {Number} width The width of the box that displays the selected element
40441 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40445 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40447 hiddenName : false,
40450 // private the array of items that are displayed..
40452 // private - the hidden field el.
40454 // private - the filed el..
40457 //validateValue : function() { return true; }, // all values are ok!
40458 //onAddClick: function() { },
40460 onRender : function(ct, position)
40463 // create the standard hidden element
40464 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40467 // give fake names to child combo;
40468 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40469 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40471 this.combo = Roo.factory(this.combo, Roo.form);
40472 this.combo.onRender(ct, position);
40473 if (typeof(this.combo.width) != 'undefined') {
40474 this.combo.onResize(this.combo.width,0);
40477 this.combo.initEvents();
40479 // assigned so form know we need to do this..
40480 this.store = this.combo.store;
40481 this.valueField = this.combo.valueField;
40482 this.displayField = this.combo.displayField ;
40485 this.combo.wrap.addClass('x-cbarray-grp');
40487 var cbwrap = this.combo.wrap.createChild(
40488 {tag: 'div', cls: 'x-cbarray-cb'},
40493 this.hiddenEl = this.combo.wrap.createChild({
40494 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40496 this.el = this.combo.wrap.createChild({
40497 tag: 'input', type:'hidden' , name: this.name, value : ''
40499 // this.el.dom.removeAttribute("name");
40502 this.outerWrap = this.combo.wrap;
40503 this.wrap = cbwrap;
40505 this.outerWrap.setWidth(this.width);
40506 this.outerWrap.dom.removeChild(this.el.dom);
40508 this.wrap.dom.appendChild(this.el.dom);
40509 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40510 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40512 this.combo.trigger.setStyle('position','relative');
40513 this.combo.trigger.setStyle('left', '0px');
40514 this.combo.trigger.setStyle('top', '2px');
40516 this.combo.el.setStyle('vertical-align', 'text-bottom');
40518 //this.trigger.setStyle('vertical-align', 'top');
40520 // this should use the code from combo really... on('add' ....)
40524 this.adder = this.outerWrap.createChild(
40525 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40527 this.adder.on('click', function(e) {
40528 _t.fireEvent('adderclick', this, e);
40532 //this.adder.on('click', this.onAddClick, _t);
40535 this.combo.on('select', function(cb, rec, ix) {
40536 this.addItem(rec.data);
40539 cb.el.dom.value = '';
40540 //cb.lastData = rec.data;
40549 getName: function()
40551 // returns hidden if it's set..
40552 if (!this.rendered) {return ''};
40553 return this.hiddenName ? this.hiddenName : this.name;
40558 onResize: function(w, h){
40561 // not sure if this is needed..
40562 //this.combo.onResize(w,h);
40564 if(typeof w != 'number'){
40565 // we do not handle it!?!?
40568 var tw = this.combo.trigger.getWidth();
40569 tw += this.addicon ? this.addicon.getWidth() : 0;
40570 tw += this.editicon ? this.editicon.getWidth() : 0;
40572 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40574 this.combo.trigger.setStyle('left', '0px');
40576 if(this.list && this.listWidth === undefined){
40577 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40578 this.list.setWidth(lw);
40579 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40586 addItem: function(rec)
40588 var valueField = this.combo.valueField;
40589 var displayField = this.combo.displayField;
40590 if (this.items.indexOfKey(rec[valueField]) > -1) {
40591 //console.log("GOT " + rec.data.id);
40595 var x = new Roo.form.ComboBoxArray.Item({
40596 //id : rec[this.idField],
40598 displayField : displayField ,
40599 tipField : displayField ,
40603 this.items.add(rec[valueField],x);
40604 // add it before the element..
40605 this.updateHiddenEl();
40606 x.render(this.outerWrap, this.wrap.dom);
40607 // add the image handler..
40610 updateHiddenEl : function()
40613 if (!this.hiddenEl) {
40617 var idField = this.combo.valueField;
40619 this.items.each(function(f) {
40620 ar.push(f.data[idField]);
40623 this.hiddenEl.dom.value = ar.join(',');
40629 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40630 this.items.each(function(f) {
40633 this.el.dom.value = '';
40634 if (this.hiddenEl) {
40635 this.hiddenEl.dom.value = '';
40639 getValue: function()
40641 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40643 setValue: function(v) // not a valid action - must use addItems..
40650 if (this.store.isLocal && (typeof(v) == 'string')) {
40651 // then we can use the store to find the values..
40652 // comma seperated at present.. this needs to allow JSON based encoding..
40653 this.hiddenEl.value = v;
40655 Roo.each(v.split(','), function(k) {
40656 Roo.log("CHECK " + this.valueField + ',' + k);
40657 var li = this.store.query(this.valueField, k);
40662 add[this.valueField] = k;
40663 add[this.displayField] = li.item(0).data[this.displayField];
40669 if (typeof(v) == 'object' ) {
40670 // then let's assume it's an array of objects..
40671 Roo.each(v, function(l) {
40679 setFromData: function(v)
40681 // this recieves an object, if setValues is called.
40683 this.el.dom.value = v[this.displayField];
40684 this.hiddenEl.dom.value = v[this.valueField];
40685 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40688 var kv = v[this.valueField];
40689 var dv = v[this.displayField];
40690 kv = typeof(kv) != 'string' ? '' : kv;
40691 dv = typeof(dv) != 'string' ? '' : dv;
40694 var keys = kv.split(',');
40695 var display = dv.split(',');
40696 for (var i = 0 ; i < keys.length; i++) {
40699 add[this.valueField] = keys[i];
40700 add[this.displayField] = display[i];
40708 * Validates the combox array value
40709 * @return {Boolean} True if the value is valid, else false
40711 validate : function(){
40712 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40713 this.clearInvalid();
40719 validateValue : function(value){
40720 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40728 isDirty : function() {
40729 if(this.disabled) {
40734 var d = Roo.decode(String(this.originalValue));
40736 return String(this.getValue()) !== String(this.originalValue);
40739 var originalValue = [];
40741 for (var i = 0; i < d.length; i++){
40742 originalValue.push(d[i][this.valueField]);
40745 return String(this.getValue()) !== String(originalValue.join(','));
40754 * @class Roo.form.ComboBoxArray.Item
40755 * @extends Roo.BoxComponent
40756 * A selected item in the list
40757 * Fred [x] Brian [x] [Pick another |v]
40760 * Create a new item.
40761 * @param {Object} config Configuration options
40764 Roo.form.ComboBoxArray.Item = function(config) {
40765 config.id = Roo.id();
40766 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40769 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40772 displayField : false,
40776 defaultAutoCreate : {
40778 cls: 'x-cbarray-item',
40785 src : Roo.BLANK_IMAGE_URL ,
40793 onRender : function(ct, position)
40795 Roo.form.Field.superclass.onRender.call(this, ct, position);
40798 var cfg = this.getAutoCreate();
40799 this.el = ct.createChild(cfg, position);
40802 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40804 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40805 this.cb.renderer(this.data) :
40806 String.format('{0}',this.data[this.displayField]);
40809 this.el.child('div').dom.setAttribute('qtip',
40810 String.format('{0}',this.data[this.tipField])
40813 this.el.child('img').on('click', this.remove, this);
40817 remove : function()
40819 if(this.cb.disabled){
40823 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
40824 this.cb.items.remove(this);
40825 this.el.child('img').un('click', this.remove, this);
40827 this.cb.updateHiddenEl();
40829 this.cb.fireEvent('remove', this.cb, this);
40835 * Ext JS Library 1.1.1
40836 * Copyright(c) 2006-2007, Ext JS, LLC.
40838 * Originally Released Under LGPL - original licence link has changed is not relivant.
40841 * <script type="text/javascript">
40844 * @class Roo.form.Checkbox
40845 * @extends Roo.form.Field
40846 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40848 * Creates a new Checkbox
40849 * @param {Object} config Configuration options
40851 Roo.form.Checkbox = function(config){
40852 Roo.form.Checkbox.superclass.constructor.call(this, config);
40856 * Fires when the checkbox is checked or unchecked.
40857 * @param {Roo.form.Checkbox} this This checkbox
40858 * @param {Boolean} checked The new checked value
40864 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40866 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40868 focusClass : undefined,
40870 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40872 fieldClass: "x-form-field",
40874 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40878 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40879 * {tag: "input", type: "checkbox", autocomplete: "off"})
40881 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40883 * @cfg {String} boxLabel The text that appears beside the checkbox
40887 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40891 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40893 valueOff: '0', // value when not checked..
40895 actionMode : 'viewEl',
40898 itemCls : 'x-menu-check-item x-form-item',
40899 groupClass : 'x-menu-group-item',
40900 inputType : 'hidden',
40903 inSetChecked: false, // check that we are not calling self...
40905 inputElement: false, // real input element?
40906 basedOn: false, // ????
40908 isFormField: true, // not sure where this is needed!!!!
40910 onResize : function(){
40911 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40912 if(!this.boxLabel){
40913 this.el.alignTo(this.wrap, 'c-c');
40917 initEvents : function(){
40918 Roo.form.Checkbox.superclass.initEvents.call(this);
40919 this.el.on("click", this.onClick, this);
40920 this.el.on("change", this.onClick, this);
40924 getResizeEl : function(){
40928 getPositionEl : function(){
40933 onRender : function(ct, position){
40934 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40936 if(this.inputValue !== undefined){
40937 this.el.dom.value = this.inputValue;
40940 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40941 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40942 var viewEl = this.wrap.createChild({
40943 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40944 this.viewEl = viewEl;
40945 this.wrap.on('click', this.onClick, this);
40947 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40948 this.el.on('propertychange', this.setFromHidden, this); //ie
40953 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40954 // viewEl.on('click', this.onClick, this);
40956 //if(this.checked){
40957 this.setChecked(this.checked);
40959 //this.checked = this.el.dom;
40965 initValue : Roo.emptyFn,
40968 * Returns the checked state of the checkbox.
40969 * @return {Boolean} True if checked, else false
40971 getValue : function(){
40973 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40975 return this.valueOff;
40980 onClick : function(){
40981 if (this.disabled) {
40984 this.setChecked(!this.checked);
40986 //if(this.el.dom.checked != this.checked){
40987 // this.setValue(this.el.dom.checked);
40992 * Sets the checked state of the checkbox.
40993 * On is always based on a string comparison between inputValue and the param.
40994 * @param {Boolean/String} value - the value to set
40995 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40997 setValue : function(v,suppressEvent){
41000 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
41001 //if(this.el && this.el.dom){
41002 // this.el.dom.checked = this.checked;
41003 // this.el.dom.defaultChecked = this.checked;
41005 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
41006 //this.fireEvent("check", this, this.checked);
41009 setChecked : function(state,suppressEvent)
41011 if (this.inSetChecked) {
41012 this.checked = state;
41018 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
41020 this.checked = state;
41021 if(suppressEvent !== true){
41022 this.fireEvent('check', this, state);
41024 this.inSetChecked = true;
41025 this.el.dom.value = state ? this.inputValue : this.valueOff;
41026 this.inSetChecked = false;
41029 // handle setting of hidden value by some other method!!?!?
41030 setFromHidden: function()
41035 //console.log("SET FROM HIDDEN");
41036 //alert('setFrom hidden');
41037 this.setValue(this.el.dom.value);
41040 onDestroy : function()
41043 Roo.get(this.viewEl).remove();
41046 Roo.form.Checkbox.superclass.onDestroy.call(this);
41051 * Ext JS Library 1.1.1
41052 * Copyright(c) 2006-2007, Ext JS, LLC.
41054 * Originally Released Under LGPL - original licence link has changed is not relivant.
41057 * <script type="text/javascript">
41061 * @class Roo.form.Radio
41062 * @extends Roo.form.Checkbox
41063 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
41064 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
41066 * Creates a new Radio
41067 * @param {Object} config Configuration options
41069 Roo.form.Radio = function(){
41070 Roo.form.Radio.superclass.constructor.apply(this, arguments);
41072 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
41073 inputType: 'radio',
41076 * If this radio is part of a group, it will return the selected value
41079 getGroupValue : function(){
41080 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
41084 onRender : function(ct, position){
41085 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
41087 if(this.inputValue !== undefined){
41088 this.el.dom.value = this.inputValue;
41091 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
41092 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
41093 //var viewEl = this.wrap.createChild({
41094 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
41095 //this.viewEl = viewEl;
41096 //this.wrap.on('click', this.onClick, this);
41098 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
41099 //this.el.on('propertychange', this.setFromHidden, this); //ie
41104 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
41105 // viewEl.on('click', this.onClick, this);
41108 this.el.dom.checked = 'checked' ;
41114 });//<script type="text/javascript">
41117 * Based Ext JS Library 1.1.1
41118 * Copyright(c) 2006-2007, Ext JS, LLC.
41124 * @class Roo.HtmlEditorCore
41125 * @extends Roo.Component
41126 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
41128 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
41131 Roo.HtmlEditorCore = function(config){
41134 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
41139 * @event initialize
41140 * Fires when the editor is fully initialized (including the iframe)
41141 * @param {Roo.HtmlEditorCore} this
41146 * Fires when the editor is first receives the focus. Any insertion must wait
41147 * until after this event.
41148 * @param {Roo.HtmlEditorCore} this
41152 * @event beforesync
41153 * Fires before the textarea is updated with content from the editor iframe. Return false
41154 * to cancel the sync.
41155 * @param {Roo.HtmlEditorCore} this
41156 * @param {String} html
41160 * @event beforepush
41161 * Fires before the iframe editor is updated with content from the textarea. Return false
41162 * to cancel the push.
41163 * @param {Roo.HtmlEditorCore} this
41164 * @param {String} html
41169 * Fires when the textarea is updated with content from the editor iframe.
41170 * @param {Roo.HtmlEditorCore} this
41171 * @param {String} html
41176 * Fires when the iframe editor is updated with content from the textarea.
41177 * @param {Roo.HtmlEditorCore} this
41178 * @param {String} html
41183 * @event editorevent
41184 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41185 * @param {Roo.HtmlEditorCore} this
41191 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
41193 // defaults : white / black...
41194 this.applyBlacklists();
41201 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41205 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41211 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41216 * @cfg {Number} height (in pixels)
41220 * @cfg {Number} width (in pixels)
41225 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41228 stylesheets: false,
41233 // private properties
41234 validationEvent : false,
41236 initialized : false,
41238 sourceEditMode : false,
41239 onFocus : Roo.emptyFn,
41241 hideMode:'offsets',
41245 // blacklist + whitelisted elements..
41252 * Protected method that will not generally be called directly. It
41253 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41254 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41256 getDocMarkup : function(){
41260 // inherit styels from page...??
41261 if (this.stylesheets === false) {
41263 Roo.get(document.head).select('style').each(function(node) {
41264 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41267 Roo.get(document.head).select('link').each(function(node) {
41268 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41271 } else if (!this.stylesheets.length) {
41273 st = '<style type="text/css">' +
41274 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41280 st += '<style type="text/css">' +
41281 'IMG { cursor: pointer } ' +
41285 return '<html><head>' + st +
41286 //<style type="text/css">' +
41287 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41289 ' </head><body class="roo-htmleditor-body"></body></html>';
41293 onRender : function(ct, position)
41296 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41297 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41300 this.el.dom.style.border = '0 none';
41301 this.el.dom.setAttribute('tabIndex', -1);
41302 this.el.addClass('x-hidden hide');
41306 if(Roo.isIE){ // fix IE 1px bogus margin
41307 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41311 this.frameId = Roo.id();
41315 var iframe = this.owner.wrap.createChild({
41317 cls: 'form-control', // bootstrap..
41319 name: this.frameId,
41320 frameBorder : 'no',
41321 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41326 this.iframe = iframe.dom;
41328 this.assignDocWin();
41330 this.doc.designMode = 'on';
41333 this.doc.write(this.getDocMarkup());
41337 var task = { // must defer to wait for browser to be ready
41339 //console.log("run task?" + this.doc.readyState);
41340 this.assignDocWin();
41341 if(this.doc.body || this.doc.readyState == 'complete'){
41343 this.doc.designMode="on";
41347 Roo.TaskMgr.stop(task);
41348 this.initEditor.defer(10, this);
41355 Roo.TaskMgr.start(task);
41360 onResize : function(w, h)
41362 Roo.log('resize: ' +w + ',' + h );
41363 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41367 if(typeof w == 'number'){
41369 this.iframe.style.width = w + 'px';
41371 if(typeof h == 'number'){
41373 this.iframe.style.height = h + 'px';
41375 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41382 * Toggles the editor between standard and source edit mode.
41383 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41385 toggleSourceEdit : function(sourceEditMode){
41387 this.sourceEditMode = sourceEditMode === true;
41389 if(this.sourceEditMode){
41391 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41394 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41395 //this.iframe.className = '';
41398 //this.setSize(this.owner.wrap.getSize());
41399 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41406 * Protected method that will not generally be called directly. If you need/want
41407 * custom HTML cleanup, this is the method you should override.
41408 * @param {String} html The HTML to be cleaned
41409 * return {String} The cleaned HTML
41411 cleanHtml : function(html){
41412 html = String(html);
41413 if(html.length > 5){
41414 if(Roo.isSafari){ // strip safari nonsense
41415 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41418 if(html == ' '){
41425 * HTML Editor -> Textarea
41426 * Protected method that will not generally be called directly. Syncs the contents
41427 * of the editor iframe with the textarea.
41429 syncValue : function(){
41430 if(this.initialized){
41431 var bd = (this.doc.body || this.doc.documentElement);
41432 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41433 var html = bd.innerHTML;
41435 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41436 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41438 html = '<div style="'+m[0]+'">' + html + '</div>';
41441 html = this.cleanHtml(html);
41442 // fix up the special chars.. normaly like back quotes in word...
41443 // however we do not want to do this with chinese..
41444 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41445 var cc = b.charCodeAt();
41447 (cc >= 0x4E00 && cc < 0xA000 ) ||
41448 (cc >= 0x3400 && cc < 0x4E00 ) ||
41449 (cc >= 0xf900 && cc < 0xfb00 )
41455 if(this.owner.fireEvent('beforesync', this, html) !== false){
41456 this.el.dom.value = html;
41457 this.owner.fireEvent('sync', this, html);
41463 * Protected method that will not generally be called directly. Pushes the value of the textarea
41464 * into the iframe editor.
41466 pushValue : function(){
41467 if(this.initialized){
41468 var v = this.el.dom.value.trim();
41470 // if(v.length < 1){
41474 if(this.owner.fireEvent('beforepush', this, v) !== false){
41475 var d = (this.doc.body || this.doc.documentElement);
41477 this.cleanUpPaste();
41478 this.el.dom.value = d.innerHTML;
41479 this.owner.fireEvent('push', this, v);
41485 deferFocus : function(){
41486 this.focus.defer(10, this);
41490 focus : function(){
41491 if(this.win && !this.sourceEditMode){
41498 assignDocWin: function()
41500 var iframe = this.iframe;
41503 this.doc = iframe.contentWindow.document;
41504 this.win = iframe.contentWindow;
41506 // if (!Roo.get(this.frameId)) {
41509 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41510 // this.win = Roo.get(this.frameId).dom.contentWindow;
41512 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
41516 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41517 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
41522 initEditor : function(){
41523 //console.log("INIT EDITOR");
41524 this.assignDocWin();
41528 this.doc.designMode="on";
41530 this.doc.write(this.getDocMarkup());
41533 var dbody = (this.doc.body || this.doc.documentElement);
41534 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41535 // this copies styles from the containing element into thsi one..
41536 // not sure why we need all of this..
41537 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41539 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41540 //ss['background-attachment'] = 'fixed'; // w3c
41541 dbody.bgProperties = 'fixed'; // ie
41542 //Roo.DomHelper.applyStyles(dbody, ss);
41543 Roo.EventManager.on(this.doc, {
41544 //'mousedown': this.onEditorEvent,
41545 'mouseup': this.onEditorEvent,
41546 'dblclick': this.onEditorEvent,
41547 'click': this.onEditorEvent,
41548 'keyup': this.onEditorEvent,
41553 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41555 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41556 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41558 this.initialized = true;
41560 this.owner.fireEvent('initialize', this);
41565 onDestroy : function(){
41571 //for (var i =0; i < this.toolbars.length;i++) {
41572 // // fixme - ask toolbars for heights?
41573 // this.toolbars[i].onDestroy();
41576 //this.wrap.dom.innerHTML = '';
41577 //this.wrap.remove();
41582 onFirstFocus : function(){
41584 this.assignDocWin();
41587 this.activated = true;
41590 if(Roo.isGecko){ // prevent silly gecko errors
41592 var s = this.win.getSelection();
41593 if(!s.focusNode || s.focusNode.nodeType != 3){
41594 var r = s.getRangeAt(0);
41595 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41600 this.execCmd('useCSS', true);
41601 this.execCmd('styleWithCSS', false);
41604 this.owner.fireEvent('activate', this);
41608 adjustFont: function(btn){
41609 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41610 //if(Roo.isSafari){ // safari
41613 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41614 if(Roo.isSafari){ // safari
41615 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41616 v = (v < 10) ? 10 : v;
41617 v = (v > 48) ? 48 : v;
41618 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41623 v = Math.max(1, v+adjust);
41625 this.execCmd('FontSize', v );
41628 onEditorEvent : function(e)
41630 this.owner.fireEvent('editorevent', this, e);
41631 // this.updateToolbar();
41632 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41635 insertTag : function(tg)
41637 // could be a bit smarter... -> wrap the current selected tRoo..
41638 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41640 range = this.createRange(this.getSelection());
41641 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41642 wrappingNode.appendChild(range.extractContents());
41643 range.insertNode(wrappingNode);
41650 this.execCmd("formatblock", tg);
41654 insertText : function(txt)
41658 var range = this.createRange();
41659 range.deleteContents();
41660 //alert(Sender.getAttribute('label'));
41662 range.insertNode(this.doc.createTextNode(txt));
41668 * Executes a Midas editor command on the editor document and performs necessary focus and
41669 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41670 * @param {String} cmd The Midas command
41671 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41673 relayCmd : function(cmd, value){
41675 this.execCmd(cmd, value);
41676 this.owner.fireEvent('editorevent', this);
41677 //this.updateToolbar();
41678 this.owner.deferFocus();
41682 * Executes a Midas editor command directly on the editor document.
41683 * For visual commands, you should use {@link #relayCmd} instead.
41684 * <b>This should only be called after the editor is initialized.</b>
41685 * @param {String} cmd The Midas command
41686 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41688 execCmd : function(cmd, value){
41689 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41696 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41698 * @param {String} text | dom node..
41700 insertAtCursor : function(text)
41705 if(!this.activated){
41711 var r = this.doc.selection.createRange();
41722 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41726 // from jquery ui (MIT licenced)
41728 var win = this.win;
41730 if (win.getSelection && win.getSelection().getRangeAt) {
41731 range = win.getSelection().getRangeAt(0);
41732 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41733 range.insertNode(node);
41734 } else if (win.document.selection && win.document.selection.createRange) {
41735 // no firefox support
41736 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41737 win.document.selection.createRange().pasteHTML(txt);
41739 // no firefox support
41740 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41741 this.execCmd('InsertHTML', txt);
41750 mozKeyPress : function(e){
41752 var c = e.getCharCode(), cmd;
41755 c = String.fromCharCode(c).toLowerCase();
41769 this.cleanUpPaste.defer(100, this);
41777 e.preventDefault();
41785 fixKeys : function(){ // load time branching for fastest keydown performance
41787 return function(e){
41788 var k = e.getKey(), r;
41791 r = this.doc.selection.createRange();
41794 r.pasteHTML('    ');
41801 r = this.doc.selection.createRange();
41803 var target = r.parentElement();
41804 if(!target || target.tagName.toLowerCase() != 'li'){
41806 r.pasteHTML('<br />');
41812 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41813 this.cleanUpPaste.defer(100, this);
41819 }else if(Roo.isOpera){
41820 return function(e){
41821 var k = e.getKey();
41825 this.execCmd('InsertHTML','    ');
41828 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41829 this.cleanUpPaste.defer(100, this);
41834 }else if(Roo.isSafari){
41835 return function(e){
41836 var k = e.getKey();
41840 this.execCmd('InsertText','\t');
41844 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41845 this.cleanUpPaste.defer(100, this);
41853 getAllAncestors: function()
41855 var p = this.getSelectedNode();
41858 a.push(p); // push blank onto stack..
41859 p = this.getParentElement();
41863 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41867 a.push(this.doc.body);
41871 lastSelNode : false,
41874 getSelection : function()
41876 this.assignDocWin();
41877 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41880 getSelectedNode: function()
41882 // this may only work on Gecko!!!
41884 // should we cache this!!!!
41889 var range = this.createRange(this.getSelection()).cloneRange();
41892 var parent = range.parentElement();
41894 var testRange = range.duplicate();
41895 testRange.moveToElementText(parent);
41896 if (testRange.inRange(range)) {
41899 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41902 parent = parent.parentElement;
41907 // is ancestor a text element.
41908 var ac = range.commonAncestorContainer;
41909 if (ac.nodeType == 3) {
41910 ac = ac.parentNode;
41913 var ar = ac.childNodes;
41916 var other_nodes = [];
41917 var has_other_nodes = false;
41918 for (var i=0;i<ar.length;i++) {
41919 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41922 // fullly contained node.
41924 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41929 // probably selected..
41930 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41931 other_nodes.push(ar[i]);
41935 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41940 has_other_nodes = true;
41942 if (!nodes.length && other_nodes.length) {
41943 nodes= other_nodes;
41945 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41951 createRange: function(sel)
41953 // this has strange effects when using with
41954 // top toolbar - not sure if it's a great idea.
41955 //this.editor.contentWindow.focus();
41956 if (typeof sel != "undefined") {
41958 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41960 return this.doc.createRange();
41963 return this.doc.createRange();
41966 getParentElement: function()
41969 this.assignDocWin();
41970 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41972 var range = this.createRange(sel);
41975 var p = range.commonAncestorContainer;
41976 while (p.nodeType == 3) { // text node
41987 * Range intersection.. the hard stuff...
41991 * [ -- selected range --- ]
41995 * if end is before start or hits it. fail.
41996 * if start is after end or hits it fail.
41998 * if either hits (but other is outside. - then it's not
42004 // @see http://www.thismuchiknow.co.uk/?p=64.
42005 rangeIntersectsNode : function(range, node)
42007 var nodeRange = node.ownerDocument.createRange();
42009 nodeRange.selectNode(node);
42011 nodeRange.selectNodeContents(node);
42014 var rangeStartRange = range.cloneRange();
42015 rangeStartRange.collapse(true);
42017 var rangeEndRange = range.cloneRange();
42018 rangeEndRange.collapse(false);
42020 var nodeStartRange = nodeRange.cloneRange();
42021 nodeStartRange.collapse(true);
42023 var nodeEndRange = nodeRange.cloneRange();
42024 nodeEndRange.collapse(false);
42026 return rangeStartRange.compareBoundaryPoints(
42027 Range.START_TO_START, nodeEndRange) == -1 &&
42028 rangeEndRange.compareBoundaryPoints(
42029 Range.START_TO_START, nodeStartRange) == 1;
42033 rangeCompareNode : function(range, node)
42035 var nodeRange = node.ownerDocument.createRange();
42037 nodeRange.selectNode(node);
42039 nodeRange.selectNodeContents(node);
42043 range.collapse(true);
42045 nodeRange.collapse(true);
42047 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
42048 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
42050 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
42052 var nodeIsBefore = ss == 1;
42053 var nodeIsAfter = ee == -1;
42055 if (nodeIsBefore && nodeIsAfter)
42057 if (!nodeIsBefore && nodeIsAfter)
42058 return 1; //right trailed.
42060 if (nodeIsBefore && !nodeIsAfter)
42061 return 2; // left trailed.
42066 // private? - in a new class?
42067 cleanUpPaste : function()
42069 // cleans up the whole document..
42070 Roo.log('cleanuppaste');
42072 this.cleanUpChildren(this.doc.body);
42073 var clean = this.cleanWordChars(this.doc.body.innerHTML);
42074 if (clean != this.doc.body.innerHTML) {
42075 this.doc.body.innerHTML = clean;
42080 cleanWordChars : function(input) {// change the chars to hex code
42081 var he = Roo.HtmlEditorCore;
42083 var output = input;
42084 Roo.each(he.swapCodes, function(sw) {
42085 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
42087 output = output.replace(swapper, sw[1]);
42094 cleanUpChildren : function (n)
42096 if (!n.childNodes.length) {
42099 for (var i = n.childNodes.length-1; i > -1 ; i--) {
42100 this.cleanUpChild(n.childNodes[i]);
42107 cleanUpChild : function (node)
42110 //console.log(node);
42111 if (node.nodeName == "#text") {
42112 // clean up silly Windows -- stuff?
42115 if (node.nodeName == "#comment") {
42116 node.parentNode.removeChild(node);
42117 // clean up silly Windows -- stuff?
42120 var lcname = node.tagName.toLowerCase();
42121 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
42122 // whitelist of tags..
42124 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
42126 node.parentNode.removeChild(node);
42131 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
42133 // remove <a name=....> as rendering on yahoo mailer is borked with this.
42134 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
42136 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
42137 // remove_keep_children = true;
42140 if (remove_keep_children) {
42141 this.cleanUpChildren(node);
42142 // inserts everything just before this node...
42143 while (node.childNodes.length) {
42144 var cn = node.childNodes[0];
42145 node.removeChild(cn);
42146 node.parentNode.insertBefore(cn, node);
42148 node.parentNode.removeChild(node);
42152 if (!node.attributes || !node.attributes.length) {
42153 this.cleanUpChildren(node);
42157 function cleanAttr(n,v)
42160 if (v.match(/^\./) || v.match(/^\//)) {
42163 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
42166 if (v.match(/^#/)) {
42169 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
42170 node.removeAttribute(n);
42174 var cwhite = this.cwhite;
42175 var cblack = this.cblack;
42177 function cleanStyle(n,v)
42179 if (v.match(/expression/)) { //XSS?? should we even bother..
42180 node.removeAttribute(n);
42184 var parts = v.split(/;/);
42187 Roo.each(parts, function(p) {
42188 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42192 var l = p.split(':').shift().replace(/\s+/g,'');
42193 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42195 if ( cwhite.length && cblack.indexOf(l) > -1) {
42196 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42197 //node.removeAttribute(n);
42201 // only allow 'c whitelisted system attributes'
42202 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42203 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42204 //node.removeAttribute(n);
42214 if (clean.length) {
42215 node.setAttribute(n, clean.join(';'));
42217 node.removeAttribute(n);
42223 for (var i = node.attributes.length-1; i > -1 ; i--) {
42224 var a = node.attributes[i];
42227 if (a.name.toLowerCase().substr(0,2)=='on') {
42228 node.removeAttribute(a.name);
42231 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42232 node.removeAttribute(a.name);
42235 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42236 cleanAttr(a.name,a.value); // fixme..
42239 if (a.name == 'style') {
42240 cleanStyle(a.name,a.value);
42243 /// clean up MS crap..
42244 // tecnically this should be a list of valid class'es..
42247 if (a.name == 'class') {
42248 if (a.value.match(/^Mso/)) {
42249 node.className = '';
42252 if (a.value.match(/body/)) {
42253 node.className = '';
42264 this.cleanUpChildren(node);
42270 * Clean up MS wordisms...
42272 cleanWord : function(node)
42277 this.cleanWord(this.doc.body);
42280 if (node.nodeName == "#text") {
42281 // clean up silly Windows -- stuff?
42284 if (node.nodeName == "#comment") {
42285 node.parentNode.removeChild(node);
42286 // clean up silly Windows -- stuff?
42290 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42291 node.parentNode.removeChild(node);
42295 // remove - but keep children..
42296 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42297 while (node.childNodes.length) {
42298 var cn = node.childNodes[0];
42299 node.removeChild(cn);
42300 node.parentNode.insertBefore(cn, node);
42302 node.parentNode.removeChild(node);
42303 this.iterateChildren(node, this.cleanWord);
42307 if (node.className.length) {
42309 var cn = node.className.split(/\W+/);
42311 Roo.each(cn, function(cls) {
42312 if (cls.match(/Mso[a-zA-Z]+/)) {
42317 node.className = cna.length ? cna.join(' ') : '';
42319 node.removeAttribute("class");
42323 if (node.hasAttribute("lang")) {
42324 node.removeAttribute("lang");
42327 if (node.hasAttribute("style")) {
42329 var styles = node.getAttribute("style").split(";");
42331 Roo.each(styles, function(s) {
42332 if (!s.match(/:/)) {
42335 var kv = s.split(":");
42336 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42339 // what ever is left... we allow.
42342 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42343 if (!nstyle.length) {
42344 node.removeAttribute('style');
42347 this.iterateChildren(node, this.cleanWord);
42353 * iterateChildren of a Node, calling fn each time, using this as the scole..
42354 * @param {DomNode} node node to iterate children of.
42355 * @param {Function} fn method of this class to call on each item.
42357 iterateChildren : function(node, fn)
42359 if (!node.childNodes.length) {
42362 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42363 fn.call(this, node.childNodes[i])
42369 * cleanTableWidths.
42371 * Quite often pasting from word etc.. results in tables with column and widths.
42372 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
42375 cleanTableWidths : function(node)
42380 this.cleanTableWidths(this.doc.body);
42385 if (node.nodeName == "#text" || node.nodeName == "#comment") {
42388 Roo.log(node.tagName);
42389 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
42390 this.iterateChildren(node, this.cleanTableWidths);
42393 if (node.hasAttribute('width')) {
42394 node.removeAttribute('width');
42398 if (node.hasAttribute("style")) {
42401 var styles = node.getAttribute("style").split(";");
42403 Roo.each(styles, function(s) {
42404 if (!s.match(/:/)) {
42407 var kv = s.split(":");
42408 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
42411 // what ever is left... we allow.
42414 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42415 if (!nstyle.length) {
42416 node.removeAttribute('style');
42420 this.iterateChildren(node, this.cleanTableWidths);
42428 domToHTML : function(currentElement, depth, nopadtext) {
42430 depth = depth || 0;
42431 nopadtext = nopadtext || false;
42433 if (!currentElement) {
42434 return this.domToHTML(this.doc.body);
42437 //Roo.log(currentElement);
42439 var allText = false;
42440 var nodeName = currentElement.nodeName;
42441 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42443 if (nodeName == '#text') {
42445 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
42450 if (nodeName != 'BODY') {
42453 // Prints the node tagName, such as <A>, <IMG>, etc
42456 for(i = 0; i < currentElement.attributes.length;i++) {
42458 var aname = currentElement.attributes.item(i).name;
42459 if (!currentElement.attributes.item(i).value.length) {
42462 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42465 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42474 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42477 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42482 // Traverse the tree
42484 var currentElementChild = currentElement.childNodes.item(i);
42485 var allText = true;
42486 var innerHTML = '';
42488 while (currentElementChild) {
42489 // Formatting code (indent the tree so it looks nice on the screen)
42490 var nopad = nopadtext;
42491 if (lastnode == 'SPAN') {
42495 if (currentElementChild.nodeName == '#text') {
42496 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42497 toadd = nopadtext ? toadd : toadd.trim();
42498 if (!nopad && toadd.length > 80) {
42499 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42501 innerHTML += toadd;
42504 currentElementChild = currentElement.childNodes.item(i);
42510 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42512 // Recursively traverse the tree structure of the child node
42513 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42514 lastnode = currentElementChild.nodeName;
42516 currentElementChild=currentElement.childNodes.item(i);
42522 // The remaining code is mostly for formatting the tree
42523 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42528 ret+= "</"+tagName+">";
42534 applyBlacklists : function()
42536 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
42537 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
42541 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
42542 if (b.indexOf(tag) > -1) {
42545 this.white.push(tag);
42549 Roo.each(w, function(tag) {
42550 if (b.indexOf(tag) > -1) {
42553 if (this.white.indexOf(tag) > -1) {
42556 this.white.push(tag);
42561 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
42562 if (w.indexOf(tag) > -1) {
42565 this.black.push(tag);
42569 Roo.each(b, function(tag) {
42570 if (w.indexOf(tag) > -1) {
42573 if (this.black.indexOf(tag) > -1) {
42576 this.black.push(tag);
42581 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
42582 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
42586 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
42587 if (b.indexOf(tag) > -1) {
42590 this.cwhite.push(tag);
42594 Roo.each(w, function(tag) {
42595 if (b.indexOf(tag) > -1) {
42598 if (this.cwhite.indexOf(tag) > -1) {
42601 this.cwhite.push(tag);
42606 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
42607 if (w.indexOf(tag) > -1) {
42610 this.cblack.push(tag);
42614 Roo.each(b, function(tag) {
42615 if (w.indexOf(tag) > -1) {
42618 if (this.cblack.indexOf(tag) > -1) {
42621 this.cblack.push(tag);
42626 setStylesheets : function(stylesheets)
42628 if(typeof(stylesheets) == 'string'){
42629 Roo.get(this.iframe.contentDocument.head).createChild({
42631 rel : 'stylesheet',
42640 Roo.each(stylesheets, function(s) {
42645 Roo.get(_this.iframe.contentDocument.head).createChild({
42647 rel : 'stylesheet',
42656 removeStylesheets : function()
42660 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
42665 // hide stuff that is not compatible
42679 * @event specialkey
42683 * @cfg {String} fieldClass @hide
42686 * @cfg {String} focusClass @hide
42689 * @cfg {String} autoCreate @hide
42692 * @cfg {String} inputType @hide
42695 * @cfg {String} invalidClass @hide
42698 * @cfg {String} invalidText @hide
42701 * @cfg {String} msgFx @hide
42704 * @cfg {String} validateOnBlur @hide
42708 Roo.HtmlEditorCore.white = [
42709 'area', 'br', 'img', 'input', 'hr', 'wbr',
42711 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42712 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42713 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42714 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42715 'table', 'ul', 'xmp',
42717 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42720 'dir', 'menu', 'ol', 'ul', 'dl',
42726 Roo.HtmlEditorCore.black = [
42727 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42729 'base', 'basefont', 'bgsound', 'blink', 'body',
42730 'frame', 'frameset', 'head', 'html', 'ilayer',
42731 'iframe', 'layer', 'link', 'meta', 'object',
42732 'script', 'style' ,'title', 'xml' // clean later..
42734 Roo.HtmlEditorCore.clean = [
42735 'script', 'style', 'title', 'xml'
42737 Roo.HtmlEditorCore.remove = [
42742 Roo.HtmlEditorCore.ablack = [
42746 Roo.HtmlEditorCore.aclean = [
42747 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42751 Roo.HtmlEditorCore.pwhite= [
42752 'http', 'https', 'mailto'
42755 // white listed style attributes.
42756 Roo.HtmlEditorCore.cwhite= [
42757 // 'text-align', /// default is to allow most things..
42763 // black listed style attributes.
42764 Roo.HtmlEditorCore.cblack= [
42765 // 'font-size' -- this can be set by the project
42769 Roo.HtmlEditorCore.swapCodes =[
42780 //<script type="text/javascript">
42783 * Ext JS Library 1.1.1
42784 * Copyright(c) 2006-2007, Ext JS, LLC.
42790 Roo.form.HtmlEditor = function(config){
42794 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42796 if (!this.toolbars) {
42797 this.toolbars = [];
42799 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42805 * @class Roo.form.HtmlEditor
42806 * @extends Roo.form.Field
42807 * Provides a lightweight HTML Editor component.
42809 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42811 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42812 * supported by this editor.</b><br/><br/>
42813 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42814 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42816 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42818 * @cfg {Boolean} clearUp
42822 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42827 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42832 * @cfg {Number} height (in pixels)
42836 * @cfg {Number} width (in pixels)
42841 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42844 stylesheets: false,
42848 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
42853 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
42859 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
42864 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
42872 // private properties
42873 validationEvent : false,
42875 initialized : false,
42878 onFocus : Roo.emptyFn,
42880 hideMode:'offsets',
42882 actionMode : 'container', // defaults to hiding it...
42884 defaultAutoCreate : { // modified by initCompnoent..
42886 style:"width:500px;height:300px;",
42887 autocomplete: "new-password"
42891 initComponent : function(){
42894 * @event initialize
42895 * Fires when the editor is fully initialized (including the iframe)
42896 * @param {HtmlEditor} this
42901 * Fires when the editor is first receives the focus. Any insertion must wait
42902 * until after this event.
42903 * @param {HtmlEditor} this
42907 * @event beforesync
42908 * Fires before the textarea is updated with content from the editor iframe. Return false
42909 * to cancel the sync.
42910 * @param {HtmlEditor} this
42911 * @param {String} html
42915 * @event beforepush
42916 * Fires before the iframe editor is updated with content from the textarea. Return false
42917 * to cancel the push.
42918 * @param {HtmlEditor} this
42919 * @param {String} html
42924 * Fires when the textarea is updated with content from the editor iframe.
42925 * @param {HtmlEditor} this
42926 * @param {String} html
42931 * Fires when the iframe editor is updated with content from the textarea.
42932 * @param {HtmlEditor} this
42933 * @param {String} html
42937 * @event editmodechange
42938 * Fires when the editor switches edit modes
42939 * @param {HtmlEditor} this
42940 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42942 editmodechange: true,
42944 * @event editorevent
42945 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42946 * @param {HtmlEditor} this
42950 * @event firstfocus
42951 * Fires when on first focus - needed by toolbars..
42952 * @param {HtmlEditor} this
42957 * Auto save the htmlEditor value as a file into Events
42958 * @param {HtmlEditor} this
42962 * @event savedpreview
42963 * preview the saved version of htmlEditor
42964 * @param {HtmlEditor} this
42966 savedpreview: true,
42969 * @event stylesheetsclick
42970 * Fires when press the Sytlesheets button
42971 * @param {Roo.HtmlEditorCore} this
42973 stylesheetsclick: true
42975 this.defaultAutoCreate = {
42977 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42978 autocomplete: "new-password"
42983 * Protected method that will not generally be called directly. It
42984 * is called when the editor creates its toolbar. Override this method if you need to
42985 * add custom toolbar buttons.
42986 * @param {HtmlEditor} editor
42988 createToolbar : function(editor){
42989 Roo.log("create toolbars");
42990 if (!editor.toolbars || !editor.toolbars.length) {
42991 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42994 for (var i =0 ; i < editor.toolbars.length;i++) {
42995 editor.toolbars[i] = Roo.factory(
42996 typeof(editor.toolbars[i]) == 'string' ?
42997 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42998 Roo.form.HtmlEditor);
42999 editor.toolbars[i].init(editor);
43007 onRender : function(ct, position)
43010 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
43012 this.wrap = this.el.wrap({
43013 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
43016 this.editorcore.onRender(ct, position);
43018 if (this.resizable) {
43019 this.resizeEl = new Roo.Resizable(this.wrap, {
43023 minHeight : this.height,
43024 height: this.height,
43025 handles : this.resizable,
43028 resize : function(r, w, h) {
43029 _t.onResize(w,h); // -something
43035 this.createToolbar(this);
43039 this.setSize(this.wrap.getSize());
43041 if (this.resizeEl) {
43042 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
43043 // should trigger onReize..
43046 this.keyNav = new Roo.KeyNav(this.el, {
43048 "tab" : function(e){
43049 e.preventDefault();
43051 var value = this.getValue();
43053 var start = this.el.dom.selectionStart;
43054 var end = this.el.dom.selectionEnd;
43058 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
43059 this.el.dom.setSelectionRange(end + 1, end + 1);
43063 var f = value.substring(0, start).split("\t");
43065 if(f.pop().length != 0){
43069 this.setValue(f.join("\t") + value.substring(end));
43070 this.el.dom.setSelectionRange(start - 1, start - 1);
43074 "home" : function(e){
43075 e.preventDefault();
43077 var curr = this.el.dom.selectionStart;
43078 var lines = this.getValue().split("\n");
43085 this.el.dom.setSelectionRange(0, 0);
43091 for (var i = 0; i < lines.length;i++) {
43092 pos += lines[i].length;
43102 pos -= lines[i].length;
43108 this.el.dom.setSelectionRange(pos, pos);
43112 this.el.dom.selectionStart = pos;
43113 this.el.dom.selectionEnd = curr;
43116 "end" : function(e){
43117 e.preventDefault();
43119 var curr = this.el.dom.selectionStart;
43120 var lines = this.getValue().split("\n");
43127 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
43133 for (var i = 0; i < lines.length;i++) {
43135 pos += lines[i].length;
43149 this.el.dom.setSelectionRange(pos, pos);
43153 this.el.dom.selectionStart = curr;
43154 this.el.dom.selectionEnd = pos;
43159 doRelay : function(foo, bar, hname){
43160 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
43166 // if(this.autosave && this.w){
43167 // this.autoSaveFn = setInterval(this.autosave, 1000);
43172 onResize : function(w, h)
43174 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
43179 if(typeof w == 'number'){
43180 var aw = w - this.wrap.getFrameWidth('lr');
43181 this.el.setWidth(this.adjustWidth('textarea', aw));
43184 if(typeof h == 'number'){
43186 for (var i =0; i < this.toolbars.length;i++) {
43187 // fixme - ask toolbars for heights?
43188 tbh += this.toolbars[i].tb.el.getHeight();
43189 if (this.toolbars[i].footer) {
43190 tbh += this.toolbars[i].footer.el.getHeight();
43197 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
43198 ah -= 5; // knock a few pixes off for look..
43200 this.el.setHeight(this.adjustWidth('textarea', ah));
43204 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
43205 this.editorcore.onResize(ew,eh);
43210 * Toggles the editor between standard and source edit mode.
43211 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43213 toggleSourceEdit : function(sourceEditMode)
43215 this.editorcore.toggleSourceEdit(sourceEditMode);
43217 if(this.editorcore.sourceEditMode){
43218 Roo.log('editor - showing textarea');
43221 // Roo.log(this.syncValue());
43222 this.editorcore.syncValue();
43223 this.el.removeClass('x-hidden');
43224 this.el.dom.removeAttribute('tabIndex');
43227 for (var i = 0; i < this.toolbars.length; i++) {
43228 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43229 this.toolbars[i].tb.hide();
43230 this.toolbars[i].footer.hide();
43235 Roo.log('editor - hiding textarea');
43237 // Roo.log(this.pushValue());
43238 this.editorcore.pushValue();
43240 this.el.addClass('x-hidden');
43241 this.el.dom.setAttribute('tabIndex', -1);
43243 for (var i = 0; i < this.toolbars.length; i++) {
43244 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43245 this.toolbars[i].tb.show();
43246 this.toolbars[i].footer.show();
43250 //this.deferFocus();
43253 this.setSize(this.wrap.getSize());
43254 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
43256 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
43259 // private (for BoxComponent)
43260 adjustSize : Roo.BoxComponent.prototype.adjustSize,
43262 // private (for BoxComponent)
43263 getResizeEl : function(){
43267 // private (for BoxComponent)
43268 getPositionEl : function(){
43273 initEvents : function(){
43274 this.originalValue = this.getValue();
43278 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43281 markInvalid : Roo.emptyFn,
43283 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43286 clearInvalid : Roo.emptyFn,
43288 setValue : function(v){
43289 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
43290 this.editorcore.pushValue();
43295 deferFocus : function(){
43296 this.focus.defer(10, this);
43300 focus : function(){
43301 this.editorcore.focus();
43307 onDestroy : function(){
43313 for (var i =0; i < this.toolbars.length;i++) {
43314 // fixme - ask toolbars for heights?
43315 this.toolbars[i].onDestroy();
43318 this.wrap.dom.innerHTML = '';
43319 this.wrap.remove();
43324 onFirstFocus : function(){
43325 //Roo.log("onFirstFocus");
43326 this.editorcore.onFirstFocus();
43327 for (var i =0; i < this.toolbars.length;i++) {
43328 this.toolbars[i].onFirstFocus();
43334 syncValue : function()
43336 this.editorcore.syncValue();
43339 pushValue : function()
43341 this.editorcore.pushValue();
43344 setStylesheets : function(stylesheets)
43346 this.editorcore.setStylesheets(stylesheets);
43349 removeStylesheets : function()
43351 this.editorcore.removeStylesheets();
43355 // hide stuff that is not compatible
43369 * @event specialkey
43373 * @cfg {String} fieldClass @hide
43376 * @cfg {String} focusClass @hide
43379 * @cfg {String} autoCreate @hide
43382 * @cfg {String} inputType @hide
43385 * @cfg {String} invalidClass @hide
43388 * @cfg {String} invalidText @hide
43391 * @cfg {String} msgFx @hide
43394 * @cfg {String} validateOnBlur @hide
43398 // <script type="text/javascript">
43401 * Ext JS Library 1.1.1
43402 * Copyright(c) 2006-2007, Ext JS, LLC.
43408 * @class Roo.form.HtmlEditorToolbar1
43413 new Roo.form.HtmlEditor({
43416 new Roo.form.HtmlEditorToolbar1({
43417 disable : { fonts: 1 , format: 1, ..., ... , ...],
43423 * @cfg {Object} disable List of elements to disable..
43424 * @cfg {Array} btns List of additional buttons.
43428 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
43431 Roo.form.HtmlEditor.ToolbarStandard = function(config)
43434 Roo.apply(this, config);
43436 // default disabled, based on 'good practice'..
43437 this.disable = this.disable || {};
43438 Roo.applyIf(this.disable, {
43441 specialElements : true
43445 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43446 // dont call parent... till later.
43449 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
43456 editorcore : false,
43458 * @cfg {Object} disable List of toolbar elements to disable
43465 * @cfg {String} createLinkText The default text for the create link prompt
43467 createLinkText : 'Please enter the URL for the link:',
43469 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
43471 defaultLinkValue : 'http:/'+'/',
43475 * @cfg {Array} fontFamilies An array of available font families
43493 // "á" , ?? a acute?
43498 "°" // , // degrees
43500 // "é" , // e ecute
43501 // "ú" , // u ecute?
43504 specialElements : [
43506 text: "Insert Table",
43509 ihtml : '<table><tr><td>Cell</td></tr></table>'
43513 text: "Insert Image",
43516 ihtml : '<img src="about:blank"/>'
43525 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
43526 "input:submit", "input:button", "select", "textarea", "label" ],
43529 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
43531 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
43539 * @cfg {String} defaultFont default font to use.
43541 defaultFont: 'tahoma',
43543 fontSelect : false,
43546 formatCombo : false,
43548 init : function(editor)
43550 this.editor = editor;
43551 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43552 var editorcore = this.editorcore;
43556 var fid = editorcore.frameId;
43558 function btn(id, toggle, handler){
43559 var xid = fid + '-'+ id ;
43563 cls : 'x-btn-icon x-edit-'+id,
43564 enableToggle:toggle !== false,
43565 scope: _t, // was editor...
43566 handler:handler||_t.relayBtnCmd,
43567 clickEvent:'mousedown',
43568 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43575 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43577 // stop form submits
43578 tb.el.on('click', function(e){
43579 e.preventDefault(); // what does this do?
43582 if(!this.disable.font) { // && !Roo.isSafari){
43583 /* why no safari for fonts
43584 editor.fontSelect = tb.el.createChild({
43587 cls:'x-font-select',
43588 html: this.createFontOptions()
43591 editor.fontSelect.on('change', function(){
43592 var font = editor.fontSelect.dom.value;
43593 editor.relayCmd('fontname', font);
43594 editor.deferFocus();
43598 editor.fontSelect.dom,
43604 if(!this.disable.formats){
43605 this.formatCombo = new Roo.form.ComboBox({
43606 store: new Roo.data.SimpleStore({
43609 data : this.formats // from states.js
43613 //autoCreate : {tag: "div", size: "20"},
43614 displayField:'tag',
43618 triggerAction: 'all',
43619 emptyText:'Add tag',
43620 selectOnFocus:true,
43623 'select': function(c, r, i) {
43624 editorcore.insertTag(r.get('tag'));
43630 tb.addField(this.formatCombo);
43634 if(!this.disable.format){
43639 btn('strikethrough')
43642 if(!this.disable.fontSize){
43647 btn('increasefontsize', false, editorcore.adjustFont),
43648 btn('decreasefontsize', false, editorcore.adjustFont)
43653 if(!this.disable.colors){
43656 id:editorcore.frameId +'-forecolor',
43657 cls:'x-btn-icon x-edit-forecolor',
43658 clickEvent:'mousedown',
43659 tooltip: this.buttonTips['forecolor'] || undefined,
43661 menu : new Roo.menu.ColorMenu({
43662 allowReselect: true,
43663 focus: Roo.emptyFn,
43666 selectHandler: function(cp, color){
43667 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43668 editor.deferFocus();
43671 clickEvent:'mousedown'
43674 id:editorcore.frameId +'backcolor',
43675 cls:'x-btn-icon x-edit-backcolor',
43676 clickEvent:'mousedown',
43677 tooltip: this.buttonTips['backcolor'] || undefined,
43679 menu : new Roo.menu.ColorMenu({
43680 focus: Roo.emptyFn,
43683 allowReselect: true,
43684 selectHandler: function(cp, color){
43686 editorcore.execCmd('useCSS', false);
43687 editorcore.execCmd('hilitecolor', color);
43688 editorcore.execCmd('useCSS', true);
43689 editor.deferFocus();
43691 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43692 Roo.isSafari || Roo.isIE ? '#'+color : color);
43693 editor.deferFocus();
43697 clickEvent:'mousedown'
43702 // now add all the items...
43705 if(!this.disable.alignments){
43708 btn('justifyleft'),
43709 btn('justifycenter'),
43710 btn('justifyright')
43714 //if(!Roo.isSafari){
43715 if(!this.disable.links){
43718 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43722 if(!this.disable.lists){
43725 btn('insertorderedlist'),
43726 btn('insertunorderedlist')
43729 if(!this.disable.sourceEdit){
43732 btn('sourceedit', true, function(btn){
43733 this.toggleSourceEdit(btn.pressed);
43740 // special menu.. - needs to be tidied up..
43741 if (!this.disable.special) {
43744 cls: 'x-edit-none',
43750 for (var i =0; i < this.specialChars.length; i++) {
43751 smenu.menu.items.push({
43753 html: this.specialChars[i],
43754 handler: function(a,b) {
43755 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43756 //editor.insertAtCursor(a.html);
43770 if (!this.disable.cleanStyles) {
43772 cls: 'x-btn-icon x-btn-clear',
43778 for (var i =0; i < this.cleanStyles.length; i++) {
43779 cmenu.menu.items.push({
43780 actiontype : this.cleanStyles[i],
43781 html: 'Remove ' + this.cleanStyles[i],
43782 handler: function(a,b) {
43785 var c = Roo.get(editorcore.doc.body);
43786 c.select('[style]').each(function(s) {
43787 s.dom.style.removeProperty(a.actiontype);
43789 editorcore.syncValue();
43794 cmenu.menu.items.push({
43795 actiontype : 'tablewidths',
43796 html: 'Remove Table Widths',
43797 handler: function(a,b) {
43798 editorcore.cleanTableWidths();
43799 editorcore.syncValue();
43803 cmenu.menu.items.push({
43804 actiontype : 'word',
43805 html: 'Remove MS Word Formating',
43806 handler: function(a,b) {
43807 editorcore.cleanWord();
43808 editorcore.syncValue();
43813 cmenu.menu.items.push({
43814 actiontype : 'all',
43815 html: 'Remove All Styles',
43816 handler: function(a,b) {
43818 var c = Roo.get(editorcore.doc.body);
43819 c.select('[style]').each(function(s) {
43820 s.dom.removeAttribute('style');
43822 editorcore.syncValue();
43827 cmenu.menu.items.push({
43828 actiontype : 'all',
43829 html: 'Remove All CSS Classes',
43830 handler: function(a,b) {
43832 var c = Roo.get(editorcore.doc.body);
43833 c.select('[class]').each(function(s) {
43834 s.dom.className = '';
43836 editorcore.syncValue();
43841 cmenu.menu.items.push({
43842 actiontype : 'tidy',
43843 html: 'Tidy HTML Source',
43844 handler: function(a,b) {
43845 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43846 editorcore.syncValue();
43855 if (!this.disable.specialElements) {
43858 cls: 'x-edit-none',
43863 for (var i =0; i < this.specialElements.length; i++) {
43864 semenu.menu.items.push(
43866 handler: function(a,b) {
43867 editor.insertAtCursor(this.ihtml);
43869 }, this.specialElements[i])
43881 for(var i =0; i< this.btns.length;i++) {
43882 var b = Roo.factory(this.btns[i],Roo.form);
43883 b.cls = 'x-edit-none';
43885 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
43886 b.cls += ' x-init-enable';
43889 b.scope = editorcore;
43897 // disable everything...
43899 this.tb.items.each(function(item){
43902 item.id != editorcore.frameId+ '-sourceedit' &&
43903 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
43909 this.rendered = true;
43911 // the all the btns;
43912 editor.on('editorevent', this.updateToolbar, this);
43913 // other toolbars need to implement this..
43914 //editor.on('editmodechange', this.updateToolbar, this);
43918 relayBtnCmd : function(btn) {
43919 this.editorcore.relayCmd(btn.cmd);
43921 // private used internally
43922 createLink : function(){
43923 Roo.log("create link?");
43924 var url = prompt(this.createLinkText, this.defaultLinkValue);
43925 if(url && url != 'http:/'+'/'){
43926 this.editorcore.relayCmd('createlink', url);
43932 * Protected method that will not generally be called directly. It triggers
43933 * a toolbar update by reading the markup state of the current selection in the editor.
43935 updateToolbar: function(){
43937 if(!this.editorcore.activated){
43938 this.editor.onFirstFocus();
43942 var btns = this.tb.items.map,
43943 doc = this.editorcore.doc,
43944 frameId = this.editorcore.frameId;
43946 if(!this.disable.font && !Roo.isSafari){
43948 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43949 if(name != this.fontSelect.dom.value){
43950 this.fontSelect.dom.value = name;
43954 if(!this.disable.format){
43955 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43956 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43957 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43958 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
43960 if(!this.disable.alignments){
43961 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43962 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43963 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43965 if(!Roo.isSafari && !this.disable.lists){
43966 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43967 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43970 var ans = this.editorcore.getAllAncestors();
43971 if (this.formatCombo) {
43974 var store = this.formatCombo.store;
43975 this.formatCombo.setValue("");
43976 for (var i =0; i < ans.length;i++) {
43977 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43979 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43987 // hides menus... - so this cant be on a menu...
43988 Roo.menu.MenuMgr.hideAll();
43990 //this.editorsyncValue();
43994 createFontOptions : function(){
43995 var buf = [], fs = this.fontFamilies, ff, lc;
43999 for(var i = 0, len = fs.length; i< len; i++){
44001 lc = ff.toLowerCase();
44003 '<option value="',lc,'" style="font-family:',ff,';"',
44004 (this.defaultFont == lc ? ' selected="true">' : '>'),
44009 return buf.join('');
44012 toggleSourceEdit : function(sourceEditMode){
44014 Roo.log("toolbar toogle");
44015 if(sourceEditMode === undefined){
44016 sourceEditMode = !this.sourceEditMode;
44018 this.sourceEditMode = sourceEditMode === true;
44019 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
44020 // just toggle the button?
44021 if(btn.pressed !== this.sourceEditMode){
44022 btn.toggle(this.sourceEditMode);
44026 if(sourceEditMode){
44027 Roo.log("disabling buttons");
44028 this.tb.items.each(function(item){
44029 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
44035 Roo.log("enabling buttons");
44036 if(this.editorcore.initialized){
44037 this.tb.items.each(function(item){
44043 Roo.log("calling toggole on editor");
44044 // tell the editor that it's been pressed..
44045 this.editor.toggleSourceEdit(sourceEditMode);
44049 * Object collection of toolbar tooltips for the buttons in the editor. The key
44050 * is the command id associated with that button and the value is a valid QuickTips object.
44055 title: 'Bold (Ctrl+B)',
44056 text: 'Make the selected text bold.',
44057 cls: 'x-html-editor-tip'
44060 title: 'Italic (Ctrl+I)',
44061 text: 'Make the selected text italic.',
44062 cls: 'x-html-editor-tip'
44070 title: 'Bold (Ctrl+B)',
44071 text: 'Make the selected text bold.',
44072 cls: 'x-html-editor-tip'
44075 title: 'Italic (Ctrl+I)',
44076 text: 'Make the selected text italic.',
44077 cls: 'x-html-editor-tip'
44080 title: 'Underline (Ctrl+U)',
44081 text: 'Underline the selected text.',
44082 cls: 'x-html-editor-tip'
44085 title: 'Strikethrough',
44086 text: 'Strikethrough the selected text.',
44087 cls: 'x-html-editor-tip'
44089 increasefontsize : {
44090 title: 'Grow Text',
44091 text: 'Increase the font size.',
44092 cls: 'x-html-editor-tip'
44094 decreasefontsize : {
44095 title: 'Shrink Text',
44096 text: 'Decrease the font size.',
44097 cls: 'x-html-editor-tip'
44100 title: 'Text Highlight Color',
44101 text: 'Change the background color of the selected text.',
44102 cls: 'x-html-editor-tip'
44105 title: 'Font Color',
44106 text: 'Change the color of the selected text.',
44107 cls: 'x-html-editor-tip'
44110 title: 'Align Text Left',
44111 text: 'Align text to the left.',
44112 cls: 'x-html-editor-tip'
44115 title: 'Center Text',
44116 text: 'Center text in the editor.',
44117 cls: 'x-html-editor-tip'
44120 title: 'Align Text Right',
44121 text: 'Align text to the right.',
44122 cls: 'x-html-editor-tip'
44124 insertunorderedlist : {
44125 title: 'Bullet List',
44126 text: 'Start a bulleted list.',
44127 cls: 'x-html-editor-tip'
44129 insertorderedlist : {
44130 title: 'Numbered List',
44131 text: 'Start a numbered list.',
44132 cls: 'x-html-editor-tip'
44135 title: 'Hyperlink',
44136 text: 'Make the selected text a hyperlink.',
44137 cls: 'x-html-editor-tip'
44140 title: 'Source Edit',
44141 text: 'Switch to source editing mode.',
44142 cls: 'x-html-editor-tip'
44146 onDestroy : function(){
44149 this.tb.items.each(function(item){
44151 item.menu.removeAll();
44153 item.menu.el.destroy();
44161 onFirstFocus: function() {
44162 this.tb.items.each(function(item){
44171 // <script type="text/javascript">
44174 * Ext JS Library 1.1.1
44175 * Copyright(c) 2006-2007, Ext JS, LLC.
44182 * @class Roo.form.HtmlEditor.ToolbarContext
44187 new Roo.form.HtmlEditor({
44190 { xtype: 'ToolbarStandard', styles : {} }
44191 { xtype: 'ToolbarContext', disable : {} }
44197 * @config : {Object} disable List of elements to disable.. (not done yet.)
44198 * @config : {Object} styles Map of styles available.
44202 Roo.form.HtmlEditor.ToolbarContext = function(config)
44205 Roo.apply(this, config);
44206 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44207 // dont call parent... till later.
44208 this.styles = this.styles || {};
44213 Roo.form.HtmlEditor.ToolbarContext.types = {
44225 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
44291 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
44296 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
44306 style : 'fontFamily',
44307 displayField: 'display',
44308 optname : 'font-family',
44357 // should we really allow this??
44358 // should this just be
44369 style : 'fontFamily',
44370 displayField: 'display',
44371 optname : 'font-family',
44378 style : 'fontFamily',
44379 displayField: 'display',
44380 optname : 'font-family',
44387 style : 'fontFamily',
44388 displayField: 'display',
44389 optname : 'font-family',
44400 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
44401 Roo.form.HtmlEditor.ToolbarContext.stores = false;
44403 Roo.form.HtmlEditor.ToolbarContext.options = {
44405 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
44406 [ 'Courier New', 'Courier New'],
44407 [ 'Tahoma', 'Tahoma'],
44408 [ 'Times New Roman,serif', 'Times'],
44409 [ 'Verdana','Verdana' ]
44413 // fixme - these need to be configurable..
44416 //Roo.form.HtmlEditor.ToolbarContext.types
44419 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
44426 editorcore : false,
44428 * @cfg {Object} disable List of toolbar elements to disable
44433 * @cfg {Object} styles List of styles
44434 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
44436 * These must be defined in the page, so they get rendered correctly..
44447 init : function(editor)
44449 this.editor = editor;
44450 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44451 var editorcore = this.editorcore;
44453 var fid = editorcore.frameId;
44455 function btn(id, toggle, handler){
44456 var xid = fid + '-'+ id ;
44460 cls : 'x-btn-icon x-edit-'+id,
44461 enableToggle:toggle !== false,
44462 scope: editorcore, // was editor...
44463 handler:handler||editorcore.relayBtnCmd,
44464 clickEvent:'mousedown',
44465 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44469 // create a new element.
44470 var wdiv = editor.wrap.createChild({
44472 }, editor.wrap.dom.firstChild.nextSibling, true);
44474 // can we do this more than once??
44476 // stop form submits
44479 // disable everything...
44480 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44481 this.toolbars = {};
44483 for (var i in ty) {
44485 this.toolbars[i] = this.buildToolbar(ty[i],i);
44487 this.tb = this.toolbars.BODY;
44489 this.buildFooter();
44490 this.footer.show();
44491 editor.on('hide', function( ) { this.footer.hide() }, this);
44492 editor.on('show', function( ) { this.footer.show() }, this);
44495 this.rendered = true;
44497 // the all the btns;
44498 editor.on('editorevent', this.updateToolbar, this);
44499 // other toolbars need to implement this..
44500 //editor.on('editmodechange', this.updateToolbar, this);
44506 * Protected method that will not generally be called directly. It triggers
44507 * a toolbar update by reading the markup state of the current selection in the editor.
44509 * Note you can force an update by calling on('editorevent', scope, false)
44511 updateToolbar: function(editor,ev,sel){
44514 // capture mouse up - this is handy for selecting images..
44515 // perhaps should go somewhere else...
44516 if(!this.editorcore.activated){
44517 this.editor.onFirstFocus();
44523 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
44524 // selectNode - might want to handle IE?
44526 (ev.type == 'mouseup' || ev.type == 'click' ) &&
44527 ev.target && ev.target.tagName == 'IMG') {
44528 // they have click on an image...
44529 // let's see if we can change the selection...
44532 var nodeRange = sel.ownerDocument.createRange();
44534 nodeRange.selectNode(sel);
44536 nodeRange.selectNodeContents(sel);
44538 //nodeRange.collapse(true);
44539 var s = this.editorcore.win.getSelection();
44540 s.removeAllRanges();
44541 s.addRange(nodeRange);
44545 var updateFooter = sel ? false : true;
44548 var ans = this.editorcore.getAllAncestors();
44551 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44554 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
44555 sel = sel ? sel : this.editorcore.doc.body;
44556 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
44559 // pick a menu that exists..
44560 var tn = sel.tagName.toUpperCase();
44561 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
44563 tn = sel.tagName.toUpperCase();
44565 var lastSel = this.tb.selectedNode;
44567 this.tb.selectedNode = sel;
44569 // if current menu does not match..
44571 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
44574 ///console.log("show: " + tn);
44575 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
44578 this.tb.items.first().el.innerHTML = tn + ': ';
44581 // update attributes
44582 if (this.tb.fields) {
44583 this.tb.fields.each(function(e) {
44585 e.setValue(sel.style[e.stylename]);
44588 e.setValue(sel.getAttribute(e.attrname));
44592 var hasStyles = false;
44593 for(var i in this.styles) {
44600 var st = this.tb.fields.item(0);
44602 st.store.removeAll();
44605 var cn = sel.className.split(/\s+/);
44608 if (this.styles['*']) {
44610 Roo.each(this.styles['*'], function(v) {
44611 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44614 if (this.styles[tn]) {
44615 Roo.each(this.styles[tn], function(v) {
44616 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44620 st.store.loadData(avs);
44624 // flag our selected Node.
44625 this.tb.selectedNode = sel;
44628 Roo.menu.MenuMgr.hideAll();
44632 if (!updateFooter) {
44633 //this.footDisp.dom.innerHTML = '';
44636 // update the footer
44640 this.footerEls = ans.reverse();
44641 Roo.each(this.footerEls, function(a,i) {
44642 if (!a) { return; }
44643 html += html.length ? ' > ' : '';
44645 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44650 var sz = this.footDisp.up('td').getSize();
44651 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44652 this.footDisp.dom.style.marginLeft = '5px';
44654 this.footDisp.dom.style.overflow = 'hidden';
44656 this.footDisp.dom.innerHTML = html;
44658 //this.editorsyncValue();
44665 onDestroy : function(){
44668 this.tb.items.each(function(item){
44670 item.menu.removeAll();
44672 item.menu.el.destroy();
44680 onFirstFocus: function() {
44681 // need to do this for all the toolbars..
44682 this.tb.items.each(function(item){
44686 buildToolbar: function(tlist, nm)
44688 var editor = this.editor;
44689 var editorcore = this.editorcore;
44690 // create a new element.
44691 var wdiv = editor.wrap.createChild({
44693 }, editor.wrap.dom.firstChild.nextSibling, true);
44696 var tb = new Roo.Toolbar(wdiv);
44699 tb.add(nm+ ": ");
44702 for(var i in this.styles) {
44707 if (styles && styles.length) {
44709 // this needs a multi-select checkbox...
44710 tb.addField( new Roo.form.ComboBox({
44711 store: new Roo.data.SimpleStore({
44713 fields: ['val', 'selected'],
44716 name : '-roo-edit-className',
44717 attrname : 'className',
44718 displayField: 'val',
44722 triggerAction: 'all',
44723 emptyText:'Select Style',
44724 selectOnFocus:true,
44727 'select': function(c, r, i) {
44728 // initial support only for on class per el..
44729 tb.selectedNode.className = r ? r.get('val') : '';
44730 editorcore.syncValue();
44737 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44738 var tbops = tbc.options;
44740 for (var i in tlist) {
44742 var item = tlist[i];
44743 tb.add(item.title + ": ");
44746 //optname == used so you can configure the options available..
44747 var opts = item.opts ? item.opts : false;
44748 if (item.optname) {
44749 opts = tbops[item.optname];
44754 // opts == pulldown..
44755 tb.addField( new Roo.form.ComboBox({
44756 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44758 fields: ['val', 'display'],
44761 name : '-roo-edit-' + i,
44763 stylename : item.style ? item.style : false,
44764 displayField: item.displayField ? item.displayField : 'val',
44765 valueField : 'val',
44767 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44769 triggerAction: 'all',
44770 emptyText:'Select',
44771 selectOnFocus:true,
44772 width: item.width ? item.width : 130,
44774 'select': function(c, r, i) {
44776 tb.selectedNode.style[c.stylename] = r.get('val');
44779 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44788 tb.addField( new Roo.form.TextField({
44791 //allowBlank:false,
44796 tb.addField( new Roo.form.TextField({
44797 name: '-roo-edit-' + i,
44804 'change' : function(f, nv, ov) {
44805 tb.selectedNode.setAttribute(f.attrname, nv);
44818 text: 'Stylesheets',
44821 click : function ()
44823 _this.editor.fireEvent('stylesheetsclick', _this.editor);
44831 text: 'Remove Tag',
44834 click : function ()
44837 // undo does not work.
44839 var sn = tb.selectedNode;
44841 var pn = sn.parentNode;
44843 var stn = sn.childNodes[0];
44844 var en = sn.childNodes[sn.childNodes.length - 1 ];
44845 while (sn.childNodes.length) {
44846 var node = sn.childNodes[0];
44847 sn.removeChild(node);
44849 pn.insertBefore(node, sn);
44852 pn.removeChild(sn);
44853 var range = editorcore.createRange();
44855 range.setStart(stn,0);
44856 range.setEnd(en,0); //????
44857 //range.selectNode(sel);
44860 var selection = editorcore.getSelection();
44861 selection.removeAllRanges();
44862 selection.addRange(range);
44866 //_this.updateToolbar(null, null, pn);
44867 _this.updateToolbar(null, null, null);
44868 _this.footDisp.dom.innerHTML = '';
44878 tb.el.on('click', function(e){
44879 e.preventDefault(); // what does this do?
44881 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44884 // dont need to disable them... as they will get hidden
44889 buildFooter : function()
44892 var fel = this.editor.wrap.createChild();
44893 this.footer = new Roo.Toolbar(fel);
44894 // toolbar has scrolly on left / right?
44895 var footDisp= new Roo.Toolbar.Fill();
44901 handler : function() {
44902 _t.footDisp.scrollTo('left',0,true)
44906 this.footer.add( footDisp );
44911 handler : function() {
44913 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44917 var fel = Roo.get(footDisp.el);
44918 fel.addClass('x-editor-context');
44919 this.footDispWrap = fel;
44920 this.footDispWrap.overflow = 'hidden';
44922 this.footDisp = fel.createChild();
44923 this.footDispWrap.on('click', this.onContextClick, this)
44927 onContextClick : function (ev,dom)
44929 ev.preventDefault();
44930 var cn = dom.className;
44932 if (!cn.match(/x-ed-loc-/)) {
44935 var n = cn.split('-').pop();
44936 var ans = this.footerEls;
44940 var range = this.editorcore.createRange();
44942 range.selectNodeContents(sel);
44943 //range.selectNode(sel);
44946 var selection = this.editorcore.getSelection();
44947 selection.removeAllRanges();
44948 selection.addRange(range);
44952 this.updateToolbar(null, null, sel);
44969 * Ext JS Library 1.1.1
44970 * Copyright(c) 2006-2007, Ext JS, LLC.
44972 * Originally Released Under LGPL - original licence link has changed is not relivant.
44975 * <script type="text/javascript">
44979 * @class Roo.form.BasicForm
44980 * @extends Roo.util.Observable
44981 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44983 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44984 * @param {Object} config Configuration options
44986 Roo.form.BasicForm = function(el, config){
44987 this.allItems = [];
44988 this.childForms = [];
44989 Roo.apply(this, config);
44991 * The Roo.form.Field items in this form.
44992 * @type MixedCollection
44996 this.items = new Roo.util.MixedCollection(false, function(o){
44997 return o.id || (o.id = Roo.id());
45001 * @event beforeaction
45002 * Fires before any action is performed. Return false to cancel the action.
45003 * @param {Form} this
45004 * @param {Action} action The action to be performed
45006 beforeaction: true,
45008 * @event actionfailed
45009 * Fires when an action fails.
45010 * @param {Form} this
45011 * @param {Action} action The action that failed
45013 actionfailed : true,
45015 * @event actioncomplete
45016 * Fires when an action is completed.
45017 * @param {Form} this
45018 * @param {Action} action The action that completed
45020 actioncomplete : true
45025 Roo.form.BasicForm.superclass.constructor.call(this);
45028 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
45030 * @cfg {String} method
45031 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
45034 * @cfg {DataReader} reader
45035 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
45036 * This is optional as there is built-in support for processing JSON.
45039 * @cfg {DataReader} errorReader
45040 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
45041 * This is completely optional as there is built-in support for processing JSON.
45044 * @cfg {String} url
45045 * The URL to use for form actions if one isn't supplied in the action options.
45048 * @cfg {Boolean} fileUpload
45049 * Set to true if this form is a file upload.
45053 * @cfg {Object} baseParams
45054 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
45059 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
45064 activeAction : null,
45067 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
45068 * or setValues() data instead of when the form was first created.
45070 trackResetOnLoad : false,
45074 * childForms - used for multi-tab forms
45077 childForms : false,
45080 * allItems - full list of fields.
45086 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
45087 * element by passing it or its id or mask the form itself by passing in true.
45090 waitMsgTarget : false,
45093 initEl : function(el){
45094 this.el = Roo.get(el);
45095 this.id = this.el.id || Roo.id();
45096 this.el.on('submit', this.onSubmit, this);
45097 this.el.addClass('x-form');
45101 onSubmit : function(e){
45106 * Returns true if client-side validation on the form is successful.
45109 isValid : function(){
45111 this.items.each(function(f){
45120 * Returns true if any fields in this form have changed since their original load.
45123 isDirty : function(){
45125 this.items.each(function(f){
45135 * Performs a predefined action (submit or load) or custom actions you define on this form.
45136 * @param {String} actionName The name of the action type
45137 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
45138 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
45139 * accept other config options):
45141 Property Type Description
45142 ---------------- --------------- ----------------------------------------------------------------------------------
45143 url String The url for the action (defaults to the form's url)
45144 method String The form method to use (defaults to the form's method, or POST if not defined)
45145 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
45146 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
45147 validate the form on the client (defaults to false)
45149 * @return {BasicForm} this
45151 doAction : function(action, options){
45152 if(typeof action == 'string'){
45153 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
45155 if(this.fireEvent('beforeaction', this, action) !== false){
45156 this.beforeAction(action);
45157 action.run.defer(100, action);
45163 * Shortcut to do a submit action.
45164 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45165 * @return {BasicForm} this
45167 submit : function(options){
45168 this.doAction('submit', options);
45173 * Shortcut to do a load action.
45174 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45175 * @return {BasicForm} this
45177 load : function(options){
45178 this.doAction('load', options);
45183 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
45184 * @param {Record} record The record to edit
45185 * @return {BasicForm} this
45187 updateRecord : function(record){
45188 record.beginEdit();
45189 var fs = record.fields;
45190 fs.each(function(f){
45191 var field = this.findField(f.name);
45193 record.set(f.name, field.getValue());
45201 * Loads an Roo.data.Record into this form.
45202 * @param {Record} record The record to load
45203 * @return {BasicForm} this
45205 loadRecord : function(record){
45206 this.setValues(record.data);
45211 beforeAction : function(action){
45212 var o = action.options;
45215 if(this.waitMsgTarget === true){
45216 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
45217 }else if(this.waitMsgTarget){
45218 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
45219 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
45221 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
45227 afterAction : function(action, success){
45228 this.activeAction = null;
45229 var o = action.options;
45231 if(this.waitMsgTarget === true){
45233 }else if(this.waitMsgTarget){
45234 this.waitMsgTarget.unmask();
45236 Roo.MessageBox.updateProgress(1);
45237 Roo.MessageBox.hide();
45244 Roo.callback(o.success, o.scope, [this, action]);
45245 this.fireEvent('actioncomplete', this, action);
45249 // failure condition..
45250 // we have a scenario where updates need confirming.
45251 // eg. if a locking scenario exists..
45252 // we look for { errors : { needs_confirm : true }} in the response.
45254 (typeof(action.result) != 'undefined') &&
45255 (typeof(action.result.errors) != 'undefined') &&
45256 (typeof(action.result.errors.needs_confirm) != 'undefined')
45259 Roo.MessageBox.confirm(
45260 "Change requires confirmation",
45261 action.result.errorMsg,
45266 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
45276 Roo.callback(o.failure, o.scope, [this, action]);
45277 // show an error message if no failed handler is set..
45278 if (!this.hasListener('actionfailed')) {
45279 Roo.MessageBox.alert("Error",
45280 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
45281 action.result.errorMsg :
45282 "Saving Failed, please check your entries or try again"
45286 this.fireEvent('actionfailed', this, action);
45292 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
45293 * @param {String} id The value to search for
45296 findField : function(id){
45297 var field = this.items.get(id);
45299 this.items.each(function(f){
45300 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
45306 return field || null;
45310 * Add a secondary form to this one,
45311 * Used to provide tabbed forms. One form is primary, with hidden values
45312 * which mirror the elements from the other forms.
45314 * @param {Roo.form.Form} form to add.
45317 addForm : function(form)
45320 if (this.childForms.indexOf(form) > -1) {
45324 this.childForms.push(form);
45326 Roo.each(form.allItems, function (fe) {
45328 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
45329 if (this.findField(n)) { // already added..
45332 var add = new Roo.form.Hidden({
45335 add.render(this.el);
45342 * Mark fields in this form invalid in bulk.
45343 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
45344 * @return {BasicForm} this
45346 markInvalid : function(errors){
45347 if(errors instanceof Array){
45348 for(var i = 0, len = errors.length; i < len; i++){
45349 var fieldError = errors[i];
45350 var f = this.findField(fieldError.id);
45352 f.markInvalid(fieldError.msg);
45358 if(typeof errors[id] != 'function' && (field = this.findField(id))){
45359 field.markInvalid(errors[id]);
45363 Roo.each(this.childForms || [], function (f) {
45364 f.markInvalid(errors);
45371 * Set values for fields in this form in bulk.
45372 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
45373 * @return {BasicForm} this
45375 setValues : function(values){
45376 if(values instanceof Array){ // array of objects
45377 for(var i = 0, len = values.length; i < len; i++){
45379 var f = this.findField(v.id);
45381 f.setValue(v.value);
45382 if(this.trackResetOnLoad){
45383 f.originalValue = f.getValue();
45387 }else{ // object hash
45390 if(typeof values[id] != 'function' && (field = this.findField(id))){
45392 if (field.setFromData &&
45393 field.valueField &&
45394 field.displayField &&
45395 // combos' with local stores can
45396 // be queried via setValue()
45397 // to set their value..
45398 (field.store && !field.store.isLocal)
45402 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
45403 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
45404 field.setFromData(sd);
45407 field.setValue(values[id]);
45411 if(this.trackResetOnLoad){
45412 field.originalValue = field.getValue();
45418 Roo.each(this.childForms || [], function (f) {
45419 f.setValues(values);
45426 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
45427 * they are returned as an array.
45428 * @param {Boolean} asString
45431 getValues : function(asString){
45432 if (this.childForms) {
45433 // copy values from the child forms
45434 Roo.each(this.childForms, function (f) {
45435 this.setValues(f.getValues());
45441 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
45442 if(asString === true){
45445 return Roo.urlDecode(fs);
45449 * Returns the fields in this form as an object with key/value pairs.
45450 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
45453 getFieldValues : function(with_hidden)
45455 if (this.childForms) {
45456 // copy values from the child forms
45457 // should this call getFieldValues - probably not as we do not currently copy
45458 // hidden fields when we generate..
45459 Roo.each(this.childForms, function (f) {
45460 this.setValues(f.getValues());
45465 this.items.each(function(f){
45466 if (!f.getName()) {
45469 var v = f.getValue();
45470 if (f.inputType =='radio') {
45471 if (typeof(ret[f.getName()]) == 'undefined') {
45472 ret[f.getName()] = ''; // empty..
45475 if (!f.el.dom.checked) {
45479 v = f.el.dom.value;
45483 // not sure if this supported any more..
45484 if ((typeof(v) == 'object') && f.getRawValue) {
45485 v = f.getRawValue() ; // dates..
45487 // combo boxes where name != hiddenName...
45488 if (f.name != f.getName()) {
45489 ret[f.name] = f.getRawValue();
45491 ret[f.getName()] = v;
45498 * Clears all invalid messages in this form.
45499 * @return {BasicForm} this
45501 clearInvalid : function(){
45502 this.items.each(function(f){
45506 Roo.each(this.childForms || [], function (f) {
45515 * Resets this form.
45516 * @return {BasicForm} this
45518 reset : function(){
45519 this.items.each(function(f){
45523 Roo.each(this.childForms || [], function (f) {
45532 * Add Roo.form components to this form.
45533 * @param {Field} field1
45534 * @param {Field} field2 (optional)
45535 * @param {Field} etc (optional)
45536 * @return {BasicForm} this
45539 this.items.addAll(Array.prototype.slice.call(arguments, 0));
45545 * Removes a field from the items collection (does NOT remove its markup).
45546 * @param {Field} field
45547 * @return {BasicForm} this
45549 remove : function(field){
45550 this.items.remove(field);
45555 * Looks at the fields in this form, checks them for an id attribute,
45556 * and calls applyTo on the existing dom element with that id.
45557 * @return {BasicForm} this
45559 render : function(){
45560 this.items.each(function(f){
45561 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
45569 * Calls {@link Ext#apply} for all fields in this form with the passed object.
45570 * @param {Object} values
45571 * @return {BasicForm} this
45573 applyToFields : function(o){
45574 this.items.each(function(f){
45581 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
45582 * @param {Object} values
45583 * @return {BasicForm} this
45585 applyIfToFields : function(o){
45586 this.items.each(function(f){
45594 Roo.BasicForm = Roo.form.BasicForm;/*
45596 * Ext JS Library 1.1.1
45597 * Copyright(c) 2006-2007, Ext JS, LLC.
45599 * Originally Released Under LGPL - original licence link has changed is not relivant.
45602 * <script type="text/javascript">
45606 * @class Roo.form.Form
45607 * @extends Roo.form.BasicForm
45608 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
45610 * @param {Object} config Configuration options
45612 Roo.form.Form = function(config){
45614 if (config.items) {
45615 xitems = config.items;
45616 delete config.items;
45620 Roo.form.Form.superclass.constructor.call(this, null, config);
45621 this.url = this.url || this.action;
45623 this.root = new Roo.form.Layout(Roo.applyIf({
45627 this.active = this.root;
45629 * Array of all the buttons that have been added to this form via {@link addButton}
45633 this.allItems = [];
45636 * @event clientvalidation
45637 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45638 * @param {Form} this
45639 * @param {Boolean} valid true if the form has passed client-side validation
45641 clientvalidation: true,
45644 * Fires when the form is rendered
45645 * @param {Roo.form.Form} form
45650 if (this.progressUrl) {
45651 // push a hidden field onto the list of fields..
45655 name : 'UPLOAD_IDENTIFIER'
45660 Roo.each(xitems, this.addxtype, this);
45666 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45668 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45671 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45674 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45676 buttonAlign:'center',
45679 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45684 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45685 * This property cascades to child containers if not set.
45690 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45691 * fires a looping event with that state. This is required to bind buttons to the valid
45692 * state using the config value formBind:true on the button.
45694 monitorValid : false,
45697 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45702 * @cfg {String} progressUrl - Url to return progress data
45705 progressUrl : false,
45708 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45709 * fields are added and the column is closed. If no fields are passed the column remains open
45710 * until end() is called.
45711 * @param {Object} config The config to pass to the column
45712 * @param {Field} field1 (optional)
45713 * @param {Field} field2 (optional)
45714 * @param {Field} etc (optional)
45715 * @return Column The column container object
45717 column : function(c){
45718 var col = new Roo.form.Column(c);
45720 if(arguments.length > 1){ // duplicate code required because of Opera
45721 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45728 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45729 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45730 * until end() is called.
45731 * @param {Object} config The config to pass to the fieldset
45732 * @param {Field} field1 (optional)
45733 * @param {Field} field2 (optional)
45734 * @param {Field} etc (optional)
45735 * @return FieldSet The fieldset container object
45737 fieldset : function(c){
45738 var fs = new Roo.form.FieldSet(c);
45740 if(arguments.length > 1){ // duplicate code required because of Opera
45741 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45748 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45749 * fields are added and the container is closed. If no fields are passed the container remains open
45750 * until end() is called.
45751 * @param {Object} config The config to pass to the Layout
45752 * @param {Field} field1 (optional)
45753 * @param {Field} field2 (optional)
45754 * @param {Field} etc (optional)
45755 * @return Layout The container object
45757 container : function(c){
45758 var l = new Roo.form.Layout(c);
45760 if(arguments.length > 1){ // duplicate code required because of Opera
45761 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45768 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45769 * @param {Object} container A Roo.form.Layout or subclass of Layout
45770 * @return {Form} this
45772 start : function(c){
45773 // cascade label info
45774 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45775 this.active.stack.push(c);
45776 c.ownerCt = this.active;
45782 * Closes the current open container
45783 * @return {Form} this
45786 if(this.active == this.root){
45789 this.active = this.active.ownerCt;
45794 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45795 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45796 * as the label of the field.
45797 * @param {Field} field1
45798 * @param {Field} field2 (optional)
45799 * @param {Field} etc. (optional)
45800 * @return {Form} this
45803 this.active.stack.push.apply(this.active.stack, arguments);
45804 this.allItems.push.apply(this.allItems,arguments);
45806 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45807 if(a[i].isFormField){
45812 Roo.form.Form.superclass.add.apply(this, r);
45822 * Find any element that has been added to a form, using it's ID or name
45823 * This can include framesets, columns etc. along with regular fields..
45824 * @param {String} id - id or name to find.
45826 * @return {Element} e - or false if nothing found.
45828 findbyId : function(id)
45834 Roo.each(this.allItems, function(f){
45835 if (f.id == id || f.name == id ){
45846 * Render this form into the passed container. This should only be called once!
45847 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45848 * @return {Form} this
45850 render : function(ct)
45856 var o = this.autoCreate || {
45858 method : this.method || 'POST',
45859 id : this.id || Roo.id()
45861 this.initEl(ct.createChild(o));
45863 this.root.render(this.el);
45867 this.items.each(function(f){
45868 f.render('x-form-el-'+f.id);
45871 if(this.buttons.length > 0){
45872 // tables are required to maintain order and for correct IE layout
45873 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45874 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45875 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45877 var tr = tb.getElementsByTagName('tr')[0];
45878 for(var i = 0, len = this.buttons.length; i < len; i++) {
45879 var b = this.buttons[i];
45880 var td = document.createElement('td');
45881 td.className = 'x-form-btn-td';
45882 b.render(tr.appendChild(td));
45885 if(this.monitorValid){ // initialize after render
45886 this.startMonitoring();
45888 this.fireEvent('rendered', this);
45893 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45894 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45895 * object or a valid Roo.DomHelper element config
45896 * @param {Function} handler The function called when the button is clicked
45897 * @param {Object} scope (optional) The scope of the handler function
45898 * @return {Roo.Button}
45900 addButton : function(config, handler, scope){
45904 minWidth: this.minButtonWidth,
45907 if(typeof config == "string"){
45910 Roo.apply(bc, config);
45912 var btn = new Roo.Button(null, bc);
45913 this.buttons.push(btn);
45918 * Adds a series of form elements (using the xtype property as the factory method.
45919 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45920 * @param {Object} config
45923 addxtype : function()
45925 var ar = Array.prototype.slice.call(arguments, 0);
45927 for(var i = 0; i < ar.length; i++) {
45929 continue; // skip -- if this happends something invalid got sent, we
45930 // should ignore it, as basically that interface element will not show up
45931 // and that should be pretty obvious!!
45934 if (Roo.form[ar[i].xtype]) {
45936 var fe = Roo.factory(ar[i], Roo.form);
45942 fe.store.form = this;
45947 this.allItems.push(fe);
45948 if (fe.items && fe.addxtype) {
45949 fe.addxtype.apply(fe, fe.items);
45959 // console.log('adding ' + ar[i].xtype);
45961 if (ar[i].xtype == 'Button') {
45962 //console.log('adding button');
45963 //console.log(ar[i]);
45964 this.addButton(ar[i]);
45965 this.allItems.push(fe);
45969 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45970 alert('end is not supported on xtype any more, use items');
45972 // //console.log('adding end');
45980 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45981 * option "monitorValid"
45983 startMonitoring : function(){
45986 Roo.TaskMgr.start({
45987 run : this.bindHandler,
45988 interval : this.monitorPoll || 200,
45995 * Stops monitoring of the valid state of this form
45997 stopMonitoring : function(){
45998 this.bound = false;
46002 bindHandler : function(){
46004 return false; // stops binding
46007 this.items.each(function(f){
46008 if(!f.isValid(true)){
46013 for(var i = 0, len = this.buttons.length; i < len; i++){
46014 var btn = this.buttons[i];
46015 if(btn.formBind === true && btn.disabled === valid){
46016 btn.setDisabled(!valid);
46019 this.fireEvent('clientvalidation', this, valid);
46033 Roo.Form = Roo.form.Form;
46036 * Ext JS Library 1.1.1
46037 * Copyright(c) 2006-2007, Ext JS, LLC.
46039 * Originally Released Under LGPL - original licence link has changed is not relivant.
46042 * <script type="text/javascript">
46045 // as we use this in bootstrap.
46046 Roo.namespace('Roo.form');
46048 * @class Roo.form.Action
46049 * Internal Class used to handle form actions
46051 * @param {Roo.form.BasicForm} el The form element or its id
46052 * @param {Object} config Configuration options
46057 // define the action interface
46058 Roo.form.Action = function(form, options){
46060 this.options = options || {};
46063 * Client Validation Failed
46066 Roo.form.Action.CLIENT_INVALID = 'client';
46068 * Server Validation Failed
46071 Roo.form.Action.SERVER_INVALID = 'server';
46073 * Connect to Server Failed
46076 Roo.form.Action.CONNECT_FAILURE = 'connect';
46078 * Reading Data from Server Failed
46081 Roo.form.Action.LOAD_FAILURE = 'load';
46083 Roo.form.Action.prototype = {
46085 failureType : undefined,
46086 response : undefined,
46087 result : undefined,
46089 // interface method
46090 run : function(options){
46094 // interface method
46095 success : function(response){
46099 // interface method
46100 handleResponse : function(response){
46104 // default connection failure
46105 failure : function(response){
46107 this.response = response;
46108 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46109 this.form.afterAction(this, false);
46112 processResponse : function(response){
46113 this.response = response;
46114 if(!response.responseText){
46117 this.result = this.handleResponse(response);
46118 return this.result;
46121 // utility functions used internally
46122 getUrl : function(appendParams){
46123 var url = this.options.url || this.form.url || this.form.el.dom.action;
46125 var p = this.getParams();
46127 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
46133 getMethod : function(){
46134 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
46137 getParams : function(){
46138 var bp = this.form.baseParams;
46139 var p = this.options.params;
46141 if(typeof p == "object"){
46142 p = Roo.urlEncode(Roo.applyIf(p, bp));
46143 }else if(typeof p == 'string' && bp){
46144 p += '&' + Roo.urlEncode(bp);
46147 p = Roo.urlEncode(bp);
46152 createCallback : function(){
46154 success: this.success,
46155 failure: this.failure,
46157 timeout: (this.form.timeout*1000),
46158 upload: this.form.fileUpload ? this.success : undefined
46163 Roo.form.Action.Submit = function(form, options){
46164 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
46167 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
46170 haveProgress : false,
46171 uploadComplete : false,
46173 // uploadProgress indicator.
46174 uploadProgress : function()
46176 if (!this.form.progressUrl) {
46180 if (!this.haveProgress) {
46181 Roo.MessageBox.progress("Uploading", "Uploading");
46183 if (this.uploadComplete) {
46184 Roo.MessageBox.hide();
46188 this.haveProgress = true;
46190 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
46192 var c = new Roo.data.Connection();
46194 url : this.form.progressUrl,
46199 success : function(req){
46200 //console.log(data);
46204 rdata = Roo.decode(req.responseText)
46206 Roo.log("Invalid data from server..");
46210 if (!rdata || !rdata.success) {
46212 Roo.MessageBox.alert(Roo.encode(rdata));
46215 var data = rdata.data;
46217 if (this.uploadComplete) {
46218 Roo.MessageBox.hide();
46223 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
46224 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
46227 this.uploadProgress.defer(2000,this);
46230 failure: function(data) {
46231 Roo.log('progress url failed ');
46242 // run get Values on the form, so it syncs any secondary forms.
46243 this.form.getValues();
46245 var o = this.options;
46246 var method = this.getMethod();
46247 var isPost = method == 'POST';
46248 if(o.clientValidation === false || this.form.isValid()){
46250 if (this.form.progressUrl) {
46251 this.form.findField('UPLOAD_IDENTIFIER').setValue(
46252 (new Date() * 1) + '' + Math.random());
46257 Roo.Ajax.request(Roo.apply(this.createCallback(), {
46258 form:this.form.el.dom,
46259 url:this.getUrl(!isPost),
46261 params:isPost ? this.getParams() : null,
46262 isUpload: this.form.fileUpload
46265 this.uploadProgress();
46267 }else if (o.clientValidation !== false){ // client validation failed
46268 this.failureType = Roo.form.Action.CLIENT_INVALID;
46269 this.form.afterAction(this, false);
46273 success : function(response)
46275 this.uploadComplete= true;
46276 if (this.haveProgress) {
46277 Roo.MessageBox.hide();
46281 var result = this.processResponse(response);
46282 if(result === true || result.success){
46283 this.form.afterAction(this, true);
46287 this.form.markInvalid(result.errors);
46288 this.failureType = Roo.form.Action.SERVER_INVALID;
46290 this.form.afterAction(this, false);
46292 failure : function(response)
46294 this.uploadComplete= true;
46295 if (this.haveProgress) {
46296 Roo.MessageBox.hide();
46299 this.response = response;
46300 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46301 this.form.afterAction(this, false);
46304 handleResponse : function(response){
46305 if(this.form.errorReader){
46306 var rs = this.form.errorReader.read(response);
46309 for(var i = 0, len = rs.records.length; i < len; i++) {
46310 var r = rs.records[i];
46311 errors[i] = r.data;
46314 if(errors.length < 1){
46318 success : rs.success,
46324 ret = Roo.decode(response.responseText);
46328 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
46338 Roo.form.Action.Load = function(form, options){
46339 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
46340 this.reader = this.form.reader;
46343 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
46348 Roo.Ajax.request(Roo.apply(
46349 this.createCallback(), {
46350 method:this.getMethod(),
46351 url:this.getUrl(false),
46352 params:this.getParams()
46356 success : function(response){
46358 var result = this.processResponse(response);
46359 if(result === true || !result.success || !result.data){
46360 this.failureType = Roo.form.Action.LOAD_FAILURE;
46361 this.form.afterAction(this, false);
46364 this.form.clearInvalid();
46365 this.form.setValues(result.data);
46366 this.form.afterAction(this, true);
46369 handleResponse : function(response){
46370 if(this.form.reader){
46371 var rs = this.form.reader.read(response);
46372 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
46374 success : rs.success,
46378 return Roo.decode(response.responseText);
46382 Roo.form.Action.ACTION_TYPES = {
46383 'load' : Roo.form.Action.Load,
46384 'submit' : Roo.form.Action.Submit
46387 * Ext JS Library 1.1.1
46388 * Copyright(c) 2006-2007, Ext JS, LLC.
46390 * Originally Released Under LGPL - original licence link has changed is not relivant.
46393 * <script type="text/javascript">
46397 * @class Roo.form.Layout
46398 * @extends Roo.Component
46399 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
46401 * @param {Object} config Configuration options
46403 Roo.form.Layout = function(config){
46405 if (config.items) {
46406 xitems = config.items;
46407 delete config.items;
46409 Roo.form.Layout.superclass.constructor.call(this, config);
46411 Roo.each(xitems, this.addxtype, this);
46415 Roo.extend(Roo.form.Layout, Roo.Component, {
46417 * @cfg {String/Object} autoCreate
46418 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
46421 * @cfg {String/Object/Function} style
46422 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
46423 * a function which returns such a specification.
46426 * @cfg {String} labelAlign
46427 * Valid values are "left," "top" and "right" (defaults to "left")
46430 * @cfg {Number} labelWidth
46431 * Fixed width in pixels of all field labels (defaults to undefined)
46434 * @cfg {Boolean} clear
46435 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
46439 * @cfg {String} labelSeparator
46440 * The separator to use after field labels (defaults to ':')
46442 labelSeparator : ':',
46444 * @cfg {Boolean} hideLabels
46445 * True to suppress the display of field labels in this layout (defaults to false)
46447 hideLabels : false,
46450 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
46455 onRender : function(ct, position){
46456 if(this.el){ // from markup
46457 this.el = Roo.get(this.el);
46458 }else { // generate
46459 var cfg = this.getAutoCreate();
46460 this.el = ct.createChild(cfg, position);
46463 this.el.applyStyles(this.style);
46465 if(this.labelAlign){
46466 this.el.addClass('x-form-label-'+this.labelAlign);
46468 if(this.hideLabels){
46469 this.labelStyle = "display:none";
46470 this.elementStyle = "padding-left:0;";
46472 if(typeof this.labelWidth == 'number'){
46473 this.labelStyle = "width:"+this.labelWidth+"px;";
46474 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
46476 if(this.labelAlign == 'top'){
46477 this.labelStyle = "width:auto;";
46478 this.elementStyle = "padding-left:0;";
46481 var stack = this.stack;
46482 var slen = stack.length;
46484 if(!this.fieldTpl){
46485 var t = new Roo.Template(
46486 '<div class="x-form-item {5}">',
46487 '<label for="{0}" style="{2}">{1}{4}</label>',
46488 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46490 '</div><div class="x-form-clear-left"></div>'
46492 t.disableFormats = true;
46494 Roo.form.Layout.prototype.fieldTpl = t;
46496 for(var i = 0; i < slen; i++) {
46497 if(stack[i].isFormField){
46498 this.renderField(stack[i]);
46500 this.renderComponent(stack[i]);
46505 this.el.createChild({cls:'x-form-clear'});
46510 renderField : function(f){
46511 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
46514 f.labelStyle||this.labelStyle||'', //2
46515 this.elementStyle||'', //3
46516 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
46517 f.itemCls||this.itemCls||'' //5
46518 ], true).getPrevSibling());
46522 renderComponent : function(c){
46523 c.render(c.isLayout ? this.el : this.el.createChild());
46526 * Adds a object form elements (using the xtype property as the factory method.)
46527 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
46528 * @param {Object} config
46530 addxtype : function(o)
46532 // create the lement.
46533 o.form = this.form;
46534 var fe = Roo.factory(o, Roo.form);
46535 this.form.allItems.push(fe);
46536 this.stack.push(fe);
46538 if (fe.isFormField) {
46539 this.form.items.add(fe);
46547 * @class Roo.form.Column
46548 * @extends Roo.form.Layout
46549 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
46551 * @param {Object} config Configuration options
46553 Roo.form.Column = function(config){
46554 Roo.form.Column.superclass.constructor.call(this, config);
46557 Roo.extend(Roo.form.Column, Roo.form.Layout, {
46559 * @cfg {Number/String} width
46560 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46563 * @cfg {String/Object} autoCreate
46564 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
46568 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
46571 onRender : function(ct, position){
46572 Roo.form.Column.superclass.onRender.call(this, ct, position);
46574 this.el.setWidth(this.width);
46581 * @class Roo.form.Row
46582 * @extends Roo.form.Layout
46583 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
46585 * @param {Object} config Configuration options
46589 Roo.form.Row = function(config){
46590 Roo.form.Row.superclass.constructor.call(this, config);
46593 Roo.extend(Roo.form.Row, Roo.form.Layout, {
46595 * @cfg {Number/String} width
46596 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46599 * @cfg {Number/String} height
46600 * The fixed height of the column in pixels or CSS value (defaults to "auto")
46602 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
46606 onRender : function(ct, position){
46607 //console.log('row render');
46609 var t = new Roo.Template(
46610 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
46611 '<label for="{0}" style="{2}">{1}{4}</label>',
46612 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46616 t.disableFormats = true;
46618 Roo.form.Layout.prototype.rowTpl = t;
46620 this.fieldTpl = this.rowTpl;
46622 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46623 var labelWidth = 100;
46625 if ((this.labelAlign != 'top')) {
46626 if (typeof this.labelWidth == 'number') {
46627 labelWidth = this.labelWidth
46629 this.padWidth = 20 + labelWidth;
46633 Roo.form.Column.superclass.onRender.call(this, ct, position);
46635 this.el.setWidth(this.width);
46638 this.el.setHeight(this.height);
46643 renderField : function(f){
46644 f.fieldEl = this.fieldTpl.append(this.el, [
46645 f.id, f.fieldLabel,
46646 f.labelStyle||this.labelStyle||'',
46647 this.elementStyle||'',
46648 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46649 f.itemCls||this.itemCls||'',
46650 f.width ? f.width + this.padWidth : 160 + this.padWidth
46657 * @class Roo.form.FieldSet
46658 * @extends Roo.form.Layout
46659 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46661 * @param {Object} config Configuration options
46663 Roo.form.FieldSet = function(config){
46664 Roo.form.FieldSet.superclass.constructor.call(this, config);
46667 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46669 * @cfg {String} legend
46670 * The text to display as the legend for the FieldSet (defaults to '')
46673 * @cfg {String/Object} autoCreate
46674 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46678 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46681 onRender : function(ct, position){
46682 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46684 this.setLegend(this.legend);
46689 setLegend : function(text){
46691 this.el.child('legend').update(text);
46696 * Ext JS Library 1.1.1
46697 * Copyright(c) 2006-2007, Ext JS, LLC.
46699 * Originally Released Under LGPL - original licence link has changed is not relivant.
46702 * <script type="text/javascript">
46705 * @class Roo.form.VTypes
46706 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46709 Roo.form.VTypes = function(){
46710 // closure these in so they are only created once.
46711 var alpha = /^[a-zA-Z_]+$/;
46712 var alphanum = /^[a-zA-Z0-9_]+$/;
46713 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46714 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46716 // All these messages and functions are configurable
46719 * The function used to validate email addresses
46720 * @param {String} value The email address
46722 'email' : function(v){
46723 return email.test(v);
46726 * The error text to display when the email validation function returns false
46729 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46731 * The keystroke filter mask to be applied on email input
46734 'emailMask' : /[a-z0-9_\.\-@]/i,
46737 * The function used to validate URLs
46738 * @param {String} value The URL
46740 'url' : function(v){
46741 return url.test(v);
46744 * The error text to display when the url validation function returns false
46747 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46750 * The function used to validate alpha values
46751 * @param {String} value The value
46753 'alpha' : function(v){
46754 return alpha.test(v);
46757 * The error text to display when the alpha validation function returns false
46760 'alphaText' : 'This field should only contain letters and _',
46762 * The keystroke filter mask to be applied on alpha input
46765 'alphaMask' : /[a-z_]/i,
46768 * The function used to validate alphanumeric values
46769 * @param {String} value The value
46771 'alphanum' : function(v){
46772 return alphanum.test(v);
46775 * The error text to display when the alphanumeric validation function returns false
46778 'alphanumText' : 'This field should only contain letters, numbers and _',
46780 * The keystroke filter mask to be applied on alphanumeric input
46783 'alphanumMask' : /[a-z0-9_]/i
46785 }();//<script type="text/javascript">
46788 * @class Roo.form.FCKeditor
46789 * @extends Roo.form.TextArea
46790 * Wrapper around the FCKEditor http://www.fckeditor.net
46792 * Creates a new FCKeditor
46793 * @param {Object} config Configuration options
46795 Roo.form.FCKeditor = function(config){
46796 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46799 * @event editorinit
46800 * Fired when the editor is initialized - you can add extra handlers here..
46801 * @param {FCKeditor} this
46802 * @param {Object} the FCK object.
46809 Roo.form.FCKeditor.editors = { };
46810 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46812 //defaultAutoCreate : {
46813 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46817 * @cfg {Object} fck options - see fck manual for details.
46822 * @cfg {Object} fck toolbar set (Basic or Default)
46824 toolbarSet : 'Basic',
46826 * @cfg {Object} fck BasePath
46828 basePath : '/fckeditor/',
46836 onRender : function(ct, position)
46839 this.defaultAutoCreate = {
46841 style:"width:300px;height:60px;",
46842 autocomplete: "new-password"
46845 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46848 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46849 if(this.preventScrollbars){
46850 this.el.setStyle("overflow", "hidden");
46852 this.el.setHeight(this.growMin);
46855 //console.log('onrender' + this.getId() );
46856 Roo.form.FCKeditor.editors[this.getId()] = this;
46859 this.replaceTextarea() ;
46863 getEditor : function() {
46864 return this.fckEditor;
46867 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46868 * @param {Mixed} value The value to set
46872 setValue : function(value)
46874 //console.log('setValue: ' + value);
46876 if(typeof(value) == 'undefined') { // not sure why this is happending...
46879 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46881 //if(!this.el || !this.getEditor()) {
46882 // this.value = value;
46883 //this.setValue.defer(100,this,[value]);
46887 if(!this.getEditor()) {
46891 this.getEditor().SetData(value);
46898 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46899 * @return {Mixed} value The field value
46901 getValue : function()
46904 if (this.frame && this.frame.dom.style.display == 'none') {
46905 return Roo.form.FCKeditor.superclass.getValue.call(this);
46908 if(!this.el || !this.getEditor()) {
46910 // this.getValue.defer(100,this);
46915 var value=this.getEditor().GetData();
46916 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46917 return Roo.form.FCKeditor.superclass.getValue.call(this);
46923 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46924 * @return {Mixed} value The field value
46926 getRawValue : function()
46928 if (this.frame && this.frame.dom.style.display == 'none') {
46929 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46932 if(!this.el || !this.getEditor()) {
46933 //this.getRawValue.defer(100,this);
46940 var value=this.getEditor().GetData();
46941 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46942 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46946 setSize : function(w,h) {
46950 //if (this.frame && this.frame.dom.style.display == 'none') {
46951 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46954 //if(!this.el || !this.getEditor()) {
46955 // this.setSize.defer(100,this, [w,h]);
46961 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46963 this.frame.dom.setAttribute('width', w);
46964 this.frame.dom.setAttribute('height', h);
46965 this.frame.setSize(w,h);
46969 toggleSourceEdit : function(value) {
46973 this.el.dom.style.display = value ? '' : 'none';
46974 this.frame.dom.style.display = value ? 'none' : '';
46979 focus: function(tag)
46981 if (this.frame.dom.style.display == 'none') {
46982 return Roo.form.FCKeditor.superclass.focus.call(this);
46984 if(!this.el || !this.getEditor()) {
46985 this.focus.defer(100,this, [tag]);
46992 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46993 this.getEditor().Focus();
46995 if (!this.getEditor().Selection.GetSelection()) {
46996 this.focus.defer(100,this, [tag]);
47001 var r = this.getEditor().EditorDocument.createRange();
47002 r.setStart(tgs[0],0);
47003 r.setEnd(tgs[0],0);
47004 this.getEditor().Selection.GetSelection().removeAllRanges();
47005 this.getEditor().Selection.GetSelection().addRange(r);
47006 this.getEditor().Focus();
47013 replaceTextarea : function()
47015 if ( document.getElementById( this.getId() + '___Frame' ) )
47017 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
47019 // We must check the elements firstly using the Id and then the name.
47020 var oTextarea = document.getElementById( this.getId() );
47022 var colElementsByName = document.getElementsByName( this.getId() ) ;
47024 oTextarea.style.display = 'none' ;
47026 if ( oTextarea.tabIndex ) {
47027 this.TabIndex = oTextarea.tabIndex ;
47030 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
47031 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
47032 this.frame = Roo.get(this.getId() + '___Frame')
47035 _getConfigHtml : function()
47039 for ( var o in this.fckconfig ) {
47040 sConfig += sConfig.length > 0 ? '&' : '';
47041 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
47044 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
47048 _getIFrameHtml : function()
47050 var sFile = 'fckeditor.html' ;
47051 /* no idea what this is about..
47054 if ( (/fcksource=true/i).test( window.top.location.search ) )
47055 sFile = 'fckeditor.original.html' ;
47060 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
47061 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
47064 var html = '<iframe id="' + this.getId() +
47065 '___Frame" src="' + sLink +
47066 '" width="' + this.width +
47067 '" height="' + this.height + '"' +
47068 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
47069 ' frameborder="0" scrolling="no"></iframe>' ;
47074 _insertHtmlBefore : function( html, element )
47076 if ( element.insertAdjacentHTML ) {
47078 element.insertAdjacentHTML( 'beforeBegin', html ) ;
47080 var oRange = document.createRange() ;
47081 oRange.setStartBefore( element ) ;
47082 var oFragment = oRange.createContextualFragment( html );
47083 element.parentNode.insertBefore( oFragment, element ) ;
47096 //Roo.reg('fckeditor', Roo.form.FCKeditor);
47098 function FCKeditor_OnComplete(editorInstance){
47099 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
47100 f.fckEditor = editorInstance;
47101 //console.log("loaded");
47102 f.fireEvent('editorinit', f, editorInstance);
47122 //<script type="text/javascript">
47124 * @class Roo.form.GridField
47125 * @extends Roo.form.Field
47126 * Embed a grid (or editable grid into a form)
47129 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
47131 * xgrid.store = Roo.data.Store
47132 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
47133 * xgrid.store.reader = Roo.data.JsonReader
47137 * Creates a new GridField
47138 * @param {Object} config Configuration options
47140 Roo.form.GridField = function(config){
47141 Roo.form.GridField.superclass.constructor.call(this, config);
47145 Roo.extend(Roo.form.GridField, Roo.form.Field, {
47147 * @cfg {Number} width - used to restrict width of grid..
47151 * @cfg {Number} height - used to restrict height of grid..
47155 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
47161 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47162 * {tag: "input", type: "checkbox", autocomplete: "off"})
47164 // defaultAutoCreate : { tag: 'div' },
47165 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
47167 * @cfg {String} addTitle Text to include for adding a title.
47171 onResize : function(){
47172 Roo.form.Field.superclass.onResize.apply(this, arguments);
47175 initEvents : function(){
47176 // Roo.form.Checkbox.superclass.initEvents.call(this);
47177 // has no events...
47182 getResizeEl : function(){
47186 getPositionEl : function(){
47191 onRender : function(ct, position){
47193 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
47194 var style = this.style;
47197 Roo.form.GridField.superclass.onRender.call(this, ct, position);
47198 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
47199 this.viewEl = this.wrap.createChild({ tag: 'div' });
47201 this.viewEl.applyStyles(style);
47204 this.viewEl.setWidth(this.width);
47207 this.viewEl.setHeight(this.height);
47209 //if(this.inputValue !== undefined){
47210 //this.setValue(this.value);
47213 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
47216 this.grid.render();
47217 this.grid.getDataSource().on('remove', this.refreshValue, this);
47218 this.grid.getDataSource().on('update', this.refreshValue, this);
47219 this.grid.on('afteredit', this.refreshValue, this);
47225 * Sets the value of the item.
47226 * @param {String} either an object or a string..
47228 setValue : function(v){
47230 v = v || []; // empty set..
47231 // this does not seem smart - it really only affects memoryproxy grids..
47232 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
47233 var ds = this.grid.getDataSource();
47234 // assumes a json reader..
47236 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
47237 ds.loadData( data);
47239 // clear selection so it does not get stale.
47240 if (this.grid.sm) {
47241 this.grid.sm.clearSelections();
47244 Roo.form.GridField.superclass.setValue.call(this, v);
47245 this.refreshValue();
47246 // should load data in the grid really....
47250 refreshValue: function() {
47252 this.grid.getDataSource().each(function(r) {
47255 this.el.dom.value = Roo.encode(val);
47263 * Ext JS Library 1.1.1
47264 * Copyright(c) 2006-2007, Ext JS, LLC.
47266 * Originally Released Under LGPL - original licence link has changed is not relivant.
47269 * <script type="text/javascript">
47272 * @class Roo.form.DisplayField
47273 * @extends Roo.form.Field
47274 * A generic Field to display non-editable data.
47276 * Creates a new Display Field item.
47277 * @param {Object} config Configuration options
47279 Roo.form.DisplayField = function(config){
47280 Roo.form.DisplayField.superclass.constructor.call(this, config);
47284 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
47285 inputType: 'hidden',
47291 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47293 focusClass : undefined,
47295 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47297 fieldClass: 'x-form-field',
47300 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
47302 valueRenderer: undefined,
47306 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47307 * {tag: "input", type: "checkbox", autocomplete: "off"})
47310 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
47312 onResize : function(){
47313 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
47317 initEvents : function(){
47318 // Roo.form.Checkbox.superclass.initEvents.call(this);
47319 // has no events...
47324 getResizeEl : function(){
47328 getPositionEl : function(){
47333 onRender : function(ct, position){
47335 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
47336 //if(this.inputValue !== undefined){
47337 this.wrap = this.el.wrap();
47339 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
47341 if (this.bodyStyle) {
47342 this.viewEl.applyStyles(this.bodyStyle);
47344 //this.viewEl.setStyle('padding', '2px');
47346 this.setValue(this.value);
47351 initValue : Roo.emptyFn,
47356 onClick : function(){
47361 * Sets the checked state of the checkbox.
47362 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
47364 setValue : function(v){
47366 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
47367 // this might be called before we have a dom element..
47368 if (!this.viewEl) {
47371 this.viewEl.dom.innerHTML = html;
47372 Roo.form.DisplayField.superclass.setValue.call(this, v);
47382 * @class Roo.form.DayPicker
47383 * @extends Roo.form.Field
47384 * A Day picker show [M] [T] [W] ....
47386 * Creates a new Day Picker
47387 * @param {Object} config Configuration options
47389 Roo.form.DayPicker= function(config){
47390 Roo.form.DayPicker.superclass.constructor.call(this, config);
47394 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
47396 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47398 focusClass : undefined,
47400 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47402 fieldClass: "x-form-field",
47405 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47406 * {tag: "input", type: "checkbox", autocomplete: "off"})
47408 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
47411 actionMode : 'viewEl',
47415 inputType : 'hidden',
47418 inputElement: false, // real input element?
47419 basedOn: false, // ????
47421 isFormField: true, // not sure where this is needed!!!!
47423 onResize : function(){
47424 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
47425 if(!this.boxLabel){
47426 this.el.alignTo(this.wrap, 'c-c');
47430 initEvents : function(){
47431 Roo.form.Checkbox.superclass.initEvents.call(this);
47432 this.el.on("click", this.onClick, this);
47433 this.el.on("change", this.onClick, this);
47437 getResizeEl : function(){
47441 getPositionEl : function(){
47447 onRender : function(ct, position){
47448 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
47450 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
47452 var r1 = '<table><tr>';
47453 var r2 = '<tr class="x-form-daypick-icons">';
47454 for (var i=0; i < 7; i++) {
47455 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
47456 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
47459 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
47460 viewEl.select('img').on('click', this.onClick, this);
47461 this.viewEl = viewEl;
47464 // this will not work on Chrome!!!
47465 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
47466 this.el.on('propertychange', this.setFromHidden, this); //ie
47474 initValue : Roo.emptyFn,
47477 * Returns the checked state of the checkbox.
47478 * @return {Boolean} True if checked, else false
47480 getValue : function(){
47481 return this.el.dom.value;
47486 onClick : function(e){
47487 //this.setChecked(!this.checked);
47488 Roo.get(e.target).toggleClass('x-menu-item-checked');
47489 this.refreshValue();
47490 //if(this.el.dom.checked != this.checked){
47491 // this.setValue(this.el.dom.checked);
47496 refreshValue : function()
47499 this.viewEl.select('img',true).each(function(e,i,n) {
47500 val += e.is(".x-menu-item-checked") ? String(n) : '';
47502 this.setValue(val, true);
47506 * Sets the checked state of the checkbox.
47507 * On is always based on a string comparison between inputValue and the param.
47508 * @param {Boolean/String} value - the value to set
47509 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
47511 setValue : function(v,suppressEvent){
47512 if (!this.el.dom) {
47515 var old = this.el.dom.value ;
47516 this.el.dom.value = v;
47517 if (suppressEvent) {
47521 // update display..
47522 this.viewEl.select('img',true).each(function(e,i,n) {
47524 var on = e.is(".x-menu-item-checked");
47525 var newv = v.indexOf(String(n)) > -1;
47527 e.toggleClass('x-menu-item-checked');
47533 this.fireEvent('change', this, v, old);
47538 // handle setting of hidden value by some other method!!?!?
47539 setFromHidden: function()
47544 //console.log("SET FROM HIDDEN");
47545 //alert('setFrom hidden');
47546 this.setValue(this.el.dom.value);
47549 onDestroy : function()
47552 Roo.get(this.viewEl).remove();
47555 Roo.form.DayPicker.superclass.onDestroy.call(this);
47559 * RooJS Library 1.1.1
47560 * Copyright(c) 2008-2011 Alan Knowles
47567 * @class Roo.form.ComboCheck
47568 * @extends Roo.form.ComboBox
47569 * A combobox for multiple select items.
47571 * FIXME - could do with a reset button..
47574 * Create a new ComboCheck
47575 * @param {Object} config Configuration options
47577 Roo.form.ComboCheck = function(config){
47578 Roo.form.ComboCheck.superclass.constructor.call(this, config);
47579 // should verify some data...
47581 // hiddenName = required..
47582 // displayField = required
47583 // valudField == required
47584 var req= [ 'hiddenName', 'displayField', 'valueField' ];
47586 Roo.each(req, function(e) {
47587 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
47588 throw "Roo.form.ComboCheck : missing value for: " + e;
47595 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
47600 selectedClass: 'x-menu-item-checked',
47603 onRender : function(ct, position){
47609 var cls = 'x-combo-list';
47612 this.tpl = new Roo.Template({
47613 html : '<div class="'+cls+'-item x-menu-check-item">' +
47614 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47615 '<span>{' + this.displayField + '}</span>' +
47622 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47623 this.view.singleSelect = false;
47624 this.view.multiSelect = true;
47625 this.view.toggleSelect = true;
47626 this.pageTb.add(new Roo.Toolbar.Fill(), {
47629 handler: function()
47636 onViewOver : function(e, t){
47642 onViewClick : function(doFocus,index){
47646 select: function () {
47647 //Roo.log("SELECT CALLED");
47650 selectByValue : function(xv, scrollIntoView){
47651 var ar = this.getValueArray();
47654 Roo.each(ar, function(v) {
47655 if(v === undefined || v === null){
47658 var r = this.findRecord(this.valueField, v);
47660 sels.push(this.store.indexOf(r))
47664 this.view.select(sels);
47670 onSelect : function(record, index){
47671 // Roo.log("onselect Called");
47672 // this is only called by the clear button now..
47673 this.view.clearSelections();
47674 this.setValue('[]');
47675 if (this.value != this.valueBefore) {
47676 this.fireEvent('change', this, this.value, this.valueBefore);
47677 this.valueBefore = this.value;
47680 getValueArray : function()
47685 //Roo.log(this.value);
47686 if (typeof(this.value) == 'undefined') {
47689 var ar = Roo.decode(this.value);
47690 return ar instanceof Array ? ar : []; //?? valid?
47693 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47698 expand : function ()
47701 Roo.form.ComboCheck.superclass.expand.call(this);
47702 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47703 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47708 collapse : function(){
47709 Roo.form.ComboCheck.superclass.collapse.call(this);
47710 var sl = this.view.getSelectedIndexes();
47711 var st = this.store;
47715 Roo.each(sl, function(i) {
47717 nv.push(r.get(this.valueField));
47719 this.setValue(Roo.encode(nv));
47720 if (this.value != this.valueBefore) {
47722 this.fireEvent('change', this, this.value, this.valueBefore);
47723 this.valueBefore = this.value;
47728 setValue : function(v){
47732 var vals = this.getValueArray();
47734 Roo.each(vals, function(k) {
47735 var r = this.findRecord(this.valueField, k);
47737 tv.push(r.data[this.displayField]);
47738 }else if(this.valueNotFoundText !== undefined){
47739 tv.push( this.valueNotFoundText );
47744 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47745 this.hiddenField.value = v;
47751 * Ext JS Library 1.1.1
47752 * Copyright(c) 2006-2007, Ext JS, LLC.
47754 * Originally Released Under LGPL - original licence link has changed is not relivant.
47757 * <script type="text/javascript">
47761 * @class Roo.form.Signature
47762 * @extends Roo.form.Field
47766 * @param {Object} config Configuration options
47769 Roo.form.Signature = function(config){
47770 Roo.form.Signature.superclass.constructor.call(this, config);
47772 this.addEvents({// not in used??
47775 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47776 * @param {Roo.form.Signature} combo This combo box
47781 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47782 * @param {Roo.form.ComboBox} combo This combo box
47783 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47789 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47791 * @cfg {Object} labels Label to use when rendering a form.
47795 * confirm : "Confirm"
47800 confirm : "Confirm"
47803 * @cfg {Number} width The signature panel width (defaults to 300)
47807 * @cfg {Number} height The signature panel height (defaults to 100)
47811 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47813 allowBlank : false,
47816 // {Object} signPanel The signature SVG panel element (defaults to {})
47818 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47819 isMouseDown : false,
47820 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47821 isConfirmed : false,
47822 // {String} signatureTmp SVG mapping string (defaults to empty string)
47826 defaultAutoCreate : { // modified by initCompnoent..
47832 onRender : function(ct, position){
47834 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47836 this.wrap = this.el.wrap({
47837 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47840 this.createToolbar(this);
47841 this.signPanel = this.wrap.createChild({
47843 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47847 this.svgID = Roo.id();
47848 this.svgEl = this.signPanel.createChild({
47849 xmlns : 'http://www.w3.org/2000/svg',
47851 id : this.svgID + "-svg",
47853 height: this.height,
47854 viewBox: '0 0 '+this.width+' '+this.height,
47858 id: this.svgID + "-svg-r",
47860 height: this.height,
47865 id: this.svgID + "-svg-l",
47867 y1: (this.height*0.8), // start set the line in 80% of height
47868 x2: this.width, // end
47869 y2: (this.height*0.8), // end set the line in 80% of height
47871 'stroke-width': "1",
47872 'stroke-dasharray': "3",
47873 'shape-rendering': "crispEdges",
47874 'pointer-events': "none"
47878 id: this.svgID + "-svg-p",
47880 'stroke-width': "3",
47882 'pointer-events': 'none'
47887 this.svgBox = this.svgEl.dom.getScreenCTM();
47889 createSVG : function(){
47890 var svg = this.signPanel;
47891 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47894 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47895 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47896 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47897 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47898 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47899 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47900 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47903 isTouchEvent : function(e){
47904 return e.type.match(/^touch/);
47906 getCoords : function (e) {
47907 var pt = this.svgEl.dom.createSVGPoint();
47910 if (this.isTouchEvent(e)) {
47911 pt.x = e.targetTouches[0].clientX;
47912 pt.y = e.targetTouches[0].clientY;
47914 var a = this.svgEl.dom.getScreenCTM();
47915 var b = a.inverse();
47916 var mx = pt.matrixTransform(b);
47917 return mx.x + ',' + mx.y;
47919 //mouse event headler
47920 down : function (e) {
47921 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47922 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47924 this.isMouseDown = true;
47926 e.preventDefault();
47928 move : function (e) {
47929 if (this.isMouseDown) {
47930 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47931 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47934 e.preventDefault();
47936 up : function (e) {
47937 this.isMouseDown = false;
47938 var sp = this.signatureTmp.split(' ');
47941 if(!sp[sp.length-2].match(/^L/)){
47945 this.signatureTmp = sp.join(" ");
47948 if(this.getValue() != this.signatureTmp){
47949 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47950 this.isConfirmed = false;
47952 e.preventDefault();
47956 * Protected method that will not generally be called directly. It
47957 * is called when the editor creates its toolbar. Override this method if you need to
47958 * add custom toolbar buttons.
47959 * @param {HtmlEditor} editor
47961 createToolbar : function(editor){
47962 function btn(id, toggle, handler){
47963 var xid = fid + '-'+ id ;
47967 cls : 'x-btn-icon x-edit-'+id,
47968 enableToggle:toggle !== false,
47969 scope: editor, // was editor...
47970 handler:handler||editor.relayBtnCmd,
47971 clickEvent:'mousedown',
47972 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47978 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47982 cls : ' x-signature-btn x-signature-'+id,
47983 scope: editor, // was editor...
47984 handler: this.reset,
47985 clickEvent:'mousedown',
47986 text: this.labels.clear
47993 cls : ' x-signature-btn x-signature-'+id,
47994 scope: editor, // was editor...
47995 handler: this.confirmHandler,
47996 clickEvent:'mousedown',
47997 text: this.labels.confirm
48004 * when user is clicked confirm then show this image.....
48006 * @return {String} Image Data URI
48008 getImageDataURI : function(){
48009 var svg = this.svgEl.dom.parentNode.innerHTML;
48010 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
48015 * @return {Boolean} this.isConfirmed
48017 getConfirmed : function(){
48018 return this.isConfirmed;
48022 * @return {Number} this.width
48024 getWidth : function(){
48029 * @return {Number} this.height
48031 getHeight : function(){
48032 return this.height;
48035 getSignature : function(){
48036 return this.signatureTmp;
48039 reset : function(){
48040 this.signatureTmp = '';
48041 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48042 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
48043 this.isConfirmed = false;
48044 Roo.form.Signature.superclass.reset.call(this);
48046 setSignature : function(s){
48047 this.signatureTmp = s;
48048 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48049 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
48051 this.isConfirmed = false;
48052 Roo.form.Signature.superclass.reset.call(this);
48055 // Roo.log(this.signPanel.dom.contentWindow.up())
48058 setConfirmed : function(){
48062 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
48065 confirmHandler : function(){
48066 if(!this.getSignature()){
48070 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
48071 this.setValue(this.getSignature());
48072 this.isConfirmed = true;
48074 this.fireEvent('confirm', this);
48077 // Subclasses should provide the validation implementation by overriding this
48078 validateValue : function(value){
48079 if(this.allowBlank){
48083 if(this.isConfirmed){
48090 * Ext JS Library 1.1.1
48091 * Copyright(c) 2006-2007, Ext JS, LLC.
48093 * Originally Released Under LGPL - original licence link has changed is not relivant.
48096 * <script type="text/javascript">
48101 * @class Roo.form.ComboBox
48102 * @extends Roo.form.TriggerField
48103 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
48105 * Create a new ComboBox.
48106 * @param {Object} config Configuration options
48108 Roo.form.Select = function(config){
48109 Roo.form.Select.superclass.constructor.call(this, config);
48113 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
48115 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
48118 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
48119 * rendering into an Roo.Editor, defaults to false)
48122 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
48123 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
48126 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
48129 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
48130 * the dropdown list (defaults to undefined, with no header element)
48134 * @cfg {String/Roo.Template} tpl The template to use to render the output
48138 defaultAutoCreate : {tag: "select" },
48140 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
48142 listWidth: undefined,
48144 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
48145 * mode = 'remote' or 'text' if mode = 'local')
48147 displayField: undefined,
48149 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
48150 * mode = 'remote' or 'value' if mode = 'local').
48151 * Note: use of a valueField requires the user make a selection
48152 * in order for a value to be mapped.
48154 valueField: undefined,
48158 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
48159 * field's data value (defaults to the underlying DOM element's name)
48161 hiddenName: undefined,
48163 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
48167 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
48169 selectedClass: 'x-combo-selected',
48171 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
48172 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
48173 * which displays a downward arrow icon).
48175 triggerClass : 'x-form-arrow-trigger',
48177 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
48181 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
48182 * anchor positions (defaults to 'tl-bl')
48184 listAlign: 'tl-bl?',
48186 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
48190 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
48191 * query specified by the allQuery config option (defaults to 'query')
48193 triggerAction: 'query',
48195 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
48196 * (defaults to 4, does not apply if editable = false)
48200 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
48201 * delay (typeAheadDelay) if it matches a known value (defaults to false)
48205 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
48206 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
48210 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
48211 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
48215 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
48216 * when editable = true (defaults to false)
48218 selectOnFocus:false,
48220 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
48222 queryParam: 'query',
48224 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
48225 * when mode = 'remote' (defaults to 'Loading...')
48227 loadingText: 'Loading...',
48229 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
48233 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
48237 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
48238 * traditional select (defaults to true)
48242 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
48246 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
48250 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
48251 * listWidth has a higher value)
48255 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
48256 * allow the user to set arbitrary text into the field (defaults to false)
48258 forceSelection:false,
48260 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
48261 * if typeAhead = true (defaults to 250)
48263 typeAheadDelay : 250,
48265 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
48266 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
48268 valueNotFoundText : undefined,
48271 * @cfg {String} defaultValue The value displayed after loading the store.
48276 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
48278 blockFocus : false,
48281 * @cfg {Boolean} disableClear Disable showing of clear button.
48283 disableClear : false,
48285 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
48287 alwaysQuery : false,
48293 // element that contains real text value.. (when hidden is used..)
48296 onRender : function(ct, position){
48297 Roo.form.Field.prototype.onRender.call(this, ct, position);
48300 this.store.on('beforeload', this.onBeforeLoad, this);
48301 this.store.on('load', this.onLoad, this);
48302 this.store.on('loadexception', this.onLoadException, this);
48303 this.store.load({});
48311 initEvents : function(){
48312 //Roo.form.ComboBox.superclass.initEvents.call(this);
48316 onDestroy : function(){
48319 this.store.un('beforeload', this.onBeforeLoad, this);
48320 this.store.un('load', this.onLoad, this);
48321 this.store.un('loadexception', this.onLoadException, this);
48323 //Roo.form.ComboBox.superclass.onDestroy.call(this);
48327 fireKey : function(e){
48328 if(e.isNavKeyPress() && !this.list.isVisible()){
48329 this.fireEvent("specialkey", this, e);
48334 onResize: function(w, h){
48342 * Allow or prevent the user from directly editing the field text. If false is passed,
48343 * the user will only be able to select from the items defined in the dropdown list. This method
48344 * is the runtime equivalent of setting the 'editable' config option at config time.
48345 * @param {Boolean} value True to allow the user to directly edit the field text
48347 setEditable : function(value){
48352 onBeforeLoad : function(){
48354 Roo.log("Select before load");
48357 this.innerList.update(this.loadingText ?
48358 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
48359 //this.restrictHeight();
48360 this.selectedIndex = -1;
48364 onLoad : function(){
48367 var dom = this.el.dom;
48368 dom.innerHTML = '';
48369 var od = dom.ownerDocument;
48371 if (this.emptyText) {
48372 var op = od.createElement('option');
48373 op.setAttribute('value', '');
48374 op.innerHTML = String.format('{0}', this.emptyText);
48375 dom.appendChild(op);
48377 if(this.store.getCount() > 0){
48379 var vf = this.valueField;
48380 var df = this.displayField;
48381 this.store.data.each(function(r) {
48382 // which colmsn to use... testing - cdoe / title..
48383 var op = od.createElement('option');
48384 op.setAttribute('value', r.data[vf]);
48385 op.innerHTML = String.format('{0}', r.data[df]);
48386 dom.appendChild(op);
48388 if (typeof(this.defaultValue != 'undefined')) {
48389 this.setValue(this.defaultValue);
48394 //this.onEmptyResults();
48399 onLoadException : function()
48401 dom.innerHTML = '';
48403 Roo.log("Select on load exception");
48407 Roo.log(this.store.reader.jsonData);
48408 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
48409 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
48415 onTypeAhead : function(){
48420 onSelect : function(record, index){
48421 Roo.log('on select?');
48423 if(this.fireEvent('beforeselect', this, record, index) !== false){
48424 this.setFromData(index > -1 ? record.data : false);
48426 this.fireEvent('select', this, record, index);
48431 * Returns the currently selected field value or empty string if no value is set.
48432 * @return {String} value The selected value
48434 getValue : function(){
48435 var dom = this.el.dom;
48436 this.value = dom.options[dom.selectedIndex].value;
48442 * Clears any text/value currently set in the field
48444 clearValue : function(){
48446 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
48451 * Sets the specified value into the field. If the value finds a match, the corresponding record text
48452 * will be displayed in the field. If the value does not match the data value of an existing item,
48453 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
48454 * Otherwise the field will be blank (although the value will still be set).
48455 * @param {String} value The value to match
48457 setValue : function(v){
48458 var d = this.el.dom;
48459 for (var i =0; i < d.options.length;i++) {
48460 if (v == d.options[i].value) {
48461 d.selectedIndex = i;
48469 * @property {Object} the last set data for the element
48474 * Sets the value of the field based on a object which is related to the record format for the store.
48475 * @param {Object} value the value to set as. or false on reset?
48477 setFromData : function(o){
48478 Roo.log('setfrom data?');
48484 reset : function(){
48488 findRecord : function(prop, value){
48493 if(this.store.getCount() > 0){
48494 this.store.each(function(r){
48495 if(r.data[prop] == value){
48505 getName: function()
48507 // returns hidden if it's set..
48508 if (!this.rendered) {return ''};
48509 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
48517 onEmptyResults : function(){
48518 Roo.log('empty results');
48523 * Returns true if the dropdown list is expanded, else false.
48525 isExpanded : function(){
48530 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
48531 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48532 * @param {String} value The data value of the item to select
48533 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48534 * selected item if it is not currently in view (defaults to true)
48535 * @return {Boolean} True if the value matched an item in the list, else false
48537 selectByValue : function(v, scrollIntoView){
48538 Roo.log('select By Value');
48541 if(v !== undefined && v !== null){
48542 var r = this.findRecord(this.valueField || this.displayField, v);
48544 this.select(this.store.indexOf(r), scrollIntoView);
48552 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
48553 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48554 * @param {Number} index The zero-based index of the list item to select
48555 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48556 * selected item if it is not currently in view (defaults to true)
48558 select : function(index, scrollIntoView){
48559 Roo.log('select ');
48562 this.selectedIndex = index;
48563 this.view.select(index);
48564 if(scrollIntoView !== false){
48565 var el = this.view.getNode(index);
48567 this.innerList.scrollChildIntoView(el, false);
48575 validateBlur : function(){
48582 initQuery : function(){
48583 this.doQuery(this.getRawValue());
48587 doForce : function(){
48588 if(this.el.dom.value.length > 0){
48589 this.el.dom.value =
48590 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
48596 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
48597 * query allowing the query action to be canceled if needed.
48598 * @param {String} query The SQL query to execute
48599 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
48600 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
48601 * saved in the current store (defaults to false)
48603 doQuery : function(q, forceAll){
48605 Roo.log('doQuery?');
48606 if(q === undefined || q === null){
48611 forceAll: forceAll,
48615 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48619 forceAll = qe.forceAll;
48620 if(forceAll === true || (q.length >= this.minChars)){
48621 if(this.lastQuery != q || this.alwaysQuery){
48622 this.lastQuery = q;
48623 if(this.mode == 'local'){
48624 this.selectedIndex = -1;
48626 this.store.clearFilter();
48628 this.store.filter(this.displayField, q);
48632 this.store.baseParams[this.queryParam] = q;
48634 params: this.getParams(q)
48639 this.selectedIndex = -1;
48646 getParams : function(q){
48648 //p[this.queryParam] = q;
48651 p.limit = this.pageSize;
48657 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48659 collapse : function(){
48664 collapseIf : function(e){
48669 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48671 expand : function(){
48679 * @cfg {Boolean} grow
48683 * @cfg {Number} growMin
48687 * @cfg {Number} growMax
48695 setWidth : function()
48699 getResizeEl : function(){
48702 });//<script type="text/javasscript">
48706 * @class Roo.DDView
48707 * A DnD enabled version of Roo.View.
48708 * @param {Element/String} container The Element in which to create the View.
48709 * @param {String} tpl The template string used to create the markup for each element of the View
48710 * @param {Object} config The configuration properties. These include all the config options of
48711 * {@link Roo.View} plus some specific to this class.<br>
48713 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48714 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48716 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48717 .x-view-drag-insert-above {
48718 border-top:1px dotted #3366cc;
48720 .x-view-drag-insert-below {
48721 border-bottom:1px dotted #3366cc;
48727 Roo.DDView = function(container, tpl, config) {
48728 Roo.DDView.superclass.constructor.apply(this, arguments);
48729 this.getEl().setStyle("outline", "0px none");
48730 this.getEl().unselectable();
48731 if (this.dragGroup) {
48732 this.setDraggable(this.dragGroup.split(","));
48734 if (this.dropGroup) {
48735 this.setDroppable(this.dropGroup.split(","));
48737 if (this.deletable) {
48738 this.setDeletable();
48740 this.isDirtyFlag = false;
48746 Roo.extend(Roo.DDView, Roo.View, {
48747 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48748 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48749 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48750 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48754 reset: Roo.emptyFn,
48756 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48758 validate: function() {
48762 destroy: function() {
48763 this.purgeListeners();
48764 this.getEl.removeAllListeners();
48765 this.getEl().remove();
48766 if (this.dragZone) {
48767 if (this.dragZone.destroy) {
48768 this.dragZone.destroy();
48771 if (this.dropZone) {
48772 if (this.dropZone.destroy) {
48773 this.dropZone.destroy();
48778 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48779 getName: function() {
48783 /** Loads the View from a JSON string representing the Records to put into the Store. */
48784 setValue: function(v) {
48786 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48789 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48790 this.store.proxy = new Roo.data.MemoryProxy(data);
48794 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48795 getValue: function() {
48797 this.store.each(function(rec) {
48798 result += rec.id + ',';
48800 return result.substr(0, result.length - 1) + ')';
48803 getIds: function() {
48804 var i = 0, result = new Array(this.store.getCount());
48805 this.store.each(function(rec) {
48806 result[i++] = rec.id;
48811 isDirty: function() {
48812 return this.isDirtyFlag;
48816 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48817 * whole Element becomes the target, and this causes the drop gesture to append.
48819 getTargetFromEvent : function(e) {
48820 var target = e.getTarget();
48821 while ((target !== null) && (target.parentNode != this.el.dom)) {
48822 target = target.parentNode;
48825 target = this.el.dom.lastChild || this.el.dom;
48831 * Create the drag data which consists of an object which has the property "ddel" as
48832 * the drag proxy element.
48834 getDragData : function(e) {
48835 var target = this.findItemFromChild(e.getTarget());
48837 this.handleSelection(e);
48838 var selNodes = this.getSelectedNodes();
48841 copy: this.copy || (this.allowCopy && e.ctrlKey),
48845 var selectedIndices = this.getSelectedIndexes();
48846 for (var i = 0; i < selectedIndices.length; i++) {
48847 dragData.records.push(this.store.getAt(selectedIndices[i]));
48849 if (selNodes.length == 1) {
48850 dragData.ddel = target.cloneNode(true); // the div element
48852 var div = document.createElement('div'); // create the multi element drag "ghost"
48853 div.className = 'multi-proxy';
48854 for (var i = 0, len = selNodes.length; i < len; i++) {
48855 div.appendChild(selNodes[i].cloneNode(true));
48857 dragData.ddel = div;
48859 //console.log(dragData)
48860 //console.log(dragData.ddel.innerHTML)
48863 //console.log('nodragData')
48867 /** Specify to which ddGroup items in this DDView may be dragged. */
48868 setDraggable: function(ddGroup) {
48869 if (ddGroup instanceof Array) {
48870 Roo.each(ddGroup, this.setDraggable, this);
48873 if (this.dragZone) {
48874 this.dragZone.addToGroup(ddGroup);
48876 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48877 containerScroll: true,
48881 // Draggability implies selection. DragZone's mousedown selects the element.
48882 if (!this.multiSelect) { this.singleSelect = true; }
48884 // Wire the DragZone's handlers up to methods in *this*
48885 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48889 /** Specify from which ddGroup this DDView accepts drops. */
48890 setDroppable: function(ddGroup) {
48891 if (ddGroup instanceof Array) {
48892 Roo.each(ddGroup, this.setDroppable, this);
48895 if (this.dropZone) {
48896 this.dropZone.addToGroup(ddGroup);
48898 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48899 containerScroll: true,
48903 // Wire the DropZone's handlers up to methods in *this*
48904 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48905 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48906 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48907 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48908 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48912 /** Decide whether to drop above or below a View node. */
48913 getDropPoint : function(e, n, dd){
48914 if (n == this.el.dom) { return "above"; }
48915 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48916 var c = t + (b - t) / 2;
48917 var y = Roo.lib.Event.getPageY(e);
48925 onNodeEnter : function(n, dd, e, data){
48929 onNodeOver : function(n, dd, e, data){
48930 var pt = this.getDropPoint(e, n, dd);
48931 // set the insert point style on the target node
48932 var dragElClass = this.dropNotAllowed;
48935 if (pt == "above"){
48936 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48937 targetElClass = "x-view-drag-insert-above";
48939 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48940 targetElClass = "x-view-drag-insert-below";
48942 if (this.lastInsertClass != targetElClass){
48943 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48944 this.lastInsertClass = targetElClass;
48947 return dragElClass;
48950 onNodeOut : function(n, dd, e, data){
48951 this.removeDropIndicators(n);
48954 onNodeDrop : function(n, dd, e, data){
48955 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48958 var pt = this.getDropPoint(e, n, dd);
48959 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48960 if (pt == "below") { insertAt++; }
48961 for (var i = 0; i < data.records.length; i++) {
48962 var r = data.records[i];
48963 var dup = this.store.getById(r.id);
48964 if (dup && (dd != this.dragZone)) {
48965 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48968 this.store.insert(insertAt++, r.copy());
48970 data.source.isDirtyFlag = true;
48972 this.store.insert(insertAt++, r);
48974 this.isDirtyFlag = true;
48977 this.dragZone.cachedTarget = null;
48981 removeDropIndicators : function(n){
48983 Roo.fly(n).removeClass([
48984 "x-view-drag-insert-above",
48985 "x-view-drag-insert-below"]);
48986 this.lastInsertClass = "_noclass";
48991 * Utility method. Add a delete option to the DDView's context menu.
48992 * @param {String} imageUrl The URL of the "delete" icon image.
48994 setDeletable: function(imageUrl) {
48995 if (!this.singleSelect && !this.multiSelect) {
48996 this.singleSelect = true;
48998 var c = this.getContextMenu();
48999 this.contextMenu.on("itemclick", function(item) {
49002 this.remove(this.getSelectedIndexes());
49006 this.contextMenu.add({
49013 /** Return the context menu for this DDView. */
49014 getContextMenu: function() {
49015 if (!this.contextMenu) {
49016 // Create the View's context menu
49017 this.contextMenu = new Roo.menu.Menu({
49018 id: this.id + "-contextmenu"
49020 this.el.on("contextmenu", this.showContextMenu, this);
49022 return this.contextMenu;
49025 disableContextMenu: function() {
49026 if (this.contextMenu) {
49027 this.el.un("contextmenu", this.showContextMenu, this);
49031 showContextMenu: function(e, item) {
49032 item = this.findItemFromChild(e.getTarget());
49035 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
49036 this.contextMenu.showAt(e.getXY());
49041 * Remove {@link Roo.data.Record}s at the specified indices.
49042 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
49044 remove: function(selectedIndices) {
49045 selectedIndices = [].concat(selectedIndices);
49046 for (var i = 0; i < selectedIndices.length; i++) {
49047 var rec = this.store.getAt(selectedIndices[i]);
49048 this.store.remove(rec);
49053 * Double click fires the event, but also, if this is draggable, and there is only one other
49054 * related DropZone, it transfers the selected node.
49056 onDblClick : function(e){
49057 var item = this.findItemFromChild(e.getTarget());
49059 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
49062 if (this.dragGroup) {
49063 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
49064 while (targets.indexOf(this.dropZone) > -1) {
49065 targets.remove(this.dropZone);
49067 if (targets.length == 1) {
49068 this.dragZone.cachedTarget = null;
49069 var el = Roo.get(targets[0].getEl());
49070 var box = el.getBox(true);
49071 targets[0].onNodeDrop(el.dom, {
49073 xy: [box.x, box.y + box.height - 1]
49074 }, null, this.getDragData(e));
49080 handleSelection: function(e) {
49081 this.dragZone.cachedTarget = null;
49082 var item = this.findItemFromChild(e.getTarget());
49084 this.clearSelections(true);
49087 if (item && (this.multiSelect || this.singleSelect)){
49088 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
49089 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
49090 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
49091 this.unselect(item);
49093 this.select(item, this.multiSelect && e.ctrlKey);
49094 this.lastSelection = item;
49099 onItemClick : function(item, index, e){
49100 if(this.fireEvent("beforeclick", this, index, item, e) === false){
49106 unselect : function(nodeInfo, suppressEvent){
49107 var node = this.getNode(nodeInfo);
49108 if(node && this.isSelected(node)){
49109 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
49110 Roo.fly(node).removeClass(this.selectedClass);
49111 this.selections.remove(node);
49112 if(!suppressEvent){
49113 this.fireEvent("selectionchange", this, this.selections);
49121 * Ext JS Library 1.1.1
49122 * Copyright(c) 2006-2007, Ext JS, LLC.
49124 * Originally Released Under LGPL - original licence link has changed is not relivant.
49127 * <script type="text/javascript">
49131 * @class Roo.LayoutManager
49132 * @extends Roo.util.Observable
49133 * Base class for layout managers.
49135 Roo.LayoutManager = function(container, config){
49136 Roo.LayoutManager.superclass.constructor.call(this);
49137 this.el = Roo.get(container);
49138 // ie scrollbar fix
49139 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
49140 document.body.scroll = "no";
49141 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
49142 this.el.position('relative');
49144 this.id = this.el.id;
49145 this.el.addClass("x-layout-container");
49146 /** false to disable window resize monitoring @type Boolean */
49147 this.monitorWindowResize = true;
49152 * Fires when a layout is performed.
49153 * @param {Roo.LayoutManager} this
49157 * @event regionresized
49158 * Fires when the user resizes a region.
49159 * @param {Roo.LayoutRegion} region The resized region
49160 * @param {Number} newSize The new size (width for east/west, height for north/south)
49162 "regionresized" : true,
49164 * @event regioncollapsed
49165 * Fires when a region is collapsed.
49166 * @param {Roo.LayoutRegion} region The collapsed region
49168 "regioncollapsed" : true,
49170 * @event regionexpanded
49171 * Fires when a region is expanded.
49172 * @param {Roo.LayoutRegion} region The expanded region
49174 "regionexpanded" : true
49176 this.updating = false;
49177 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
49180 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
49182 * Returns true if this layout is currently being updated
49183 * @return {Boolean}
49185 isUpdating : function(){
49186 return this.updating;
49190 * Suspend the LayoutManager from doing auto-layouts while
49191 * making multiple add or remove calls
49193 beginUpdate : function(){
49194 this.updating = true;
49198 * Restore auto-layouts and optionally disable the manager from performing a layout
49199 * @param {Boolean} noLayout true to disable a layout update
49201 endUpdate : function(noLayout){
49202 this.updating = false;
49208 layout: function(){
49212 onRegionResized : function(region, newSize){
49213 this.fireEvent("regionresized", region, newSize);
49217 onRegionCollapsed : function(region){
49218 this.fireEvent("regioncollapsed", region);
49221 onRegionExpanded : function(region){
49222 this.fireEvent("regionexpanded", region);
49226 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
49227 * performs box-model adjustments.
49228 * @return {Object} The size as an object {width: (the width), height: (the height)}
49230 getViewSize : function(){
49232 if(this.el.dom != document.body){
49233 size = this.el.getSize();
49235 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
49237 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
49238 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
49243 * Returns the Element this layout is bound to.
49244 * @return {Roo.Element}
49246 getEl : function(){
49251 * Returns the specified region.
49252 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
49253 * @return {Roo.LayoutRegion}
49255 getRegion : function(target){
49256 return this.regions[target.toLowerCase()];
49259 onWindowResize : function(){
49260 if(this.monitorWindowResize){
49266 * Ext JS Library 1.1.1
49267 * Copyright(c) 2006-2007, Ext JS, LLC.
49269 * Originally Released Under LGPL - original licence link has changed is not relivant.
49272 * <script type="text/javascript">
49275 * @class Roo.BorderLayout
49276 * @extends Roo.LayoutManager
49277 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
49278 * please see: <br><br>
49279 * <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>
49280 * <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>
49283 var layout = new Roo.BorderLayout(document.body, {
49317 preferredTabWidth: 150
49322 var CP = Roo.ContentPanel;
49324 layout.beginUpdate();
49325 layout.add("north", new CP("north", "North"));
49326 layout.add("south", new CP("south", {title: "South", closable: true}));
49327 layout.add("west", new CP("west", {title: "West"}));
49328 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
49329 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
49330 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
49331 layout.getRegion("center").showPanel("center1");
49332 layout.endUpdate();
49335 <b>The container the layout is rendered into can be either the body element or any other element.
49336 If it is not the body element, the container needs to either be an absolute positioned element,
49337 or you will need to add "position:relative" to the css of the container. You will also need to specify
49338 the container size if it is not the body element.</b>
49341 * Create a new BorderLayout
49342 * @param {String/HTMLElement/Element} container The container this layout is bound to
49343 * @param {Object} config Configuration options
49345 Roo.BorderLayout = function(container, config){
49346 config = config || {};
49347 Roo.BorderLayout.superclass.constructor.call(this, container, config);
49348 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
49349 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
49350 var target = this.factory.validRegions[i];
49351 if(config[target]){
49352 this.addRegion(target, config[target]);
49357 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
49359 * Creates and adds a new region if it doesn't already exist.
49360 * @param {String} target The target region key (north, south, east, west or center).
49361 * @param {Object} config The regions config object
49362 * @return {BorderLayoutRegion} The new region
49364 addRegion : function(target, config){
49365 if(!this.regions[target]){
49366 var r = this.factory.create(target, this, config);
49367 this.bindRegion(target, r);
49369 return this.regions[target];
49373 bindRegion : function(name, r){
49374 this.regions[name] = r;
49375 r.on("visibilitychange", this.layout, this);
49376 r.on("paneladded", this.layout, this);
49377 r.on("panelremoved", this.layout, this);
49378 r.on("invalidated", this.layout, this);
49379 r.on("resized", this.onRegionResized, this);
49380 r.on("collapsed", this.onRegionCollapsed, this);
49381 r.on("expanded", this.onRegionExpanded, this);
49385 * Performs a layout update.
49387 layout : function(){
49388 if(this.updating) return;
49389 var size = this.getViewSize();
49390 var w = size.width;
49391 var h = size.height;
49396 //var x = 0, y = 0;
49398 var rs = this.regions;
49399 var north = rs["north"];
49400 var south = rs["south"];
49401 var west = rs["west"];
49402 var east = rs["east"];
49403 var center = rs["center"];
49404 //if(this.hideOnLayout){ // not supported anymore
49405 //c.el.setStyle("display", "none");
49407 if(north && north.isVisible()){
49408 var b = north.getBox();
49409 var m = north.getMargins();
49410 b.width = w - (m.left+m.right);
49413 centerY = b.height + b.y + m.bottom;
49414 centerH -= centerY;
49415 north.updateBox(this.safeBox(b));
49417 if(south && south.isVisible()){
49418 var b = south.getBox();
49419 var m = south.getMargins();
49420 b.width = w - (m.left+m.right);
49422 var totalHeight = (b.height + m.top + m.bottom);
49423 b.y = h - totalHeight + m.top;
49424 centerH -= totalHeight;
49425 south.updateBox(this.safeBox(b));
49427 if(west && west.isVisible()){
49428 var b = west.getBox();
49429 var m = west.getMargins();
49430 b.height = centerH - (m.top+m.bottom);
49432 b.y = centerY + m.top;
49433 var totalWidth = (b.width + m.left + m.right);
49434 centerX += totalWidth;
49435 centerW -= totalWidth;
49436 west.updateBox(this.safeBox(b));
49438 if(east && east.isVisible()){
49439 var b = east.getBox();
49440 var m = east.getMargins();
49441 b.height = centerH - (m.top+m.bottom);
49442 var totalWidth = (b.width + m.left + m.right);
49443 b.x = w - totalWidth + m.left;
49444 b.y = centerY + m.top;
49445 centerW -= totalWidth;
49446 east.updateBox(this.safeBox(b));
49449 var m = center.getMargins();
49451 x: centerX + m.left,
49452 y: centerY + m.top,
49453 width: centerW - (m.left+m.right),
49454 height: centerH - (m.top+m.bottom)
49456 //if(this.hideOnLayout){
49457 //center.el.setStyle("display", "block");
49459 center.updateBox(this.safeBox(centerBox));
49462 this.fireEvent("layout", this);
49466 safeBox : function(box){
49467 box.width = Math.max(0, box.width);
49468 box.height = Math.max(0, box.height);
49473 * Adds a ContentPanel (or subclass) to this layout.
49474 * @param {String} target The target region key (north, south, east, west or center).
49475 * @param {Roo.ContentPanel} panel The panel to add
49476 * @return {Roo.ContentPanel} The added panel
49478 add : function(target, panel){
49480 target = target.toLowerCase();
49481 return this.regions[target].add(panel);
49485 * Remove a ContentPanel (or subclass) to this layout.
49486 * @param {String} target The target region key (north, south, east, west or center).
49487 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
49488 * @return {Roo.ContentPanel} The removed panel
49490 remove : function(target, panel){
49491 target = target.toLowerCase();
49492 return this.regions[target].remove(panel);
49496 * Searches all regions for a panel with the specified id
49497 * @param {String} panelId
49498 * @return {Roo.ContentPanel} The panel or null if it wasn't found
49500 findPanel : function(panelId){
49501 var rs = this.regions;
49502 for(var target in rs){
49503 if(typeof rs[target] != "function"){
49504 var p = rs[target].getPanel(panelId);
49514 * Searches all regions for a panel with the specified id and activates (shows) it.
49515 * @param {String/ContentPanel} panelId The panels id or the panel itself
49516 * @return {Roo.ContentPanel} The shown panel or null
49518 showPanel : function(panelId) {
49519 var rs = this.regions;
49520 for(var target in rs){
49521 var r = rs[target];
49522 if(typeof r != "function"){
49523 if(r.hasPanel(panelId)){
49524 return r.showPanel(panelId);
49532 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
49533 * @param {Roo.state.Provider} provider (optional) An alternate state provider
49535 restoreState : function(provider){
49537 provider = Roo.state.Manager;
49539 var sm = new Roo.LayoutStateManager();
49540 sm.init(this, provider);
49544 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
49545 * object should contain properties for each region to add ContentPanels to, and each property's value should be
49546 * a valid ContentPanel config object. Example:
49548 // Create the main layout
49549 var layout = new Roo.BorderLayout('main-ct', {
49560 // Create and add multiple ContentPanels at once via configs
49563 id: 'source-files',
49565 title:'Ext Source Files',
49578 * @param {Object} regions An object containing ContentPanel configs by region name
49580 batchAdd : function(regions){
49581 this.beginUpdate();
49582 for(var rname in regions){
49583 var lr = this.regions[rname];
49585 this.addTypedPanels(lr, regions[rname]);
49592 addTypedPanels : function(lr, ps){
49593 if(typeof ps == 'string'){
49594 lr.add(new Roo.ContentPanel(ps));
49596 else if(ps instanceof Array){
49597 for(var i =0, len = ps.length; i < len; i++){
49598 this.addTypedPanels(lr, ps[i]);
49601 else if(!ps.events){ // raw config?
49603 delete ps.el; // prevent conflict
49604 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
49606 else { // panel object assumed!
49611 * Adds a xtype elements to the layout.
49615 xtype : 'ContentPanel',
49622 xtype : 'NestedLayoutPanel',
49628 items : [ ... list of content panels or nested layout panels.. ]
49632 * @param {Object} cfg Xtype definition of item to add.
49634 addxtype : function(cfg)
49636 // basically accepts a pannel...
49637 // can accept a layout region..!?!?
49638 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49640 if (!cfg.xtype.match(/Panel$/)) {
49645 if (typeof(cfg.region) == 'undefined') {
49646 Roo.log("Failed to add Panel, region was not set");
49650 var region = cfg.region;
49656 xitems = cfg.items;
49663 case 'ContentPanel': // ContentPanel (el, cfg)
49664 case 'ScrollPanel': // ContentPanel (el, cfg)
49666 if(cfg.autoCreate) {
49667 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49669 var el = this.el.createChild();
49670 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49673 this.add(region, ret);
49677 case 'TreePanel': // our new panel!
49678 cfg.el = this.el.createChild();
49679 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49680 this.add(region, ret);
49683 case 'NestedLayoutPanel':
49684 // create a new Layout (which is a Border Layout...
49685 var el = this.el.createChild();
49686 var clayout = cfg.layout;
49688 clayout.items = clayout.items || [];
49689 // replace this exitems with the clayout ones..
49690 xitems = clayout.items;
49693 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49694 cfg.background = false;
49696 var layout = new Roo.BorderLayout(el, clayout);
49698 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49699 //console.log('adding nested layout panel ' + cfg.toSource());
49700 this.add(region, ret);
49701 nb = {}; /// find first...
49706 // needs grid and region
49708 //var el = this.getRegion(region).el.createChild();
49709 var el = this.el.createChild();
49710 // create the grid first...
49712 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49714 if (region == 'center' && this.active ) {
49715 cfg.background = false;
49717 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49719 this.add(region, ret);
49720 if (cfg.background) {
49721 ret.on('activate', function(gp) {
49722 if (!gp.grid.rendered) {
49737 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49739 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49740 this.add(region, ret);
49743 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49747 // GridPanel (grid, cfg)
49750 this.beginUpdate();
49754 Roo.each(xitems, function(i) {
49755 region = nb && i.region ? i.region : false;
49757 var add = ret.addxtype(i);
49760 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49761 if (!i.background) {
49762 abn[region] = nb[region] ;
49769 // make the last non-background panel active..
49770 //if (nb) { Roo.log(abn); }
49773 for(var r in abn) {
49774 region = this.getRegion(r);
49776 // tried using nb[r], but it does not work..
49778 region.showPanel(abn[r]);
49789 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49790 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49791 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49792 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49795 var CP = Roo.ContentPanel;
49797 var layout = Roo.BorderLayout.create({
49801 panels: [new CP("north", "North")]
49810 panels: [new CP("west", {title: "West"})]
49819 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49828 panels: [new CP("south", {title: "South", closable: true})]
49835 preferredTabWidth: 150,
49837 new CP("center1", {title: "Close Me", closable: true}),
49838 new CP("center2", {title: "Center Panel", closable: false})
49843 layout.getRegion("center").showPanel("center1");
49848 Roo.BorderLayout.create = function(config, targetEl){
49849 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49850 layout.beginUpdate();
49851 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49852 for(var j = 0, jlen = regions.length; j < jlen; j++){
49853 var lr = regions[j];
49854 if(layout.regions[lr] && config[lr].panels){
49855 var r = layout.regions[lr];
49856 var ps = config[lr].panels;
49857 layout.addTypedPanels(r, ps);
49860 layout.endUpdate();
49865 Roo.BorderLayout.RegionFactory = {
49867 validRegions : ["north","south","east","west","center"],
49870 create : function(target, mgr, config){
49871 target = target.toLowerCase();
49872 if(config.lightweight || config.basic){
49873 return new Roo.BasicLayoutRegion(mgr, config, target);
49877 return new Roo.NorthLayoutRegion(mgr, config);
49879 return new Roo.SouthLayoutRegion(mgr, config);
49881 return new Roo.EastLayoutRegion(mgr, config);
49883 return new Roo.WestLayoutRegion(mgr, config);
49885 return new Roo.CenterLayoutRegion(mgr, config);
49887 throw 'Layout region "'+target+'" not supported.';
49891 * Ext JS Library 1.1.1
49892 * Copyright(c) 2006-2007, Ext JS, LLC.
49894 * Originally Released Under LGPL - original licence link has changed is not relivant.
49897 * <script type="text/javascript">
49901 * @class Roo.BasicLayoutRegion
49902 * @extends Roo.util.Observable
49903 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49904 * and does not have a titlebar, tabs or any other features. All it does is size and position
49905 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49907 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49909 this.position = pos;
49912 * @scope Roo.BasicLayoutRegion
49916 * @event beforeremove
49917 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49918 * @param {Roo.LayoutRegion} this
49919 * @param {Roo.ContentPanel} panel The panel
49920 * @param {Object} e The cancel event object
49922 "beforeremove" : true,
49924 * @event invalidated
49925 * Fires when the layout for this region is changed.
49926 * @param {Roo.LayoutRegion} this
49928 "invalidated" : true,
49930 * @event visibilitychange
49931 * Fires when this region is shown or hidden
49932 * @param {Roo.LayoutRegion} this
49933 * @param {Boolean} visibility true or false
49935 "visibilitychange" : true,
49937 * @event paneladded
49938 * Fires when a panel is added.
49939 * @param {Roo.LayoutRegion} this
49940 * @param {Roo.ContentPanel} panel The panel
49942 "paneladded" : true,
49944 * @event panelremoved
49945 * Fires when a panel is removed.
49946 * @param {Roo.LayoutRegion} this
49947 * @param {Roo.ContentPanel} panel The panel
49949 "panelremoved" : true,
49952 * Fires when this region is collapsed.
49953 * @param {Roo.LayoutRegion} this
49955 "collapsed" : true,
49958 * Fires when this region is expanded.
49959 * @param {Roo.LayoutRegion} this
49964 * Fires when this region is slid into view.
49965 * @param {Roo.LayoutRegion} this
49967 "slideshow" : true,
49970 * Fires when this region slides out of view.
49971 * @param {Roo.LayoutRegion} this
49973 "slidehide" : true,
49975 * @event panelactivated
49976 * Fires when a panel is activated.
49977 * @param {Roo.LayoutRegion} this
49978 * @param {Roo.ContentPanel} panel The activated panel
49980 "panelactivated" : true,
49983 * Fires when the user resizes this region.
49984 * @param {Roo.LayoutRegion} this
49985 * @param {Number} newSize The new size (width for east/west, height for north/south)
49989 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49990 this.panels = new Roo.util.MixedCollection();
49991 this.panels.getKey = this.getPanelId.createDelegate(this);
49993 this.activePanel = null;
49994 // ensure listeners are added...
49996 if (config.listeners || config.events) {
49997 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49998 listeners : config.listeners || {},
49999 events : config.events || {}
50003 if(skipConfig !== true){
50004 this.applyConfig(config);
50008 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
50009 getPanelId : function(p){
50013 applyConfig : function(config){
50014 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50015 this.config = config;
50020 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
50021 * the width, for horizontal (north, south) the height.
50022 * @param {Number} newSize The new width or height
50024 resizeTo : function(newSize){
50025 var el = this.el ? this.el :
50026 (this.activePanel ? this.activePanel.getEl() : null);
50028 switch(this.position){
50031 el.setWidth(newSize);
50032 this.fireEvent("resized", this, newSize);
50036 el.setHeight(newSize);
50037 this.fireEvent("resized", this, newSize);
50043 getBox : function(){
50044 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
50047 getMargins : function(){
50048 return this.margins;
50051 updateBox : function(box){
50053 var el = this.activePanel.getEl();
50054 el.dom.style.left = box.x + "px";
50055 el.dom.style.top = box.y + "px";
50056 this.activePanel.setSize(box.width, box.height);
50060 * Returns the container element for this region.
50061 * @return {Roo.Element}
50063 getEl : function(){
50064 return this.activePanel;
50068 * Returns true if this region is currently visible.
50069 * @return {Boolean}
50071 isVisible : function(){
50072 return this.activePanel ? true : false;
50075 setActivePanel : function(panel){
50076 panel = this.getPanel(panel);
50077 if(this.activePanel && this.activePanel != panel){
50078 this.activePanel.setActiveState(false);
50079 this.activePanel.getEl().setLeftTop(-10000,-10000);
50081 this.activePanel = panel;
50082 panel.setActiveState(true);
50084 panel.setSize(this.box.width, this.box.height);
50086 this.fireEvent("panelactivated", this, panel);
50087 this.fireEvent("invalidated");
50091 * Show the specified panel.
50092 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
50093 * @return {Roo.ContentPanel} The shown panel or null
50095 showPanel : function(panel){
50096 if(panel = this.getPanel(panel)){
50097 this.setActivePanel(panel);
50103 * Get the active panel for this region.
50104 * @return {Roo.ContentPanel} The active panel or null
50106 getActivePanel : function(){
50107 return this.activePanel;
50111 * Add the passed ContentPanel(s)
50112 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50113 * @return {Roo.ContentPanel} The panel added (if only one was added)
50115 add : function(panel){
50116 if(arguments.length > 1){
50117 for(var i = 0, len = arguments.length; i < len; i++) {
50118 this.add(arguments[i]);
50122 if(this.hasPanel(panel)){
50123 this.showPanel(panel);
50126 var el = panel.getEl();
50127 if(el.dom.parentNode != this.mgr.el.dom){
50128 this.mgr.el.dom.appendChild(el.dom);
50130 if(panel.setRegion){
50131 panel.setRegion(this);
50133 this.panels.add(panel);
50134 el.setStyle("position", "absolute");
50135 if(!panel.background){
50136 this.setActivePanel(panel);
50137 if(this.config.initialSize && this.panels.getCount()==1){
50138 this.resizeTo(this.config.initialSize);
50141 this.fireEvent("paneladded", this, panel);
50146 * Returns true if the panel is in this region.
50147 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50148 * @return {Boolean}
50150 hasPanel : function(panel){
50151 if(typeof panel == "object"){ // must be panel obj
50152 panel = panel.getId();
50154 return this.getPanel(panel) ? true : false;
50158 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50159 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50160 * @param {Boolean} preservePanel Overrides the config preservePanel option
50161 * @return {Roo.ContentPanel} The panel that was removed
50163 remove : function(panel, preservePanel){
50164 panel = this.getPanel(panel);
50169 this.fireEvent("beforeremove", this, panel, e);
50170 if(e.cancel === true){
50173 var panelId = panel.getId();
50174 this.panels.removeKey(panelId);
50179 * Returns the panel specified or null if it's not in this region.
50180 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50181 * @return {Roo.ContentPanel}
50183 getPanel : function(id){
50184 if(typeof id == "object"){ // must be panel obj
50187 return this.panels.get(id);
50191 * Returns this regions position (north/south/east/west/center).
50194 getPosition: function(){
50195 return this.position;
50199 * Ext JS Library 1.1.1
50200 * Copyright(c) 2006-2007, Ext JS, LLC.
50202 * Originally Released Under LGPL - original licence link has changed is not relivant.
50205 * <script type="text/javascript">
50209 * @class Roo.LayoutRegion
50210 * @extends Roo.BasicLayoutRegion
50211 * This class represents a region in a layout manager.
50212 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
50213 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
50214 * @cfg {Boolean} floatable False to disable floating (defaults to true)
50215 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
50216 * @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})
50217 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
50218 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
50219 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
50220 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
50221 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
50222 * @cfg {String} title The title for the region (overrides panel titles)
50223 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
50224 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
50225 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
50226 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
50227 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
50228 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
50229 * the space available, similar to FireFox 1.5 tabs (defaults to false)
50230 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
50231 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
50232 * @cfg {Boolean} showPin True to show a pin button
50233 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
50234 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
50235 * @cfg {Boolean} disableTabTips True to disable tab tooltips
50236 * @cfg {Number} width For East/West panels
50237 * @cfg {Number} height For North/South panels
50238 * @cfg {Boolean} split To show the splitter
50239 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
50241 Roo.LayoutRegion = function(mgr, config, pos){
50242 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
50243 var dh = Roo.DomHelper;
50244 /** This region's container element
50245 * @type Roo.Element */
50246 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
50247 /** This region's title element
50248 * @type Roo.Element */
50250 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
50251 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
50252 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
50254 this.titleEl.enableDisplayMode();
50255 /** This region's title text element
50256 * @type HTMLElement */
50257 this.titleTextEl = this.titleEl.dom.firstChild;
50258 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
50259 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
50260 this.closeBtn.enableDisplayMode();
50261 this.closeBtn.on("click", this.closeClicked, this);
50262 this.closeBtn.hide();
50264 this.createBody(config);
50265 this.visible = true;
50266 this.collapsed = false;
50268 if(config.hideWhenEmpty){
50270 this.on("paneladded", this.validateVisibility, this);
50271 this.on("panelremoved", this.validateVisibility, this);
50273 this.applyConfig(config);
50276 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
50278 createBody : function(){
50279 /** This region's body element
50280 * @type Roo.Element */
50281 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
50284 applyConfig : function(c){
50285 if(c.collapsible && this.position != "center" && !this.collapsedEl){
50286 var dh = Roo.DomHelper;
50287 if(c.titlebar !== false){
50288 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
50289 this.collapseBtn.on("click", this.collapse, this);
50290 this.collapseBtn.enableDisplayMode();
50292 if(c.showPin === true || this.showPin){
50293 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
50294 this.stickBtn.enableDisplayMode();
50295 this.stickBtn.on("click", this.expand, this);
50296 this.stickBtn.hide();
50299 /** This region's collapsed element
50300 * @type Roo.Element */
50301 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
50302 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
50304 if(c.floatable !== false){
50305 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
50306 this.collapsedEl.on("click", this.collapseClick, this);
50309 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
50310 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
50311 id: "message", unselectable: "on", style:{"float":"left"}});
50312 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
50314 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
50315 this.expandBtn.on("click", this.expand, this);
50317 if(this.collapseBtn){
50318 this.collapseBtn.setVisible(c.collapsible == true);
50320 this.cmargins = c.cmargins || this.cmargins ||
50321 (this.position == "west" || this.position == "east" ?
50322 {top: 0, left: 2, right:2, bottom: 0} :
50323 {top: 2, left: 0, right:0, bottom: 2});
50324 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50325 this.bottomTabs = c.tabPosition != "top";
50326 this.autoScroll = c.autoScroll || false;
50327 if(this.autoScroll){
50328 this.bodyEl.setStyle("overflow", "auto");
50330 this.bodyEl.setStyle("overflow", "hidden");
50332 //if(c.titlebar !== false){
50333 if((!c.titlebar && !c.title) || c.titlebar === false){
50334 this.titleEl.hide();
50336 this.titleEl.show();
50338 this.titleTextEl.innerHTML = c.title;
50342 this.duration = c.duration || .30;
50343 this.slideDuration = c.slideDuration || .45;
50346 this.collapse(true);
50353 * Returns true if this region is currently visible.
50354 * @return {Boolean}
50356 isVisible : function(){
50357 return this.visible;
50361 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
50362 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
50364 setCollapsedTitle : function(title){
50365 title = title || " ";
50366 if(this.collapsedTitleTextEl){
50367 this.collapsedTitleTextEl.innerHTML = title;
50371 getBox : function(){
50373 if(!this.collapsed){
50374 b = this.el.getBox(false, true);
50376 b = this.collapsedEl.getBox(false, true);
50381 getMargins : function(){
50382 return this.collapsed ? this.cmargins : this.margins;
50385 highlight : function(){
50386 this.el.addClass("x-layout-panel-dragover");
50389 unhighlight : function(){
50390 this.el.removeClass("x-layout-panel-dragover");
50393 updateBox : function(box){
50395 if(!this.collapsed){
50396 this.el.dom.style.left = box.x + "px";
50397 this.el.dom.style.top = box.y + "px";
50398 this.updateBody(box.width, box.height);
50400 this.collapsedEl.dom.style.left = box.x + "px";
50401 this.collapsedEl.dom.style.top = box.y + "px";
50402 this.collapsedEl.setSize(box.width, box.height);
50405 this.tabs.autoSizeTabs();
50409 updateBody : function(w, h){
50411 this.el.setWidth(w);
50412 w -= this.el.getBorderWidth("rl");
50413 if(this.config.adjustments){
50414 w += this.config.adjustments[0];
50418 this.el.setHeight(h);
50419 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
50420 h -= this.el.getBorderWidth("tb");
50421 if(this.config.adjustments){
50422 h += this.config.adjustments[1];
50424 this.bodyEl.setHeight(h);
50426 h = this.tabs.syncHeight(h);
50429 if(this.panelSize){
50430 w = w !== null ? w : this.panelSize.width;
50431 h = h !== null ? h : this.panelSize.height;
50433 if(this.activePanel){
50434 var el = this.activePanel.getEl();
50435 w = w !== null ? w : el.getWidth();
50436 h = h !== null ? h : el.getHeight();
50437 this.panelSize = {width: w, height: h};
50438 this.activePanel.setSize(w, h);
50440 if(Roo.isIE && this.tabs){
50441 this.tabs.el.repaint();
50446 * Returns the container element for this region.
50447 * @return {Roo.Element}
50449 getEl : function(){
50454 * Hides this region.
50457 if(!this.collapsed){
50458 this.el.dom.style.left = "-2000px";
50461 this.collapsedEl.dom.style.left = "-2000px";
50462 this.collapsedEl.hide();
50464 this.visible = false;
50465 this.fireEvent("visibilitychange", this, false);
50469 * Shows this region if it was previously hidden.
50472 if(!this.collapsed){
50475 this.collapsedEl.show();
50477 this.visible = true;
50478 this.fireEvent("visibilitychange", this, true);
50481 closeClicked : function(){
50482 if(this.activePanel){
50483 this.remove(this.activePanel);
50487 collapseClick : function(e){
50489 e.stopPropagation();
50492 e.stopPropagation();
50498 * Collapses this region.
50499 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
50501 collapse : function(skipAnim){
50502 if(this.collapsed) return;
50503 this.collapsed = true;
50505 this.split.el.hide();
50507 if(this.config.animate && skipAnim !== true){
50508 this.fireEvent("invalidated", this);
50509 this.animateCollapse();
50511 this.el.setLocation(-20000,-20000);
50513 this.collapsedEl.show();
50514 this.fireEvent("collapsed", this);
50515 this.fireEvent("invalidated", this);
50519 animateCollapse : function(){
50524 * Expands this region if it was previously collapsed.
50525 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
50526 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
50528 expand : function(e, skipAnim){
50529 if(e) e.stopPropagation();
50530 if(!this.collapsed || this.el.hasActiveFx()) return;
50532 this.afterSlideIn();
50535 this.collapsed = false;
50536 if(this.config.animate && skipAnim !== true){
50537 this.animateExpand();
50541 this.split.el.show();
50543 this.collapsedEl.setLocation(-2000,-2000);
50544 this.collapsedEl.hide();
50545 this.fireEvent("invalidated", this);
50546 this.fireEvent("expanded", this);
50550 animateExpand : function(){
50554 initTabs : function()
50556 this.bodyEl.setStyle("overflow", "hidden");
50557 var ts = new Roo.TabPanel(
50560 tabPosition: this.bottomTabs ? 'bottom' : 'top',
50561 disableTooltips: this.config.disableTabTips,
50562 toolbar : this.config.toolbar
50565 if(this.config.hideTabs){
50566 ts.stripWrap.setDisplayed(false);
50569 ts.resizeTabs = this.config.resizeTabs === true;
50570 ts.minTabWidth = this.config.minTabWidth || 40;
50571 ts.maxTabWidth = this.config.maxTabWidth || 250;
50572 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
50573 ts.monitorResize = false;
50574 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50575 ts.bodyEl.addClass('x-layout-tabs-body');
50576 this.panels.each(this.initPanelAsTab, this);
50579 initPanelAsTab : function(panel){
50580 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
50581 this.config.closeOnTab && panel.isClosable());
50582 if(panel.tabTip !== undefined){
50583 ti.setTooltip(panel.tabTip);
50585 ti.on("activate", function(){
50586 this.setActivePanel(panel);
50588 if(this.config.closeOnTab){
50589 ti.on("beforeclose", function(t, e){
50591 this.remove(panel);
50597 updatePanelTitle : function(panel, title){
50598 if(this.activePanel == panel){
50599 this.updateTitle(title);
50602 var ti = this.tabs.getTab(panel.getEl().id);
50604 if(panel.tabTip !== undefined){
50605 ti.setTooltip(panel.tabTip);
50610 updateTitle : function(title){
50611 if(this.titleTextEl && !this.config.title){
50612 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50616 setActivePanel : function(panel){
50617 panel = this.getPanel(panel);
50618 if(this.activePanel && this.activePanel != panel){
50619 this.activePanel.setActiveState(false);
50621 this.activePanel = panel;
50622 panel.setActiveState(true);
50623 if(this.panelSize){
50624 panel.setSize(this.panelSize.width, this.panelSize.height);
50627 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50629 this.updateTitle(panel.getTitle());
50631 this.fireEvent("invalidated", this);
50633 this.fireEvent("panelactivated", this, panel);
50637 * Shows the specified panel.
50638 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50639 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50641 showPanel : function(panel)
50643 panel = this.getPanel(panel);
50646 var tab = this.tabs.getTab(panel.getEl().id);
50647 if(tab.isHidden()){
50648 this.tabs.unhideTab(tab.id);
50652 this.setActivePanel(panel);
50659 * Get the active panel for this region.
50660 * @return {Roo.ContentPanel} The active panel or null
50662 getActivePanel : function(){
50663 return this.activePanel;
50666 validateVisibility : function(){
50667 if(this.panels.getCount() < 1){
50668 this.updateTitle(" ");
50669 this.closeBtn.hide();
50672 if(!this.isVisible()){
50679 * Adds the passed ContentPanel(s) to this region.
50680 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50681 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50683 add : function(panel){
50684 if(arguments.length > 1){
50685 for(var i = 0, len = arguments.length; i < len; i++) {
50686 this.add(arguments[i]);
50690 if(this.hasPanel(panel)){
50691 this.showPanel(panel);
50694 panel.setRegion(this);
50695 this.panels.add(panel);
50696 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50697 this.bodyEl.dom.appendChild(panel.getEl().dom);
50698 if(panel.background !== true){
50699 this.setActivePanel(panel);
50701 this.fireEvent("paneladded", this, panel);
50707 this.initPanelAsTab(panel);
50709 if(panel.background !== true){
50710 this.tabs.activate(panel.getEl().id);
50712 this.fireEvent("paneladded", this, panel);
50717 * Hides the tab for the specified panel.
50718 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50720 hidePanel : function(panel){
50721 if(this.tabs && (panel = this.getPanel(panel))){
50722 this.tabs.hideTab(panel.getEl().id);
50727 * Unhides the tab for a previously hidden panel.
50728 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50730 unhidePanel : function(panel){
50731 if(this.tabs && (panel = this.getPanel(panel))){
50732 this.tabs.unhideTab(panel.getEl().id);
50736 clearPanels : function(){
50737 while(this.panels.getCount() > 0){
50738 this.remove(this.panels.first());
50743 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50744 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50745 * @param {Boolean} preservePanel Overrides the config preservePanel option
50746 * @return {Roo.ContentPanel} The panel that was removed
50748 remove : function(panel, preservePanel){
50749 panel = this.getPanel(panel);
50754 this.fireEvent("beforeremove", this, panel, e);
50755 if(e.cancel === true){
50758 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50759 var panelId = panel.getId();
50760 this.panels.removeKey(panelId);
50762 document.body.appendChild(panel.getEl().dom);
50765 this.tabs.removeTab(panel.getEl().id);
50766 }else if (!preservePanel){
50767 this.bodyEl.dom.removeChild(panel.getEl().dom);
50769 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50770 var p = this.panels.first();
50771 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50772 tempEl.appendChild(p.getEl().dom);
50773 this.bodyEl.update("");
50774 this.bodyEl.dom.appendChild(p.getEl().dom);
50776 this.updateTitle(p.getTitle());
50778 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50779 this.setActivePanel(p);
50781 panel.setRegion(null);
50782 if(this.activePanel == panel){
50783 this.activePanel = null;
50785 if(this.config.autoDestroy !== false && preservePanel !== true){
50786 try{panel.destroy();}catch(e){}
50788 this.fireEvent("panelremoved", this, panel);
50793 * Returns the TabPanel component used by this region
50794 * @return {Roo.TabPanel}
50796 getTabs : function(){
50800 createTool : function(parentEl, className){
50801 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50802 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50803 btn.addClassOnOver("x-layout-tools-button-over");
50808 * Ext JS Library 1.1.1
50809 * Copyright(c) 2006-2007, Ext JS, LLC.
50811 * Originally Released Under LGPL - original licence link has changed is not relivant.
50814 * <script type="text/javascript">
50820 * @class Roo.SplitLayoutRegion
50821 * @extends Roo.LayoutRegion
50822 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50824 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50825 this.cursor = cursor;
50826 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50829 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50830 splitTip : "Drag to resize.",
50831 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50832 useSplitTips : false,
50834 applyConfig : function(config){
50835 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50838 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50839 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50840 /** The SplitBar for this region
50841 * @type Roo.SplitBar */
50842 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50843 this.split.on("moved", this.onSplitMove, this);
50844 this.split.useShim = config.useShim === true;
50845 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50846 if(this.useSplitTips){
50847 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50849 if(config.collapsible){
50850 this.split.el.on("dblclick", this.collapse, this);
50853 if(typeof config.minSize != "undefined"){
50854 this.split.minSize = config.minSize;
50856 if(typeof config.maxSize != "undefined"){
50857 this.split.maxSize = config.maxSize;
50859 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50860 this.hideSplitter();
50865 getHMaxSize : function(){
50866 var cmax = this.config.maxSize || 10000;
50867 var center = this.mgr.getRegion("center");
50868 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50871 getVMaxSize : function(){
50872 var cmax = this.config.maxSize || 10000;
50873 var center = this.mgr.getRegion("center");
50874 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50877 onSplitMove : function(split, newSize){
50878 this.fireEvent("resized", this, newSize);
50882 * Returns the {@link Roo.SplitBar} for this region.
50883 * @return {Roo.SplitBar}
50885 getSplitBar : function(){
50890 this.hideSplitter();
50891 Roo.SplitLayoutRegion.superclass.hide.call(this);
50894 hideSplitter : function(){
50896 this.split.el.setLocation(-2000,-2000);
50897 this.split.el.hide();
50903 this.split.el.show();
50905 Roo.SplitLayoutRegion.superclass.show.call(this);
50908 beforeSlide: function(){
50909 if(Roo.isGecko){// firefox overflow auto bug workaround
50910 this.bodyEl.clip();
50911 if(this.tabs) this.tabs.bodyEl.clip();
50912 if(this.activePanel){
50913 this.activePanel.getEl().clip();
50915 if(this.activePanel.beforeSlide){
50916 this.activePanel.beforeSlide();
50922 afterSlide : function(){
50923 if(Roo.isGecko){// firefox overflow auto bug workaround
50924 this.bodyEl.unclip();
50925 if(this.tabs) this.tabs.bodyEl.unclip();
50926 if(this.activePanel){
50927 this.activePanel.getEl().unclip();
50928 if(this.activePanel.afterSlide){
50929 this.activePanel.afterSlide();
50935 initAutoHide : function(){
50936 if(this.autoHide !== false){
50937 if(!this.autoHideHd){
50938 var st = new Roo.util.DelayedTask(this.slideIn, this);
50939 this.autoHideHd = {
50940 "mouseout": function(e){
50941 if(!e.within(this.el, true)){
50945 "mouseover" : function(e){
50951 this.el.on(this.autoHideHd);
50955 clearAutoHide : function(){
50956 if(this.autoHide !== false){
50957 this.el.un("mouseout", this.autoHideHd.mouseout);
50958 this.el.un("mouseover", this.autoHideHd.mouseover);
50962 clearMonitor : function(){
50963 Roo.get(document).un("click", this.slideInIf, this);
50966 // these names are backwards but not changed for compat
50967 slideOut : function(){
50968 if(this.isSlid || this.el.hasActiveFx()){
50971 this.isSlid = true;
50972 if(this.collapseBtn){
50973 this.collapseBtn.hide();
50975 this.closeBtnState = this.closeBtn.getStyle('display');
50976 this.closeBtn.hide();
50978 this.stickBtn.show();
50981 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50982 this.beforeSlide();
50983 this.el.setStyle("z-index", 10001);
50984 this.el.slideIn(this.getSlideAnchor(), {
50985 callback: function(){
50987 this.initAutoHide();
50988 Roo.get(document).on("click", this.slideInIf, this);
50989 this.fireEvent("slideshow", this);
50996 afterSlideIn : function(){
50997 this.clearAutoHide();
50998 this.isSlid = false;
50999 this.clearMonitor();
51000 this.el.setStyle("z-index", "");
51001 if(this.collapseBtn){
51002 this.collapseBtn.show();
51004 this.closeBtn.setStyle('display', this.closeBtnState);
51006 this.stickBtn.hide();
51008 this.fireEvent("slidehide", this);
51011 slideIn : function(cb){
51012 if(!this.isSlid || this.el.hasActiveFx()){
51016 this.isSlid = false;
51017 this.beforeSlide();
51018 this.el.slideOut(this.getSlideAnchor(), {
51019 callback: function(){
51020 this.el.setLeftTop(-10000, -10000);
51022 this.afterSlideIn();
51030 slideInIf : function(e){
51031 if(!e.within(this.el)){
51036 animateCollapse : function(){
51037 this.beforeSlide();
51038 this.el.setStyle("z-index", 20000);
51039 var anchor = this.getSlideAnchor();
51040 this.el.slideOut(anchor, {
51041 callback : function(){
51042 this.el.setStyle("z-index", "");
51043 this.collapsedEl.slideIn(anchor, {duration:.3});
51045 this.el.setLocation(-10000,-10000);
51047 this.fireEvent("collapsed", this);
51054 animateExpand : function(){
51055 this.beforeSlide();
51056 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
51057 this.el.setStyle("z-index", 20000);
51058 this.collapsedEl.hide({
51061 this.el.slideIn(this.getSlideAnchor(), {
51062 callback : function(){
51063 this.el.setStyle("z-index", "");
51066 this.split.el.show();
51068 this.fireEvent("invalidated", this);
51069 this.fireEvent("expanded", this);
51097 getAnchor : function(){
51098 return this.anchors[this.position];
51101 getCollapseAnchor : function(){
51102 return this.canchors[this.position];
51105 getSlideAnchor : function(){
51106 return this.sanchors[this.position];
51109 getAlignAdj : function(){
51110 var cm = this.cmargins;
51111 switch(this.position){
51127 getExpandAdj : function(){
51128 var c = this.collapsedEl, cm = this.cmargins;
51129 switch(this.position){
51131 return [-(cm.right+c.getWidth()+cm.left), 0];
51134 return [cm.right+c.getWidth()+cm.left, 0];
51137 return [0, -(cm.top+cm.bottom+c.getHeight())];
51140 return [0, cm.top+cm.bottom+c.getHeight()];
51146 * Ext JS Library 1.1.1
51147 * Copyright(c) 2006-2007, Ext JS, LLC.
51149 * Originally Released Under LGPL - original licence link has changed is not relivant.
51152 * <script type="text/javascript">
51155 * These classes are private internal classes
51157 Roo.CenterLayoutRegion = function(mgr, config){
51158 Roo.LayoutRegion.call(this, mgr, config, "center");
51159 this.visible = true;
51160 this.minWidth = config.minWidth || 20;
51161 this.minHeight = config.minHeight || 20;
51164 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
51166 // center panel can't be hidden
51170 // center panel can't be hidden
51173 getMinWidth: function(){
51174 return this.minWidth;
51177 getMinHeight: function(){
51178 return this.minHeight;
51183 Roo.NorthLayoutRegion = function(mgr, config){
51184 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
51186 this.split.placement = Roo.SplitBar.TOP;
51187 this.split.orientation = Roo.SplitBar.VERTICAL;
51188 this.split.el.addClass("x-layout-split-v");
51190 var size = config.initialSize || config.height;
51191 if(typeof size != "undefined"){
51192 this.el.setHeight(size);
51195 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
51196 orientation: Roo.SplitBar.VERTICAL,
51197 getBox : function(){
51198 if(this.collapsed){
51199 return this.collapsedEl.getBox();
51201 var box = this.el.getBox();
51203 box.height += this.split.el.getHeight();
51208 updateBox : function(box){
51209 if(this.split && !this.collapsed){
51210 box.height -= this.split.el.getHeight();
51211 this.split.el.setLeft(box.x);
51212 this.split.el.setTop(box.y+box.height);
51213 this.split.el.setWidth(box.width);
51215 if(this.collapsed){
51216 this.updateBody(box.width, null);
51218 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51222 Roo.SouthLayoutRegion = function(mgr, config){
51223 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
51225 this.split.placement = Roo.SplitBar.BOTTOM;
51226 this.split.orientation = Roo.SplitBar.VERTICAL;
51227 this.split.el.addClass("x-layout-split-v");
51229 var size = config.initialSize || config.height;
51230 if(typeof size != "undefined"){
51231 this.el.setHeight(size);
51234 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
51235 orientation: Roo.SplitBar.VERTICAL,
51236 getBox : function(){
51237 if(this.collapsed){
51238 return this.collapsedEl.getBox();
51240 var box = this.el.getBox();
51242 var sh = this.split.el.getHeight();
51249 updateBox : function(box){
51250 if(this.split && !this.collapsed){
51251 var sh = this.split.el.getHeight();
51254 this.split.el.setLeft(box.x);
51255 this.split.el.setTop(box.y-sh);
51256 this.split.el.setWidth(box.width);
51258 if(this.collapsed){
51259 this.updateBody(box.width, null);
51261 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51265 Roo.EastLayoutRegion = function(mgr, config){
51266 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
51268 this.split.placement = Roo.SplitBar.RIGHT;
51269 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51270 this.split.el.addClass("x-layout-split-h");
51272 var size = config.initialSize || config.width;
51273 if(typeof size != "undefined"){
51274 this.el.setWidth(size);
51277 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
51278 orientation: Roo.SplitBar.HORIZONTAL,
51279 getBox : function(){
51280 if(this.collapsed){
51281 return this.collapsedEl.getBox();
51283 var box = this.el.getBox();
51285 var sw = this.split.el.getWidth();
51292 updateBox : function(box){
51293 if(this.split && !this.collapsed){
51294 var sw = this.split.el.getWidth();
51296 this.split.el.setLeft(box.x);
51297 this.split.el.setTop(box.y);
51298 this.split.el.setHeight(box.height);
51301 if(this.collapsed){
51302 this.updateBody(null, box.height);
51304 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51308 Roo.WestLayoutRegion = function(mgr, config){
51309 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
51311 this.split.placement = Roo.SplitBar.LEFT;
51312 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51313 this.split.el.addClass("x-layout-split-h");
51315 var size = config.initialSize || config.width;
51316 if(typeof size != "undefined"){
51317 this.el.setWidth(size);
51320 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
51321 orientation: Roo.SplitBar.HORIZONTAL,
51322 getBox : function(){
51323 if(this.collapsed){
51324 return this.collapsedEl.getBox();
51326 var box = this.el.getBox();
51328 box.width += this.split.el.getWidth();
51333 updateBox : function(box){
51334 if(this.split && !this.collapsed){
51335 var sw = this.split.el.getWidth();
51337 this.split.el.setLeft(box.x+box.width);
51338 this.split.el.setTop(box.y);
51339 this.split.el.setHeight(box.height);
51341 if(this.collapsed){
51342 this.updateBody(null, box.height);
51344 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51349 * Ext JS Library 1.1.1
51350 * Copyright(c) 2006-2007, Ext JS, LLC.
51352 * Originally Released Under LGPL - original licence link has changed is not relivant.
51355 * <script type="text/javascript">
51360 * Private internal class for reading and applying state
51362 Roo.LayoutStateManager = function(layout){
51363 // default empty state
51372 Roo.LayoutStateManager.prototype = {
51373 init : function(layout, provider){
51374 this.provider = provider;
51375 var state = provider.get(layout.id+"-layout-state");
51377 var wasUpdating = layout.isUpdating();
51379 layout.beginUpdate();
51381 for(var key in state){
51382 if(typeof state[key] != "function"){
51383 var rstate = state[key];
51384 var r = layout.getRegion(key);
51387 r.resizeTo(rstate.size);
51389 if(rstate.collapsed == true){
51392 r.expand(null, true);
51398 layout.endUpdate();
51400 this.state = state;
51402 this.layout = layout;
51403 layout.on("regionresized", this.onRegionResized, this);
51404 layout.on("regioncollapsed", this.onRegionCollapsed, this);
51405 layout.on("regionexpanded", this.onRegionExpanded, this);
51408 storeState : function(){
51409 this.provider.set(this.layout.id+"-layout-state", this.state);
51412 onRegionResized : function(region, newSize){
51413 this.state[region.getPosition()].size = newSize;
51417 onRegionCollapsed : function(region){
51418 this.state[region.getPosition()].collapsed = true;
51422 onRegionExpanded : function(region){
51423 this.state[region.getPosition()].collapsed = false;
51428 * Ext JS Library 1.1.1
51429 * Copyright(c) 2006-2007, Ext JS, LLC.
51431 * Originally Released Under LGPL - original licence link has changed is not relivant.
51434 * <script type="text/javascript">
51437 * @class Roo.ContentPanel
51438 * @extends Roo.util.Observable
51439 * A basic ContentPanel element.
51440 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
51441 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
51442 * @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
51443 * @cfg {Boolean} closable True if the panel can be closed/removed
51444 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
51445 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
51446 * @cfg {Toolbar} toolbar A toolbar for this panel
51447 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
51448 * @cfg {String} title The title for this panel
51449 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
51450 * @cfg {String} url Calls {@link #setUrl} with this value
51451 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
51452 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
51453 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
51454 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
51457 * Create a new ContentPanel.
51458 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
51459 * @param {String/Object} config A string to set only the title or a config object
51460 * @param {String} content (optional) Set the HTML content for this panel
51461 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
51463 Roo.ContentPanel = function(el, config, content){
51467 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
51471 if (config && config.parentLayout) {
51472 el = config.parentLayout.el.createChild();
51475 if(el.autoCreate){ // xtype is available if this is called from factory
51479 this.el = Roo.get(el);
51480 if(!this.el && config && config.autoCreate){
51481 if(typeof config.autoCreate == "object"){
51482 if(!config.autoCreate.id){
51483 config.autoCreate.id = config.id||el;
51485 this.el = Roo.DomHelper.append(document.body,
51486 config.autoCreate, true);
51488 this.el = Roo.DomHelper.append(document.body,
51489 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
51492 this.closable = false;
51493 this.loaded = false;
51494 this.active = false;
51495 if(typeof config == "string"){
51496 this.title = config;
51498 Roo.apply(this, config);
51501 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
51502 this.wrapEl = this.el.wrap();
51503 this.toolbar.container = this.el.insertSibling(false, 'before');
51504 this.toolbar = new Roo.Toolbar(this.toolbar);
51507 // xtype created footer. - not sure if will work as we normally have to render first..
51508 if (this.footer && !this.footer.el && this.footer.xtype) {
51509 if (!this.wrapEl) {
51510 this.wrapEl = this.el.wrap();
51513 this.footer.container = this.wrapEl.createChild();
51515 this.footer = Roo.factory(this.footer, Roo);
51520 this.resizeEl = Roo.get(this.resizeEl, true);
51522 this.resizeEl = this.el;
51524 // handle view.xtype
51532 * Fires when this panel is activated.
51533 * @param {Roo.ContentPanel} this
51537 * @event deactivate
51538 * Fires when this panel is activated.
51539 * @param {Roo.ContentPanel} this
51541 "deactivate" : true,
51545 * Fires when this panel is resized if fitToFrame is true.
51546 * @param {Roo.ContentPanel} this
51547 * @param {Number} width The width after any component adjustments
51548 * @param {Number} height The height after any component adjustments
51554 * Fires when this tab is created
51555 * @param {Roo.ContentPanel} this
51566 if(this.autoScroll){
51567 this.resizeEl.setStyle("overflow", "auto");
51569 // fix randome scrolling
51570 this.el.on('scroll', function() {
51571 Roo.log('fix random scolling');
51572 this.scrollTo('top',0);
51575 content = content || this.content;
51577 this.setContent(content);
51579 if(config && config.url){
51580 this.setUrl(this.url, this.params, this.loadOnce);
51585 Roo.ContentPanel.superclass.constructor.call(this);
51587 if (this.view && typeof(this.view.xtype) != 'undefined') {
51588 this.view.el = this.el.appendChild(document.createElement("div"));
51589 this.view = Roo.factory(this.view);
51590 this.view.render && this.view.render(false, '');
51594 this.fireEvent('render', this);
51597 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
51599 setRegion : function(region){
51600 this.region = region;
51602 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
51604 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
51609 * Returns the toolbar for this Panel if one was configured.
51610 * @return {Roo.Toolbar}
51612 getToolbar : function(){
51613 return this.toolbar;
51616 setActiveState : function(active){
51617 this.active = active;
51619 this.fireEvent("deactivate", this);
51621 this.fireEvent("activate", this);
51625 * Updates this panel's element
51626 * @param {String} content The new content
51627 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51629 setContent : function(content, loadScripts){
51630 this.el.update(content, loadScripts);
51633 ignoreResize : function(w, h){
51634 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51637 this.lastSize = {width: w, height: h};
51642 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51643 * @return {Roo.UpdateManager} The UpdateManager
51645 getUpdateManager : function(){
51646 return this.el.getUpdateManager();
51649 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51650 * @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:
51653 url: "your-url.php",
51654 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51655 callback: yourFunction,
51656 scope: yourObject, //(optional scope)
51659 text: "Loading...",
51664 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51665 * 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.
51666 * @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}
51667 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51668 * @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.
51669 * @return {Roo.ContentPanel} this
51672 var um = this.el.getUpdateManager();
51673 um.update.apply(um, arguments);
51679 * 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.
51680 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51681 * @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)
51682 * @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)
51683 * @return {Roo.UpdateManager} The UpdateManager
51685 setUrl : function(url, params, loadOnce){
51686 if(this.refreshDelegate){
51687 this.removeListener("activate", this.refreshDelegate);
51689 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51690 this.on("activate", this.refreshDelegate);
51691 return this.el.getUpdateManager();
51694 _handleRefresh : function(url, params, loadOnce){
51695 if(!loadOnce || !this.loaded){
51696 var updater = this.el.getUpdateManager();
51697 updater.update(url, params, this._setLoaded.createDelegate(this));
51701 _setLoaded : function(){
51702 this.loaded = true;
51706 * Returns this panel's id
51709 getId : function(){
51714 * Returns this panel's element - used by regiosn to add.
51715 * @return {Roo.Element}
51717 getEl : function(){
51718 return this.wrapEl || this.el;
51721 adjustForComponents : function(width, height)
51723 //Roo.log('adjustForComponents ');
51724 if(this.resizeEl != this.el){
51725 width -= this.el.getFrameWidth('lr');
51726 height -= this.el.getFrameWidth('tb');
51729 var te = this.toolbar.getEl();
51730 height -= te.getHeight();
51731 te.setWidth(width);
51734 var te = this.footer.getEl();
51735 Roo.log("footer:" + te.getHeight());
51737 height -= te.getHeight();
51738 te.setWidth(width);
51742 if(this.adjustments){
51743 width += this.adjustments[0];
51744 height += this.adjustments[1];
51746 return {"width": width, "height": height};
51749 setSize : function(width, height){
51750 if(this.fitToFrame && !this.ignoreResize(width, height)){
51751 if(this.fitContainer && this.resizeEl != this.el){
51752 this.el.setSize(width, height);
51754 var size = this.adjustForComponents(width, height);
51755 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51756 this.fireEvent('resize', this, size.width, size.height);
51761 * Returns this panel's title
51764 getTitle : function(){
51769 * Set this panel's title
51770 * @param {String} title
51772 setTitle : function(title){
51773 this.title = title;
51775 this.region.updatePanelTitle(this, title);
51780 * Returns true is this panel was configured to be closable
51781 * @return {Boolean}
51783 isClosable : function(){
51784 return this.closable;
51787 beforeSlide : function(){
51789 this.resizeEl.clip();
51792 afterSlide : function(){
51794 this.resizeEl.unclip();
51798 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51799 * Will fail silently if the {@link #setUrl} method has not been called.
51800 * This does not activate the panel, just updates its content.
51802 refresh : function(){
51803 if(this.refreshDelegate){
51804 this.loaded = false;
51805 this.refreshDelegate();
51810 * Destroys this panel
51812 destroy : function(){
51813 this.el.removeAllListeners();
51814 var tempEl = document.createElement("span");
51815 tempEl.appendChild(this.el.dom);
51816 tempEl.innerHTML = "";
51822 * form - if the content panel contains a form - this is a reference to it.
51823 * @type {Roo.form.Form}
51827 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51828 * This contains a reference to it.
51834 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51844 * @param {Object} cfg Xtype definition of item to add.
51847 addxtype : function(cfg) {
51849 if (cfg.xtype.match(/^Form$/)) {
51852 //if (this.footer) {
51853 // el = this.footer.container.insertSibling(false, 'before');
51855 el = this.el.createChild();
51858 this.form = new Roo.form.Form(cfg);
51861 if ( this.form.allItems.length) this.form.render(el.dom);
51864 // should only have one of theses..
51865 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51866 // views.. should not be just added - used named prop 'view''
51868 cfg.el = this.el.appendChild(document.createElement("div"));
51871 var ret = new Roo.factory(cfg);
51873 ret.render && ret.render(false, ''); // render blank..
51882 * @class Roo.GridPanel
51883 * @extends Roo.ContentPanel
51885 * Create a new GridPanel.
51886 * @param {Roo.grid.Grid} grid The grid for this panel
51887 * @param {String/Object} config A string to set only the panel's title, or a config object
51889 Roo.GridPanel = function(grid, config){
51892 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51893 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51895 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51897 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51900 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51902 // xtype created footer. - not sure if will work as we normally have to render first..
51903 if (this.footer && !this.footer.el && this.footer.xtype) {
51905 this.footer.container = this.grid.getView().getFooterPanel(true);
51906 this.footer.dataSource = this.grid.dataSource;
51907 this.footer = Roo.factory(this.footer, Roo);
51911 grid.monitorWindowResize = false; // turn off autosizing
51912 grid.autoHeight = false;
51913 grid.autoWidth = false;
51915 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51918 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51919 getId : function(){
51920 return this.grid.id;
51924 * Returns the grid for this panel
51925 * @return {Roo.grid.Grid}
51927 getGrid : function(){
51931 setSize : function(width, height){
51932 if(!this.ignoreResize(width, height)){
51933 var grid = this.grid;
51934 var size = this.adjustForComponents(width, height);
51935 grid.getGridEl().setSize(size.width, size.height);
51940 beforeSlide : function(){
51941 this.grid.getView().scroller.clip();
51944 afterSlide : function(){
51945 this.grid.getView().scroller.unclip();
51948 destroy : function(){
51949 this.grid.destroy();
51951 Roo.GridPanel.superclass.destroy.call(this);
51957 * @class Roo.NestedLayoutPanel
51958 * @extends Roo.ContentPanel
51960 * Create a new NestedLayoutPanel.
51963 * @param {Roo.BorderLayout} layout The layout for this panel
51964 * @param {String/Object} config A string to set only the title or a config object
51966 Roo.NestedLayoutPanel = function(layout, config)
51968 // construct with only one argument..
51969 /* FIXME - implement nicer consturctors
51970 if (layout.layout) {
51972 layout = config.layout;
51973 delete config.layout;
51975 if (layout.xtype && !layout.getEl) {
51976 // then layout needs constructing..
51977 layout = Roo.factory(layout, Roo);
51982 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51984 layout.monitorWindowResize = false; // turn off autosizing
51985 this.layout = layout;
51986 this.layout.getEl().addClass("x-layout-nested-layout");
51993 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51995 setSize : function(width, height){
51996 if(!this.ignoreResize(width, height)){
51997 var size = this.adjustForComponents(width, height);
51998 var el = this.layout.getEl();
51999 el.setSize(size.width, size.height);
52000 var touch = el.dom.offsetWidth;
52001 this.layout.layout();
52002 // ie requires a double layout on the first pass
52003 if(Roo.isIE && !this.initialized){
52004 this.initialized = true;
52005 this.layout.layout();
52010 // activate all subpanels if not currently active..
52012 setActiveState : function(active){
52013 this.active = active;
52015 this.fireEvent("deactivate", this);
52019 this.fireEvent("activate", this);
52020 // not sure if this should happen before or after..
52021 if (!this.layout) {
52022 return; // should not happen..
52025 for (var r in this.layout.regions) {
52026 reg = this.layout.getRegion(r);
52027 if (reg.getActivePanel()) {
52028 //reg.showPanel(reg.getActivePanel()); // force it to activate..
52029 reg.setActivePanel(reg.getActivePanel());
52032 if (!reg.panels.length) {
52035 reg.showPanel(reg.getPanel(0));
52044 * Returns the nested BorderLayout for this panel
52045 * @return {Roo.BorderLayout}
52047 getLayout : function(){
52048 return this.layout;
52052 * Adds a xtype elements to the layout of the nested panel
52056 xtype : 'ContentPanel',
52063 xtype : 'NestedLayoutPanel',
52069 items : [ ... list of content panels or nested layout panels.. ]
52073 * @param {Object} cfg Xtype definition of item to add.
52075 addxtype : function(cfg) {
52076 return this.layout.addxtype(cfg);
52081 Roo.ScrollPanel = function(el, config, content){
52082 config = config || {};
52083 config.fitToFrame = true;
52084 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
52086 this.el.dom.style.overflow = "hidden";
52087 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
52088 this.el.removeClass("x-layout-inactive-content");
52089 this.el.on("mousewheel", this.onWheel, this);
52091 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
52092 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
52093 up.unselectable(); down.unselectable();
52094 up.on("click", this.scrollUp, this);
52095 down.on("click", this.scrollDown, this);
52096 up.addClassOnOver("x-scroller-btn-over");
52097 down.addClassOnOver("x-scroller-btn-over");
52098 up.addClassOnClick("x-scroller-btn-click");
52099 down.addClassOnClick("x-scroller-btn-click");
52100 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
52102 this.resizeEl = this.el;
52103 this.el = wrap; this.up = up; this.down = down;
52106 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
52108 wheelIncrement : 5,
52109 scrollUp : function(){
52110 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
52113 scrollDown : function(){
52114 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
52117 afterScroll : function(){
52118 var el = this.resizeEl;
52119 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
52120 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52121 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52124 setSize : function(){
52125 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
52126 this.afterScroll();
52129 onWheel : function(e){
52130 var d = e.getWheelDelta();
52131 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
52132 this.afterScroll();
52136 setContent : function(content, loadScripts){
52137 this.resizeEl.update(content, loadScripts);
52151 * @class Roo.TreePanel
52152 * @extends Roo.ContentPanel
52154 * Create a new TreePanel. - defaults to fit/scoll contents.
52155 * @param {String/Object} config A string to set only the panel's title, or a config object
52156 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
52158 Roo.TreePanel = function(config){
52159 var el = config.el;
52160 var tree = config.tree;
52161 delete config.tree;
52162 delete config.el; // hopefull!
52164 // wrapper for IE7 strict & safari scroll issue
52166 var treeEl = el.createChild();
52167 config.resizeEl = treeEl;
52171 Roo.TreePanel.superclass.constructor.call(this, el, config);
52174 this.tree = new Roo.tree.TreePanel(treeEl , tree);
52175 //console.log(tree);
52176 this.on('activate', function()
52178 if (this.tree.rendered) {
52181 //console.log('render tree');
52182 this.tree.render();
52184 // this should not be needed.. - it's actually the 'el' that resizes?
52185 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
52187 //this.on('resize', function (cp, w, h) {
52188 // this.tree.innerCt.setWidth(w);
52189 // this.tree.innerCt.setHeight(h);
52190 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
52197 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
52214 * Ext JS Library 1.1.1
52215 * Copyright(c) 2006-2007, Ext JS, LLC.
52217 * Originally Released Under LGPL - original licence link has changed is not relivant.
52220 * <script type="text/javascript">
52225 * @class Roo.ReaderLayout
52226 * @extends Roo.BorderLayout
52227 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
52228 * center region containing two nested regions (a top one for a list view and one for item preview below),
52229 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
52230 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
52231 * expedites the setup of the overall layout and regions for this common application style.
52234 var reader = new Roo.ReaderLayout();
52235 var CP = Roo.ContentPanel; // shortcut for adding
52237 reader.beginUpdate();
52238 reader.add("north", new CP("north", "North"));
52239 reader.add("west", new CP("west", {title: "West"}));
52240 reader.add("east", new CP("east", {title: "East"}));
52242 reader.regions.listView.add(new CP("listView", "List"));
52243 reader.regions.preview.add(new CP("preview", "Preview"));
52244 reader.endUpdate();
52247 * Create a new ReaderLayout
52248 * @param {Object} config Configuration options
52249 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
52250 * document.body if omitted)
52252 Roo.ReaderLayout = function(config, renderTo){
52253 var c = config || {size:{}};
52254 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
52255 north: c.north !== false ? Roo.apply({
52259 }, c.north) : false,
52260 west: c.west !== false ? Roo.apply({
52268 margins:{left:5,right:0,bottom:5,top:5},
52269 cmargins:{left:5,right:5,bottom:5,top:5}
52270 }, c.west) : false,
52271 east: c.east !== false ? Roo.apply({
52279 margins:{left:0,right:5,bottom:5,top:5},
52280 cmargins:{left:5,right:5,bottom:5,top:5}
52281 }, c.east) : false,
52282 center: Roo.apply({
52283 tabPosition: 'top',
52287 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
52291 this.el.addClass('x-reader');
52293 this.beginUpdate();
52295 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
52296 south: c.preview !== false ? Roo.apply({
52303 cmargins:{top:5,left:0, right:0, bottom:0}
52304 }, c.preview) : false,
52305 center: Roo.apply({
52311 this.add('center', new Roo.NestedLayoutPanel(inner,
52312 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
52316 this.regions.preview = inner.getRegion('south');
52317 this.regions.listView = inner.getRegion('center');
52320 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
52322 * Ext JS Library 1.1.1
52323 * Copyright(c) 2006-2007, Ext JS, LLC.
52325 * Originally Released Under LGPL - original licence link has changed is not relivant.
52328 * <script type="text/javascript">
52332 * @class Roo.grid.Grid
52333 * @extends Roo.util.Observable
52334 * This class represents the primary interface of a component based grid control.
52335 * <br><br>Usage:<pre><code>
52336 var grid = new Roo.grid.Grid("my-container-id", {
52339 selModel: mySelectionModel,
52340 autoSizeColumns: true,
52341 monitorWindowResize: false,
52342 trackMouseOver: true
52347 * <b>Common Problems:</b><br/>
52348 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
52349 * element will correct this<br/>
52350 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
52351 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
52352 * are unpredictable.<br/>
52353 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
52354 * grid to calculate dimensions/offsets.<br/>
52356 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
52357 * The container MUST have some type of size defined for the grid to fill. The container will be
52358 * automatically set to position relative if it isn't already.
52359 * @param {Object} config A config object that sets properties on this grid.
52361 Roo.grid.Grid = function(container, config){
52362 // initialize the container
52363 this.container = Roo.get(container);
52364 this.container.update("");
52365 this.container.setStyle("overflow", "hidden");
52366 this.container.addClass('x-grid-container');
52368 this.id = this.container.id;
52370 Roo.apply(this, config);
52371 // check and correct shorthanded configs
52373 this.dataSource = this.ds;
52377 this.colModel = this.cm;
52381 this.selModel = this.sm;
52385 if (this.selModel) {
52386 this.selModel = Roo.factory(this.selModel, Roo.grid);
52387 this.sm = this.selModel;
52388 this.sm.xmodule = this.xmodule || false;
52390 if (typeof(this.colModel.config) == 'undefined') {
52391 this.colModel = new Roo.grid.ColumnModel(this.colModel);
52392 this.cm = this.colModel;
52393 this.cm.xmodule = this.xmodule || false;
52395 if (this.dataSource) {
52396 this.dataSource= Roo.factory(this.dataSource, Roo.data);
52397 this.ds = this.dataSource;
52398 this.ds.xmodule = this.xmodule || false;
52405 this.container.setWidth(this.width);
52409 this.container.setHeight(this.height);
52416 * The raw click event for the entire grid.
52417 * @param {Roo.EventObject} e
52422 * The raw dblclick event for the entire grid.
52423 * @param {Roo.EventObject} e
52427 * @event contextmenu
52428 * The raw contextmenu event for the entire grid.
52429 * @param {Roo.EventObject} e
52431 "contextmenu" : true,
52434 * The raw mousedown event for the entire grid.
52435 * @param {Roo.EventObject} e
52437 "mousedown" : true,
52440 * The raw mouseup event for the entire grid.
52441 * @param {Roo.EventObject} e
52446 * The raw mouseover event for the entire grid.
52447 * @param {Roo.EventObject} e
52449 "mouseover" : true,
52452 * The raw mouseout event for the entire grid.
52453 * @param {Roo.EventObject} e
52458 * The raw keypress event for the entire grid.
52459 * @param {Roo.EventObject} e
52464 * The raw keydown event for the entire grid.
52465 * @param {Roo.EventObject} e
52473 * Fires when a cell is clicked
52474 * @param {Grid} this
52475 * @param {Number} rowIndex
52476 * @param {Number} columnIndex
52477 * @param {Roo.EventObject} e
52479 "cellclick" : true,
52481 * @event celldblclick
52482 * Fires when a cell is double clicked
52483 * @param {Grid} this
52484 * @param {Number} rowIndex
52485 * @param {Number} columnIndex
52486 * @param {Roo.EventObject} e
52488 "celldblclick" : true,
52491 * Fires when a row is clicked
52492 * @param {Grid} this
52493 * @param {Number} rowIndex
52494 * @param {Roo.EventObject} e
52498 * @event rowdblclick
52499 * Fires when a row is double clicked
52500 * @param {Grid} this
52501 * @param {Number} rowIndex
52502 * @param {Roo.EventObject} e
52504 "rowdblclick" : true,
52506 * @event headerclick
52507 * Fires when a header is clicked
52508 * @param {Grid} this
52509 * @param {Number} columnIndex
52510 * @param {Roo.EventObject} e
52512 "headerclick" : true,
52514 * @event headerdblclick
52515 * Fires when a header cell is double clicked
52516 * @param {Grid} this
52517 * @param {Number} columnIndex
52518 * @param {Roo.EventObject} e
52520 "headerdblclick" : true,
52522 * @event rowcontextmenu
52523 * Fires when a row is right clicked
52524 * @param {Grid} this
52525 * @param {Number} rowIndex
52526 * @param {Roo.EventObject} e
52528 "rowcontextmenu" : true,
52530 * @event cellcontextmenu
52531 * Fires when a cell is right clicked
52532 * @param {Grid} this
52533 * @param {Number} rowIndex
52534 * @param {Number} cellIndex
52535 * @param {Roo.EventObject} e
52537 "cellcontextmenu" : true,
52539 * @event headercontextmenu
52540 * Fires when a header is right clicked
52541 * @param {Grid} this
52542 * @param {Number} columnIndex
52543 * @param {Roo.EventObject} e
52545 "headercontextmenu" : true,
52547 * @event bodyscroll
52548 * Fires when the body element is scrolled
52549 * @param {Number} scrollLeft
52550 * @param {Number} scrollTop
52552 "bodyscroll" : true,
52554 * @event columnresize
52555 * Fires when the user resizes a column
52556 * @param {Number} columnIndex
52557 * @param {Number} newSize
52559 "columnresize" : true,
52561 * @event columnmove
52562 * Fires when the user moves a column
52563 * @param {Number} oldIndex
52564 * @param {Number} newIndex
52566 "columnmove" : true,
52569 * Fires when row(s) start being dragged
52570 * @param {Grid} this
52571 * @param {Roo.GridDD} dd The drag drop object
52572 * @param {event} e The raw browser event
52574 "startdrag" : true,
52577 * Fires when a drag operation is complete
52578 * @param {Grid} this
52579 * @param {Roo.GridDD} dd The drag drop object
52580 * @param {event} e The raw browser event
52585 * Fires when dragged row(s) are dropped on a valid DD target
52586 * @param {Grid} this
52587 * @param {Roo.GridDD} dd The drag drop object
52588 * @param {String} targetId The target drag drop object
52589 * @param {event} e The raw browser event
52594 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
52595 * @param {Grid} this
52596 * @param {Roo.GridDD} dd The drag drop object
52597 * @param {String} targetId The target drag drop object
52598 * @param {event} e The raw browser event
52603 * Fires when the dragged row(s) first cross another DD target while being dragged
52604 * @param {Grid} this
52605 * @param {Roo.GridDD} dd The drag drop object
52606 * @param {String} targetId The target drag drop object
52607 * @param {event} e The raw browser event
52609 "dragenter" : true,
52612 * Fires when the dragged row(s) leave another DD target while being dragged
52613 * @param {Grid} this
52614 * @param {Roo.GridDD} dd The drag drop object
52615 * @param {String} targetId The target drag drop object
52616 * @param {event} e The raw browser event
52621 * Fires when a row is rendered, so you can change add a style to it.
52622 * @param {GridView} gridview The grid view
52623 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52629 * Fires when the grid is rendered
52630 * @param {Grid} grid
52635 Roo.grid.Grid.superclass.constructor.call(this);
52637 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52640 * @cfg {String} ddGroup - drag drop group.
52644 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52646 minColumnWidth : 25,
52649 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52650 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52651 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52653 autoSizeColumns : false,
52656 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52658 autoSizeHeaders : true,
52661 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52663 monitorWindowResize : true,
52666 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52667 * rows measured to get a columns size. Default is 0 (all rows).
52669 maxRowsToMeasure : 0,
52672 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52674 trackMouseOver : true,
52677 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52681 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52683 enableDragDrop : false,
52686 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52688 enableColumnMove : true,
52691 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52693 enableColumnHide : true,
52696 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52698 enableRowHeightSync : false,
52701 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52706 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52708 autoHeight : false,
52711 * @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.
52713 autoExpandColumn : false,
52716 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52719 autoExpandMin : 50,
52722 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52724 autoExpandMax : 1000,
52727 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52732 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52736 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52746 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52747 * of a fixed width. Default is false.
52750 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52753 * Called once after all setup has been completed and the grid is ready to be rendered.
52754 * @return {Roo.grid.Grid} this
52756 render : function()
52758 var c = this.container;
52759 // try to detect autoHeight/width mode
52760 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52761 this.autoHeight = true;
52763 var view = this.getView();
52766 c.on("click", this.onClick, this);
52767 c.on("dblclick", this.onDblClick, this);
52768 c.on("contextmenu", this.onContextMenu, this);
52769 c.on("keydown", this.onKeyDown, this);
52771 c.on("touchstart", this.onTouchStart, this);
52774 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52776 this.getSelectionModel().init(this);
52781 this.loadMask = new Roo.LoadMask(this.container,
52782 Roo.apply({store:this.dataSource}, this.loadMask));
52786 if (this.toolbar && this.toolbar.xtype) {
52787 this.toolbar.container = this.getView().getHeaderPanel(true);
52788 this.toolbar = new Roo.Toolbar(this.toolbar);
52790 if (this.footer && this.footer.xtype) {
52791 this.footer.dataSource = this.getDataSource();
52792 this.footer.container = this.getView().getFooterPanel(true);
52793 this.footer = Roo.factory(this.footer, Roo);
52795 if (this.dropTarget && this.dropTarget.xtype) {
52796 delete this.dropTarget.xtype;
52797 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52801 this.rendered = true;
52802 this.fireEvent('render', this);
52807 * Reconfigures the grid to use a different Store and Column Model.
52808 * The View will be bound to the new objects and refreshed.
52809 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52810 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52812 reconfigure : function(dataSource, colModel){
52814 this.loadMask.destroy();
52815 this.loadMask = new Roo.LoadMask(this.container,
52816 Roo.apply({store:dataSource}, this.loadMask));
52818 this.view.bind(dataSource, colModel);
52819 this.dataSource = dataSource;
52820 this.colModel = colModel;
52821 this.view.refresh(true);
52825 onKeyDown : function(e){
52826 this.fireEvent("keydown", e);
52830 * Destroy this grid.
52831 * @param {Boolean} removeEl True to remove the element
52833 destroy : function(removeEl, keepListeners){
52835 this.loadMask.destroy();
52837 var c = this.container;
52838 c.removeAllListeners();
52839 this.view.destroy();
52840 this.colModel.purgeListeners();
52841 if(!keepListeners){
52842 this.purgeListeners();
52845 if(removeEl === true){
52851 processEvent : function(name, e){
52852 // does this fire select???
52853 //Roo.log('grid:processEvent ' + name);
52855 if (name != 'touchstart' ) {
52856 this.fireEvent(name, e);
52859 var t = e.getTarget();
52861 var header = v.findHeaderIndex(t);
52862 if(header !== false){
52863 var ename = name == 'touchstart' ? 'click' : name;
52865 this.fireEvent("header" + ename, this, header, e);
52867 var row = v.findRowIndex(t);
52868 var cell = v.findCellIndex(t);
52869 if (name == 'touchstart') {
52870 // first touch is always a click.
52871 // hopefull this happens after selection is updated.?
52874 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52875 var cs = this.selModel.getSelectedCell();
52876 if (row == cs[0] && cell == cs[1]){
52880 if (typeof(this.selModel.getSelections) != 'undefined') {
52881 var cs = this.selModel.getSelections();
52882 var ds = this.dataSource;
52883 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52894 this.fireEvent("row" + name, this, row, e);
52895 if(cell !== false){
52896 this.fireEvent("cell" + name, this, row, cell, e);
52903 onClick : function(e){
52904 this.processEvent("click", e);
52907 onTouchStart : function(e){
52908 this.processEvent("touchstart", e);
52912 onContextMenu : function(e, t){
52913 this.processEvent("contextmenu", e);
52917 onDblClick : function(e){
52918 this.processEvent("dblclick", e);
52922 walkCells : function(row, col, step, fn, scope){
52923 var cm = this.colModel, clen = cm.getColumnCount();
52924 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52936 if(fn.call(scope || this, row, col, cm) === true){
52954 if(fn.call(scope || this, row, col, cm) === true){
52966 getSelections : function(){
52967 return this.selModel.getSelections();
52971 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52972 * but if manual update is required this method will initiate it.
52974 autoSize : function(){
52976 this.view.layout();
52977 if(this.view.adjustForScroll){
52978 this.view.adjustForScroll();
52984 * Returns the grid's underlying element.
52985 * @return {Element} The element
52987 getGridEl : function(){
52988 return this.container;
52991 // private for compatibility, overridden by editor grid
52992 stopEditing : function(){},
52995 * Returns the grid's SelectionModel.
52996 * @return {SelectionModel}
52998 getSelectionModel : function(){
52999 if(!this.selModel){
53000 this.selModel = new Roo.grid.RowSelectionModel();
53002 return this.selModel;
53006 * Returns the grid's DataSource.
53007 * @return {DataSource}
53009 getDataSource : function(){
53010 return this.dataSource;
53014 * Returns the grid's ColumnModel.
53015 * @return {ColumnModel}
53017 getColumnModel : function(){
53018 return this.colModel;
53022 * Returns the grid's GridView object.
53023 * @return {GridView}
53025 getView : function(){
53027 this.view = new Roo.grid.GridView(this.viewConfig);
53032 * Called to get grid's drag proxy text, by default returns this.ddText.
53035 getDragDropText : function(){
53036 var count = this.selModel.getCount();
53037 return String.format(this.ddText, count, count == 1 ? '' : 's');
53041 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
53042 * %0 is replaced with the number of selected rows.
53045 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
53047 * Ext JS Library 1.1.1
53048 * Copyright(c) 2006-2007, Ext JS, LLC.
53050 * Originally Released Under LGPL - original licence link has changed is not relivant.
53053 * <script type="text/javascript">
53056 Roo.grid.AbstractGridView = function(){
53060 "beforerowremoved" : true,
53061 "beforerowsinserted" : true,
53062 "beforerefresh" : true,
53063 "rowremoved" : true,
53064 "rowsinserted" : true,
53065 "rowupdated" : true,
53068 Roo.grid.AbstractGridView.superclass.constructor.call(this);
53071 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
53072 rowClass : "x-grid-row",
53073 cellClass : "x-grid-cell",
53074 tdClass : "x-grid-td",
53075 hdClass : "x-grid-hd",
53076 splitClass : "x-grid-hd-split",
53078 init: function(grid){
53080 var cid = this.grid.getGridEl().id;
53081 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
53082 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
53083 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
53084 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
53087 getColumnRenderers : function(){
53088 var renderers = [];
53089 var cm = this.grid.colModel;
53090 var colCount = cm.getColumnCount();
53091 for(var i = 0; i < colCount; i++){
53092 renderers[i] = cm.getRenderer(i);
53097 getColumnIds : function(){
53099 var cm = this.grid.colModel;
53100 var colCount = cm.getColumnCount();
53101 for(var i = 0; i < colCount; i++){
53102 ids[i] = cm.getColumnId(i);
53107 getDataIndexes : function(){
53108 if(!this.indexMap){
53109 this.indexMap = this.buildIndexMap();
53111 return this.indexMap.colToData;
53114 getColumnIndexByDataIndex : function(dataIndex){
53115 if(!this.indexMap){
53116 this.indexMap = this.buildIndexMap();
53118 return this.indexMap.dataToCol[dataIndex];
53122 * Set a css style for a column dynamically.
53123 * @param {Number} colIndex The index of the column
53124 * @param {String} name The css property name
53125 * @param {String} value The css value
53127 setCSSStyle : function(colIndex, name, value){
53128 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
53129 Roo.util.CSS.updateRule(selector, name, value);
53132 generateRules : function(cm){
53133 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
53134 Roo.util.CSS.removeStyleSheet(rulesId);
53135 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53136 var cid = cm.getColumnId(i);
53137 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
53138 this.tdSelector, cid, " {\n}\n",
53139 this.hdSelector, cid, " {\n}\n",
53140 this.splitSelector, cid, " {\n}\n");
53142 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53146 * Ext JS Library 1.1.1
53147 * Copyright(c) 2006-2007, Ext JS, LLC.
53149 * Originally Released Under LGPL - original licence link has changed is not relivant.
53152 * <script type="text/javascript">
53156 // This is a support class used internally by the Grid components
53157 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
53159 this.view = grid.getView();
53160 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53161 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
53163 this.setHandleElId(Roo.id(hd));
53164 this.setOuterHandleElId(Roo.id(hd2));
53166 this.scroll = false;
53168 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
53170 getDragData : function(e){
53171 var t = Roo.lib.Event.getTarget(e);
53172 var h = this.view.findHeaderCell(t);
53174 return {ddel: h.firstChild, header:h};
53179 onInitDrag : function(e){
53180 this.view.headersDisabled = true;
53181 var clone = this.dragData.ddel.cloneNode(true);
53182 clone.id = Roo.id();
53183 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
53184 this.proxy.update(clone);
53188 afterValidDrop : function(){
53190 setTimeout(function(){
53191 v.headersDisabled = false;
53195 afterInvalidDrop : function(){
53197 setTimeout(function(){
53198 v.headersDisabled = false;
53204 * Ext JS Library 1.1.1
53205 * Copyright(c) 2006-2007, Ext JS, LLC.
53207 * Originally Released Under LGPL - original licence link has changed is not relivant.
53210 * <script type="text/javascript">
53213 // This is a support class used internally by the Grid components
53214 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
53216 this.view = grid.getView();
53217 // split the proxies so they don't interfere with mouse events
53218 this.proxyTop = Roo.DomHelper.append(document.body, {
53219 cls:"col-move-top", html:" "
53221 this.proxyBottom = Roo.DomHelper.append(document.body, {
53222 cls:"col-move-bottom", html:" "
53224 this.proxyTop.hide = this.proxyBottom.hide = function(){
53225 this.setLeftTop(-100,-100);
53226 this.setStyle("visibility", "hidden");
53228 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53229 // temporarily disabled
53230 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
53231 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
53233 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
53234 proxyOffsets : [-4, -9],
53235 fly: Roo.Element.fly,
53237 getTargetFromEvent : function(e){
53238 var t = Roo.lib.Event.getTarget(e);
53239 var cindex = this.view.findCellIndex(t);
53240 if(cindex !== false){
53241 return this.view.getHeaderCell(cindex);
53246 nextVisible : function(h){
53247 var v = this.view, cm = this.grid.colModel;
53250 if(!cm.isHidden(v.getCellIndex(h))){
53258 prevVisible : function(h){
53259 var v = this.view, cm = this.grid.colModel;
53262 if(!cm.isHidden(v.getCellIndex(h))){
53270 positionIndicator : function(h, n, e){
53271 var x = Roo.lib.Event.getPageX(e);
53272 var r = Roo.lib.Dom.getRegion(n.firstChild);
53273 var px, pt, py = r.top + this.proxyOffsets[1];
53274 if((r.right - x) <= (r.right-r.left)/2){
53275 px = r.right+this.view.borderWidth;
53281 var oldIndex = this.view.getCellIndex(h);
53282 var newIndex = this.view.getCellIndex(n);
53284 if(this.grid.colModel.isFixed(newIndex)){
53288 var locked = this.grid.colModel.isLocked(newIndex);
53293 if(oldIndex < newIndex){
53296 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
53299 px += this.proxyOffsets[0];
53300 this.proxyTop.setLeftTop(px, py);
53301 this.proxyTop.show();
53302 if(!this.bottomOffset){
53303 this.bottomOffset = this.view.mainHd.getHeight();
53305 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
53306 this.proxyBottom.show();
53310 onNodeEnter : function(n, dd, e, data){
53311 if(data.header != n){
53312 this.positionIndicator(data.header, n, e);
53316 onNodeOver : function(n, dd, e, data){
53317 var result = false;
53318 if(data.header != n){
53319 result = this.positionIndicator(data.header, n, e);
53322 this.proxyTop.hide();
53323 this.proxyBottom.hide();
53325 return result ? this.dropAllowed : this.dropNotAllowed;
53328 onNodeOut : function(n, dd, e, data){
53329 this.proxyTop.hide();
53330 this.proxyBottom.hide();
53333 onNodeDrop : function(n, dd, e, data){
53334 var h = data.header;
53336 var cm = this.grid.colModel;
53337 var x = Roo.lib.Event.getPageX(e);
53338 var r = Roo.lib.Dom.getRegion(n.firstChild);
53339 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
53340 var oldIndex = this.view.getCellIndex(h);
53341 var newIndex = this.view.getCellIndex(n);
53342 var locked = cm.isLocked(newIndex);
53346 if(oldIndex < newIndex){
53349 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
53352 cm.setLocked(oldIndex, locked, true);
53353 cm.moveColumn(oldIndex, newIndex);
53354 this.grid.fireEvent("columnmove", oldIndex, newIndex);
53362 * Ext JS Library 1.1.1
53363 * Copyright(c) 2006-2007, Ext JS, LLC.
53365 * Originally Released Under LGPL - original licence link has changed is not relivant.
53368 * <script type="text/javascript">
53372 * @class Roo.grid.GridView
53373 * @extends Roo.util.Observable
53376 * @param {Object} config
53378 Roo.grid.GridView = function(config){
53379 Roo.grid.GridView.superclass.constructor.call(this);
53382 Roo.apply(this, config);
53385 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
53387 unselectable : 'unselectable="on"',
53388 unselectableCls : 'x-unselectable',
53391 rowClass : "x-grid-row",
53393 cellClass : "x-grid-col",
53395 tdClass : "x-grid-td",
53397 hdClass : "x-grid-hd",
53399 splitClass : "x-grid-split",
53401 sortClasses : ["sort-asc", "sort-desc"],
53403 enableMoveAnim : false,
53407 dh : Roo.DomHelper,
53409 fly : Roo.Element.fly,
53411 css : Roo.util.CSS,
53417 scrollIncrement : 22,
53419 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
53421 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
53423 bind : function(ds, cm){
53425 this.ds.un("load", this.onLoad, this);
53426 this.ds.un("datachanged", this.onDataChange, this);
53427 this.ds.un("add", this.onAdd, this);
53428 this.ds.un("remove", this.onRemove, this);
53429 this.ds.un("update", this.onUpdate, this);
53430 this.ds.un("clear", this.onClear, this);
53433 ds.on("load", this.onLoad, this);
53434 ds.on("datachanged", this.onDataChange, this);
53435 ds.on("add", this.onAdd, this);
53436 ds.on("remove", this.onRemove, this);
53437 ds.on("update", this.onUpdate, this);
53438 ds.on("clear", this.onClear, this);
53443 this.cm.un("widthchange", this.onColWidthChange, this);
53444 this.cm.un("headerchange", this.onHeaderChange, this);
53445 this.cm.un("hiddenchange", this.onHiddenChange, this);
53446 this.cm.un("columnmoved", this.onColumnMove, this);
53447 this.cm.un("columnlockchange", this.onColumnLock, this);
53450 this.generateRules(cm);
53451 cm.on("widthchange", this.onColWidthChange, this);
53452 cm.on("headerchange", this.onHeaderChange, this);
53453 cm.on("hiddenchange", this.onHiddenChange, this);
53454 cm.on("columnmoved", this.onColumnMove, this);
53455 cm.on("columnlockchange", this.onColumnLock, this);
53460 init: function(grid){
53461 Roo.grid.GridView.superclass.init.call(this, grid);
53463 this.bind(grid.dataSource, grid.colModel);
53465 grid.on("headerclick", this.handleHeaderClick, this);
53467 if(grid.trackMouseOver){
53468 grid.on("mouseover", this.onRowOver, this);
53469 grid.on("mouseout", this.onRowOut, this);
53471 grid.cancelTextSelection = function(){};
53472 this.gridId = grid.id;
53474 var tpls = this.templates || {};
53477 tpls.master = new Roo.Template(
53478 '<div class="x-grid" hidefocus="true">',
53479 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
53480 '<div class="x-grid-topbar"></div>',
53481 '<div class="x-grid-scroller"><div></div></div>',
53482 '<div class="x-grid-locked">',
53483 '<div class="x-grid-header">{lockedHeader}</div>',
53484 '<div class="x-grid-body">{lockedBody}</div>',
53486 '<div class="x-grid-viewport">',
53487 '<div class="x-grid-header">{header}</div>',
53488 '<div class="x-grid-body">{body}</div>',
53490 '<div class="x-grid-bottombar"></div>',
53492 '<div class="x-grid-resize-proxy"> </div>',
53495 tpls.master.disableformats = true;
53499 tpls.header = new Roo.Template(
53500 '<table border="0" cellspacing="0" cellpadding="0">',
53501 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
53504 tpls.header.disableformats = true;
53506 tpls.header.compile();
53509 tpls.hcell = new Roo.Template(
53510 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
53511 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
53514 tpls.hcell.disableFormats = true;
53516 tpls.hcell.compile();
53519 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
53520 this.unselectableCls + '" ' + this.unselectable +'> </div>');
53521 tpls.hsplit.disableFormats = true;
53523 tpls.hsplit.compile();
53526 tpls.body = new Roo.Template(
53527 '<table border="0" cellspacing="0" cellpadding="0">',
53528 "<tbody>{rows}</tbody>",
53531 tpls.body.disableFormats = true;
53533 tpls.body.compile();
53536 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
53537 tpls.row.disableFormats = true;
53539 tpls.row.compile();
53542 tpls.cell = new Roo.Template(
53543 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
53544 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
53545 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
53548 tpls.cell.disableFormats = true;
53550 tpls.cell.compile();
53552 this.templates = tpls;
53555 // remap these for backwards compat
53556 onColWidthChange : function(){
53557 this.updateColumns.apply(this, arguments);
53559 onHeaderChange : function(){
53560 this.updateHeaders.apply(this, arguments);
53562 onHiddenChange : function(){
53563 this.handleHiddenChange.apply(this, arguments);
53565 onColumnMove : function(){
53566 this.handleColumnMove.apply(this, arguments);
53568 onColumnLock : function(){
53569 this.handleLockChange.apply(this, arguments);
53572 onDataChange : function(){
53574 this.updateHeaderSortState();
53577 onClear : function(){
53581 onUpdate : function(ds, record){
53582 this.refreshRow(record);
53585 refreshRow : function(record){
53586 var ds = this.ds, index;
53587 if(typeof record == 'number'){
53589 record = ds.getAt(index);
53591 index = ds.indexOf(record);
53593 this.insertRows(ds, index, index, true);
53594 this.onRemove(ds, record, index+1, true);
53595 this.syncRowHeights(index, index);
53597 this.fireEvent("rowupdated", this, index, record);
53600 onAdd : function(ds, records, index){
53601 this.insertRows(ds, index, index + (records.length-1));
53604 onRemove : function(ds, record, index, isUpdate){
53605 if(isUpdate !== true){
53606 this.fireEvent("beforerowremoved", this, index, record);
53608 var bt = this.getBodyTable(), lt = this.getLockedTable();
53609 if(bt.rows[index]){
53610 bt.firstChild.removeChild(bt.rows[index]);
53612 if(lt.rows[index]){
53613 lt.firstChild.removeChild(lt.rows[index]);
53615 if(isUpdate !== true){
53616 this.stripeRows(index);
53617 this.syncRowHeights(index, index);
53619 this.fireEvent("rowremoved", this, index, record);
53623 onLoad : function(){
53624 this.scrollToTop();
53628 * Scrolls the grid to the top
53630 scrollToTop : function(){
53632 this.scroller.dom.scrollTop = 0;
53638 * Gets a panel in the header 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 header is hidden. Pass true to show the panel
53642 * @return Roo.Element
53644 getHeaderPanel : function(doShow){
53646 this.headerPanel.show();
53648 return this.headerPanel;
53652 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53653 * After modifying the contents of this panel a call to grid.autoSize() may be
53654 * required to register any changes in size.
53655 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53656 * @return Roo.Element
53658 getFooterPanel : function(doShow){
53660 this.footerPanel.show();
53662 return this.footerPanel;
53665 initElements : function(){
53666 var E = Roo.Element;
53667 var el = this.grid.getGridEl().dom.firstChild;
53668 var cs = el.childNodes;
53670 this.el = new E(el);
53672 this.focusEl = new E(el.firstChild);
53673 this.focusEl.swallowEvent("click", true);
53675 this.headerPanel = new E(cs[1]);
53676 this.headerPanel.enableDisplayMode("block");
53678 this.scroller = new E(cs[2]);
53679 this.scrollSizer = new E(this.scroller.dom.firstChild);
53681 this.lockedWrap = new E(cs[3]);
53682 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53683 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53685 this.mainWrap = new E(cs[4]);
53686 this.mainHd = new E(this.mainWrap.dom.firstChild);
53687 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53689 this.footerPanel = new E(cs[5]);
53690 this.footerPanel.enableDisplayMode("block");
53692 this.resizeProxy = new E(cs[6]);
53694 this.headerSelector = String.format(
53695 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53696 this.lockedHd.id, this.mainHd.id
53699 this.splitterSelector = String.format(
53700 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53701 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53704 idToCssName : function(s)
53706 return s.replace(/[^a-z0-9]+/ig, '-');
53709 getHeaderCell : function(index){
53710 return Roo.DomQuery.select(this.headerSelector)[index];
53713 getHeaderCellMeasure : function(index){
53714 return this.getHeaderCell(index).firstChild;
53717 getHeaderCellText : function(index){
53718 return this.getHeaderCell(index).firstChild.firstChild;
53721 getLockedTable : function(){
53722 return this.lockedBody.dom.firstChild;
53725 getBodyTable : function(){
53726 return this.mainBody.dom.firstChild;
53729 getLockedRow : function(index){
53730 return this.getLockedTable().rows[index];
53733 getRow : function(index){
53734 return this.getBodyTable().rows[index];
53737 getRowComposite : function(index){
53739 this.rowEl = new Roo.CompositeElementLite();
53741 var els = [], lrow, mrow;
53742 if(lrow = this.getLockedRow(index)){
53745 if(mrow = this.getRow(index)){
53748 this.rowEl.elements = els;
53752 * Gets the 'td' of the cell
53754 * @param {Integer} rowIndex row to select
53755 * @param {Integer} colIndex column to select
53759 getCell : function(rowIndex, colIndex){
53760 var locked = this.cm.getLockedCount();
53762 if(colIndex < locked){
53763 source = this.lockedBody.dom.firstChild;
53765 source = this.mainBody.dom.firstChild;
53766 colIndex -= locked;
53768 return source.rows[rowIndex].childNodes[colIndex];
53771 getCellText : function(rowIndex, colIndex){
53772 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53775 getCellBox : function(cell){
53776 var b = this.fly(cell).getBox();
53777 if(Roo.isOpera){ // opera fails to report the Y
53778 b.y = cell.offsetTop + this.mainBody.getY();
53783 getCellIndex : function(cell){
53784 var id = String(cell.className).match(this.cellRE);
53786 return parseInt(id[1], 10);
53791 findHeaderIndex : function(n){
53792 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53793 return r ? this.getCellIndex(r) : false;
53796 findHeaderCell : function(n){
53797 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53798 return r ? r : false;
53801 findRowIndex : function(n){
53805 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53806 return r ? r.rowIndex : false;
53809 findCellIndex : function(node){
53810 var stop = this.el.dom;
53811 while(node && node != stop){
53812 if(this.findRE.test(node.className)){
53813 return this.getCellIndex(node);
53815 node = node.parentNode;
53820 getColumnId : function(index){
53821 return this.cm.getColumnId(index);
53824 getSplitters : function()
53826 if(this.splitterSelector){
53827 return Roo.DomQuery.select(this.splitterSelector);
53833 getSplitter : function(index){
53834 return this.getSplitters()[index];
53837 onRowOver : function(e, t){
53839 if((row = this.findRowIndex(t)) !== false){
53840 this.getRowComposite(row).addClass("x-grid-row-over");
53844 onRowOut : function(e, t){
53846 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53847 this.getRowComposite(row).removeClass("x-grid-row-over");
53851 renderHeaders : function(){
53853 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53854 var cb = [], lb = [], sb = [], lsb = [], p = {};
53855 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53856 p.cellId = "x-grid-hd-0-" + i;
53857 p.splitId = "x-grid-csplit-0-" + i;
53858 p.id = cm.getColumnId(i);
53859 p.title = cm.getColumnTooltip(i) || "";
53860 p.value = cm.getColumnHeader(i) || "";
53861 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53862 if(!cm.isLocked(i)){
53863 cb[cb.length] = ct.apply(p);
53864 sb[sb.length] = st.apply(p);
53866 lb[lb.length] = ct.apply(p);
53867 lsb[lsb.length] = st.apply(p);
53870 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53871 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53874 updateHeaders : function(){
53875 var html = this.renderHeaders();
53876 this.lockedHd.update(html[0]);
53877 this.mainHd.update(html[1]);
53881 * Focuses the specified row.
53882 * @param {Number} row The row index
53884 focusRow : function(row)
53886 //Roo.log('GridView.focusRow');
53887 var x = this.scroller.dom.scrollLeft;
53888 this.focusCell(row, 0, false);
53889 this.scroller.dom.scrollLeft = x;
53893 * Focuses the specified cell.
53894 * @param {Number} row The row index
53895 * @param {Number} col The column index
53896 * @param {Boolean} hscroll false to disable horizontal scrolling
53898 focusCell : function(row, col, hscroll)
53900 //Roo.log('GridView.focusCell');
53901 var el = this.ensureVisible(row, col, hscroll);
53902 this.focusEl.alignTo(el, "tl-tl");
53904 this.focusEl.focus();
53906 this.focusEl.focus.defer(1, this.focusEl);
53911 * Scrolls the specified cell into view
53912 * @param {Number} row The row index
53913 * @param {Number} col The column index
53914 * @param {Boolean} hscroll false to disable horizontal scrolling
53916 ensureVisible : function(row, col, hscroll)
53918 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53919 //return null; //disable for testing.
53920 if(typeof row != "number"){
53921 row = row.rowIndex;
53923 if(row < 0 && row >= this.ds.getCount()){
53926 col = (col !== undefined ? col : 0);
53927 var cm = this.grid.colModel;
53928 while(cm.isHidden(col)){
53932 var el = this.getCell(row, col);
53936 var c = this.scroller.dom;
53938 var ctop = parseInt(el.offsetTop, 10);
53939 var cleft = parseInt(el.offsetLeft, 10);
53940 var cbot = ctop + el.offsetHeight;
53941 var cright = cleft + el.offsetWidth;
53943 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53944 var stop = parseInt(c.scrollTop, 10);
53945 var sleft = parseInt(c.scrollLeft, 10);
53946 var sbot = stop + ch;
53947 var sright = sleft + c.clientWidth;
53949 Roo.log('GridView.ensureVisible:' +
53951 ' c.clientHeight:' + c.clientHeight +
53952 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53960 c.scrollTop = ctop;
53961 //Roo.log("set scrolltop to ctop DISABLE?");
53962 }else if(cbot > sbot){
53963 //Roo.log("set scrolltop to cbot-ch");
53964 c.scrollTop = cbot-ch;
53967 if(hscroll !== false){
53969 c.scrollLeft = cleft;
53970 }else if(cright > sright){
53971 c.scrollLeft = cright-c.clientWidth;
53978 updateColumns : function(){
53979 this.grid.stopEditing();
53980 var cm = this.grid.colModel, colIds = this.getColumnIds();
53981 //var totalWidth = cm.getTotalWidth();
53983 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53984 //if(cm.isHidden(i)) continue;
53985 var w = cm.getColumnWidth(i);
53986 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53987 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53989 this.updateSplitters();
53992 generateRules : function(cm){
53993 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53994 Roo.util.CSS.removeStyleSheet(rulesId);
53995 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53996 var cid = cm.getColumnId(i);
53998 if(cm.config[i].align){
53999 align = 'text-align:'+cm.config[i].align+';';
54002 if(cm.isHidden(i)){
54003 hidden = 'display:none;';
54005 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
54007 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
54008 this.hdSelector, cid, " {\n", align, width, "}\n",
54009 this.tdSelector, cid, " {\n",hidden,"\n}\n",
54010 this.splitSelector, cid, " {\n", hidden , "\n}\n");
54012 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54015 updateSplitters : function(){
54016 var cm = this.cm, s = this.getSplitters();
54017 if(s){ // splitters not created yet
54018 var pos = 0, locked = true;
54019 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54020 if(cm.isHidden(i)) continue;
54021 var w = cm.getColumnWidth(i); // make sure it's a number
54022 if(!cm.isLocked(i) && locked){
54027 s[i].style.left = (pos-this.splitOffset) + "px";
54032 handleHiddenChange : function(colModel, colIndex, hidden){
54034 this.hideColumn(colIndex);
54036 this.unhideColumn(colIndex);
54040 hideColumn : function(colIndex){
54041 var cid = this.getColumnId(colIndex);
54042 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
54043 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
54045 this.updateHeaders();
54047 this.updateSplitters();
54051 unhideColumn : function(colIndex){
54052 var cid = this.getColumnId(colIndex);
54053 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
54054 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
54057 this.updateHeaders();
54059 this.updateSplitters();
54063 insertRows : function(dm, firstRow, lastRow, isUpdate){
54064 if(firstRow == 0 && lastRow == dm.getCount()-1){
54068 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
54070 var s = this.getScrollState();
54071 var markup = this.renderRows(firstRow, lastRow);
54072 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
54073 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
54074 this.restoreScroll(s);
54076 this.fireEvent("rowsinserted", this, firstRow, lastRow);
54077 this.syncRowHeights(firstRow, lastRow);
54078 this.stripeRows(firstRow);
54084 bufferRows : function(markup, target, index){
54085 var before = null, trows = target.rows, tbody = target.tBodies[0];
54086 if(index < trows.length){
54087 before = trows[index];
54089 var b = document.createElement("div");
54090 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
54091 var rows = b.firstChild.rows;
54092 for(var i = 0, len = rows.length; i < len; i++){
54094 tbody.insertBefore(rows[0], before);
54096 tbody.appendChild(rows[0]);
54103 deleteRows : function(dm, firstRow, lastRow){
54104 if(dm.getRowCount()<1){
54105 this.fireEvent("beforerefresh", this);
54106 this.mainBody.update("");
54107 this.lockedBody.update("");
54108 this.fireEvent("refresh", this);
54110 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
54111 var bt = this.getBodyTable();
54112 var tbody = bt.firstChild;
54113 var rows = bt.rows;
54114 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
54115 tbody.removeChild(rows[firstRow]);
54117 this.stripeRows(firstRow);
54118 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
54122 updateRows : function(dataSource, firstRow, lastRow){
54123 var s = this.getScrollState();
54125 this.restoreScroll(s);
54128 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
54132 this.updateHeaderSortState();
54135 getScrollState : function(){
54137 var sb = this.scroller.dom;
54138 return {left: sb.scrollLeft, top: sb.scrollTop};
54141 stripeRows : function(startRow){
54142 if(!this.grid.stripeRows || this.ds.getCount() < 1){
54145 startRow = startRow || 0;
54146 var rows = this.getBodyTable().rows;
54147 var lrows = this.getLockedTable().rows;
54148 var cls = ' x-grid-row-alt ';
54149 for(var i = startRow, len = rows.length; i < len; i++){
54150 var row = rows[i], lrow = lrows[i];
54151 var isAlt = ((i+1) % 2 == 0);
54152 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
54153 if(isAlt == hasAlt){
54157 row.className += " x-grid-row-alt";
54159 row.className = row.className.replace("x-grid-row-alt", "");
54162 lrow.className = row.className;
54167 restoreScroll : function(state){
54168 //Roo.log('GridView.restoreScroll');
54169 var sb = this.scroller.dom;
54170 sb.scrollLeft = state.left;
54171 sb.scrollTop = state.top;
54175 syncScroll : function(){
54176 //Roo.log('GridView.syncScroll');
54177 var sb = this.scroller.dom;
54178 var sh = this.mainHd.dom;
54179 var bs = this.mainBody.dom;
54180 var lv = this.lockedBody.dom;
54181 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
54182 lv.scrollTop = bs.scrollTop = sb.scrollTop;
54185 handleScroll : function(e){
54187 var sb = this.scroller.dom;
54188 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
54192 handleWheel : function(e){
54193 var d = e.getWheelDelta();
54194 this.scroller.dom.scrollTop -= d*22;
54195 // set this here to prevent jumpy scrolling on large tables
54196 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
54200 renderRows : function(startRow, endRow){
54201 // pull in all the crap needed to render rows
54202 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
54203 var colCount = cm.getColumnCount();
54205 if(ds.getCount() < 1){
54209 // build a map for all the columns
54211 for(var i = 0; i < colCount; i++){
54212 var name = cm.getDataIndex(i);
54214 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
54215 renderer : cm.getRenderer(i),
54216 id : cm.getColumnId(i),
54217 locked : cm.isLocked(i)
54221 startRow = startRow || 0;
54222 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
54224 // records to render
54225 var rs = ds.getRange(startRow, endRow);
54227 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
54230 // As much as I hate to duplicate code, this was branched because FireFox really hates
54231 // [].join("") on strings. The performance difference was substantial enough to
54232 // branch this function
54233 doRender : Roo.isGecko ?
54234 function(cs, rs, ds, startRow, colCount, stripe){
54235 var ts = this.templates, ct = ts.cell, rt = ts.row;
54237 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54239 var hasListener = this.grid.hasListener('rowclass');
54241 for(var j = 0, len = rs.length; j < len; j++){
54242 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
54243 for(var i = 0; i < colCount; i++){
54245 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54247 p.css = p.attr = "";
54248 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54249 if(p.value == undefined || p.value === "") p.value = " ";
54250 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54251 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54253 var markup = ct.apply(p);
54261 if(stripe && ((rowIndex+1) % 2 == 0)){
54262 alt.push("x-grid-row-alt")
54265 alt.push( " x-grid-dirty-row");
54268 if(this.getRowClass){
54269 alt.push(this.getRowClass(r, rowIndex));
54275 rowIndex : rowIndex,
54278 this.grid.fireEvent('rowclass', this, rowcfg);
54279 alt.push(rowcfg.rowClass);
54281 rp.alt = alt.join(" ");
54282 lbuf+= rt.apply(rp);
54284 buf+= rt.apply(rp);
54286 return [lbuf, buf];
54288 function(cs, rs, ds, startRow, colCount, stripe){
54289 var ts = this.templates, ct = ts.cell, rt = ts.row;
54291 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54292 var hasListener = this.grid.hasListener('rowclass');
54295 for(var j = 0, len = rs.length; j < len; j++){
54296 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
54297 for(var i = 0; i < colCount; i++){
54299 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54301 p.css = p.attr = "";
54302 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54303 if(p.value == undefined || p.value === "") p.value = " ";
54304 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54305 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54308 var markup = ct.apply(p);
54310 cb[cb.length] = markup;
54312 lcb[lcb.length] = markup;
54316 if(stripe && ((rowIndex+1) % 2 == 0)){
54317 alt.push( "x-grid-row-alt");
54320 alt.push(" x-grid-dirty-row");
54323 if(this.getRowClass){
54324 alt.push( this.getRowClass(r, rowIndex));
54330 rowIndex : rowIndex,
54333 this.grid.fireEvent('rowclass', this, rowcfg);
54334 alt.push(rowcfg.rowClass);
54336 rp.alt = alt.join(" ");
54337 rp.cells = lcb.join("");
54338 lbuf[lbuf.length] = rt.apply(rp);
54339 rp.cells = cb.join("");
54340 buf[buf.length] = rt.apply(rp);
54342 return [lbuf.join(""), buf.join("")];
54345 renderBody : function(){
54346 var markup = this.renderRows();
54347 var bt = this.templates.body;
54348 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
54352 * Refreshes the grid
54353 * @param {Boolean} headersToo
54355 refresh : function(headersToo){
54356 this.fireEvent("beforerefresh", this);
54357 this.grid.stopEditing();
54358 var result = this.renderBody();
54359 this.lockedBody.update(result[0]);
54360 this.mainBody.update(result[1]);
54361 if(headersToo === true){
54362 this.updateHeaders();
54363 this.updateColumns();
54364 this.updateSplitters();
54365 this.updateHeaderSortState();
54367 this.syncRowHeights();
54369 this.fireEvent("refresh", this);
54372 handleColumnMove : function(cm, oldIndex, newIndex){
54373 this.indexMap = null;
54374 var s = this.getScrollState();
54375 this.refresh(true);
54376 this.restoreScroll(s);
54377 this.afterMove(newIndex);
54380 afterMove : function(colIndex){
54381 if(this.enableMoveAnim && Roo.enableFx){
54382 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
54384 // if multisort - fix sortOrder, and reload..
54385 if (this.grid.dataSource.multiSort) {
54386 // the we can call sort again..
54387 var dm = this.grid.dataSource;
54388 var cm = this.grid.colModel;
54390 for(var i = 0; i < cm.config.length; i++ ) {
54392 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
54393 continue; // dont' bother, it's not in sort list or being set.
54396 so.push(cm.config[i].dataIndex);
54399 dm.load(dm.lastOptions);
54406 updateCell : function(dm, rowIndex, dataIndex){
54407 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
54408 if(typeof colIndex == "undefined"){ // not present in grid
54411 var cm = this.grid.colModel;
54412 var cell = this.getCell(rowIndex, colIndex);
54413 var cellText = this.getCellText(rowIndex, colIndex);
54416 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
54417 id : cm.getColumnId(colIndex),
54418 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
54420 var renderer = cm.getRenderer(colIndex);
54421 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
54422 if(typeof val == "undefined" || val === "") val = " ";
54423 cellText.innerHTML = val;
54424 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
54425 this.syncRowHeights(rowIndex, rowIndex);
54428 calcColumnWidth : function(colIndex, maxRowsToMeasure){
54430 if(this.grid.autoSizeHeaders){
54431 var h = this.getHeaderCellMeasure(colIndex);
54432 maxWidth = Math.max(maxWidth, h.scrollWidth);
54435 if(this.cm.isLocked(colIndex)){
54436 tb = this.getLockedTable();
54439 tb = this.getBodyTable();
54440 index = colIndex - this.cm.getLockedCount();
54443 var rows = tb.rows;
54444 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
54445 for(var i = 0; i < stopIndex; i++){
54446 var cell = rows[i].childNodes[index].firstChild;
54447 maxWidth = Math.max(maxWidth, cell.scrollWidth);
54450 return maxWidth + /*margin for error in IE*/ 5;
54453 * Autofit a column to its content.
54454 * @param {Number} colIndex
54455 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
54457 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
54458 if(this.cm.isHidden(colIndex)){
54459 return; // can't calc a hidden column
54462 var cid = this.cm.getColumnId(colIndex);
54463 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
54464 if(this.grid.autoSizeHeaders){
54465 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
54468 var newWidth = this.calcColumnWidth(colIndex);
54469 this.cm.setColumnWidth(colIndex,
54470 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
54471 if(!suppressEvent){
54472 this.grid.fireEvent("columnresize", colIndex, newWidth);
54477 * Autofits all columns to their content and then expands to fit any extra space in the grid
54479 autoSizeColumns : function(){
54480 var cm = this.grid.colModel;
54481 var colCount = cm.getColumnCount();
54482 for(var i = 0; i < colCount; i++){
54483 this.autoSizeColumn(i, true, true);
54485 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
54488 this.updateColumns();
54494 * Autofits all columns to the grid's width proportionate with their current size
54495 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
54497 fitColumns : function(reserveScrollSpace){
54498 var cm = this.grid.colModel;
54499 var colCount = cm.getColumnCount();
54503 for (i = 0; i < colCount; i++){
54504 if(!cm.isHidden(i) && !cm.isFixed(i)){
54505 w = cm.getColumnWidth(i);
54511 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
54512 if(reserveScrollSpace){
54515 var frac = (avail - cm.getTotalWidth())/width;
54516 while (cols.length){
54519 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
54521 this.updateColumns();
54525 onRowSelect : function(rowIndex){
54526 var row = this.getRowComposite(rowIndex);
54527 row.addClass("x-grid-row-selected");
54530 onRowDeselect : function(rowIndex){
54531 var row = this.getRowComposite(rowIndex);
54532 row.removeClass("x-grid-row-selected");
54535 onCellSelect : function(row, col){
54536 var cell = this.getCell(row, col);
54538 Roo.fly(cell).addClass("x-grid-cell-selected");
54542 onCellDeselect : function(row, col){
54543 var cell = this.getCell(row, col);
54545 Roo.fly(cell).removeClass("x-grid-cell-selected");
54549 updateHeaderSortState : function(){
54551 // sort state can be single { field: xxx, direction : yyy}
54552 // or { xxx=>ASC , yyy : DESC ..... }
54555 if (!this.ds.multiSort) {
54556 var state = this.ds.getSortState();
54560 mstate[state.field] = state.direction;
54561 // FIXME... - this is not used here.. but might be elsewhere..
54562 this.sortState = state;
54565 mstate = this.ds.sortToggle;
54567 //remove existing sort classes..
54569 var sc = this.sortClasses;
54570 var hds = this.el.select(this.headerSelector).removeClass(sc);
54572 for(var f in mstate) {
54574 var sortColumn = this.cm.findColumnIndex(f);
54576 if(sortColumn != -1){
54577 var sortDir = mstate[f];
54578 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
54587 handleHeaderClick : function(g, index,e){
54589 Roo.log("header click");
54592 // touch events on header are handled by context
54593 this.handleHdCtx(g,index,e);
54598 if(this.headersDisabled){
54601 var dm = g.dataSource, cm = g.colModel;
54602 if(!cm.isSortable(index)){
54607 if (dm.multiSort) {
54608 // update the sortOrder
54610 for(var i = 0; i < cm.config.length; i++ ) {
54612 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
54613 continue; // dont' bother, it's not in sort list or being set.
54616 so.push(cm.config[i].dataIndex);
54622 dm.sort(cm.getDataIndex(index));
54626 destroy : function(){
54628 this.colMenu.removeAll();
54629 Roo.menu.MenuMgr.unregister(this.colMenu);
54630 this.colMenu.getEl().remove();
54631 delete this.colMenu;
54634 this.hmenu.removeAll();
54635 Roo.menu.MenuMgr.unregister(this.hmenu);
54636 this.hmenu.getEl().remove();
54639 if(this.grid.enableColumnMove){
54640 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54642 for(var dd in dds){
54643 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54644 var elid = dds[dd].dragElId;
54646 Roo.get(elid).remove();
54647 } else if(dds[dd].config.isTarget){
54648 dds[dd].proxyTop.remove();
54649 dds[dd].proxyBottom.remove();
54652 if(Roo.dd.DDM.locationCache[dd]){
54653 delete Roo.dd.DDM.locationCache[dd];
54656 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54659 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54660 this.bind(null, null);
54661 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54664 handleLockChange : function(){
54665 this.refresh(true);
54668 onDenyColumnLock : function(){
54672 onDenyColumnHide : function(){
54676 handleHdMenuClick : function(item){
54677 var index = this.hdCtxIndex;
54678 var cm = this.cm, ds = this.ds;
54681 ds.sort(cm.getDataIndex(index), "ASC");
54684 ds.sort(cm.getDataIndex(index), "DESC");
54687 var lc = cm.getLockedCount();
54688 if(cm.getColumnCount(true) <= lc+1){
54689 this.onDenyColumnLock();
54693 cm.setLocked(index, true, true);
54694 cm.moveColumn(index, lc);
54695 this.grid.fireEvent("columnmove", index, lc);
54697 cm.setLocked(index, true);
54701 var lc = cm.getLockedCount();
54702 if((lc-1) != index){
54703 cm.setLocked(index, false, true);
54704 cm.moveColumn(index, lc-1);
54705 this.grid.fireEvent("columnmove", index, lc-1);
54707 cm.setLocked(index, false);
54710 case 'wider': // used to expand cols on touch..
54712 var cw = cm.getColumnWidth(index);
54713 cw += (item.id == 'wider' ? 1 : -1) * 50;
54714 cw = Math.max(0, cw);
54715 cw = Math.min(cw,4000);
54716 cm.setColumnWidth(index, cw);
54720 index = cm.getIndexById(item.id.substr(4));
54722 if(item.checked && cm.getColumnCount(true) <= 1){
54723 this.onDenyColumnHide();
54726 cm.setHidden(index, item.checked);
54732 beforeColMenuShow : function(){
54733 var cm = this.cm, colCount = cm.getColumnCount();
54734 this.colMenu.removeAll();
54735 for(var i = 0; i < colCount; i++){
54736 this.colMenu.add(new Roo.menu.CheckItem({
54737 id: "col-"+cm.getColumnId(i),
54738 text: cm.getColumnHeader(i),
54739 checked: !cm.isHidden(i),
54745 handleHdCtx : function(g, index, e){
54747 var hd = this.getHeaderCell(index);
54748 this.hdCtxIndex = index;
54749 var ms = this.hmenu.items, cm = this.cm;
54750 ms.get("asc").setDisabled(!cm.isSortable(index));
54751 ms.get("desc").setDisabled(!cm.isSortable(index));
54752 if(this.grid.enableColLock !== false){
54753 ms.get("lock").setDisabled(cm.isLocked(index));
54754 ms.get("unlock").setDisabled(!cm.isLocked(index));
54756 this.hmenu.show(hd, "tl-bl");
54759 handleHdOver : function(e){
54760 var hd = this.findHeaderCell(e.getTarget());
54761 if(hd && !this.headersDisabled){
54762 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54763 this.fly(hd).addClass("x-grid-hd-over");
54768 handleHdOut : function(e){
54769 var hd = this.findHeaderCell(e.getTarget());
54771 this.fly(hd).removeClass("x-grid-hd-over");
54775 handleSplitDblClick : function(e, t){
54776 var i = this.getCellIndex(t);
54777 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54778 this.autoSizeColumn(i, true);
54783 render : function(){
54786 var colCount = cm.getColumnCount();
54788 if(this.grid.monitorWindowResize === true){
54789 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54791 var header = this.renderHeaders();
54792 var body = this.templates.body.apply({rows:""});
54793 var html = this.templates.master.apply({
54796 lockedHeader: header[0],
54800 //this.updateColumns();
54802 this.grid.getGridEl().dom.innerHTML = html;
54804 this.initElements();
54806 // a kludge to fix the random scolling effect in webkit
54807 this.el.on("scroll", function() {
54808 this.el.dom.scrollTop=0; // hopefully not recursive..
54811 this.scroller.on("scroll", this.handleScroll, this);
54812 this.lockedBody.on("mousewheel", this.handleWheel, this);
54813 this.mainBody.on("mousewheel", this.handleWheel, this);
54815 this.mainHd.on("mouseover", this.handleHdOver, this);
54816 this.mainHd.on("mouseout", this.handleHdOut, this);
54817 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54818 {delegate: "."+this.splitClass});
54820 this.lockedHd.on("mouseover", this.handleHdOver, this);
54821 this.lockedHd.on("mouseout", this.handleHdOut, this);
54822 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54823 {delegate: "."+this.splitClass});
54825 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54826 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54829 this.updateSplitters();
54831 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54832 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54833 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54836 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54837 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54839 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54840 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54842 if(this.grid.enableColLock !== false){
54843 this.hmenu.add('-',
54844 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54845 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54849 this.hmenu.add('-',
54850 {id:"wider", text: this.columnsWiderText},
54851 {id:"narrow", text: this.columnsNarrowText }
54857 if(this.grid.enableColumnHide !== false){
54859 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54860 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54861 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54863 this.hmenu.add('-',
54864 {id:"columns", text: this.columnsText, menu: this.colMenu}
54867 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54869 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54872 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54873 this.dd = new Roo.grid.GridDragZone(this.grid, {
54874 ddGroup : this.grid.ddGroup || 'GridDD'
54880 for(var i = 0; i < colCount; i++){
54881 if(cm.isHidden(i)){
54882 this.hideColumn(i);
54884 if(cm.config[i].align){
54885 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54886 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54890 this.updateHeaderSortState();
54892 this.beforeInitialResize();
54895 // two part rendering gives faster view to the user
54896 this.renderPhase2.defer(1, this);
54899 renderPhase2 : function(){
54900 // render the rows now
54902 if(this.grid.autoSizeColumns){
54903 this.autoSizeColumns();
54907 beforeInitialResize : function(){
54911 onColumnSplitterMoved : function(i, w){
54912 this.userResized = true;
54913 var cm = this.grid.colModel;
54914 cm.setColumnWidth(i, w, true);
54915 var cid = cm.getColumnId(i);
54916 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54917 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54918 this.updateSplitters();
54920 this.grid.fireEvent("columnresize", i, w);
54923 syncRowHeights : function(startIndex, endIndex){
54924 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54925 startIndex = startIndex || 0;
54926 var mrows = this.getBodyTable().rows;
54927 var lrows = this.getLockedTable().rows;
54928 var len = mrows.length-1;
54929 endIndex = Math.min(endIndex || len, len);
54930 for(var i = startIndex; i <= endIndex; i++){
54931 var m = mrows[i], l = lrows[i];
54932 var h = Math.max(m.offsetHeight, l.offsetHeight);
54933 m.style.height = l.style.height = h + "px";
54938 layout : function(initialRender, is2ndPass){
54940 var auto = g.autoHeight;
54941 var scrollOffset = 16;
54942 var c = g.getGridEl(), cm = this.cm,
54943 expandCol = g.autoExpandColumn,
54945 //c.beginMeasure();
54947 if(!c.dom.offsetWidth){ // display:none?
54949 this.lockedWrap.show();
54950 this.mainWrap.show();
54955 var hasLock = this.cm.isLocked(0);
54957 var tbh = this.headerPanel.getHeight();
54958 var bbh = this.footerPanel.getHeight();
54961 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54962 var newHeight = ch + c.getBorderWidth("tb");
54964 newHeight = Math.min(g.maxHeight, newHeight);
54966 c.setHeight(newHeight);
54970 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54973 var s = this.scroller;
54975 var csize = c.getSize(true);
54977 this.el.setSize(csize.width, csize.height);
54979 this.headerPanel.setWidth(csize.width);
54980 this.footerPanel.setWidth(csize.width);
54982 var hdHeight = this.mainHd.getHeight();
54983 var vw = csize.width;
54984 var vh = csize.height - (tbh + bbh);
54988 var bt = this.getBodyTable();
54989 var ltWidth = hasLock ?
54990 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54992 var scrollHeight = bt.offsetHeight;
54993 var scrollWidth = ltWidth + bt.offsetWidth;
54994 var vscroll = false, hscroll = false;
54996 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54998 var lw = this.lockedWrap, mw = this.mainWrap;
54999 var lb = this.lockedBody, mb = this.mainBody;
55001 setTimeout(function(){
55002 var t = s.dom.offsetTop;
55003 var w = s.dom.clientWidth,
55004 h = s.dom.clientHeight;
55007 lw.setSize(ltWidth, h);
55009 mw.setLeftTop(ltWidth, t);
55010 mw.setSize(w-ltWidth, h);
55012 lb.setHeight(h-hdHeight);
55013 mb.setHeight(h-hdHeight);
55015 if(is2ndPass !== true && !gv.userResized && expandCol){
55016 // high speed resize without full column calculation
55018 var ci = cm.getIndexById(expandCol);
55020 ci = cm.findColumnIndex(expandCol);
55022 ci = Math.max(0, ci); // make sure it's got at least the first col.
55023 var expandId = cm.getColumnId(ci);
55024 var tw = cm.getTotalWidth(false);
55025 var currentWidth = cm.getColumnWidth(ci);
55026 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
55027 if(currentWidth != cw){
55028 cm.setColumnWidth(ci, cw, true);
55029 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
55030 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
55031 gv.updateSplitters();
55032 gv.layout(false, true);
55044 onWindowResize : function(){
55045 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
55051 appendFooter : function(parentEl){
55055 sortAscText : "Sort Ascending",
55056 sortDescText : "Sort Descending",
55057 lockText : "Lock Column",
55058 unlockText : "Unlock Column",
55059 columnsText : "Columns",
55061 columnsWiderText : "Wider",
55062 columnsNarrowText : "Thinner"
55066 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
55067 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
55068 this.proxy.el.addClass('x-grid3-col-dd');
55071 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
55072 handleMouseDown : function(e){
55076 callHandleMouseDown : function(e){
55077 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
55082 * Ext JS Library 1.1.1
55083 * Copyright(c) 2006-2007, Ext JS, LLC.
55085 * Originally Released Under LGPL - original licence link has changed is not relivant.
55088 * <script type="text/javascript">
55092 // This is a support class used internally by the Grid components
55093 Roo.grid.SplitDragZone = function(grid, hd, hd2){
55095 this.view = grid.getView();
55096 this.proxy = this.view.resizeProxy;
55097 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
55098 "gridSplitters" + this.grid.getGridEl().id, {
55099 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
55101 this.setHandleElId(Roo.id(hd));
55102 this.setOuterHandleElId(Roo.id(hd2));
55103 this.scroll = false;
55105 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
55106 fly: Roo.Element.fly,
55108 b4StartDrag : function(x, y){
55109 this.view.headersDisabled = true;
55110 this.proxy.setHeight(this.view.mainWrap.getHeight());
55111 var w = this.cm.getColumnWidth(this.cellIndex);
55112 var minw = Math.max(w-this.grid.minColumnWidth, 0);
55113 this.resetConstraints();
55114 this.setXConstraint(minw, 1000);
55115 this.setYConstraint(0, 0);
55116 this.minX = x - minw;
55117 this.maxX = x + 1000;
55119 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
55123 handleMouseDown : function(e){
55124 ev = Roo.EventObject.setEvent(e);
55125 var t = this.fly(ev.getTarget());
55126 if(t.hasClass("x-grid-split")){
55127 this.cellIndex = this.view.getCellIndex(t.dom);
55128 this.split = t.dom;
55129 this.cm = this.grid.colModel;
55130 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
55131 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
55136 endDrag : function(e){
55137 this.view.headersDisabled = false;
55138 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
55139 var diff = endX - this.startPos;
55140 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
55143 autoOffset : function(){
55144 this.setDelta(0,0);
55148 * Ext JS Library 1.1.1
55149 * Copyright(c) 2006-2007, Ext JS, LLC.
55151 * Originally Released Under LGPL - original licence link has changed is not relivant.
55154 * <script type="text/javascript">
55158 // This is a support class used internally by the Grid components
55159 Roo.grid.GridDragZone = function(grid, config){
55160 this.view = grid.getView();
55161 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
55162 if(this.view.lockedBody){
55163 this.setHandleElId(Roo.id(this.view.mainBody.dom));
55164 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
55166 this.scroll = false;
55168 this.ddel = document.createElement('div');
55169 this.ddel.className = 'x-grid-dd-wrap';
55172 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
55173 ddGroup : "GridDD",
55175 getDragData : function(e){
55176 var t = Roo.lib.Event.getTarget(e);
55177 var rowIndex = this.view.findRowIndex(t);
55178 var sm = this.grid.selModel;
55180 //Roo.log(rowIndex);
55182 if (sm.getSelectedCell) {
55183 // cell selection..
55184 if (!sm.getSelectedCell()) {
55187 if (rowIndex != sm.getSelectedCell()[0]) {
55193 if(rowIndex !== false){
55198 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
55200 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
55203 if (e.hasModifier()){
55204 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
55207 Roo.log("getDragData");
55212 rowIndex: rowIndex,
55213 selections:sm.getSelections ? sm.getSelections() : (
55214 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
55221 onInitDrag : function(e){
55222 var data = this.dragData;
55223 this.ddel.innerHTML = this.grid.getDragDropText();
55224 this.proxy.update(this.ddel);
55225 // fire start drag?
55228 afterRepair : function(){
55229 this.dragging = false;
55232 getRepairXY : function(e, data){
55236 onEndDrag : function(data, e){
55240 onValidDrop : function(dd, e, id){
55245 beforeInvalidDrop : function(e, id){
55250 * Ext JS Library 1.1.1
55251 * Copyright(c) 2006-2007, Ext JS, LLC.
55253 * Originally Released Under LGPL - original licence link has changed is not relivant.
55256 * <script type="text/javascript">
55261 * @class Roo.grid.ColumnModel
55262 * @extends Roo.util.Observable
55263 * This is the default implementation of a ColumnModel used by the Grid. It defines
55264 * the columns in the grid.
55267 var colModel = new Roo.grid.ColumnModel([
55268 {header: "Ticker", width: 60, sortable: true, locked: true},
55269 {header: "Company Name", width: 150, sortable: true},
55270 {header: "Market Cap.", width: 100, sortable: true},
55271 {header: "$ Sales", width: 100, sortable: true, renderer: money},
55272 {header: "Employees", width: 100, sortable: true, resizable: false}
55277 * The config options listed for this class are options which may appear in each
55278 * individual column definition.
55279 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
55281 * @param {Object} config An Array of column config objects. See this class's
55282 * config objects for details.
55284 Roo.grid.ColumnModel = function(config){
55286 * The config passed into the constructor
55288 this.config = config;
55291 // if no id, create one
55292 // if the column does not have a dataIndex mapping,
55293 // map it to the order it is in the config
55294 for(var i = 0, len = config.length; i < len; i++){
55296 if(typeof c.dataIndex == "undefined"){
55299 if(typeof c.renderer == "string"){
55300 c.renderer = Roo.util.Format[c.renderer];
55302 if(typeof c.id == "undefined"){
55305 if(c.editor && c.editor.xtype){
55306 c.editor = Roo.factory(c.editor, Roo.grid);
55308 if(c.editor && c.editor.isFormField){
55309 c.editor = new Roo.grid.GridEditor(c.editor);
55311 this.lookup[c.id] = c;
55315 * The width of columns which have no width specified (defaults to 100)
55318 this.defaultWidth = 100;
55321 * Default sortable of columns which have no sortable specified (defaults to false)
55324 this.defaultSortable = false;
55328 * @event widthchange
55329 * Fires when the width of a column changes.
55330 * @param {ColumnModel} this
55331 * @param {Number} columnIndex The column index
55332 * @param {Number} newWidth The new width
55334 "widthchange": true,
55336 * @event headerchange
55337 * Fires when the text of a header changes.
55338 * @param {ColumnModel} this
55339 * @param {Number} columnIndex The column index
55340 * @param {Number} newText The new header text
55342 "headerchange": true,
55344 * @event hiddenchange
55345 * Fires when a column is hidden or "unhidden".
55346 * @param {ColumnModel} this
55347 * @param {Number} columnIndex The column index
55348 * @param {Boolean} hidden true if hidden, false otherwise
55350 "hiddenchange": true,
55352 * @event columnmoved
55353 * Fires when a column is moved.
55354 * @param {ColumnModel} this
55355 * @param {Number} oldIndex
55356 * @param {Number} newIndex
55358 "columnmoved" : true,
55360 * @event columlockchange
55361 * Fires when a column's locked state is changed
55362 * @param {ColumnModel} this
55363 * @param {Number} colIndex
55364 * @param {Boolean} locked true if locked
55366 "columnlockchange" : true
55368 Roo.grid.ColumnModel.superclass.constructor.call(this);
55370 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
55372 * @cfg {String} header The header text to display in the Grid view.
55375 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
55376 * {@link Roo.data.Record} definition from which to draw the column's value. If not
55377 * specified, the column's index is used as an index into the Record's data Array.
55380 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
55381 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
55384 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
55385 * Defaults to the value of the {@link #defaultSortable} property.
55386 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
55389 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
55392 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
55395 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
55398 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
55401 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
55402 * given the cell's data value. See {@link #setRenderer}. If not specified, the
55403 * default renderer uses the raw data value. If an object is returned (bootstrap only)
55404 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
55407 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
55410 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
55413 * @cfg {String} cursor (Optional)
55416 * @cfg {String} tooltip (Optional)
55419 * @cfg {Number} xs (Optional)
55422 * @cfg {Number} sm (Optional)
55425 * @cfg {Number} md (Optional)
55428 * @cfg {Number} lg (Optional)
55431 * Returns the id of the column at the specified index.
55432 * @param {Number} index The column index
55433 * @return {String} the id
55435 getColumnId : function(index){
55436 return this.config[index].id;
55440 * Returns the column for a specified id.
55441 * @param {String} id The column id
55442 * @return {Object} the column
55444 getColumnById : function(id){
55445 return this.lookup[id];
55450 * Returns the column for a specified dataIndex.
55451 * @param {String} dataIndex The column dataIndex
55452 * @return {Object|Boolean} the column or false if not found
55454 getColumnByDataIndex: function(dataIndex){
55455 var index = this.findColumnIndex(dataIndex);
55456 return index > -1 ? this.config[index] : false;
55460 * Returns the index for a specified column id.
55461 * @param {String} id The column id
55462 * @return {Number} the index, or -1 if not found
55464 getIndexById : function(id){
55465 for(var i = 0, len = this.config.length; i < len; i++){
55466 if(this.config[i].id == id){
55474 * Returns the index for a specified column dataIndex.
55475 * @param {String} dataIndex The column dataIndex
55476 * @return {Number} the index, or -1 if not found
55479 findColumnIndex : function(dataIndex){
55480 for(var i = 0, len = this.config.length; i < len; i++){
55481 if(this.config[i].dataIndex == dataIndex){
55489 moveColumn : function(oldIndex, newIndex){
55490 var c = this.config[oldIndex];
55491 this.config.splice(oldIndex, 1);
55492 this.config.splice(newIndex, 0, c);
55493 this.dataMap = null;
55494 this.fireEvent("columnmoved", this, oldIndex, newIndex);
55497 isLocked : function(colIndex){
55498 return this.config[colIndex].locked === true;
55501 setLocked : function(colIndex, value, suppressEvent){
55502 if(this.isLocked(colIndex) == value){
55505 this.config[colIndex].locked = value;
55506 if(!suppressEvent){
55507 this.fireEvent("columnlockchange", this, colIndex, value);
55511 getTotalLockedWidth : function(){
55512 var totalWidth = 0;
55513 for(var i = 0; i < this.config.length; i++){
55514 if(this.isLocked(i) && !this.isHidden(i)){
55515 this.totalWidth += this.getColumnWidth(i);
55521 getLockedCount : function(){
55522 for(var i = 0, len = this.config.length; i < len; i++){
55523 if(!this.isLocked(i)){
55530 * Returns the number of columns.
55533 getColumnCount : function(visibleOnly){
55534 if(visibleOnly === true){
55536 for(var i = 0, len = this.config.length; i < len; i++){
55537 if(!this.isHidden(i)){
55543 return this.config.length;
55547 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
55548 * @param {Function} fn
55549 * @param {Object} scope (optional)
55550 * @return {Array} result
55552 getColumnsBy : function(fn, scope){
55554 for(var i = 0, len = this.config.length; i < len; i++){
55555 var c = this.config[i];
55556 if(fn.call(scope||this, c, i) === true){
55564 * Returns true if the specified column is sortable.
55565 * @param {Number} col The column index
55566 * @return {Boolean}
55568 isSortable : function(col){
55569 if(typeof this.config[col].sortable == "undefined"){
55570 return this.defaultSortable;
55572 return this.config[col].sortable;
55576 * Returns the rendering (formatting) function defined for the column.
55577 * @param {Number} col The column index.
55578 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
55580 getRenderer : function(col){
55581 if(!this.config[col].renderer){
55582 return Roo.grid.ColumnModel.defaultRenderer;
55584 return this.config[col].renderer;
55588 * Sets the rendering (formatting) function for a column.
55589 * @param {Number} col The column index
55590 * @param {Function} fn The function to use to process the cell's raw data
55591 * to return HTML markup for the grid view. The render function is called with
55592 * the following parameters:<ul>
55593 * <li>Data value.</li>
55594 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
55595 * <li>css A CSS style string to apply to the table cell.</li>
55596 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
55597 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
55598 * <li>Row index</li>
55599 * <li>Column index</li>
55600 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
55602 setRenderer : function(col, fn){
55603 this.config[col].renderer = fn;
55607 * Returns the width for the specified column.
55608 * @param {Number} col The column index
55611 getColumnWidth : function(col){
55612 return this.config[col].width * 1 || this.defaultWidth;
55616 * Sets the width for a column.
55617 * @param {Number} col The column index
55618 * @param {Number} width The new width
55620 setColumnWidth : function(col, width, suppressEvent){
55621 this.config[col].width = width;
55622 this.totalWidth = null;
55623 if(!suppressEvent){
55624 this.fireEvent("widthchange", this, col, width);
55629 * Returns the total width of all columns.
55630 * @param {Boolean} includeHidden True to include hidden column widths
55633 getTotalWidth : function(includeHidden){
55634 if(!this.totalWidth){
55635 this.totalWidth = 0;
55636 for(var i = 0, len = this.config.length; i < len; i++){
55637 if(includeHidden || !this.isHidden(i)){
55638 this.totalWidth += this.getColumnWidth(i);
55642 return this.totalWidth;
55646 * Returns the header for the specified column.
55647 * @param {Number} col The column index
55650 getColumnHeader : function(col){
55651 return this.config[col].header;
55655 * Sets the header for a column.
55656 * @param {Number} col The column index
55657 * @param {String} header The new header
55659 setColumnHeader : function(col, header){
55660 this.config[col].header = header;
55661 this.fireEvent("headerchange", this, col, header);
55665 * Returns the tooltip for the specified column.
55666 * @param {Number} col The column index
55669 getColumnTooltip : function(col){
55670 return this.config[col].tooltip;
55673 * Sets the tooltip for a column.
55674 * @param {Number} col The column index
55675 * @param {String} tooltip The new tooltip
55677 setColumnTooltip : function(col, tooltip){
55678 this.config[col].tooltip = tooltip;
55682 * Returns the dataIndex for the specified column.
55683 * @param {Number} col The column index
55686 getDataIndex : function(col){
55687 return this.config[col].dataIndex;
55691 * Sets the dataIndex for a column.
55692 * @param {Number} col The column index
55693 * @param {Number} dataIndex The new dataIndex
55695 setDataIndex : function(col, dataIndex){
55696 this.config[col].dataIndex = dataIndex;
55702 * Returns true if the cell is editable.
55703 * @param {Number} colIndex The column index
55704 * @param {Number} rowIndex The row index
55705 * @return {Boolean}
55707 isCellEditable : function(colIndex, rowIndex){
55708 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55712 * Returns the editor defined for the cell/column.
55713 * return false or null to disable editing.
55714 * @param {Number} colIndex The column index
55715 * @param {Number} rowIndex The row index
55718 getCellEditor : function(colIndex, rowIndex){
55719 return this.config[colIndex].editor;
55723 * Sets if a column is editable.
55724 * @param {Number} col The column index
55725 * @param {Boolean} editable True if the column is editable
55727 setEditable : function(col, editable){
55728 this.config[col].editable = editable;
55733 * Returns true if the column is hidden.
55734 * @param {Number} colIndex The column index
55735 * @return {Boolean}
55737 isHidden : function(colIndex){
55738 return this.config[colIndex].hidden;
55743 * Returns true if the column width cannot be changed
55745 isFixed : function(colIndex){
55746 return this.config[colIndex].fixed;
55750 * Returns true if the column can be resized
55751 * @return {Boolean}
55753 isResizable : function(colIndex){
55754 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55757 * Sets if a column is hidden.
55758 * @param {Number} colIndex The column index
55759 * @param {Boolean} hidden True if the column is hidden
55761 setHidden : function(colIndex, hidden){
55762 this.config[colIndex].hidden = hidden;
55763 this.totalWidth = null;
55764 this.fireEvent("hiddenchange", this, colIndex, hidden);
55768 * Sets the editor for a column.
55769 * @param {Number} col The column index
55770 * @param {Object} editor The editor object
55772 setEditor : function(col, editor){
55773 this.config[col].editor = editor;
55777 Roo.grid.ColumnModel.defaultRenderer = function(value){
55778 if(typeof value == "string" && value.length < 1){
55784 // Alias for backwards compatibility
55785 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55788 * Ext JS Library 1.1.1
55789 * Copyright(c) 2006-2007, Ext JS, LLC.
55791 * Originally Released Under LGPL - original licence link has changed is not relivant.
55794 * <script type="text/javascript">
55798 * @class Roo.grid.AbstractSelectionModel
55799 * @extends Roo.util.Observable
55800 * Abstract base class for grid SelectionModels. It provides the interface that should be
55801 * implemented by descendant classes. This class should not be directly instantiated.
55804 Roo.grid.AbstractSelectionModel = function(){
55805 this.locked = false;
55806 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55809 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55810 /** @ignore Called by the grid automatically. Do not call directly. */
55811 init : function(grid){
55817 * Locks the selections.
55820 this.locked = true;
55824 * Unlocks the selections.
55826 unlock : function(){
55827 this.locked = false;
55831 * Returns true if the selections are locked.
55832 * @return {Boolean}
55834 isLocked : function(){
55835 return this.locked;
55839 * Ext JS Library 1.1.1
55840 * Copyright(c) 2006-2007, Ext JS, LLC.
55842 * Originally Released Under LGPL - original licence link has changed is not relivant.
55845 * <script type="text/javascript">
55848 * @extends Roo.grid.AbstractSelectionModel
55849 * @class Roo.grid.RowSelectionModel
55850 * The default SelectionModel used by {@link Roo.grid.Grid}.
55851 * It supports multiple selections and keyboard selection/navigation.
55853 * @param {Object} config
55855 Roo.grid.RowSelectionModel = function(config){
55856 Roo.apply(this, config);
55857 this.selections = new Roo.util.MixedCollection(false, function(o){
55862 this.lastActive = false;
55866 * @event selectionchange
55867 * Fires when the selection changes
55868 * @param {SelectionModel} this
55870 "selectionchange" : true,
55872 * @event afterselectionchange
55873 * Fires after the selection changes (eg. by key press or clicking)
55874 * @param {SelectionModel} this
55876 "afterselectionchange" : true,
55878 * @event beforerowselect
55879 * Fires when a row is selected being selected, return false to cancel.
55880 * @param {SelectionModel} this
55881 * @param {Number} rowIndex The selected index
55882 * @param {Boolean} keepExisting False if other selections will be cleared
55884 "beforerowselect" : true,
55887 * Fires when a row is selected.
55888 * @param {SelectionModel} this
55889 * @param {Number} rowIndex The selected index
55890 * @param {Roo.data.Record} r The record
55892 "rowselect" : true,
55894 * @event rowdeselect
55895 * Fires when a row is deselected.
55896 * @param {SelectionModel} this
55897 * @param {Number} rowIndex The selected index
55899 "rowdeselect" : true
55901 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55902 this.locked = false;
55905 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55907 * @cfg {Boolean} singleSelect
55908 * True to allow selection of only one row at a time (defaults to false)
55910 singleSelect : false,
55913 initEvents : function(){
55915 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55916 this.grid.on("mousedown", this.handleMouseDown, this);
55917 }else{ // allow click to work like normal
55918 this.grid.on("rowclick", this.handleDragableRowClick, this);
55921 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55922 "up" : function(e){
55924 this.selectPrevious(e.shiftKey);
55925 }else if(this.last !== false && this.lastActive !== false){
55926 var last = this.last;
55927 this.selectRange(this.last, this.lastActive-1);
55928 this.grid.getView().focusRow(this.lastActive);
55929 if(last !== false){
55933 this.selectFirstRow();
55935 this.fireEvent("afterselectionchange", this);
55937 "down" : function(e){
55939 this.selectNext(e.shiftKey);
55940 }else if(this.last !== false && this.lastActive !== false){
55941 var last = this.last;
55942 this.selectRange(this.last, this.lastActive+1);
55943 this.grid.getView().focusRow(this.lastActive);
55944 if(last !== false){
55948 this.selectFirstRow();
55950 this.fireEvent("afterselectionchange", this);
55955 var view = this.grid.view;
55956 view.on("refresh", this.onRefresh, this);
55957 view.on("rowupdated", this.onRowUpdated, this);
55958 view.on("rowremoved", this.onRemove, this);
55962 onRefresh : function(){
55963 var ds = this.grid.dataSource, i, v = this.grid.view;
55964 var s = this.selections;
55965 s.each(function(r){
55966 if((i = ds.indexOfId(r.id)) != -1){
55968 s.add(ds.getAt(i)); // updating the selection relate data
55976 onRemove : function(v, index, r){
55977 this.selections.remove(r);
55981 onRowUpdated : function(v, index, r){
55982 if(this.isSelected(r)){
55983 v.onRowSelect(index);
55989 * @param {Array} records The records to select
55990 * @param {Boolean} keepExisting (optional) True to keep existing selections
55992 selectRecords : function(records, keepExisting){
55994 this.clearSelections();
55996 var ds = this.grid.dataSource;
55997 for(var i = 0, len = records.length; i < len; i++){
55998 this.selectRow(ds.indexOf(records[i]), true);
56003 * Gets the number of selected rows.
56006 getCount : function(){
56007 return this.selections.length;
56011 * Selects the first row in the grid.
56013 selectFirstRow : function(){
56018 * Select the last row.
56019 * @param {Boolean} keepExisting (optional) True to keep existing selections
56021 selectLastRow : function(keepExisting){
56022 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
56026 * Selects the row immediately following the last selected row.
56027 * @param {Boolean} keepExisting (optional) True to keep existing selections
56029 selectNext : function(keepExisting){
56030 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
56031 this.selectRow(this.last+1, keepExisting);
56032 this.grid.getView().focusRow(this.last);
56037 * Selects the row that precedes the last selected row.
56038 * @param {Boolean} keepExisting (optional) True to keep existing selections
56040 selectPrevious : function(keepExisting){
56042 this.selectRow(this.last-1, keepExisting);
56043 this.grid.getView().focusRow(this.last);
56048 * Returns the selected records
56049 * @return {Array} Array of selected records
56051 getSelections : function(){
56052 return [].concat(this.selections.items);
56056 * Returns the first selected record.
56059 getSelected : function(){
56060 return this.selections.itemAt(0);
56065 * Clears all selections.
56067 clearSelections : function(fast){
56068 if(this.locked) return;
56070 var ds = this.grid.dataSource;
56071 var s = this.selections;
56072 s.each(function(r){
56073 this.deselectRow(ds.indexOfId(r.id));
56077 this.selections.clear();
56084 * Selects all rows.
56086 selectAll : function(){
56087 if(this.locked) return;
56088 this.selections.clear();
56089 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
56090 this.selectRow(i, true);
56095 * Returns True if there is a selection.
56096 * @return {Boolean}
56098 hasSelection : function(){
56099 return this.selections.length > 0;
56103 * Returns True if the specified row is selected.
56104 * @param {Number/Record} record The record or index of the record to check
56105 * @return {Boolean}
56107 isSelected : function(index){
56108 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
56109 return (r && this.selections.key(r.id) ? true : false);
56113 * Returns True if the specified record id is selected.
56114 * @param {String} id The id of record to check
56115 * @return {Boolean}
56117 isIdSelected : function(id){
56118 return (this.selections.key(id) ? true : false);
56122 handleMouseDown : function(e, t){
56123 var view = this.grid.getView(), rowIndex;
56124 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
56127 if(e.shiftKey && this.last !== false){
56128 var last = this.last;
56129 this.selectRange(last, rowIndex, e.ctrlKey);
56130 this.last = last; // reset the last
56131 view.focusRow(rowIndex);
56133 var isSelected = this.isSelected(rowIndex);
56134 if(e.button !== 0 && isSelected){
56135 view.focusRow(rowIndex);
56136 }else if(e.ctrlKey && isSelected){
56137 this.deselectRow(rowIndex);
56138 }else if(!isSelected){
56139 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
56140 view.focusRow(rowIndex);
56143 this.fireEvent("afterselectionchange", this);
56146 handleDragableRowClick : function(grid, rowIndex, e)
56148 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
56149 this.selectRow(rowIndex, false);
56150 grid.view.focusRow(rowIndex);
56151 this.fireEvent("afterselectionchange", this);
56156 * Selects multiple rows.
56157 * @param {Array} rows Array of the indexes of the row to select
56158 * @param {Boolean} keepExisting (optional) True to keep existing selections
56160 selectRows : function(rows, keepExisting){
56162 this.clearSelections();
56164 for(var i = 0, len = rows.length; i < len; i++){
56165 this.selectRow(rows[i], true);
56170 * Selects a range of rows. All rows in between startRow and endRow are also selected.
56171 * @param {Number} startRow The index of the first row in the range
56172 * @param {Number} endRow The index of the last row in the range
56173 * @param {Boolean} keepExisting (optional) True to retain existing selections
56175 selectRange : function(startRow, endRow, keepExisting){
56176 if(this.locked) return;
56178 this.clearSelections();
56180 if(startRow <= endRow){
56181 for(var i = startRow; i <= endRow; i++){
56182 this.selectRow(i, true);
56185 for(var i = startRow; i >= endRow; i--){
56186 this.selectRow(i, true);
56192 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
56193 * @param {Number} startRow The index of the first row in the range
56194 * @param {Number} endRow The index of the last row in the range
56196 deselectRange : function(startRow, endRow, preventViewNotify){
56197 if(this.locked) return;
56198 for(var i = startRow; i <= endRow; i++){
56199 this.deselectRow(i, preventViewNotify);
56205 * @param {Number} row The index of the row to select
56206 * @param {Boolean} keepExisting (optional) True to keep existing selections
56208 selectRow : function(index, keepExisting, preventViewNotify){
56209 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
56210 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
56211 if(!keepExisting || this.singleSelect){
56212 this.clearSelections();
56214 var r = this.grid.dataSource.getAt(index);
56215 this.selections.add(r);
56216 this.last = this.lastActive = index;
56217 if(!preventViewNotify){
56218 this.grid.getView().onRowSelect(index);
56220 this.fireEvent("rowselect", this, index, r);
56221 this.fireEvent("selectionchange", this);
56227 * @param {Number} row The index of the row to deselect
56229 deselectRow : function(index, preventViewNotify){
56230 if(this.locked) return;
56231 if(this.last == index){
56234 if(this.lastActive == index){
56235 this.lastActive = false;
56237 var r = this.grid.dataSource.getAt(index);
56238 this.selections.remove(r);
56239 if(!preventViewNotify){
56240 this.grid.getView().onRowDeselect(index);
56242 this.fireEvent("rowdeselect", this, index);
56243 this.fireEvent("selectionchange", this);
56247 restoreLast : function(){
56249 this.last = this._last;
56254 acceptsNav : function(row, col, cm){
56255 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56259 onEditorKey : function(field, e){
56260 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
56265 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56267 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56269 }else if(k == e.ENTER && !e.ctrlKey){
56273 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
56275 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
56277 }else if(k == e.ESC){
56281 g.startEditing(newCell[0], newCell[1]);
56286 * Ext JS Library 1.1.1
56287 * Copyright(c) 2006-2007, Ext JS, LLC.
56289 * Originally Released Under LGPL - original licence link has changed is not relivant.
56292 * <script type="text/javascript">
56295 * @class Roo.grid.CellSelectionModel
56296 * @extends Roo.grid.AbstractSelectionModel
56297 * This class provides the basic implementation for cell selection in a grid.
56299 * @param {Object} config The object containing the configuration of this model.
56300 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
56302 Roo.grid.CellSelectionModel = function(config){
56303 Roo.apply(this, config);
56305 this.selection = null;
56309 * @event beforerowselect
56310 * Fires before a cell is selected.
56311 * @param {SelectionModel} this
56312 * @param {Number} rowIndex The selected row index
56313 * @param {Number} colIndex The selected cell index
56315 "beforecellselect" : true,
56317 * @event cellselect
56318 * Fires when a cell is selected.
56319 * @param {SelectionModel} this
56320 * @param {Number} rowIndex The selected row index
56321 * @param {Number} colIndex The selected cell index
56323 "cellselect" : true,
56325 * @event selectionchange
56326 * Fires when the active selection changes.
56327 * @param {SelectionModel} this
56328 * @param {Object} selection null for no selection or an object (o) with two properties
56330 <li>o.record: the record object for the row the selection is in</li>
56331 <li>o.cell: An array of [rowIndex, columnIndex]</li>
56334 "selectionchange" : true,
56337 * Fires when the tab (or enter) was pressed on the last editable cell
56338 * You can use this to trigger add new row.
56339 * @param {SelectionModel} this
56343 * @event beforeeditnext
56344 * Fires before the next editable sell is made active
56345 * You can use this to skip to another cell or fire the tabend
56346 * if you set cell to false
56347 * @param {Object} eventdata object : { cell : [ row, col ] }
56349 "beforeeditnext" : true
56351 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
56354 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
56356 enter_is_tab: false,
56359 initEvents : function(){
56360 this.grid.on("mousedown", this.handleMouseDown, this);
56361 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
56362 var view = this.grid.view;
56363 view.on("refresh", this.onViewChange, this);
56364 view.on("rowupdated", this.onRowUpdated, this);
56365 view.on("beforerowremoved", this.clearSelections, this);
56366 view.on("beforerowsinserted", this.clearSelections, this);
56367 if(this.grid.isEditor){
56368 this.grid.on("beforeedit", this.beforeEdit, this);
56373 beforeEdit : function(e){
56374 this.select(e.row, e.column, false, true, e.record);
56378 onRowUpdated : function(v, index, r){
56379 if(this.selection && this.selection.record == r){
56380 v.onCellSelect(index, this.selection.cell[1]);
56385 onViewChange : function(){
56386 this.clearSelections(true);
56390 * Returns the currently selected cell,.
56391 * @return {Array} The selected cell (row, column) or null if none selected.
56393 getSelectedCell : function(){
56394 return this.selection ? this.selection.cell : null;
56398 * Clears all selections.
56399 * @param {Boolean} true to prevent the gridview from being notified about the change.
56401 clearSelections : function(preventNotify){
56402 var s = this.selection;
56404 if(preventNotify !== true){
56405 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
56407 this.selection = null;
56408 this.fireEvent("selectionchange", this, null);
56413 * Returns true if there is a selection.
56414 * @return {Boolean}
56416 hasSelection : function(){
56417 return this.selection ? true : false;
56421 handleMouseDown : function(e, t){
56422 var v = this.grid.getView();
56423 if(this.isLocked()){
56426 var row = v.findRowIndex(t);
56427 var cell = v.findCellIndex(t);
56428 if(row !== false && cell !== false){
56429 this.select(row, cell);
56435 * @param {Number} rowIndex
56436 * @param {Number} collIndex
56438 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
56439 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
56440 this.clearSelections();
56441 r = r || this.grid.dataSource.getAt(rowIndex);
56444 cell : [rowIndex, colIndex]
56446 if(!preventViewNotify){
56447 var v = this.grid.getView();
56448 v.onCellSelect(rowIndex, colIndex);
56449 if(preventFocus !== true){
56450 v.focusCell(rowIndex, colIndex);
56453 this.fireEvent("cellselect", this, rowIndex, colIndex);
56454 this.fireEvent("selectionchange", this, this.selection);
56459 isSelectable : function(rowIndex, colIndex, cm){
56460 return !cm.isHidden(colIndex);
56464 handleKeyDown : function(e){
56465 //Roo.log('Cell Sel Model handleKeyDown');
56466 if(!e.isNavKeyPress()){
56469 var g = this.grid, s = this.selection;
56472 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
56474 this.select(cell[0], cell[1]);
56479 var walk = function(row, col, step){
56480 return g.walkCells(row, col, step, sm.isSelectable, sm);
56482 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
56489 // handled by onEditorKey
56490 if (g.isEditor && g.editing) {
56494 newCell = walk(r, c-1, -1);
56496 newCell = walk(r, c+1, 1);
56501 newCell = walk(r+1, c, 1);
56505 newCell = walk(r-1, c, -1);
56509 newCell = walk(r, c+1, 1);
56513 newCell = walk(r, c-1, -1);
56518 if(g.isEditor && !g.editing){
56519 g.startEditing(r, c);
56528 this.select(newCell[0], newCell[1]);
56534 acceptsNav : function(row, col, cm){
56535 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56539 * @param {Number} field (not used) - as it's normally used as a listener
56540 * @param {Number} e - event - fake it by using
56542 * var e = Roo.EventObjectImpl.prototype;
56543 * e.keyCode = e.TAB
56547 onEditorKey : function(field, e){
56549 var k = e.getKey(),
56552 ed = g.activeEditor,
56554 ///Roo.log('onEditorKey' + k);
56557 if (this.enter_is_tab && k == e.ENTER) {
56563 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56565 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56571 } else if(k == e.ENTER && !e.ctrlKey){
56574 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56576 } else if(k == e.ESC){
56581 var ecall = { cell : newCell, forward : forward };
56582 this.fireEvent('beforeeditnext', ecall );
56583 newCell = ecall.cell;
56584 forward = ecall.forward;
56588 //Roo.log('next cell after edit');
56589 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
56590 } else if (forward) {
56591 // tabbed past last
56592 this.fireEvent.defer(100, this, ['tabend',this]);
56597 * Ext JS Library 1.1.1
56598 * Copyright(c) 2006-2007, Ext JS, LLC.
56600 * Originally Released Under LGPL - original licence link has changed is not relivant.
56603 * <script type="text/javascript">
56607 * @class Roo.grid.EditorGrid
56608 * @extends Roo.grid.Grid
56609 * Class for creating and editable grid.
56610 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56611 * The container MUST have some type of size defined for the grid to fill. The container will be
56612 * automatically set to position relative if it isn't already.
56613 * @param {Object} dataSource The data model to bind to
56614 * @param {Object} colModel The column model with info about this grid's columns
56616 Roo.grid.EditorGrid = function(container, config){
56617 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
56618 this.getGridEl().addClass("xedit-grid");
56620 if(!this.selModel){
56621 this.selModel = new Roo.grid.CellSelectionModel();
56624 this.activeEditor = null;
56628 * @event beforeedit
56629 * Fires before cell editing is triggered. The edit event object has the following properties <br />
56630 * <ul style="padding:5px;padding-left:16px;">
56631 * <li>grid - This grid</li>
56632 * <li>record - The record being edited</li>
56633 * <li>field - The field name being edited</li>
56634 * <li>value - The value for the field being edited.</li>
56635 * <li>row - The grid row index</li>
56636 * <li>column - The grid column index</li>
56637 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56639 * @param {Object} e An edit event (see above for description)
56641 "beforeedit" : true,
56644 * Fires after a cell is edited. <br />
56645 * <ul style="padding:5px;padding-left:16px;">
56646 * <li>grid - This grid</li>
56647 * <li>record - The record being edited</li>
56648 * <li>field - The field name being edited</li>
56649 * <li>value - The value being set</li>
56650 * <li>originalValue - The original value for the field, before the edit.</li>
56651 * <li>row - The grid row index</li>
56652 * <li>column - The grid column index</li>
56654 * @param {Object} e An edit event (see above for description)
56656 "afteredit" : true,
56658 * @event validateedit
56659 * Fires after a cell is edited, but before the value is set in the record.
56660 * You can use this to modify the value being set in the field, Return false
56661 * to cancel the change. The edit event object has the following properties <br />
56662 * <ul style="padding:5px;padding-left:16px;">
56663 * <li>editor - This editor</li>
56664 * <li>grid - This grid</li>
56665 * <li>record - The record being edited</li>
56666 * <li>field - The field name being edited</li>
56667 * <li>value - The value being set</li>
56668 * <li>originalValue - The original value for the field, before the edit.</li>
56669 * <li>row - The grid row index</li>
56670 * <li>column - The grid column index</li>
56671 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56673 * @param {Object} e An edit event (see above for description)
56675 "validateedit" : true
56677 this.on("bodyscroll", this.stopEditing, this);
56678 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56681 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56683 * @cfg {Number} clicksToEdit
56684 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56691 trackMouseOver: false, // causes very odd FF errors
56693 onCellDblClick : function(g, row, col){
56694 this.startEditing(row, col);
56697 onEditComplete : function(ed, value, startValue){
56698 this.editing = false;
56699 this.activeEditor = null;
56700 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56702 var field = this.colModel.getDataIndex(ed.col);
56707 originalValue: startValue,
56714 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56717 if(String(value) !== String(startValue)){
56719 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56720 r.set(field, e.value);
56721 // if we are dealing with a combo box..
56722 // then we also set the 'name' colum to be the displayField
56723 if (ed.field.displayField && ed.field.name) {
56724 r.set(ed.field.name, ed.field.el.dom.value);
56727 delete e.cancel; //?? why!!!
56728 this.fireEvent("afteredit", e);
56731 this.fireEvent("afteredit", e); // always fire it!
56733 this.view.focusCell(ed.row, ed.col);
56737 * Starts editing the specified for the specified row/column
56738 * @param {Number} rowIndex
56739 * @param {Number} colIndex
56741 startEditing : function(row, col){
56742 this.stopEditing();
56743 if(this.colModel.isCellEditable(col, row)){
56744 this.view.ensureVisible(row, col, true);
56746 var r = this.dataSource.getAt(row);
56747 var field = this.colModel.getDataIndex(col);
56748 var cell = Roo.get(this.view.getCell(row,col));
56753 value: r.data[field],
56758 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56759 this.editing = true;
56760 var ed = this.colModel.getCellEditor(col, row);
56766 ed.render(ed.parentEl || document.body);
56772 (function(){ // complex but required for focus issues in safari, ie and opera
56776 ed.on("complete", this.onEditComplete, this, {single: true});
56777 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56778 this.activeEditor = ed;
56779 var v = r.data[field];
56780 ed.startEdit(this.view.getCell(row, col), v);
56781 // combo's with 'displayField and name set
56782 if (ed.field.displayField && ed.field.name) {
56783 ed.field.el.dom.value = r.data[ed.field.name];
56787 }).defer(50, this);
56793 * Stops any active editing
56795 stopEditing : function(){
56796 if(this.activeEditor){
56797 this.activeEditor.completeEdit();
56799 this.activeEditor = null;
56803 * Called to get grid's drag proxy text, by default returns this.ddText.
56806 getDragDropText : function(){
56807 var count = this.selModel.getSelectedCell() ? 1 : 0;
56808 return String.format(this.ddText, count, count == 1 ? '' : 's');
56813 * Ext JS Library 1.1.1
56814 * Copyright(c) 2006-2007, Ext JS, LLC.
56816 * Originally Released Under LGPL - original licence link has changed is not relivant.
56819 * <script type="text/javascript">
56822 // private - not really -- you end up using it !
56823 // This is a support class used internally by the Grid components
56826 * @class Roo.grid.GridEditor
56827 * @extends Roo.Editor
56828 * Class for creating and editable grid elements.
56829 * @param {Object} config any settings (must include field)
56831 Roo.grid.GridEditor = function(field, config){
56832 if (!config && field.field) {
56834 field = Roo.factory(config.field, Roo.form);
56836 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56837 field.monitorTab = false;
56840 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56843 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56846 alignment: "tl-tl",
56849 cls: "x-small-editor x-grid-editor",
56854 * Ext JS Library 1.1.1
56855 * Copyright(c) 2006-2007, Ext JS, LLC.
56857 * Originally Released Under LGPL - original licence link has changed is not relivant.
56860 * <script type="text/javascript">
56865 Roo.grid.PropertyRecord = Roo.data.Record.create([
56866 {name:'name',type:'string'}, 'value'
56870 Roo.grid.PropertyStore = function(grid, source){
56872 this.store = new Roo.data.Store({
56873 recordType : Roo.grid.PropertyRecord
56875 this.store.on('update', this.onUpdate, this);
56877 this.setSource(source);
56879 Roo.grid.PropertyStore.superclass.constructor.call(this);
56884 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56885 setSource : function(o){
56887 this.store.removeAll();
56890 if(this.isEditableValue(o[k])){
56891 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56894 this.store.loadRecords({records: data}, {}, true);
56897 onUpdate : function(ds, record, type){
56898 if(type == Roo.data.Record.EDIT){
56899 var v = record.data['value'];
56900 var oldValue = record.modified['value'];
56901 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56902 this.source[record.id] = v;
56904 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56911 getProperty : function(row){
56912 return this.store.getAt(row);
56915 isEditableValue: function(val){
56916 if(val && val instanceof Date){
56918 }else if(typeof val == 'object' || typeof val == 'function'){
56924 setValue : function(prop, value){
56925 this.source[prop] = value;
56926 this.store.getById(prop).set('value', value);
56929 getSource : function(){
56930 return this.source;
56934 Roo.grid.PropertyColumnModel = function(grid, store){
56937 g.PropertyColumnModel.superclass.constructor.call(this, [
56938 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56939 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56941 this.store = store;
56942 this.bselect = Roo.DomHelper.append(document.body, {
56943 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56944 {tag: 'option', value: 'true', html: 'true'},
56945 {tag: 'option', value: 'false', html: 'false'}
56948 Roo.id(this.bselect);
56951 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56952 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56953 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56954 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56955 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56957 this.renderCellDelegate = this.renderCell.createDelegate(this);
56958 this.renderPropDelegate = this.renderProp.createDelegate(this);
56961 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56965 valueText : 'Value',
56967 dateFormat : 'm/j/Y',
56970 renderDate : function(dateVal){
56971 return dateVal.dateFormat(this.dateFormat);
56974 renderBool : function(bVal){
56975 return bVal ? 'true' : 'false';
56978 isCellEditable : function(colIndex, rowIndex){
56979 return colIndex == 1;
56982 getRenderer : function(col){
56984 this.renderCellDelegate : this.renderPropDelegate;
56987 renderProp : function(v){
56988 return this.getPropertyName(v);
56991 renderCell : function(val){
56993 if(val instanceof Date){
56994 rv = this.renderDate(val);
56995 }else if(typeof val == 'boolean'){
56996 rv = this.renderBool(val);
56998 return Roo.util.Format.htmlEncode(rv);
57001 getPropertyName : function(name){
57002 var pn = this.grid.propertyNames;
57003 return pn && pn[name] ? pn[name] : name;
57006 getCellEditor : function(colIndex, rowIndex){
57007 var p = this.store.getProperty(rowIndex);
57008 var n = p.data['name'], val = p.data['value'];
57010 if(typeof(this.grid.customEditors[n]) == 'string'){
57011 return this.editors[this.grid.customEditors[n]];
57013 if(typeof(this.grid.customEditors[n]) != 'undefined'){
57014 return this.grid.customEditors[n];
57016 if(val instanceof Date){
57017 return this.editors['date'];
57018 }else if(typeof val == 'number'){
57019 return this.editors['number'];
57020 }else if(typeof val == 'boolean'){
57021 return this.editors['boolean'];
57023 return this.editors['string'];
57029 * @class Roo.grid.PropertyGrid
57030 * @extends Roo.grid.EditorGrid
57031 * This class represents the interface of a component based property grid control.
57032 * <br><br>Usage:<pre><code>
57033 var grid = new Roo.grid.PropertyGrid("my-container-id", {
57041 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57042 * The container MUST have some type of size defined for the grid to fill. The container will be
57043 * automatically set to position relative if it isn't already.
57044 * @param {Object} config A config object that sets properties on this grid.
57046 Roo.grid.PropertyGrid = function(container, config){
57047 config = config || {};
57048 var store = new Roo.grid.PropertyStore(this);
57049 this.store = store;
57050 var cm = new Roo.grid.PropertyColumnModel(this, store);
57051 store.store.sort('name', 'ASC');
57052 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
57055 enableColLock:false,
57056 enableColumnMove:false,
57058 trackMouseOver: false,
57061 this.getGridEl().addClass('x-props-grid');
57062 this.lastEditRow = null;
57063 this.on('columnresize', this.onColumnResize, this);
57066 * @event beforepropertychange
57067 * Fires before a property changes (return false to stop?)
57068 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57069 * @param {String} id Record Id
57070 * @param {String} newval New Value
57071 * @param {String} oldval Old Value
57073 "beforepropertychange": true,
57075 * @event propertychange
57076 * Fires after a property changes
57077 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57078 * @param {String} id Record Id
57079 * @param {String} newval New Value
57080 * @param {String} oldval Old Value
57082 "propertychange": true
57084 this.customEditors = this.customEditors || {};
57086 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
57089 * @cfg {Object} customEditors map of colnames=> custom editors.
57090 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
57091 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
57092 * false disables editing of the field.
57096 * @cfg {Object} propertyNames map of property Names to their displayed value
57099 render : function(){
57100 Roo.grid.PropertyGrid.superclass.render.call(this);
57101 this.autoSize.defer(100, this);
57104 autoSize : function(){
57105 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
57107 this.view.fitColumns();
57111 onColumnResize : function(){
57112 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
57116 * Sets the data for the Grid
57117 * accepts a Key => Value object of all the elements avaiable.
57118 * @param {Object} data to appear in grid.
57120 setSource : function(source){
57121 this.store.setSource(source);
57125 * Gets all the data from the grid.
57126 * @return {Object} data data stored in grid
57128 getSource : function(){
57129 return this.store.getSource();
57138 * @class Roo.grid.Calendar
57139 * @extends Roo.util.Grid
57140 * This class extends the Grid to provide a calendar widget
57141 * <br><br>Usage:<pre><code>
57142 var grid = new Roo.grid.Calendar("my-container-id", {
57145 selModel: mySelectionModel,
57146 autoSizeColumns: true,
57147 monitorWindowResize: false,
57148 trackMouseOver: true
57149 eventstore : real data store..
57155 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57156 * The container MUST have some type of size defined for the grid to fill. The container will be
57157 * automatically set to position relative if it isn't already.
57158 * @param {Object} config A config object that sets properties on this grid.
57160 Roo.grid.Calendar = function(container, config){
57161 // initialize the container
57162 this.container = Roo.get(container);
57163 this.container.update("");
57164 this.container.setStyle("overflow", "hidden");
57165 this.container.addClass('x-grid-container');
57167 this.id = this.container.id;
57169 Roo.apply(this, config);
57170 // check and correct shorthanded configs
57174 for (var r = 0;r < 6;r++) {
57177 for (var c =0;c < 7;c++) {
57181 if (this.eventStore) {
57182 this.eventStore= Roo.factory(this.eventStore, Roo.data);
57183 this.eventStore.on('load',this.onLoad, this);
57184 this.eventStore.on('beforeload',this.clearEvents, this);
57188 this.dataSource = new Roo.data.Store({
57189 proxy: new Roo.data.MemoryProxy(rows),
57190 reader: new Roo.data.ArrayReader({}, [
57191 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
57194 this.dataSource.load();
57195 this.ds = this.dataSource;
57196 this.ds.xmodule = this.xmodule || false;
57199 var cellRender = function(v,x,r)
57201 return String.format(
57202 '<div class="fc-day fc-widget-content"><div>' +
57203 '<div class="fc-event-container"></div>' +
57204 '<div class="fc-day-number">{0}</div>'+
57206 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
57207 '</div></div>', v);
57212 this.colModel = new Roo.grid.ColumnModel( [
57214 xtype: 'ColumnModel',
57216 dataIndex : 'weekday0',
57218 renderer : cellRender
57221 xtype: 'ColumnModel',
57223 dataIndex : 'weekday1',
57225 renderer : cellRender
57228 xtype: 'ColumnModel',
57230 dataIndex : 'weekday2',
57231 header : 'Tuesday',
57232 renderer : cellRender
57235 xtype: 'ColumnModel',
57237 dataIndex : 'weekday3',
57238 header : 'Wednesday',
57239 renderer : cellRender
57242 xtype: 'ColumnModel',
57244 dataIndex : 'weekday4',
57245 header : 'Thursday',
57246 renderer : cellRender
57249 xtype: 'ColumnModel',
57251 dataIndex : 'weekday5',
57253 renderer : cellRender
57256 xtype: 'ColumnModel',
57258 dataIndex : 'weekday6',
57259 header : 'Saturday',
57260 renderer : cellRender
57263 this.cm = this.colModel;
57264 this.cm.xmodule = this.xmodule || false;
57268 //this.selModel = new Roo.grid.CellSelectionModel();
57269 //this.sm = this.selModel;
57270 //this.selModel.init(this);
57274 this.container.setWidth(this.width);
57278 this.container.setHeight(this.height);
57285 * The raw click event for the entire grid.
57286 * @param {Roo.EventObject} e
57291 * The raw dblclick event for the entire grid.
57292 * @param {Roo.EventObject} e
57296 * @event contextmenu
57297 * The raw contextmenu event for the entire grid.
57298 * @param {Roo.EventObject} e
57300 "contextmenu" : true,
57303 * The raw mousedown event for the entire grid.
57304 * @param {Roo.EventObject} e
57306 "mousedown" : true,
57309 * The raw mouseup event for the entire grid.
57310 * @param {Roo.EventObject} e
57315 * The raw mouseover event for the entire grid.
57316 * @param {Roo.EventObject} e
57318 "mouseover" : true,
57321 * The raw mouseout event for the entire grid.
57322 * @param {Roo.EventObject} e
57327 * The raw keypress event for the entire grid.
57328 * @param {Roo.EventObject} e
57333 * The raw keydown event for the entire grid.
57334 * @param {Roo.EventObject} e
57342 * Fires when a cell is clicked
57343 * @param {Grid} this
57344 * @param {Number} rowIndex
57345 * @param {Number} columnIndex
57346 * @param {Roo.EventObject} e
57348 "cellclick" : true,
57350 * @event celldblclick
57351 * Fires when a cell is double clicked
57352 * @param {Grid} this
57353 * @param {Number} rowIndex
57354 * @param {Number} columnIndex
57355 * @param {Roo.EventObject} e
57357 "celldblclick" : true,
57360 * Fires when a row is clicked
57361 * @param {Grid} this
57362 * @param {Number} rowIndex
57363 * @param {Roo.EventObject} e
57367 * @event rowdblclick
57368 * Fires when a row is double clicked
57369 * @param {Grid} this
57370 * @param {Number} rowIndex
57371 * @param {Roo.EventObject} e
57373 "rowdblclick" : true,
57375 * @event headerclick
57376 * Fires when a header is clicked
57377 * @param {Grid} this
57378 * @param {Number} columnIndex
57379 * @param {Roo.EventObject} e
57381 "headerclick" : true,
57383 * @event headerdblclick
57384 * Fires when a header cell is double clicked
57385 * @param {Grid} this
57386 * @param {Number} columnIndex
57387 * @param {Roo.EventObject} e
57389 "headerdblclick" : true,
57391 * @event rowcontextmenu
57392 * Fires when a row is right clicked
57393 * @param {Grid} this
57394 * @param {Number} rowIndex
57395 * @param {Roo.EventObject} e
57397 "rowcontextmenu" : true,
57399 * @event cellcontextmenu
57400 * Fires when a cell is right clicked
57401 * @param {Grid} this
57402 * @param {Number} rowIndex
57403 * @param {Number} cellIndex
57404 * @param {Roo.EventObject} e
57406 "cellcontextmenu" : true,
57408 * @event headercontextmenu
57409 * Fires when a header is right clicked
57410 * @param {Grid} this
57411 * @param {Number} columnIndex
57412 * @param {Roo.EventObject} e
57414 "headercontextmenu" : true,
57416 * @event bodyscroll
57417 * Fires when the body element is scrolled
57418 * @param {Number} scrollLeft
57419 * @param {Number} scrollTop
57421 "bodyscroll" : true,
57423 * @event columnresize
57424 * Fires when the user resizes a column
57425 * @param {Number} columnIndex
57426 * @param {Number} newSize
57428 "columnresize" : true,
57430 * @event columnmove
57431 * Fires when the user moves a column
57432 * @param {Number} oldIndex
57433 * @param {Number} newIndex
57435 "columnmove" : true,
57438 * Fires when row(s) start being dragged
57439 * @param {Grid} this
57440 * @param {Roo.GridDD} dd The drag drop object
57441 * @param {event} e The raw browser event
57443 "startdrag" : true,
57446 * Fires when a drag operation is complete
57447 * @param {Grid} this
57448 * @param {Roo.GridDD} dd The drag drop object
57449 * @param {event} e The raw browser event
57454 * Fires when dragged row(s) are dropped on a valid DD target
57455 * @param {Grid} this
57456 * @param {Roo.GridDD} dd The drag drop object
57457 * @param {String} targetId The target drag drop object
57458 * @param {event} e The raw browser event
57463 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
57464 * @param {Grid} this
57465 * @param {Roo.GridDD} dd The drag drop object
57466 * @param {String} targetId The target drag drop object
57467 * @param {event} e The raw browser event
57472 * Fires when the dragged row(s) first cross another DD target while being dragged
57473 * @param {Grid} this
57474 * @param {Roo.GridDD} dd The drag drop object
57475 * @param {String} targetId The target drag drop object
57476 * @param {event} e The raw browser event
57478 "dragenter" : true,
57481 * Fires when the dragged row(s) leave another DD target while being dragged
57482 * @param {Grid} this
57483 * @param {Roo.GridDD} dd The drag drop object
57484 * @param {String} targetId The target drag drop object
57485 * @param {event} e The raw browser event
57490 * Fires when a row is rendered, so you can change add a style to it.
57491 * @param {GridView} gridview The grid view
57492 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
57498 * Fires when the grid is rendered
57499 * @param {Grid} grid
57504 * Fires when a date is selected
57505 * @param {DatePicker} this
57506 * @param {Date} date The selected date
57510 * @event monthchange
57511 * Fires when the displayed month changes
57512 * @param {DatePicker} this
57513 * @param {Date} date The selected month
57515 'monthchange': true,
57517 * @event evententer
57518 * Fires when mouse over an event
57519 * @param {Calendar} this
57520 * @param {event} Event
57522 'evententer': true,
57524 * @event eventleave
57525 * Fires when the mouse leaves an
57526 * @param {Calendar} this
57529 'eventleave': true,
57531 * @event eventclick
57532 * Fires when the mouse click an
57533 * @param {Calendar} this
57536 'eventclick': true,
57538 * @event eventrender
57539 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
57540 * @param {Calendar} this
57541 * @param {data} data to be modified
57543 'eventrender': true
57547 Roo.grid.Grid.superclass.constructor.call(this);
57548 this.on('render', function() {
57549 this.view.el.addClass('x-grid-cal');
57551 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
57555 if (!Roo.grid.Calendar.style) {
57556 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
57559 '.x-grid-cal .x-grid-col' : {
57560 height: 'auto !important',
57561 'vertical-align': 'top'
57563 '.x-grid-cal .fc-event-hori' : {
57574 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
57576 * @cfg {Store} eventStore The store that loads events.
57581 activeDate : false,
57584 monitorWindowResize : false,
57587 resizeColumns : function() {
57588 var col = (this.view.el.getWidth() / 7) - 3;
57589 // loop through cols, and setWidth
57590 for(var i =0 ; i < 7 ; i++){
57591 this.cm.setColumnWidth(i, col);
57594 setDate :function(date) {
57596 Roo.log('setDate?');
57598 this.resizeColumns();
57599 var vd = this.activeDate;
57600 this.activeDate = date;
57601 // if(vd && this.el){
57602 // var t = date.getTime();
57603 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
57604 // Roo.log('using add remove');
57606 // this.fireEvent('monthchange', this, date);
57608 // this.cells.removeClass("fc-state-highlight");
57609 // this.cells.each(function(c){
57610 // if(c.dateValue == t){
57611 // c.addClass("fc-state-highlight");
57612 // setTimeout(function(){
57613 // try{c.dom.firstChild.focus();}catch(e){}
57623 var days = date.getDaysInMonth();
57625 var firstOfMonth = date.getFirstDateOfMonth();
57626 var startingPos = firstOfMonth.getDay()-this.startDay;
57628 if(startingPos < this.startDay){
57632 var pm = date.add(Date.MONTH, -1);
57633 var prevStart = pm.getDaysInMonth()-startingPos;
57637 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57639 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57640 //this.cells.addClassOnOver('fc-state-hover');
57642 var cells = this.cells.elements;
57643 var textEls = this.textNodes;
57645 //Roo.each(cells, function(cell){
57646 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57649 days += startingPos;
57651 // convert everything to numbers so it's fast
57652 var day = 86400000;
57653 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57656 //Roo.log(prevStart);
57658 var today = new Date().clearTime().getTime();
57659 var sel = date.clearTime().getTime();
57660 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57661 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57662 var ddMatch = this.disabledDatesRE;
57663 var ddText = this.disabledDatesText;
57664 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57665 var ddaysText = this.disabledDaysText;
57666 var format = this.format;
57668 var setCellClass = function(cal, cell){
57670 //Roo.log('set Cell Class');
57672 var t = d.getTime();
57677 cell.dateValue = t;
57679 cell.className += " fc-today";
57680 cell.className += " fc-state-highlight";
57681 cell.title = cal.todayText;
57684 // disable highlight in other month..
57685 cell.className += " fc-state-highlight";
57690 //cell.className = " fc-state-disabled";
57691 cell.title = cal.minText;
57695 //cell.className = " fc-state-disabled";
57696 cell.title = cal.maxText;
57700 if(ddays.indexOf(d.getDay()) != -1){
57701 // cell.title = ddaysText;
57702 // cell.className = " fc-state-disabled";
57705 if(ddMatch && format){
57706 var fvalue = d.dateFormat(format);
57707 if(ddMatch.test(fvalue)){
57708 cell.title = ddText.replace("%0", fvalue);
57709 cell.className = " fc-state-disabled";
57713 if (!cell.initialClassName) {
57714 cell.initialClassName = cell.dom.className;
57717 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57722 for(; i < startingPos; i++) {
57723 cells[i].dayName = (++prevStart);
57724 Roo.log(textEls[i]);
57725 d.setDate(d.getDate()+1);
57727 //cells[i].className = "fc-past fc-other-month";
57728 setCellClass(this, cells[i]);
57733 for(; i < days; i++){
57734 intDay = i - startingPos + 1;
57735 cells[i].dayName = (intDay);
57736 d.setDate(d.getDate()+1);
57738 cells[i].className = ''; // "x-date-active";
57739 setCellClass(this, cells[i]);
57743 for(; i < 42; i++) {
57744 //textEls[i].innerHTML = (++extraDays);
57746 d.setDate(d.getDate()+1);
57747 cells[i].dayName = (++extraDays);
57748 cells[i].className = "fc-future fc-other-month";
57749 setCellClass(this, cells[i]);
57752 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57754 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57756 // this will cause all the cells to mis
57759 for (var r = 0;r < 6;r++) {
57760 for (var c =0;c < 7;c++) {
57761 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57765 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57766 for(i=0;i<cells.length;i++) {
57768 this.cells.elements[i].dayName = cells[i].dayName ;
57769 this.cells.elements[i].className = cells[i].className;
57770 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57771 this.cells.elements[i].title = cells[i].title ;
57772 this.cells.elements[i].dateValue = cells[i].dateValue ;
57778 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57779 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57781 ////if(totalRows != 6){
57782 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57783 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57786 this.fireEvent('monthchange', this, date);
57791 * Returns the grid's SelectionModel.
57792 * @return {SelectionModel}
57794 getSelectionModel : function(){
57795 if(!this.selModel){
57796 this.selModel = new Roo.grid.CellSelectionModel();
57798 return this.selModel;
57802 this.eventStore.load()
57808 findCell : function(dt) {
57809 dt = dt.clearTime().getTime();
57811 this.cells.each(function(c){
57812 //Roo.log("check " +c.dateValue + '?=' + dt);
57813 if(c.dateValue == dt){
57823 findCells : function(rec) {
57824 var s = rec.data.start_dt.clone().clearTime().getTime();
57826 var e= rec.data.end_dt.clone().clearTime().getTime();
57829 this.cells.each(function(c){
57830 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57832 if(c.dateValue > e){
57835 if(c.dateValue < s){
57844 findBestRow: function(cells)
57848 for (var i =0 ; i < cells.length;i++) {
57849 ret = Math.max(cells[i].rows || 0,ret);
57856 addItem : function(rec)
57858 // look for vertical location slot in
57859 var cells = this.findCells(rec);
57861 rec.row = this.findBestRow(cells);
57863 // work out the location.
57867 for(var i =0; i < cells.length; i++) {
57875 if (crow.start.getY() == cells[i].getY()) {
57877 crow.end = cells[i];
57893 for (var i = 0; i < cells.length;i++) {
57894 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57901 clearEvents: function() {
57903 if (!this.eventStore.getCount()) {
57906 // reset number of rows in cells.
57907 Roo.each(this.cells.elements, function(c){
57911 this.eventStore.each(function(e) {
57912 this.clearEvent(e);
57917 clearEvent : function(ev)
57920 Roo.each(ev.els, function(el) {
57921 el.un('mouseenter' ,this.onEventEnter, this);
57922 el.un('mouseleave' ,this.onEventLeave, this);
57930 renderEvent : function(ev,ctr) {
57932 ctr = this.view.el.select('.fc-event-container',true).first();
57936 this.clearEvent(ev);
57942 var cells = ev.cells;
57943 var rows = ev.rows;
57944 this.fireEvent('eventrender', this, ev);
57946 for(var i =0; i < rows.length; i++) {
57950 cls += ' fc-event-start';
57952 if ((i+1) == rows.length) {
57953 cls += ' fc-event-end';
57956 //Roo.log(ev.data);
57957 // how many rows should it span..
57958 var cg = this.eventTmpl.append(ctr,Roo.apply({
57961 }, ev.data) , true);
57964 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57965 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57966 cg.on('click', this.onEventClick, this, ev);
57970 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57971 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57974 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57975 cg.setWidth(ebox.right - sbox.x -2);
57979 renderEvents: function()
57981 // first make sure there is enough space..
57983 if (!this.eventTmpl) {
57984 this.eventTmpl = new Roo.Template(
57985 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57986 '<div class="fc-event-inner">' +
57987 '<span class="fc-event-time">{time}</span>' +
57988 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57990 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57998 this.cells.each(function(c) {
57999 //Roo.log(c.select('.fc-day-content div',true).first());
58000 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
58003 var ctr = this.view.el.select('.fc-event-container',true).first();
58006 this.eventStore.each(function(ev){
58008 this.renderEvent(ev);
58012 this.view.layout();
58016 onEventEnter: function (e, el,event,d) {
58017 this.fireEvent('evententer', this, el, event);
58020 onEventLeave: function (e, el,event,d) {
58021 this.fireEvent('eventleave', this, el, event);
58024 onEventClick: function (e, el,event,d) {
58025 this.fireEvent('eventclick', this, el, event);
58028 onMonthChange: function () {
58032 onLoad: function () {
58034 //Roo.log('calendar onload');
58036 if(this.eventStore.getCount() > 0){
58040 this.eventStore.each(function(d){
58045 if (typeof(add.end_dt) == 'undefined') {
58046 Roo.log("Missing End time in calendar data: ");
58050 if (typeof(add.start_dt) == 'undefined') {
58051 Roo.log("Missing Start time in calendar data: ");
58055 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
58056 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
58057 add.id = add.id || d.id;
58058 add.title = add.title || '??';
58066 this.renderEvents();
58076 render : function ()
58080 if (!this.view.el.hasClass('course-timesheet')) {
58081 this.view.el.addClass('course-timesheet');
58083 if (this.tsStyle) {
58088 Roo.log(_this.grid.view.el.getWidth());
58091 this.tsStyle = Roo.util.CSS.createStyleSheet({
58092 '.course-timesheet .x-grid-row' : {
58095 '.x-grid-row td' : {
58096 'vertical-align' : 0
58098 '.course-edit-link' : {
58100 'text-overflow' : 'ellipsis',
58101 'overflow' : 'hidden',
58102 'white-space' : 'nowrap',
58103 'cursor' : 'pointer'
58108 '.de-act-sup-link' : {
58109 'color' : 'purple',
58110 'text-decoration' : 'line-through'
58114 'text-decoration' : 'line-through'
58116 '.course-timesheet .course-highlight' : {
58117 'border-top-style': 'dashed !important',
58118 'border-bottom-bottom': 'dashed !important'
58120 '.course-timesheet .course-item' : {
58121 'font-family' : 'tahoma, arial, helvetica',
58122 'font-size' : '11px',
58123 'overflow' : 'hidden',
58124 'padding-left' : '10px',
58125 'padding-right' : '10px',
58126 'padding-top' : '10px'
58134 monitorWindowResize : false,
58135 cellrenderer : function(v,x,r)
58140 xtype: 'CellSelectionModel',
58147 beforeload : function (_self, options)
58149 options.params = options.params || {};
58150 options.params._month = _this.monthField.getValue();
58151 options.params.limit = 9999;
58152 options.params['sort'] = 'when_dt';
58153 options.params['dir'] = 'ASC';
58154 this.proxy.loadResponse = this.loadResponse;
58156 //this.addColumns();
58158 load : function (_self, records, options)
58160 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
58161 // if you click on the translation.. you can edit it...
58162 var el = Roo.get(this);
58163 var id = el.dom.getAttribute('data-id');
58164 var d = el.dom.getAttribute('data-date');
58165 var t = el.dom.getAttribute('data-time');
58166 //var id = this.child('span').dom.textContent;
58169 Pman.Dialog.CourseCalendar.show({
58173 productitem_active : id ? 1 : 0
58175 _this.grid.ds.load({});
58180 _this.panel.fireEvent('resize', [ '', '' ]);
58183 loadResponse : function(o, success, response){
58184 // this is overridden on before load..
58186 Roo.log("our code?");
58187 //Roo.log(success);
58188 //Roo.log(response)
58189 delete this.activeRequest;
58191 this.fireEvent("loadexception", this, o, response);
58192 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58197 result = o.reader.read(response);
58199 Roo.log("load exception?");
58200 this.fireEvent("loadexception", this, o, response, e);
58201 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58204 Roo.log("ready...");
58205 // loop through result.records;
58206 // and set this.tdate[date] = [] << array of records..
58208 Roo.each(result.records, function(r){
58210 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
58211 _this.tdata[r.data.when_dt.format('j')] = [];
58213 _this.tdata[r.data.when_dt.format('j')].push(r.data);
58216 //Roo.log(_this.tdata);
58218 result.records = [];
58219 result.totalRecords = 6;
58221 // let's generate some duumy records for the rows.
58222 //var st = _this.dateField.getValue();
58224 // work out monday..
58225 //st = st.add(Date.DAY, -1 * st.format('w'));
58227 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58229 var firstOfMonth = date.getFirstDayOfMonth();
58230 var days = date.getDaysInMonth();
58232 var firstAdded = false;
58233 for (var i = 0; i < result.totalRecords ; i++) {
58234 //var d= st.add(Date.DAY, i);
58237 for(var w = 0 ; w < 7 ; w++){
58238 if(!firstAdded && firstOfMonth != w){
58245 var dd = (d > 0 && d < 10) ? "0"+d : d;
58246 row['weekday'+w] = String.format(
58247 '<span style="font-size: 16px;"><b>{0}</b></span>'+
58248 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
58250 date.format('Y-m-')+dd
58253 if(typeof(_this.tdata[d]) != 'undefined'){
58254 Roo.each(_this.tdata[d], function(r){
58258 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
58259 if(r.parent_id*1>0){
58260 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
58263 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
58264 deactive = 'de-act-link';
58267 row['weekday'+w] += String.format(
58268 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
58270 r.product_id_name, //1
58271 r.when_dt.format('h:ia'), //2
58281 // only do this if something added..
58283 result.records.push(_this.grid.dataSource.reader.newRow(row));
58287 // push it twice. (second one with an hour..
58291 this.fireEvent("load", this, o, o.request.arg);
58292 o.request.callback.call(o.request.scope, result, o.request.arg, true);
58294 sortInfo : {field: 'when_dt', direction : 'ASC' },
58296 xtype: 'HttpProxy',
58299 url : baseURL + '/Roo/Shop_course.php'
58302 xtype: 'JsonReader',
58319 'name': 'parent_id',
58323 'name': 'product_id',
58327 'name': 'productitem_id',
58345 click : function (_self, e)
58347 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58348 sd.setMonth(sd.getMonth()-1);
58349 _this.monthField.setValue(sd.format('Y-m-d'));
58350 _this.grid.ds.load({});
58356 xtype: 'Separator',
58360 xtype: 'MonthField',
58363 render : function (_self)
58365 _this.monthField = _self;
58366 // _this.monthField.set today
58368 select : function (combo, date)
58370 _this.grid.ds.load({});
58373 value : (function() { return new Date(); })()
58376 xtype: 'Separator',
58382 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
58392 click : function (_self, e)
58394 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58395 sd.setMonth(sd.getMonth()+1);
58396 _this.monthField.setValue(sd.format('Y-m-d'));
58397 _this.grid.ds.load({});
58410 * Ext JS Library 1.1.1
58411 * Copyright(c) 2006-2007, Ext JS, LLC.
58413 * Originally Released Under LGPL - original licence link has changed is not relivant.
58416 * <script type="text/javascript">
58420 * @class Roo.LoadMask
58421 * A simple utility class for generically masking elements while loading data. If the element being masked has
58422 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
58423 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
58424 * element's UpdateManager load indicator and will be destroyed after the initial load.
58426 * Create a new LoadMask
58427 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
58428 * @param {Object} config The config object
58430 Roo.LoadMask = function(el, config){
58431 this.el = Roo.get(el);
58432 Roo.apply(this, config);
58434 this.store.on('beforeload', this.onBeforeLoad, this);
58435 this.store.on('load', this.onLoad, this);
58436 this.store.on('loadexception', this.onLoadException, this);
58437 this.removeMask = false;
58439 var um = this.el.getUpdateManager();
58440 um.showLoadIndicator = false; // disable the default indicator
58441 um.on('beforeupdate', this.onBeforeLoad, this);
58442 um.on('update', this.onLoad, this);
58443 um.on('failure', this.onLoad, this);
58444 this.removeMask = true;
58448 Roo.LoadMask.prototype = {
58450 * @cfg {Boolean} removeMask
58451 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
58452 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
58455 * @cfg {String} msg
58456 * The text to display in a centered loading message box (defaults to 'Loading...')
58458 msg : 'Loading...',
58460 * @cfg {String} msgCls
58461 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
58463 msgCls : 'x-mask-loading',
58466 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
58472 * Disables the mask to prevent it from being displayed
58474 disable : function(){
58475 this.disabled = true;
58479 * Enables the mask so that it can be displayed
58481 enable : function(){
58482 this.disabled = false;
58485 onLoadException : function()
58487 Roo.log(arguments);
58489 if (typeof(arguments[3]) != 'undefined') {
58490 Roo.MessageBox.alert("Error loading",arguments[3]);
58494 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
58495 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
58504 this.el.unmask(this.removeMask);
58507 onLoad : function()
58509 this.el.unmask(this.removeMask);
58513 onBeforeLoad : function(){
58514 if(!this.disabled){
58515 this.el.mask(this.msg, this.msgCls);
58520 destroy : function(){
58522 this.store.un('beforeload', this.onBeforeLoad, this);
58523 this.store.un('load', this.onLoad, this);
58524 this.store.un('loadexception', this.onLoadException, this);
58526 var um = this.el.getUpdateManager();
58527 um.un('beforeupdate', this.onBeforeLoad, this);
58528 um.un('update', this.onLoad, this);
58529 um.un('failure', this.onLoad, this);
58534 * Ext JS Library 1.1.1
58535 * Copyright(c) 2006-2007, Ext JS, LLC.
58537 * Originally Released Under LGPL - original licence link has changed is not relivant.
58540 * <script type="text/javascript">
58545 * @class Roo.XTemplate
58546 * @extends Roo.Template
58547 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
58549 var t = new Roo.XTemplate(
58550 '<select name="{name}">',
58551 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
58555 // then append, applying the master template values
58558 * Supported features:
58563 {a_variable} - output encoded.
58564 {a_variable.format:("Y-m-d")} - call a method on the variable
58565 {a_variable:raw} - unencoded output
58566 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
58567 {a_variable:this.method_on_template(...)} - call a method on the template object.
58572 <tpl for="a_variable or condition.."></tpl>
58573 <tpl if="a_variable or condition"></tpl>
58574 <tpl exec="some javascript"></tpl>
58575 <tpl name="named_template"></tpl> (experimental)
58577 <tpl for="."></tpl> - just iterate the property..
58578 <tpl for=".."></tpl> - iterates with the parent (probably the template)
58582 Roo.XTemplate = function()
58584 Roo.XTemplate.superclass.constructor.apply(this, arguments);
58591 Roo.extend(Roo.XTemplate, Roo.Template, {
58594 * The various sub templates
58599 * basic tag replacing syntax
58602 * // you can fake an object call by doing this
58606 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
58609 * compile the template
58611 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
58614 compile: function()
58618 s = ['<tpl>', s, '</tpl>'].join('');
58620 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
58621 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
58622 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
58623 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
58624 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
58629 while(true == !!(m = s.match(re))){
58630 var forMatch = m[0].match(nameRe),
58631 ifMatch = m[0].match(ifRe),
58632 execMatch = m[0].match(execRe),
58633 namedMatch = m[0].match(namedRe),
58638 name = forMatch && forMatch[1] ? forMatch[1] : '';
58641 // if - puts fn into test..
58642 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58644 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58649 // exec - calls a function... returns empty if true is returned.
58650 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58652 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58660 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58661 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58662 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58665 var uid = namedMatch ? namedMatch[1] : id;
58669 id: namedMatch ? namedMatch[1] : id,
58676 s = s.replace(m[0], '');
58678 s = s.replace(m[0], '{xtpl'+ id + '}');
58683 for(var i = tpls.length-1; i >= 0; --i){
58684 this.compileTpl(tpls[i]);
58685 this.tpls[tpls[i].id] = tpls[i];
58687 this.master = tpls[tpls.length-1];
58691 * same as applyTemplate, except it's done to one of the subTemplates
58692 * when using named templates, you can do:
58694 * var str = pl.applySubTemplate('your-name', values);
58697 * @param {Number} id of the template
58698 * @param {Object} values to apply to template
58699 * @param {Object} parent (normaly the instance of this object)
58701 applySubTemplate : function(id, values, parent)
58705 var t = this.tpls[id];
58709 if(t.test && !t.test.call(this, values, parent)){
58713 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58714 Roo.log(e.toString());
58720 if(t.exec && t.exec.call(this, values, parent)){
58724 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58725 Roo.log(e.toString());
58730 var vs = t.target ? t.target.call(this, values, parent) : values;
58731 parent = t.target ? values : parent;
58732 if(t.target && vs instanceof Array){
58734 for(var i = 0, len = vs.length; i < len; i++){
58735 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58737 return buf.join('');
58739 return t.compiled.call(this, vs, parent);
58741 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58742 Roo.log(e.toString());
58743 Roo.log(t.compiled);
58748 compileTpl : function(tpl)
58750 var fm = Roo.util.Format;
58751 var useF = this.disableFormats !== true;
58752 var sep = Roo.isGecko ? "+" : ",";
58753 var undef = function(str) {
58754 Roo.log("Property not found :" + str);
58758 var fn = function(m, name, format, args)
58760 //Roo.log(arguments);
58761 args = args ? args.replace(/\\'/g,"'") : args;
58762 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58763 if (typeof(format) == 'undefined') {
58764 format= 'htmlEncode';
58766 if (format == 'raw' ) {
58770 if(name.substr(0, 4) == 'xtpl'){
58771 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58774 // build an array of options to determine if value is undefined..
58776 // basically get 'xxxx.yyyy' then do
58777 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58778 // (function () { Roo.log("Property not found"); return ''; })() :
58783 Roo.each(name.split('.'), function(st) {
58784 lookfor += (lookfor.length ? '.': '') + st;
58785 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58788 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58791 if(format && useF){
58793 args = args ? ',' + args : "";
58795 if(format.substr(0, 5) != "this."){
58796 format = "fm." + format + '(';
58798 format = 'this.call("'+ format.substr(5) + '", ';
58802 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58806 // called with xxyx.yuu:(test,test)
58808 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58810 // raw.. - :raw modifier..
58811 return "'"+ sep + udef_st + name + ")"+sep+"'";
58815 // branched to use + in gecko and [].join() in others
58817 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58818 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58821 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58822 body.push(tpl.body.replace(/(\r\n|\n)/g,
58823 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58824 body.push("'].join('');};};");
58825 body = body.join('');
58828 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58830 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58836 applyTemplate : function(values){
58837 return this.master.compiled.call(this, values, {});
58838 //var s = this.subs;
58841 apply : function(){
58842 return this.applyTemplate.apply(this, arguments);
58847 Roo.XTemplate.from = function(el){
58848 el = Roo.getDom(el);
58849 return new Roo.XTemplate(el.value || el.innerHTML);