4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isGecko = !isSafari && ua.indexOf("gecko") > -1,
61 isBorderBox = isIE && !isStrict,
62 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64 isLinux = (ua.indexOf("linux") != -1),
65 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66 isIOS = /iphone|ipad/.test(ua),
67 isTouch = (function() {
69 document.createEvent("TouchEvent");
76 // remove css image flicker
79 document.execCommand("BackgroundImageCache", false, true);
85 * True if the browser is in strict mode
90 * True if the page is running over SSL
95 * True when the document is fully initialized and ready for action
100 * Turn on debugging output (currently only the factory uses this)
107 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
110 enableGarbageCollector : true,
113 * True to automatically purge event listeners after uncaching an element (defaults to false).
114 * Note: this only happens if enableGarbageCollector is true.
117 enableListenerCollection:false,
120 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
121 * the IE insecure content warning (defaults to javascript:false).
124 SSL_SECURE_URL : "javascript:false",
127 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
128 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
131 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
133 emptyFn : function(){},
136 * Copies all the properties of config to obj if they don't already exist.
137 * @param {Object} obj The receiver of the properties
138 * @param {Object} config The source of the properties
139 * @return {Object} returns obj
141 applyIf : function(o, c){
144 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
151 * Applies event listeners to elements by selectors when the document is ready.
152 * The event name is specified with an @ suffix.
155 // add a listener for click on all anchors in element with id foo
156 '#foo a@click' : function(e, t){
160 // add the same listener to multiple selectors (separated by comma BEFORE the @)
161 '#foo a, #bar span.some-class@mouseover' : function(){
166 * @param {Object} obj The list of behaviors to apply
168 addBehaviors : function(o){
170 Roo.onReady(function(){
175 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
177 var parts = b.split('@');
178 if(parts[1]){ // for Object prototype breakers
181 cache[s] = Roo.select(s);
183 cache[s].on(parts[1], o[b]);
190 * Generates unique ids. If the element already has an id, it is unchanged
191 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
192 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
193 * @return {String} The generated Id.
195 id : function(el, prefix){
196 prefix = prefix || "roo-gen";
198 var id = prefix + (++idSeed);
199 return el ? (el.id ? el.id : (el.id = id)) : id;
204 * Extends one class with another class and optionally overrides members with the passed literal. This class
205 * also adds the function "override()" to the class that can be used to override
206 * members on an instance.
207 * @param {Object} subclass The class inheriting the functionality
208 * @param {Object} superclass The class being extended
209 * @param {Object} overrides (optional) A literal with members
214 var io = function(o){
219 return function(sb, sp, overrides){
220 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
223 sb = function(){sp.apply(this, arguments);};
225 var F = function(){}, sbp, spp = sp.prototype;
227 sbp = sb.prototype = new F();
231 if(spp.constructor == Object.prototype.constructor){
236 sb.override = function(o){
240 Roo.override(sb, overrides);
246 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
248 Roo.override(MyClass, {
249 newMethod1: function(){
252 newMethod2: function(foo){
257 * @param {Object} origclass The class to override
258 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
259 * containing one or more methods.
262 override : function(origclass, overrides){
264 var p = origclass.prototype;
265 for(var method in overrides){
266 p[method] = overrides[method];
271 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
273 Roo.namespace('Company', 'Company.data');
274 Company.Widget = function() { ... }
275 Company.data.CustomStore = function(config) { ... }
277 * @param {String} namespace1
278 * @param {String} namespace2
279 * @param {String} etc
282 namespace : function(){
283 var a=arguments, o=null, i, j, d, rt;
284 for (i=0; i<a.length; ++i) {
288 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
289 for (j=1; j<d.length; ++j) {
290 o[d[j]]=o[d[j]] || {};
296 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
298 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
299 Roo.factory(conf, Roo.data);
301 * @param {String} classname
302 * @param {String} namespace (optional)
306 factory : function(c, ns)
308 // no xtype, no ns or c.xns - or forced off by c.xns
309 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
312 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
313 if (c.constructor == ns[c.xtype]) {// already created...
317 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
318 var ret = new ns[c.xtype](c);
322 c.xns = false; // prevent recursion..
326 * Logs to console if it can.
328 * @param {String|Object} string
333 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
340 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
344 urlEncode : function(o){
350 var ov = o[key], k = Roo.encodeURIComponent(key);
351 var type = typeof ov;
352 if(type == 'undefined'){
354 }else if(type != "function" && type != "object"){
355 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
356 }else if(ov instanceof Array){
358 for(var i = 0, len = ov.length; i < len; i++) {
359 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
370 * Safe version of encodeURIComponent
371 * @param {String} data
375 encodeURIComponent : function (data)
378 return encodeURIComponent(data);
379 } catch(e) {} // should be an uri encode error.
381 if (data == '' || data == null){
384 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
385 function nibble_to_hex(nibble){
386 var chars = '0123456789ABCDEF';
387 return chars.charAt(nibble);
389 data = data.toString();
391 for(var i=0; i<data.length; i++){
392 var c = data.charCodeAt(i);
393 var bs = new Array();
396 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
397 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
398 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
399 bs[3] = 0x80 | (c & 0x3F);
400 }else if (c > 0x800){
402 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
403 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
404 bs[2] = 0x80 | (c & 0x3F);
407 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
408 bs[1] = 0x80 | (c & 0x3F);
413 for(var j=0; j<bs.length; j++){
415 var hex = nibble_to_hex((b & 0xF0) >>> 4)
416 + nibble_to_hex(b &0x0F);
425 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
426 * @param {String} string
427 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
428 * @return {Object} A literal with members
430 urlDecode : function(string, overwrite){
431 if(!string || !string.length){
435 var pairs = string.split('&');
436 var pair, name, value;
437 for(var i = 0, len = pairs.length; i < len; i++){
438 pair = pairs[i].split('=');
439 name = decodeURIComponent(pair[0]);
440 value = decodeURIComponent(pair[1]);
441 if(overwrite !== true){
442 if(typeof obj[name] == "undefined"){
444 }else if(typeof obj[name] == "string"){
445 obj[name] = [obj[name]];
446 obj[name].push(value);
448 obj[name].push(value);
458 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
459 * passed array is not really an array, your function is called once with it.
460 * The supplied function is called with (Object item, Number index, Array allItems).
461 * @param {Array/NodeList/Mixed} array
462 * @param {Function} fn
463 * @param {Object} scope
465 each : function(array, fn, scope){
466 if(typeof array.length == "undefined" || typeof array == "string"){
469 for(var i = 0, len = array.length; i < len; i++){
470 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
475 combine : function(){
476 var as = arguments, l = as.length, r = [];
477 for(var i = 0; i < l; i++){
479 if(a instanceof Array){
481 }else if(a.length !== undefined && !a.substr){
482 r = r.concat(Array.prototype.slice.call(a, 0));
491 * Escapes the passed string for use in a regular expression
492 * @param {String} str
495 escapeRe : function(s) {
496 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
500 callback : function(cb, scope, args, delay){
501 if(typeof cb == "function"){
503 cb.defer(delay, scope, args || []);
505 cb.apply(scope, args || []);
511 * Return the dom node for the passed string (id), dom node, or Roo.Element
512 * @param {String/HTMLElement/Roo.Element} el
513 * @return HTMLElement
515 getDom : function(el){
519 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
523 * Shorthand for {@link Roo.ComponentMgr#get}
525 * @return Roo.Component
527 getCmp : function(id){
528 return Roo.ComponentMgr.get(id);
531 num : function(v, defaultValue){
532 if(typeof v != 'number'){
538 destroy : function(){
539 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
543 as.removeAllListeners();
547 if(typeof as.purgeListeners == 'function'){
550 if(typeof as.destroy == 'function'){
557 // inpired by a similar function in mootools library
559 * Returns the type of object that is passed in. If the object passed in is null or undefined it
560 * return false otherwise it returns one of the following values:<ul>
561 * <li><b>string</b>: If the object passed is a string</li>
562 * <li><b>number</b>: If the object passed is a number</li>
563 * <li><b>boolean</b>: If the object passed is a boolean value</li>
564 * <li><b>function</b>: If the object passed is a function reference</li>
565 * <li><b>object</b>: If the object passed is an object</li>
566 * <li><b>array</b>: If the object passed is an array</li>
567 * <li><b>regexp</b>: If the object passed is a regular expression</li>
568 * <li><b>element</b>: If the object passed is a DOM Element</li>
569 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
570 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
571 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
572 * @param {Mixed} object
576 if(o === undefined || o === null){
583 if(t == 'object' && o.nodeName) {
585 case 1: return 'element';
586 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
589 if(t == 'object' || t == 'function') {
590 switch(o.constructor) {
591 case Array: return 'array';
592 case RegExp: return 'regexp';
594 if(typeof o.length == 'number' && typeof o.item == 'function') {
602 * Returns true if the passed value is null, undefined or an empty string (optional).
603 * @param {Mixed} value The value to test
604 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
607 isEmpty : function(v, allowBlank){
608 return v === null || v === undefined || (!allowBlank ? v === '' : false);
616 isFirefox : isFirefox,
626 isBorderBox : isBorderBox,
628 isWindows : isWindows,
639 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
640 * you may want to set this to true.
643 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
648 * Selects a single element as a Roo Element
649 * This is about as close as you can get to jQuery's $('do crazy stuff')
650 * @param {String} selector The selector/xpath query
651 * @param {Node} root (optional) The start of the query (defaults to document).
652 * @return {Roo.Element}
654 selectNode : function(selector, root)
656 var node = Roo.DomQuery.selectNode(selector,root);
657 return node ? Roo.get(node) : new Roo.Element(false);
665 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
666 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
669 "Roo.bootstrap.dash");
672 * Ext JS Library 1.1.1
673 * Copyright(c) 2006-2007, Ext JS, LLC.
675 * Originally Released Under LGPL - original licence link has changed is not relivant.
678 * <script type="text/javascript">
682 // wrappedn so fnCleanup is not in global scope...
684 function fnCleanUp() {
685 var p = Function.prototype;
686 delete p.createSequence;
688 delete p.createDelegate;
689 delete p.createCallback;
690 delete p.createInterceptor;
692 window.detachEvent("onunload", fnCleanUp);
694 window.attachEvent("onunload", fnCleanUp);
701 * These functions are available on every Function object (any JavaScript function).
703 Roo.apply(Function.prototype, {
705 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
706 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
707 * Will create a function that is bound to those 2 args.
708 * @return {Function} The new function
710 createCallback : function(/*args...*/){
711 // make args available, in function below
712 var args = arguments;
715 return method.apply(window, args);
720 * Creates a delegate (callback) that sets the scope to obj.
721 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
722 * Will create a function that is automatically scoped to this.
723 * @param {Object} obj (optional) The object for which the scope is set
724 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
725 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
726 * if a number the args are inserted at the specified position
727 * @return {Function} The new function
729 createDelegate : function(obj, args, appendArgs){
732 var callArgs = args || arguments;
733 if(appendArgs === true){
734 callArgs = Array.prototype.slice.call(arguments, 0);
735 callArgs = callArgs.concat(args);
736 }else if(typeof appendArgs == "number"){
737 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
738 var applyArgs = [appendArgs, 0].concat(args); // create method call params
739 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
741 return method.apply(obj || window, callArgs);
746 * Calls this function after the number of millseconds specified.
747 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
748 * @param {Object} obj (optional) The object for which the scope is set
749 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
750 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
751 * if a number the args are inserted at the specified position
752 * @return {Number} The timeout id that can be used with clearTimeout
754 defer : function(millis, obj, args, appendArgs){
755 var fn = this.createDelegate(obj, args, appendArgs);
757 return setTimeout(fn, millis);
763 * Create a combined function call sequence of the original function + the passed function.
764 * The resulting function returns the results of the original function.
765 * The passed fcn is called with the parameters of the original function
766 * @param {Function} fcn The function to sequence
767 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
768 * @return {Function} The new function
770 createSequence : function(fcn, scope){
771 if(typeof fcn != "function"){
776 var retval = method.apply(this || window, arguments);
777 fcn.apply(scope || this || window, arguments);
783 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
784 * The resulting function returns the results of the original function.
785 * The passed fcn is called with the parameters of the original function.
787 * @param {Function} fcn The function to call before the original
788 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
789 * @return {Function} The new function
791 createInterceptor : function(fcn, scope){
792 if(typeof fcn != "function"){
799 if(fcn.apply(scope || this || window, arguments) === false){
802 return method.apply(this || window, arguments);
808 * Ext JS Library 1.1.1
809 * Copyright(c) 2006-2007, Ext JS, LLC.
811 * Originally Released Under LGPL - original licence link has changed is not relivant.
814 * <script type="text/javascript">
817 Roo.applyIf(String, {
822 * Escapes the passed string for ' and \
823 * @param {String} string The string to escape
824 * @return {String} The escaped string
827 escape : function(string) {
828 return string.replace(/('|\\)/g, "\\$1");
832 * Pads the left side of a string with a specified character. This is especially useful
833 * for normalizing number and date strings. Example usage:
835 var s = String.leftPad('123', 5, '0');
836 // s now contains the string: '00123'
838 * @param {String} string The original string
839 * @param {Number} size The total length of the output string
840 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
841 * @return {String} The padded string
844 leftPad : function (val, size, ch) {
845 var result = new String(val);
846 if(ch === null || ch === undefined || ch === '') {
849 while (result.length < size) {
850 result = ch + result;
856 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
857 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
859 var cls = 'my-class', text = 'Some text';
860 var s = String.format('<div class="{0}">{1}</div>', cls, text);
861 // s now contains the string: '<div class="my-class">Some text</div>'
863 * @param {String} string The tokenized string to be formatted
864 * @param {String} value1 The value to replace token {0}
865 * @param {String} value2 Etc...
866 * @return {String} The formatted string
869 format : function(format){
870 var args = Array.prototype.slice.call(arguments, 1);
871 return format.replace(/\{(\d+)\}/g, function(m, i){
872 return Roo.util.Format.htmlEncode(args[i]);
878 * Utility function that allows you to easily switch a string between two alternating values. The passed value
879 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
880 * they are already different, the first value passed in is returned. Note that this method returns the new value
881 * but does not change the current string.
883 // alternate sort directions
884 sort = sort.toggle('ASC', 'DESC');
886 // instead of conditional logic:
887 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
889 * @param {String} value The value to compare to the current string
890 * @param {String} other The new value to use if the string already equals the first value passed in
891 * @return {String} The new value
894 String.prototype.toggle = function(value, other){
895 return this == value ? other : value;
898 * Ext JS Library 1.1.1
899 * Copyright(c) 2006-2007, Ext JS, LLC.
901 * Originally Released Under LGPL - original licence link has changed is not relivant.
904 * <script type="text/javascript">
910 Roo.applyIf(Number.prototype, {
912 * Checks whether or not the current number is within a desired range. If the number is already within the
913 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
914 * exceeded. Note that this method returns the constrained value but does not change the current number.
915 * @param {Number} min The minimum number in the range
916 * @param {Number} max The maximum number in the range
917 * @return {Number} The constrained value if outside the range, otherwise the current value
919 constrain : function(min, max){
920 return Math.min(Math.max(this, min), max);
924 * Ext JS Library 1.1.1
925 * Copyright(c) 2006-2007, Ext JS, LLC.
927 * Originally Released Under LGPL - original licence link has changed is not relivant.
930 * <script type="text/javascript">
935 Roo.applyIf(Array.prototype, {
938 * Checks whether or not the specified object exists in the array.
939 * @param {Object} o The object to check for
940 * @return {Number} The index of o in the array (or -1 if it is not found)
942 indexOf : function(o){
943 for (var i = 0, len = this.length; i < len; i++){
944 if(this[i] == o) return i;
950 * Removes the specified object from the array. If the object is not found nothing happens.
951 * @param {Object} o The object to remove
953 remove : function(o){
954 var index = this.indexOf(o);
956 this.splice(index, 1);
960 * Map (JS 1.6 compatibility)
961 * @param {Function} function to call
965 var len = this.length >>> 0;
966 if (typeof fun != "function")
967 throw new TypeError();
969 var res = new Array(len);
970 var thisp = arguments[1];
971 for (var i = 0; i < len; i++)
974 res[i] = fun.call(thisp, this[i], i, this);
985 * Ext JS Library 1.1.1
986 * Copyright(c) 2006-2007, Ext JS, LLC.
988 * Originally Released Under LGPL - original licence link has changed is not relivant.
991 * <script type="text/javascript">
997 * The date parsing and format syntax is a subset of
998 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
999 * supported will provide results equivalent to their PHP versions.
1001 * Following is the list of all currently supported formats:
1004 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1006 Format Output Description
1007 ------ ---------- --------------------------------------------------------------
1008 d 10 Day of the month, 2 digits with leading zeros
1009 D Wed A textual representation of a day, three letters
1010 j 10 Day of the month without leading zeros
1011 l Wednesday A full textual representation of the day of the week
1012 S th English ordinal day of month suffix, 2 chars (use with j)
1013 w 3 Numeric representation of the day of the week
1014 z 9 The julian date, or day of the year (0-365)
1015 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1016 F January A full textual representation of the month
1017 m 01 Numeric representation of a month, with leading zeros
1018 M Jan Month name abbreviation, three letters
1019 n 1 Numeric representation of a month, without leading zeros
1020 t 31 Number of days in the given month
1021 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1022 Y 2007 A full numeric representation of a year, 4 digits
1023 y 07 A two digit representation of a year
1024 a pm Lowercase Ante meridiem and Post meridiem
1025 A PM Uppercase Ante meridiem and Post meridiem
1026 g 3 12-hour format of an hour without leading zeros
1027 G 15 24-hour format of an hour without leading zeros
1028 h 03 12-hour format of an hour with leading zeros
1029 H 15 24-hour format of an hour with leading zeros
1030 i 05 Minutes with leading zeros
1031 s 01 Seconds, with leading zeros
1032 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1033 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1034 T CST Timezone setting of the machine running the code
1035 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1038 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1040 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1041 document.write(dt.format('Y-m-d')); //2007-01-10
1042 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1043 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1046 * Here are some standard date/time patterns that you might find helpful. They
1047 * are not part of the source of Date.js, but to use them you can simply copy this
1048 * block of code into any script that is included after Date.js and they will also become
1049 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1052 ISO8601Long:"Y-m-d H:i:s",
1053 ISO8601Short:"Y-m-d",
1055 LongDate: "l, F d, Y",
1056 FullDateTime: "l, F d, Y g:i:s A",
1059 LongTime: "g:i:s A",
1060 SortableDateTime: "Y-m-d\\TH:i:s",
1061 UniversalSortableDateTime: "Y-m-d H:i:sO",
1068 var dt = new Date();
1069 document.write(dt.format(Date.patterns.ShortDate));
1074 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1075 * They generate precompiled functions from date formats instead of parsing and
1076 * processing the pattern every time you format a date. These functions are available
1077 * on every Date object (any javascript function).
1079 * The original article and download are here:
1080 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1087 Returns the number of milliseconds between this date and date
1088 @param {Date} date (optional) Defaults to now
1089 @return {Number} The diff in milliseconds
1090 @member Date getElapsed
1092 Date.prototype.getElapsed = function(date) {
1093 return Math.abs((date || new Date()).getTime()-this.getTime());
1095 // was in date file..
1099 Date.parseFunctions = {count:0};
1101 Date.parseRegexes = [];
1103 Date.formatFunctions = {count:0};
1106 Date.prototype.dateFormat = function(format) {
1107 if (Date.formatFunctions[format] == null) {
1108 Date.createNewFormat(format);
1110 var func = Date.formatFunctions[format];
1111 return this[func]();
1116 * Formats a date given the supplied format string
1117 * @param {String} format The format string
1118 * @return {String} The formatted date
1121 Date.prototype.format = Date.prototype.dateFormat;
1124 Date.createNewFormat = function(format) {
1125 var funcName = "format" + Date.formatFunctions.count++;
1126 Date.formatFunctions[format] = funcName;
1127 var code = "Date.prototype." + funcName + " = function(){return ";
1128 var special = false;
1130 for (var i = 0; i < format.length; ++i) {
1131 ch = format.charAt(i);
1132 if (!special && ch == "\\") {
1137 code += "'" + String.escape(ch) + "' + ";
1140 code += Date.getFormatCode(ch);
1143 /** eval:var:zzzzzzzzzzzzz */
1144 eval(code.substring(0, code.length - 3) + ";}");
1148 Date.getFormatCode = function(character) {
1149 switch (character) {
1151 return "String.leftPad(this.getDate(), 2, '0') + ";
1153 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1155 return "this.getDate() + ";
1157 return "Date.dayNames[this.getDay()] + ";
1159 return "this.getSuffix() + ";
1161 return "this.getDay() + ";
1163 return "this.getDayOfYear() + ";
1165 return "this.getWeekOfYear() + ";
1167 return "Date.monthNames[this.getMonth()] + ";
1169 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1171 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1173 return "(this.getMonth() + 1) + ";
1175 return "this.getDaysInMonth() + ";
1177 return "(this.isLeapYear() ? 1 : 0) + ";
1179 return "this.getFullYear() + ";
1181 return "('' + this.getFullYear()).substring(2, 4) + ";
1183 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1185 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1187 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1189 return "this.getHours() + ";
1191 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1193 return "String.leftPad(this.getHours(), 2, '0') + ";
1195 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1197 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1199 return "this.getGMTOffset() + ";
1201 return "this.getGMTColonOffset() + ";
1203 return "this.getTimezone() + ";
1205 return "(this.getTimezoneOffset() * -60) + ";
1207 return "'" + String.escape(character) + "' + ";
1212 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1213 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1214 * the date format that is not specified will default to the current date value for that part. Time parts can also
1215 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1216 * string or the parse operation will fail.
1219 //dt = Fri May 25 2007 (current date)
1220 var dt = new Date();
1222 //dt = Thu May 25 2006 (today's month/day in 2006)
1223 dt = Date.parseDate("2006", "Y");
1225 //dt = Sun Jan 15 2006 (all date parts specified)
1226 dt = Date.parseDate("2006-1-15", "Y-m-d");
1228 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1229 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1231 * @param {String} input The unparsed date as a string
1232 * @param {String} format The format the date is in
1233 * @return {Date} The parsed date
1236 Date.parseDate = function(input, format) {
1237 if (Date.parseFunctions[format] == null) {
1238 Date.createParser(format);
1240 var func = Date.parseFunctions[format];
1241 return Date[func](input);
1247 Date.createParser = function(format) {
1248 var funcName = "parse" + Date.parseFunctions.count++;
1249 var regexNum = Date.parseRegexes.length;
1250 var currentGroup = 1;
1251 Date.parseFunctions[format] = funcName;
1253 var code = "Date." + funcName + " = function(input){\n"
1254 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1255 + "var d = new Date();\n"
1256 + "y = d.getFullYear();\n"
1257 + "m = d.getMonth();\n"
1258 + "d = d.getDate();\n"
1259 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1260 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1261 + "if (results && results.length > 0) {";
1264 var special = false;
1266 for (var i = 0; i < format.length; ++i) {
1267 ch = format.charAt(i);
1268 if (!special && ch == "\\") {
1273 regex += String.escape(ch);
1276 var obj = Date.formatCodeToRegex(ch, currentGroup);
1277 currentGroup += obj.g;
1279 if (obj.g && obj.c) {
1285 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1286 + "{v = new Date(y, m, d, h, i, s);}\n"
1287 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1288 + "{v = new Date(y, m, d, h, i);}\n"
1289 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1290 + "{v = new Date(y, m, d, h);}\n"
1291 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1292 + "{v = new Date(y, m, d);}\n"
1293 + "else if (y >= 0 && m >= 0)\n"
1294 + "{v = new Date(y, m);}\n"
1295 + "else if (y >= 0)\n"
1296 + "{v = new Date(y);}\n"
1297 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1298 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1299 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1302 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1303 /** eval:var:zzzzzzzzzzzzz */
1308 Date.formatCodeToRegex = function(character, currentGroup) {
1309 switch (character) {
1313 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1316 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1317 s:"(\\d{1,2})"}; // day of month without leading zeroes
1320 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1321 s:"(\\d{2})"}; // day of month with leading zeroes
1325 s:"(?:" + Date.dayNames.join("|") + ")"};
1329 s:"(?:st|nd|rd|th)"};
1344 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1345 s:"(" + Date.monthNames.join("|") + ")"};
1348 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1349 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1352 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1353 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1356 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1357 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1368 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1372 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1373 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1377 c:"if (results[" + currentGroup + "] == 'am') {\n"
1378 + "if (h == 12) { h = 0; }\n"
1379 + "} else { if (h < 12) { h += 12; }}",
1383 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1384 + "if (h == 12) { h = 0; }\n"
1385 + "} else { if (h < 12) { h += 12; }}",
1390 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1391 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1395 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1396 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1399 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1403 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1408 "o = results[", currentGroup, "];\n",
1409 "var sn = o.substring(0,1);\n", // get + / - sign
1410 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1411 "var mn = o.substring(3,5) % 60;\n", // get minutes
1412 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1413 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1415 s:"([+\-]\\d{2,4})"};
1421 "o = results[", currentGroup, "];\n",
1422 "var sn = o.substring(0,1);\n",
1423 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1424 "var mn = o.substring(4,6) % 60;\n",
1425 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1426 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1432 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1435 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1436 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1437 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1441 s:String.escape(character)};
1446 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1447 * @return {String} The abbreviated timezone name (e.g. 'CST')
1449 Date.prototype.getTimezone = function() {
1450 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1454 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1455 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1457 Date.prototype.getGMTOffset = function() {
1458 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1459 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1460 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1464 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1465 * @return {String} 2-characters representing hours and 2-characters representing minutes
1466 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1468 Date.prototype.getGMTColonOffset = function() {
1469 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1470 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1472 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1476 * Get the numeric day number of the year, adjusted for leap year.
1477 * @return {Number} 0 through 364 (365 in leap years)
1479 Date.prototype.getDayOfYear = function() {
1481 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1482 for (var i = 0; i < this.getMonth(); ++i) {
1483 num += Date.daysInMonth[i];
1485 return num + this.getDate() - 1;
1489 * Get the string representation of the numeric week number of the year
1490 * (equivalent to the format specifier 'W').
1491 * @return {String} '00' through '52'
1493 Date.prototype.getWeekOfYear = function() {
1494 // Skip to Thursday of this week
1495 var now = this.getDayOfYear() + (4 - this.getDay());
1496 // Find the first Thursday of the year
1497 var jan1 = new Date(this.getFullYear(), 0, 1);
1498 var then = (7 - jan1.getDay() + 4);
1499 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1503 * Whether or not the current date is in a leap year.
1504 * @return {Boolean} True if the current date is in a leap year, else false
1506 Date.prototype.isLeapYear = function() {
1507 var year = this.getFullYear();
1508 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1512 * Get the first day of the current month, adjusted for leap year. The returned value
1513 * is the numeric day index within the week (0-6) which can be used in conjunction with
1514 * the {@link #monthNames} array to retrieve the textual day name.
1517 var dt = new Date('1/10/2007');
1518 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1520 * @return {Number} The day number (0-6)
1522 Date.prototype.getFirstDayOfMonth = function() {
1523 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1524 return (day < 0) ? (day + 7) : day;
1528 * Get the last day of the current month, adjusted for leap year. The returned value
1529 * is the numeric day index within the week (0-6) which can be used in conjunction with
1530 * the {@link #monthNames} array to retrieve the textual day name.
1533 var dt = new Date('1/10/2007');
1534 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1536 * @return {Number} The day number (0-6)
1538 Date.prototype.getLastDayOfMonth = function() {
1539 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1540 return (day < 0) ? (day + 7) : day;
1545 * Get the first date of this date's month
1548 Date.prototype.getFirstDateOfMonth = function() {
1549 return new Date(this.getFullYear(), this.getMonth(), 1);
1553 * Get the last date of this date's month
1556 Date.prototype.getLastDateOfMonth = function() {
1557 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1560 * Get the number of days in the current month, adjusted for leap year.
1561 * @return {Number} The number of days in the month
1563 Date.prototype.getDaysInMonth = function() {
1564 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1565 return Date.daysInMonth[this.getMonth()];
1569 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1570 * @return {String} 'st, 'nd', 'rd' or 'th'
1572 Date.prototype.getSuffix = function() {
1573 switch (this.getDate()) {
1590 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1593 * An array of textual month names.
1594 * Override these values for international dates, for example...
1595 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1614 * An array of textual day names.
1615 * Override these values for international dates, for example...
1616 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1632 Date.monthNumbers = {
1647 * Creates and returns a new Date instance with the exact same date value as the called instance.
1648 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1649 * variable will also be changed. When the intention is to create a new variable that will not
1650 * modify the original instance, you should create a clone.
1652 * Example of correctly cloning a date:
1655 var orig = new Date('10/1/2006');
1658 document.write(orig); //returns 'Thu Oct 05 2006'!
1661 var orig = new Date('10/1/2006');
1662 var copy = orig.clone();
1664 document.write(orig); //returns 'Thu Oct 01 2006'
1666 * @return {Date} The new Date instance
1668 Date.prototype.clone = function() {
1669 return new Date(this.getTime());
1673 * Clears any time information from this date
1674 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1675 @return {Date} this or the clone
1677 Date.prototype.clearTime = function(clone){
1679 return this.clone().clearTime();
1684 this.setMilliseconds(0);
1689 // safari setMonth is broken
1691 Date.brokenSetMonth = Date.prototype.setMonth;
1692 Date.prototype.setMonth = function(num){
1694 var n = Math.ceil(-num);
1695 var back_year = Math.ceil(n/12);
1696 var month = (n % 12) ? 12 - n % 12 : 0 ;
1697 this.setFullYear(this.getFullYear() - back_year);
1698 return Date.brokenSetMonth.call(this, month);
1700 return Date.brokenSetMonth.apply(this, arguments);
1705 /** Date interval constant
1709 /** Date interval constant
1713 /** Date interval constant
1717 /** Date interval constant
1721 /** Date interval constant
1725 /** Date interval constant
1729 /** Date interval constant
1735 * Provides a convenient method of performing basic date arithmetic. This method
1736 * does not modify the Date instance being called - it creates and returns
1737 * a new Date instance containing the resulting date value.
1742 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1743 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1745 //Negative values will subtract correctly:
1746 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1747 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1749 //You can even chain several calls together in one line!
1750 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1751 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1754 * @param {String} interval A valid date interval enum value
1755 * @param {Number} value The amount to add to the current date
1756 * @return {Date} The new Date instance
1758 Date.prototype.add = function(interval, value){
1759 var d = this.clone();
1760 if (!interval || value === 0) return d;
1761 switch(interval.toLowerCase()){
1763 d.setMilliseconds(this.getMilliseconds() + value);
1766 d.setSeconds(this.getSeconds() + value);
1769 d.setMinutes(this.getMinutes() + value);
1772 d.setHours(this.getHours() + value);
1775 d.setDate(this.getDate() + value);
1778 var day = this.getDate();
1780 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1783 d.setMonth(this.getMonth() + value);
1786 d.setFullYear(this.getFullYear() + value);
1793 * Ext JS Library 1.1.1
1794 * Copyright(c) 2006-2007, Ext JS, LLC.
1796 * Originally Released Under LGPL - original licence link has changed is not relivant.
1799 * <script type="text/javascript">
1803 * @class Roo.lib.Dom
1806 * Dom utils (from YIU afaik)
1811 * Get the view width
1812 * @param {Boolean} full True will get the full document, otherwise it's the view width
1813 * @return {Number} The width
1816 getViewWidth : function(full) {
1817 return full ? this.getDocumentWidth() : this.getViewportWidth();
1820 * Get the view height
1821 * @param {Boolean} full True will get the full document, otherwise it's the view height
1822 * @return {Number} The height
1824 getViewHeight : function(full) {
1825 return full ? this.getDocumentHeight() : this.getViewportHeight();
1828 getDocumentHeight: function() {
1829 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1830 return Math.max(scrollHeight, this.getViewportHeight());
1833 getDocumentWidth: function() {
1834 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1835 return Math.max(scrollWidth, this.getViewportWidth());
1838 getViewportHeight: function() {
1839 var height = self.innerHeight;
1840 var mode = document.compatMode;
1842 if ((mode || Roo.isIE) && !Roo.isOpera) {
1843 height = (mode == "CSS1Compat") ?
1844 document.documentElement.clientHeight :
1845 document.body.clientHeight;
1851 getViewportWidth: function() {
1852 var width = self.innerWidth;
1853 var mode = document.compatMode;
1855 if (mode || Roo.isIE) {
1856 width = (mode == "CSS1Compat") ?
1857 document.documentElement.clientWidth :
1858 document.body.clientWidth;
1863 isAncestor : function(p, c) {
1870 if (p.contains && !Roo.isSafari) {
1871 return p.contains(c);
1872 } else if (p.compareDocumentPosition) {
1873 return !!(p.compareDocumentPosition(c) & 16);
1875 var parent = c.parentNode;
1880 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1883 parent = parent.parentNode;
1889 getRegion : function(el) {
1890 return Roo.lib.Region.getRegion(el);
1893 getY : function(el) {
1894 return this.getXY(el)[1];
1897 getX : function(el) {
1898 return this.getXY(el)[0];
1901 getXY : function(el) {
1902 var p, pe, b, scroll, bd = document.body;
1903 el = Roo.getDom(el);
1904 var fly = Roo.lib.AnimBase.fly;
1905 if (el.getBoundingClientRect) {
1906 b = el.getBoundingClientRect();
1907 scroll = fly(document).getScroll();
1908 return [b.left + scroll.left, b.top + scroll.top];
1914 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1921 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1928 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1929 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1936 if (p != el && pe.getStyle('overflow') != 'visible') {
1944 if (Roo.isSafari && hasAbsolute) {
1949 if (Roo.isGecko && !hasAbsolute) {
1951 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1952 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1956 while (p && p != bd) {
1957 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1969 setXY : function(el, xy) {
1970 el = Roo.fly(el, '_setXY');
1972 var pts = el.translatePoints(xy);
1973 if (xy[0] !== false) {
1974 el.dom.style.left = pts.left + "px";
1976 if (xy[1] !== false) {
1977 el.dom.style.top = pts.top + "px";
1981 setX : function(el, x) {
1982 this.setXY(el, [x, false]);
1985 setY : function(el, y) {
1986 this.setXY(el, [false, y]);
1990 * Portions of this file are based on pieces of Yahoo User Interface Library
1991 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1992 * YUI licensed under the BSD License:
1993 * http://developer.yahoo.net/yui/license.txt
1994 * <script type="text/javascript">
1998 Roo.lib.Event = function() {
1999 var loadComplete = false;
2001 var unloadListeners = [];
2003 var onAvailStack = [];
2005 var lastError = null;
2018 startInterval: function() {
2019 if (!this._interval) {
2021 var callback = function() {
2022 self._tryPreloadAttach();
2024 this._interval = setInterval(callback, this.POLL_INTERVAL);
2029 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2030 onAvailStack.push({ id: p_id,
2033 override: p_override,
2034 checkReady: false });
2036 retryCount = this.POLL_RETRYS;
2037 this.startInterval();
2041 addListener: function(el, eventName, fn) {
2042 el = Roo.getDom(el);
2047 if ("unload" == eventName) {
2048 unloadListeners[unloadListeners.length] =
2049 [el, eventName, fn];
2053 var wrappedFn = function(e) {
2054 return fn(Roo.lib.Event.getEvent(e));
2057 var li = [el, eventName, fn, wrappedFn];
2059 var index = listeners.length;
2060 listeners[index] = li;
2062 this.doAdd(el, eventName, wrappedFn, false);
2068 removeListener: function(el, eventName, fn) {
2071 el = Roo.getDom(el);
2074 return this.purgeElement(el, false, eventName);
2078 if ("unload" == eventName) {
2080 for (i = 0,len = unloadListeners.length; i < len; i++) {
2081 var li = unloadListeners[i];
2084 li[1] == eventName &&
2086 unloadListeners.splice(i, 1);
2094 var cacheItem = null;
2097 var index = arguments[3];
2099 if ("undefined" == typeof index) {
2100 index = this._getCacheIndex(el, eventName, fn);
2104 cacheItem = listeners[index];
2107 if (!el || !cacheItem) {
2111 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2113 delete listeners[index][this.WFN];
2114 delete listeners[index][this.FN];
2115 listeners.splice(index, 1);
2122 getTarget: function(ev, resolveTextNode) {
2123 ev = ev.browserEvent || ev;
2124 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2125 var t = ev.target || ev.srcElement;
2126 return this.resolveTextNode(t);
2130 resolveTextNode: function(node) {
2131 if (Roo.isSafari && node && 3 == node.nodeType) {
2132 return node.parentNode;
2139 getPageX: function(ev) {
2140 ev = ev.browserEvent || ev;
2141 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2143 if (!x && 0 !== x) {
2144 x = ev.clientX || 0;
2147 x += this.getScroll()[1];
2155 getPageY: function(ev) {
2156 ev = ev.browserEvent || ev;
2157 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2159 if (!y && 0 !== y) {
2160 y = ev.clientY || 0;
2163 y += this.getScroll()[0];
2172 getXY: function(ev) {
2173 ev = ev.browserEvent || ev;
2174 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2175 return [this.getPageX(ev), this.getPageY(ev)];
2179 getRelatedTarget: function(ev) {
2180 ev = ev.browserEvent || ev;
2181 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2182 var t = ev.relatedTarget;
2184 if (ev.type == "mouseout") {
2186 } else if (ev.type == "mouseover") {
2191 return this.resolveTextNode(t);
2195 getTime: function(ev) {
2196 ev = ev.browserEvent || ev;
2197 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2199 var t = new Date().getTime();
2203 this.lastError = ex;
2212 stopEvent: function(ev) {
2213 this.stopPropagation(ev);
2214 this.preventDefault(ev);
2218 stopPropagation: function(ev) {
2219 ev = ev.browserEvent || ev;
2220 if (ev.stopPropagation) {
2221 ev.stopPropagation();
2223 ev.cancelBubble = true;
2228 preventDefault: function(ev) {
2229 ev = ev.browserEvent || ev;
2230 if(ev.preventDefault) {
2231 ev.preventDefault();
2233 ev.returnValue = false;
2238 getEvent: function(e) {
2239 var ev = e || window.event;
2241 var c = this.getEvent.caller;
2243 ev = c.arguments[0];
2244 if (ev && Event == ev.constructor) {
2254 getCharCode: function(ev) {
2255 ev = ev.browserEvent || ev;
2256 return ev.charCode || ev.keyCode || 0;
2260 _getCacheIndex: function(el, eventName, fn) {
2261 for (var i = 0,len = listeners.length; i < len; ++i) {
2262 var li = listeners[i];
2264 li[this.FN] == fn &&
2265 li[this.EL] == el &&
2266 li[this.TYPE] == eventName) {
2278 getEl: function(id) {
2279 return document.getElementById(id);
2283 clearCache: function() {
2287 _load: function(e) {
2288 loadComplete = true;
2289 var EU = Roo.lib.Event;
2293 EU.doRemove(window, "load", EU._load);
2298 _tryPreloadAttach: function() {
2307 var tryAgain = !loadComplete;
2309 tryAgain = (retryCount > 0);
2314 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2315 var item = onAvailStack[i];
2317 var el = this.getEl(item.id);
2320 if (!item.checkReady ||
2323 (document && document.body)) {
2326 if (item.override) {
2327 if (item.override === true) {
2330 scope = item.override;
2333 item.fn.call(scope, item.obj);
2334 onAvailStack[i] = null;
2337 notAvail.push(item);
2342 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2346 this.startInterval();
2348 clearInterval(this._interval);
2349 this._interval = null;
2352 this.locked = false;
2359 purgeElement: function(el, recurse, eventName) {
2360 var elListeners = this.getListeners(el, eventName);
2362 for (var i = 0,len = elListeners.length; i < len; ++i) {
2363 var l = elListeners[i];
2364 this.removeListener(el, l.type, l.fn);
2368 if (recurse && el && el.childNodes) {
2369 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2370 this.purgeElement(el.childNodes[i], recurse, eventName);
2376 getListeners: function(el, eventName) {
2377 var results = [], searchLists;
2379 searchLists = [listeners, unloadListeners];
2380 } else if (eventName == "unload") {
2381 searchLists = [unloadListeners];
2383 searchLists = [listeners];
2386 for (var j = 0; j < searchLists.length; ++j) {
2387 var searchList = searchLists[j];
2388 if (searchList && searchList.length > 0) {
2389 for (var i = 0,len = searchList.length; i < len; ++i) {
2390 var l = searchList[i];
2391 if (l && l[this.EL] === el &&
2392 (!eventName || eventName === l[this.TYPE])) {
2397 adjust: l[this.ADJ_SCOPE],
2405 return (results.length) ? results : null;
2409 _unload: function(e) {
2411 var EU = Roo.lib.Event, i, j, l, len, index;
2413 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2414 l = unloadListeners[i];
2417 if (l[EU.ADJ_SCOPE]) {
2418 if (l[EU.ADJ_SCOPE] === true) {
2421 scope = l[EU.ADJ_SCOPE];
2424 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2425 unloadListeners[i] = null;
2431 unloadListeners = null;
2433 if (listeners && listeners.length > 0) {
2434 j = listeners.length;
2437 l = listeners[index];
2439 EU.removeListener(l[EU.EL], l[EU.TYPE],
2449 EU.doRemove(window, "unload", EU._unload);
2454 getScroll: function() {
2455 var dd = document.documentElement, db = document.body;
2456 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2457 return [dd.scrollTop, dd.scrollLeft];
2459 return [db.scrollTop, db.scrollLeft];
2466 doAdd: function () {
2467 if (window.addEventListener) {
2468 return function(el, eventName, fn, capture) {
2469 el.addEventListener(eventName, fn, (capture));
2471 } else if (window.attachEvent) {
2472 return function(el, eventName, fn, capture) {
2473 el.attachEvent("on" + eventName, fn);
2482 doRemove: function() {
2483 if (window.removeEventListener) {
2484 return function (el, eventName, fn, capture) {
2485 el.removeEventListener(eventName, fn, (capture));
2487 } else if (window.detachEvent) {
2488 return function (el, eventName, fn) {
2489 el.detachEvent("on" + eventName, fn);
2501 var E = Roo.lib.Event;
2502 E.on = E.addListener;
2503 E.un = E.removeListener;
2505 if (document && document.body) {
2508 E.doAdd(window, "load", E._load);
2510 E.doAdd(window, "unload", E._unload);
2511 E._tryPreloadAttach();
2515 * Portions of this file are based on pieces of Yahoo User Interface Library
2516 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2517 * YUI licensed under the BSD License:
2518 * http://developer.yahoo.net/yui/license.txt
2519 * <script type="text/javascript">
2525 * @class Roo.lib.Ajax
2532 request : function(method, uri, cb, data, options) {
2534 var hs = options.headers;
2537 if(hs.hasOwnProperty(h)){
2538 this.initHeader(h, hs[h], false);
2542 if(options.xmlData){
2543 this.initHeader('Content-Type', 'text/xml', false);
2545 data = options.xmlData;
2549 return this.asyncRequest(method, uri, cb, data);
2552 serializeForm : function(form) {
2553 if(typeof form == 'string') {
2554 form = (document.getElementById(form) || document.forms[form]);
2557 var el, name, val, disabled, data = '', hasSubmit = false;
2558 for (var i = 0; i < form.elements.length; i++) {
2559 el = form.elements[i];
2560 disabled = form.elements[i].disabled;
2561 name = form.elements[i].name;
2562 val = form.elements[i].value;
2564 if (!disabled && name){
2568 case 'select-multiple':
2569 for (var j = 0; j < el.options.length; j++) {
2570 if (el.options[j].selected) {
2572 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2575 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2583 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2596 if(hasSubmit == false) {
2597 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2602 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2607 data = data.substr(0, data.length - 1);
2615 useDefaultHeader:true,
2617 defaultPostHeader:'application/x-www-form-urlencoded',
2619 useDefaultXhrHeader:true,
2621 defaultXhrHeader:'XMLHttpRequest',
2623 hasDefaultHeaders:true,
2635 setProgId:function(id)
2637 this.activeX.unshift(id);
2640 setDefaultPostHeader:function(b)
2642 this.useDefaultHeader = b;
2645 setDefaultXhrHeader:function(b)
2647 this.useDefaultXhrHeader = b;
2650 setPollingInterval:function(i)
2652 if (typeof i == 'number' && isFinite(i)) {
2653 this.pollInterval = i;
2657 createXhrObject:function(transactionId)
2663 http = new XMLHttpRequest();
2665 obj = { conn:http, tId:transactionId };
2669 for (var i = 0; i < this.activeX.length; ++i) {
2673 http = new ActiveXObject(this.activeX[i]);
2675 obj = { conn:http, tId:transactionId };
2688 getConnectionObject:function()
2691 var tId = this.transactionId;
2695 o = this.createXhrObject(tId);
2697 this.transactionId++;
2708 asyncRequest:function(method, uri, callback, postData)
2710 var o = this.getConnectionObject();
2716 o.conn.open(method, uri, true);
2718 if (this.useDefaultXhrHeader) {
2719 if (!this.defaultHeaders['X-Requested-With']) {
2720 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2724 if(postData && this.useDefaultHeader){
2725 this.initHeader('Content-Type', this.defaultPostHeader);
2728 if (this.hasDefaultHeaders || this.hasHeaders) {
2732 this.handleReadyState(o, callback);
2733 o.conn.send(postData || null);
2739 handleReadyState:function(o, callback)
2743 if (callback && callback.timeout) {
2745 this.timeout[o.tId] = window.setTimeout(function() {
2746 oConn.abort(o, callback, true);
2747 }, callback.timeout);
2750 this.poll[o.tId] = window.setInterval(
2752 if (o.conn && o.conn.readyState == 4) {
2753 window.clearInterval(oConn.poll[o.tId]);
2754 delete oConn.poll[o.tId];
2756 if(callback && callback.timeout) {
2757 window.clearTimeout(oConn.timeout[o.tId]);
2758 delete oConn.timeout[o.tId];
2761 oConn.handleTransactionResponse(o, callback);
2764 , this.pollInterval);
2767 handleTransactionResponse:function(o, callback, isAbort)
2771 this.releaseObject(o);
2775 var httpStatus, responseObject;
2779 if (o.conn.status !== undefined && o.conn.status != 0) {
2780 httpStatus = o.conn.status;
2792 if (httpStatus >= 200 && httpStatus < 300) {
2793 responseObject = this.createResponseObject(o, callback.argument);
2794 if (callback.success) {
2795 if (!callback.scope) {
2796 callback.success(responseObject);
2801 callback.success.apply(callback.scope, [responseObject]);
2806 switch (httpStatus) {
2814 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2815 if (callback.failure) {
2816 if (!callback.scope) {
2817 callback.failure(responseObject);
2820 callback.failure.apply(callback.scope, [responseObject]);
2825 responseObject = this.createResponseObject(o, callback.argument);
2826 if (callback.failure) {
2827 if (!callback.scope) {
2828 callback.failure(responseObject);
2831 callback.failure.apply(callback.scope, [responseObject]);
2837 this.releaseObject(o);
2838 responseObject = null;
2841 createResponseObject:function(o, callbackArg)
2848 var headerStr = o.conn.getAllResponseHeaders();
2849 var header = headerStr.split('\n');
2850 for (var i = 0; i < header.length; i++) {
2851 var delimitPos = header[i].indexOf(':');
2852 if (delimitPos != -1) {
2853 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2861 obj.status = o.conn.status;
2862 obj.statusText = o.conn.statusText;
2863 obj.getResponseHeader = headerObj;
2864 obj.getAllResponseHeaders = headerStr;
2865 obj.responseText = o.conn.responseText;
2866 obj.responseXML = o.conn.responseXML;
2868 if (typeof callbackArg !== undefined) {
2869 obj.argument = callbackArg;
2875 createExceptionObject:function(tId, callbackArg, isAbort)
2878 var COMM_ERROR = 'communication failure';
2879 var ABORT_CODE = -1;
2880 var ABORT_ERROR = 'transaction aborted';
2886 obj.status = ABORT_CODE;
2887 obj.statusText = ABORT_ERROR;
2890 obj.status = COMM_CODE;
2891 obj.statusText = COMM_ERROR;
2895 obj.argument = callbackArg;
2901 initHeader:function(label, value, isDefault)
2903 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2905 if (headerObj[label] === undefined) {
2906 headerObj[label] = value;
2911 headerObj[label] = value + "," + headerObj[label];
2915 this.hasDefaultHeaders = true;
2918 this.hasHeaders = true;
2923 setHeader:function(o)
2925 if (this.hasDefaultHeaders) {
2926 for (var prop in this.defaultHeaders) {
2927 if (this.defaultHeaders.hasOwnProperty(prop)) {
2928 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2933 if (this.hasHeaders) {
2934 for (var prop in this.headers) {
2935 if (this.headers.hasOwnProperty(prop)) {
2936 o.conn.setRequestHeader(prop, this.headers[prop]);
2940 this.hasHeaders = false;
2944 resetDefaultHeaders:function() {
2945 delete this.defaultHeaders;
2946 this.defaultHeaders = {};
2947 this.hasDefaultHeaders = false;
2950 abort:function(o, callback, isTimeout)
2952 if(this.isCallInProgress(o)) {
2954 window.clearInterval(this.poll[o.tId]);
2955 delete this.poll[o.tId];
2957 delete this.timeout[o.tId];
2960 this.handleTransactionResponse(o, callback, true);
2970 isCallInProgress:function(o)
2973 return o.conn.readyState != 4 && o.conn.readyState != 0;
2982 releaseObject:function(o)
2991 'MSXML2.XMLHTTP.3.0',
2999 * Portions of this file are based on pieces of Yahoo User Interface Library
3000 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3001 * YUI licensed under the BSD License:
3002 * http://developer.yahoo.net/yui/license.txt
3003 * <script type="text/javascript">
3007 Roo.lib.Region = function(t, r, b, l) {
3017 Roo.lib.Region.prototype = {
3018 contains : function(region) {
3019 return ( region.left >= this.left &&
3020 region.right <= this.right &&
3021 region.top >= this.top &&
3022 region.bottom <= this.bottom );
3026 getArea : function() {
3027 return ( (this.bottom - this.top) * (this.right - this.left) );
3030 intersect : function(region) {
3031 var t = Math.max(this.top, region.top);
3032 var r = Math.min(this.right, region.right);
3033 var b = Math.min(this.bottom, region.bottom);
3034 var l = Math.max(this.left, region.left);
3036 if (b >= t && r >= l) {
3037 return new Roo.lib.Region(t, r, b, l);
3042 union : function(region) {
3043 var t = Math.min(this.top, region.top);
3044 var r = Math.max(this.right, region.right);
3045 var b = Math.max(this.bottom, region.bottom);
3046 var l = Math.min(this.left, region.left);
3048 return new Roo.lib.Region(t, r, b, l);
3051 adjust : function(t, l, b, r) {
3060 Roo.lib.Region.getRegion = function(el) {
3061 var p = Roo.lib.Dom.getXY(el);
3064 var r = p[0] + el.offsetWidth;
3065 var b = p[1] + el.offsetHeight;
3068 return new Roo.lib.Region(t, r, b, l);
3071 * Portions of this file are based on pieces of Yahoo User Interface Library
3072 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3073 * YUI licensed under the BSD License:
3074 * http://developer.yahoo.net/yui/license.txt
3075 * <script type="text/javascript">
3078 //@@dep Roo.lib.Region
3081 Roo.lib.Point = function(x, y) {
3082 if (x instanceof Array) {
3086 this.x = this.right = this.left = this[0] = x;
3087 this.y = this.top = this.bottom = this[1] = y;
3090 Roo.lib.Point.prototype = new Roo.lib.Region();
3092 * Portions of this file are based on pieces of Yahoo User Interface Library
3093 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3094 * YUI licensed under the BSD License:
3095 * http://developer.yahoo.net/yui/license.txt
3096 * <script type="text/javascript">
3103 scroll : function(el, args, duration, easing, cb, scope) {
3104 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3107 motion : function(el, args, duration, easing, cb, scope) {
3108 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3111 color : function(el, args, duration, easing, cb, scope) {
3112 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3115 run : function(el, args, duration, easing, cb, scope, type) {
3116 type = type || Roo.lib.AnimBase;
3117 if (typeof easing == "string") {
3118 easing = Roo.lib.Easing[easing];
3120 var anim = new type(el, args, duration, easing);
3121 anim.animateX(function() {
3122 Roo.callback(cb, scope);
3128 * Portions of this file are based on pieces of Yahoo User Interface Library
3129 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3130 * YUI licensed under the BSD License:
3131 * http://developer.yahoo.net/yui/license.txt
3132 * <script type="text/javascript">
3140 if (!libFlyweight) {
3141 libFlyweight = new Roo.Element.Flyweight();
3143 libFlyweight.dom = el;
3144 return libFlyweight;
3147 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3151 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3153 this.init(el, attributes, duration, method);
3157 Roo.lib.AnimBase.fly = fly;
3161 Roo.lib.AnimBase.prototype = {
3163 toString: function() {
3164 var el = this.getEl();
3165 var id = el.id || el.tagName;
3166 return ("Anim " + id);
3170 noNegatives: /width|height|opacity|padding/i,
3171 offsetAttribute: /^((width|height)|(top|left))$/,
3172 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3173 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3177 doMethod: function(attr, start, end) {
3178 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3182 setAttribute: function(attr, val, unit) {
3183 if (this.patterns.noNegatives.test(attr)) {
3184 val = (val > 0) ? val : 0;
3187 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3191 getAttribute: function(attr) {
3192 var el = this.getEl();
3193 var val = fly(el).getStyle(attr);
3195 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3196 return parseFloat(val);
3199 var a = this.patterns.offsetAttribute.exec(attr) || [];
3200 var pos = !!( a[3] );
3201 var box = !!( a[2] );
3204 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3205 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3214 getDefaultUnit: function(attr) {
3215 if (this.patterns.defaultUnit.test(attr)) {
3222 animateX : function(callback, scope) {
3223 var f = function() {
3224 this.onComplete.removeListener(f);
3225 if (typeof callback == "function") {
3226 callback.call(scope || this, this);
3229 this.onComplete.addListener(f, this);
3234 setRuntimeAttribute: function(attr) {
3237 var attributes = this.attributes;
3239 this.runtimeAttributes[attr] = {};
3241 var isset = function(prop) {
3242 return (typeof prop !== 'undefined');
3245 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3249 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3252 if (isset(attributes[attr]['to'])) {
3253 end = attributes[attr]['to'];
3254 } else if (isset(attributes[attr]['by'])) {
3255 if (start.constructor == Array) {
3257 for (var i = 0, len = start.length; i < len; ++i) {
3258 end[i] = start[i] + attributes[attr]['by'][i];
3261 end = start + attributes[attr]['by'];
3265 this.runtimeAttributes[attr].start = start;
3266 this.runtimeAttributes[attr].end = end;
3269 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3273 init: function(el, attributes, duration, method) {
3275 var isAnimated = false;
3278 var startTime = null;
3281 var actualFrames = 0;
3284 el = Roo.getDom(el);
3287 this.attributes = attributes || {};
3290 this.duration = duration || 1;
3293 this.method = method || Roo.lib.Easing.easeNone;
3296 this.useSeconds = true;
3299 this.currentFrame = 0;
3302 this.totalFrames = Roo.lib.AnimMgr.fps;
3305 this.getEl = function() {
3310 this.isAnimated = function() {
3315 this.getStartTime = function() {
3319 this.runtimeAttributes = {};
3322 this.animate = function() {
3323 if (this.isAnimated()) {
3327 this.currentFrame = 0;
3329 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3331 Roo.lib.AnimMgr.registerElement(this);
3335 this.stop = function(finish) {
3337 this.currentFrame = this.totalFrames;
3338 this._onTween.fire();
3340 Roo.lib.AnimMgr.stop(this);
3343 var onStart = function() {
3344 this.onStart.fire();
3346 this.runtimeAttributes = {};
3347 for (var attr in this.attributes) {
3348 this.setRuntimeAttribute(attr);
3353 startTime = new Date();
3357 var onTween = function() {
3359 duration: new Date() - this.getStartTime(),
3360 currentFrame: this.currentFrame
3363 data.toString = function() {
3365 'duration: ' + data.duration +
3366 ', currentFrame: ' + data.currentFrame
3370 this.onTween.fire(data);
3372 var runtimeAttributes = this.runtimeAttributes;
3374 for (var attr in runtimeAttributes) {
3375 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3381 var onComplete = function() {
3382 var actual_duration = (new Date() - startTime) / 1000 ;
3385 duration: actual_duration,
3386 frames: actualFrames,
3387 fps: actualFrames / actual_duration
3390 data.toString = function() {
3392 'duration: ' + data.duration +
3393 ', frames: ' + data.frames +
3394 ', fps: ' + data.fps
3400 this.onComplete.fire(data);
3404 this._onStart = new Roo.util.Event(this);
3405 this.onStart = new Roo.util.Event(this);
3406 this.onTween = new Roo.util.Event(this);
3407 this._onTween = new Roo.util.Event(this);
3408 this.onComplete = new Roo.util.Event(this);
3409 this._onComplete = new Roo.util.Event(this);
3410 this._onStart.addListener(onStart);
3411 this._onTween.addListener(onTween);
3412 this._onComplete.addListener(onComplete);
3417 * Portions of this file are based on pieces of Yahoo User Interface Library
3418 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3419 * YUI licensed under the BSD License:
3420 * http://developer.yahoo.net/yui/license.txt
3421 * <script type="text/javascript">
3425 Roo.lib.AnimMgr = new function() {
3442 this.registerElement = function(tween) {
3443 queue[queue.length] = tween;
3445 tween._onStart.fire();
3450 this.unRegister = function(tween, index) {
3451 tween._onComplete.fire();
3452 index = index || getIndex(tween);
3454 queue.splice(index, 1);
3458 if (tweenCount <= 0) {
3464 this.start = function() {
3465 if (thread === null) {
3466 thread = setInterval(this.run, this.delay);
3471 this.stop = function(tween) {
3473 clearInterval(thread);
3475 for (var i = 0, len = queue.length; i < len; ++i) {
3476 if (queue[0].isAnimated()) {
3477 this.unRegister(queue[0], 0);
3486 this.unRegister(tween);
3491 this.run = function() {
3492 for (var i = 0, len = queue.length; i < len; ++i) {
3493 var tween = queue[i];
3494 if (!tween || !tween.isAnimated()) {
3498 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3500 tween.currentFrame += 1;
3502 if (tween.useSeconds) {
3503 correctFrame(tween);
3505 tween._onTween.fire();
3508 Roo.lib.AnimMgr.stop(tween, i);
3513 var getIndex = function(anim) {
3514 for (var i = 0, len = queue.length; i < len; ++i) {
3515 if (queue[i] == anim) {
3523 var correctFrame = function(tween) {
3524 var frames = tween.totalFrames;
3525 var frame = tween.currentFrame;
3526 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3527 var elapsed = (new Date() - tween.getStartTime());
3530 if (elapsed < tween.duration * 1000) {
3531 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3533 tweak = frames - (frame + 1);
3535 if (tweak > 0 && isFinite(tweak)) {
3536 if (tween.currentFrame + tweak >= frames) {
3537 tweak = frames - (frame + 1);
3540 tween.currentFrame += tweak;
3546 * Portions of this file are based on pieces of Yahoo User Interface Library
3547 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3548 * YUI licensed under the BSD License:
3549 * http://developer.yahoo.net/yui/license.txt
3550 * <script type="text/javascript">
3553 Roo.lib.Bezier = new function() {
3555 this.getPosition = function(points, t) {
3556 var n = points.length;
3559 for (var i = 0; i < n; ++i) {
3560 tmp[i] = [points[i][0], points[i][1]];
3563 for (var j = 1; j < n; ++j) {
3564 for (i = 0; i < n - j; ++i) {
3565 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3566 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3570 return [ tmp[0][0], tmp[0][1] ];
3574 * Portions of this file are based on pieces of Yahoo User Interface Library
3575 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3576 * YUI licensed under the BSD License:
3577 * http://developer.yahoo.net/yui/license.txt
3578 * <script type="text/javascript">
3583 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3584 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3587 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3589 var fly = Roo.lib.AnimBase.fly;
3591 var superclass = Y.ColorAnim.superclass;
3592 var proto = Y.ColorAnim.prototype;
3594 proto.toString = function() {
3595 var el = this.getEl();
3596 var id = el.id || el.tagName;
3597 return ("ColorAnim " + id);
3600 proto.patterns.color = /color$/i;
3601 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3602 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3603 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3604 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3607 proto.parseColor = function(s) {
3608 if (s.length == 3) {
3612 var c = this.patterns.hex.exec(s);
3613 if (c && c.length == 4) {
3614 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3617 c = this.patterns.rgb.exec(s);
3618 if (c && c.length == 4) {
3619 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3622 c = this.patterns.hex3.exec(s);
3623 if (c && c.length == 4) {
3624 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3629 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3630 proto.getAttribute = function(attr) {
3631 var el = this.getEl();
3632 if (this.patterns.color.test(attr)) {
3633 var val = fly(el).getStyle(attr);
3635 if (this.patterns.transparent.test(val)) {
3636 var parent = el.parentNode;
3637 val = fly(parent).getStyle(attr);
3639 while (parent && this.patterns.transparent.test(val)) {
3640 parent = parent.parentNode;
3641 val = fly(parent).getStyle(attr);
3642 if (parent.tagName.toUpperCase() == 'HTML') {
3648 val = superclass.getAttribute.call(this, attr);
3653 proto.getAttribute = function(attr) {
3654 var el = this.getEl();
3655 if (this.patterns.color.test(attr)) {
3656 var val = fly(el).getStyle(attr);
3658 if (this.patterns.transparent.test(val)) {
3659 var parent = el.parentNode;
3660 val = fly(parent).getStyle(attr);
3662 while (parent && this.patterns.transparent.test(val)) {
3663 parent = parent.parentNode;
3664 val = fly(parent).getStyle(attr);
3665 if (parent.tagName.toUpperCase() == 'HTML') {
3671 val = superclass.getAttribute.call(this, attr);
3677 proto.doMethod = function(attr, start, end) {
3680 if (this.patterns.color.test(attr)) {
3682 for (var i = 0, len = start.length; i < len; ++i) {
3683 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3686 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3689 val = superclass.doMethod.call(this, attr, start, end);
3695 proto.setRuntimeAttribute = function(attr) {
3696 superclass.setRuntimeAttribute.call(this, attr);
3698 if (this.patterns.color.test(attr)) {
3699 var attributes = this.attributes;
3700 var start = this.parseColor(this.runtimeAttributes[attr].start);
3701 var end = this.parseColor(this.runtimeAttributes[attr].end);
3703 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3704 end = this.parseColor(attributes[attr].by);
3706 for (var i = 0, len = start.length; i < len; ++i) {
3707 end[i] = start[i] + end[i];
3711 this.runtimeAttributes[attr].start = start;
3712 this.runtimeAttributes[attr].end = end;
3718 * Portions of this file are based on pieces of Yahoo User Interface Library
3719 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3720 * YUI licensed under the BSD License:
3721 * http://developer.yahoo.net/yui/license.txt
3722 * <script type="text/javascript">
3728 easeNone: function (t, b, c, d) {
3729 return c * t / d + b;
3733 easeIn: function (t, b, c, d) {
3734 return c * (t /= d) * t + b;
3738 easeOut: function (t, b, c, d) {
3739 return -c * (t /= d) * (t - 2) + b;
3743 easeBoth: function (t, b, c, d) {
3744 if ((t /= d / 2) < 1) {
3745 return c / 2 * t * t + b;
3748 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3752 easeInStrong: function (t, b, c, d) {
3753 return c * (t /= d) * t * t * t + b;
3757 easeOutStrong: function (t, b, c, d) {
3758 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3762 easeBothStrong: function (t, b, c, d) {
3763 if ((t /= d / 2) < 1) {
3764 return c / 2 * t * t * t * t + b;
3767 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3772 elasticIn: function (t, b, c, d, a, p) {
3776 if ((t /= d) == 1) {
3783 if (!a || a < Math.abs(c)) {
3788 var s = p / (2 * Math.PI) * Math.asin(c / a);
3791 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3795 elasticOut: function (t, b, c, d, a, p) {
3799 if ((t /= d) == 1) {
3806 if (!a || a < Math.abs(c)) {
3811 var s = p / (2 * Math.PI) * Math.asin(c / a);
3814 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3818 elasticBoth: function (t, b, c, d, a, p) {
3823 if ((t /= d / 2) == 2) {
3831 if (!a || a < Math.abs(c)) {
3836 var s = p / (2 * Math.PI) * Math.asin(c / a);
3840 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3841 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3843 return a * Math.pow(2, -10 * (t -= 1)) *
3844 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3849 backIn: function (t, b, c, d, s) {
3850 if (typeof s == 'undefined') {
3853 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3857 backOut: function (t, b, c, d, s) {
3858 if (typeof s == 'undefined') {
3861 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3865 backBoth: function (t, b, c, d, s) {
3866 if (typeof s == 'undefined') {
3870 if ((t /= d / 2 ) < 1) {
3871 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3873 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3877 bounceIn: function (t, b, c, d) {
3878 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3882 bounceOut: function (t, b, c, d) {
3883 if ((t /= d) < (1 / 2.75)) {
3884 return c * (7.5625 * t * t) + b;
3885 } else if (t < (2 / 2.75)) {
3886 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3887 } else if (t < (2.5 / 2.75)) {
3888 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3890 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3894 bounceBoth: function (t, b, c, d) {
3896 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3898 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3901 * Portions of this file are based on pieces of Yahoo User Interface Library
3902 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3903 * YUI licensed under the BSD License:
3904 * http://developer.yahoo.net/yui/license.txt
3905 * <script type="text/javascript">
3909 Roo.lib.Motion = function(el, attributes, duration, method) {
3911 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3915 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3919 var superclass = Y.Motion.superclass;
3920 var proto = Y.Motion.prototype;
3922 proto.toString = function() {
3923 var el = this.getEl();
3924 var id = el.id || el.tagName;
3925 return ("Motion " + id);
3928 proto.patterns.points = /^points$/i;
3930 proto.setAttribute = function(attr, val, unit) {
3931 if (this.patterns.points.test(attr)) {
3932 unit = unit || 'px';
3933 superclass.setAttribute.call(this, 'left', val[0], unit);
3934 superclass.setAttribute.call(this, 'top', val[1], unit);
3936 superclass.setAttribute.call(this, attr, val, unit);
3940 proto.getAttribute = function(attr) {
3941 if (this.patterns.points.test(attr)) {
3943 superclass.getAttribute.call(this, 'left'),
3944 superclass.getAttribute.call(this, 'top')
3947 val = superclass.getAttribute.call(this, attr);
3953 proto.doMethod = function(attr, start, end) {
3956 if (this.patterns.points.test(attr)) {
3957 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3958 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3960 val = superclass.doMethod.call(this, attr, start, end);
3965 proto.setRuntimeAttribute = function(attr) {
3966 if (this.patterns.points.test(attr)) {
3967 var el = this.getEl();
3968 var attributes = this.attributes;
3970 var control = attributes['points']['control'] || [];
3974 if (control.length > 0 && !(control[0] instanceof Array)) {
3975 control = [control];
3978 for (i = 0,len = control.length; i < len; ++i) {
3979 tmp[i] = control[i];
3984 Roo.fly(el).position();
3986 if (isset(attributes['points']['from'])) {
3987 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3990 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3993 start = this.getAttribute('points');
3996 if (isset(attributes['points']['to'])) {
3997 end = translateValues.call(this, attributes['points']['to'], start);
3999 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4000 for (i = 0,len = control.length; i < len; ++i) {
4001 control[i] = translateValues.call(this, control[i], start);
4005 } else if (isset(attributes['points']['by'])) {
4006 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4008 for (i = 0,len = control.length; i < len; ++i) {
4009 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4013 this.runtimeAttributes[attr] = [start];
4015 if (control.length > 0) {
4016 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4019 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4022 superclass.setRuntimeAttribute.call(this, attr);
4026 var translateValues = function(val, start) {
4027 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4028 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4033 var isset = function(prop) {
4034 return (typeof prop !== 'undefined');
4038 * Portions of this file are based on pieces of Yahoo User Interface Library
4039 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4040 * YUI licensed under the BSD License:
4041 * http://developer.yahoo.net/yui/license.txt
4042 * <script type="text/javascript">
4046 Roo.lib.Scroll = function(el, attributes, duration, method) {
4048 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4052 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4056 var superclass = Y.Scroll.superclass;
4057 var proto = Y.Scroll.prototype;
4059 proto.toString = function() {
4060 var el = this.getEl();
4061 var id = el.id || el.tagName;
4062 return ("Scroll " + id);
4065 proto.doMethod = function(attr, start, end) {
4068 if (attr == 'scroll') {
4070 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4071 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4075 val = superclass.doMethod.call(this, attr, start, end);
4080 proto.getAttribute = function(attr) {
4082 var el = this.getEl();
4084 if (attr == 'scroll') {
4085 val = [ el.scrollLeft, el.scrollTop ];
4087 val = superclass.getAttribute.call(this, attr);
4093 proto.setAttribute = function(attr, val, unit) {
4094 var el = this.getEl();
4096 if (attr == 'scroll') {
4097 el.scrollLeft = val[0];
4098 el.scrollTop = val[1];
4100 superclass.setAttribute.call(this, attr, val, unit);
4106 * Ext JS Library 1.1.1
4107 * Copyright(c) 2006-2007, Ext JS, LLC.
4109 * Originally Released Under LGPL - original licence link has changed is not relivant.
4112 * <script type="text/javascript">
4116 // nasty IE9 hack - what a pile of crap that is..
4118 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4119 Range.prototype.createContextualFragment = function (html) {
4120 var doc = window.document;
4121 var container = doc.createElement("div");
4122 container.innerHTML = html;
4123 var frag = doc.createDocumentFragment(), n;
4124 while ((n = container.firstChild)) {
4125 frag.appendChild(n);
4132 * @class Roo.DomHelper
4133 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4134 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4137 Roo.DomHelper = function(){
4138 var tempTableEl = null;
4139 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4140 var tableRe = /^table|tbody|tr|td$/i;
4142 // build as innerHTML where available
4144 var createHtml = function(o){
4145 if(typeof o == 'string'){
4154 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4155 if(attr == "style"){
4157 if(typeof s == "function"){
4160 if(typeof s == "string"){
4161 b += ' style="' + s + '"';
4162 }else if(typeof s == "object"){
4165 if(typeof s[key] != "function"){
4166 b += key + ":" + s[key] + ";";
4173 b += ' class="' + o["cls"] + '"';
4174 }else if(attr == "htmlFor"){
4175 b += ' for="' + o["htmlFor"] + '"';
4177 b += " " + attr + '="' + o[attr] + '"';
4181 if(emptyTags.test(o.tag)){
4185 var cn = o.children || o.cn;
4187 //http://bugs.kde.org/show_bug.cgi?id=71506
4188 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4189 for(var i = 0, len = cn.length; i < len; i++) {
4190 b += createHtml(cn[i], b);
4193 b += createHtml(cn, b);
4199 b += "</" + o.tag + ">";
4206 var createDom = function(o, parentNode){
4208 // defininition craeted..
4210 if (o.ns && o.ns != 'html') {
4212 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4213 xmlns[o.ns] = o.xmlns;
4216 if (typeof(xmlns[o.ns]) == 'undefined') {
4217 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4223 if (typeof(o) == 'string') {
4224 return parentNode.appendChild(document.createTextNode(o));
4226 o.tag = o.tag || div;
4227 if (o.ns && Roo.isIE) {
4229 o.tag = o.ns + ':' + o.tag;
4232 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4233 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4236 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4237 attr == "style" || typeof o[attr] == "function") continue;
4239 if(attr=="cls" && Roo.isIE){
4240 el.className = o["cls"];
4242 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4248 Roo.DomHelper.applyStyles(el, o.style);
4249 var cn = o.children || o.cn;
4251 //http://bugs.kde.org/show_bug.cgi?id=71506
4252 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4253 for(var i = 0, len = cn.length; i < len; i++) {
4254 createDom(cn[i], el);
4261 el.innerHTML = o.html;
4264 parentNode.appendChild(el);
4269 var ieTable = function(depth, s, h, e){
4270 tempTableEl.innerHTML = [s, h, e].join('');
4271 var i = -1, el = tempTableEl;
4278 // kill repeat to save bytes
4282 tbe = '</tbody>'+te,
4288 * Nasty code for IE's broken table implementation
4290 var insertIntoTable = function(tag, where, el, html){
4292 tempTableEl = document.createElement('div');
4297 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4300 if(where == 'beforebegin'){
4304 before = el.nextSibling;
4307 node = ieTable(4, trs, html, tre);
4309 else if(tag == 'tr'){
4310 if(where == 'beforebegin'){
4313 node = ieTable(3, tbs, html, tbe);
4314 } else if(where == 'afterend'){
4315 before = el.nextSibling;
4317 node = ieTable(3, tbs, html, tbe);
4318 } else{ // INTO a TR
4319 if(where == 'afterbegin'){
4320 before = el.firstChild;
4322 node = ieTable(4, trs, html, tre);
4324 } else if(tag == 'tbody'){
4325 if(where == 'beforebegin'){
4328 node = ieTable(2, ts, html, te);
4329 } else if(where == 'afterend'){
4330 before = el.nextSibling;
4332 node = ieTable(2, ts, html, te);
4334 if(where == 'afterbegin'){
4335 before = el.firstChild;
4337 node = ieTable(3, tbs, html, tbe);
4340 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4343 if(where == 'afterbegin'){
4344 before = el.firstChild;
4346 node = ieTable(2, ts, html, te);
4348 el.insertBefore(node, before);
4353 /** True to force the use of DOM instead of html fragments @type Boolean */
4357 * Returns the markup for the passed Element(s) config
4358 * @param {Object} o The Dom object spec (and children)
4361 markup : function(o){
4362 return createHtml(o);
4366 * Applies a style specification to an element
4367 * @param {String/HTMLElement} el The element to apply styles to
4368 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4369 * a function which returns such a specification.
4371 applyStyles : function(el, styles){
4374 if(typeof styles == "string"){
4375 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4377 while ((matches = re.exec(styles)) != null){
4378 el.setStyle(matches[1], matches[2]);
4380 }else if (typeof styles == "object"){
4381 for (var style in styles){
4382 el.setStyle(style, styles[style]);
4384 }else if (typeof styles == "function"){
4385 Roo.DomHelper.applyStyles(el, styles.call());
4391 * Inserts an HTML fragment into the Dom
4392 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4393 * @param {HTMLElement} el The context element
4394 * @param {String} html The HTML fragmenet
4395 * @return {HTMLElement} The new node
4397 insertHtml : function(where, el, html){
4398 where = where.toLowerCase();
4399 if(el.insertAdjacentHTML){
4400 if(tableRe.test(el.tagName)){
4402 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4408 el.insertAdjacentHTML('BeforeBegin', html);
4409 return el.previousSibling;
4411 el.insertAdjacentHTML('AfterBegin', html);
4412 return el.firstChild;
4414 el.insertAdjacentHTML('BeforeEnd', html);
4415 return el.lastChild;
4417 el.insertAdjacentHTML('AfterEnd', html);
4418 return el.nextSibling;
4420 throw 'Illegal insertion point -> "' + where + '"';
4422 var range = el.ownerDocument.createRange();
4426 range.setStartBefore(el);
4427 frag = range.createContextualFragment(html);
4428 el.parentNode.insertBefore(frag, el);
4429 return el.previousSibling;
4432 range.setStartBefore(el.firstChild);
4433 frag = range.createContextualFragment(html);
4434 el.insertBefore(frag, el.firstChild);
4435 return el.firstChild;
4437 el.innerHTML = html;
4438 return el.firstChild;
4442 range.setStartAfter(el.lastChild);
4443 frag = range.createContextualFragment(html);
4444 el.appendChild(frag);
4445 return el.lastChild;
4447 el.innerHTML = html;
4448 return el.lastChild;
4451 range.setStartAfter(el);
4452 frag = range.createContextualFragment(html);
4453 el.parentNode.insertBefore(frag, el.nextSibling);
4454 return el.nextSibling;
4456 throw 'Illegal insertion point -> "' + where + '"';
4460 * Creates new Dom element(s) and inserts them before el
4461 * @param {String/HTMLElement/Element} el The context element
4462 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4463 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4464 * @return {HTMLElement/Roo.Element} The new node
4466 insertBefore : function(el, o, returnElement){
4467 return this.doInsert(el, o, returnElement, "beforeBegin");
4471 * Creates new Dom element(s) and inserts them after el
4472 * @param {String/HTMLElement/Element} el The context element
4473 * @param {Object} o The Dom object spec (and children)
4474 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4475 * @return {HTMLElement/Roo.Element} The new node
4477 insertAfter : function(el, o, returnElement){
4478 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4482 * Creates new Dom element(s) and inserts them as the first child of el
4483 * @param {String/HTMLElement/Element} el The context element
4484 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4485 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4486 * @return {HTMLElement/Roo.Element} The new node
4488 insertFirst : function(el, o, returnElement){
4489 return this.doInsert(el, o, returnElement, "afterBegin");
4493 doInsert : function(el, o, returnElement, pos, sibling){
4494 el = Roo.getDom(el);
4496 if(this.useDom || o.ns){
4497 newNode = createDom(o, null);
4498 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4500 var html = createHtml(o);
4501 newNode = this.insertHtml(pos, el, html);
4503 return returnElement ? Roo.get(newNode, true) : newNode;
4507 * Creates new Dom element(s) and appends them to el
4508 * @param {String/HTMLElement/Element} el The context element
4509 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4510 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4511 * @return {HTMLElement/Roo.Element} The new node
4513 append : function(el, o, returnElement){
4514 el = Roo.getDom(el);
4516 if(this.useDom || o.ns){
4517 newNode = createDom(o, null);
4518 el.appendChild(newNode);
4520 var html = createHtml(o);
4521 newNode = this.insertHtml("beforeEnd", el, html);
4523 return returnElement ? Roo.get(newNode, true) : newNode;
4527 * Creates new Dom element(s) and overwrites the contents of el with them
4528 * @param {String/HTMLElement/Element} el The context element
4529 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4530 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4531 * @return {HTMLElement/Roo.Element} The new node
4533 overwrite : function(el, o, returnElement){
4534 el = Roo.getDom(el);
4537 while (el.childNodes.length) {
4538 el.removeChild(el.firstChild);
4542 el.innerHTML = createHtml(o);
4545 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4549 * Creates a new Roo.DomHelper.Template from the Dom object spec
4550 * @param {Object} o The Dom object spec (and children)
4551 * @return {Roo.DomHelper.Template} The new template
4553 createTemplate : function(o){
4554 var html = createHtml(o);
4555 return new Roo.Template(html);
4561 * Ext JS Library 1.1.1
4562 * Copyright(c) 2006-2007, Ext JS, LLC.
4564 * Originally Released Under LGPL - original licence link has changed is not relivant.
4567 * <script type="text/javascript">
4571 * @class Roo.Template
4572 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4573 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4576 var t = new Roo.Template({
4577 html : '<div name="{id}">' +
4578 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4580 myformat: function (value, allValues) {
4581 return 'XX' + value;
4584 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4586 * For more information see this blog post with examples:
4587 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4588 - Create Elements using DOM, HTML fragments and Templates</a>.
4590 * @param {Object} cfg - Configuration object.
4592 Roo.Template = function(cfg){
4594 if(cfg instanceof Array){
4596 }else if(arguments.length > 1){
4597 cfg = Array.prototype.join.call(arguments, "");
4601 if (typeof(cfg) == 'object') {
4612 Roo.Template.prototype = {
4615 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4616 * it should be fixed so that template is observable...
4620 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4624 * Returns an HTML fragment of this template with the specified values applied.
4625 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4626 * @return {String} The HTML fragment
4628 applyTemplate : function(values){
4632 return this.compiled(values);
4634 var useF = this.disableFormats !== true;
4635 var fm = Roo.util.Format, tpl = this;
4636 var fn = function(m, name, format, args){
4638 if(format.substr(0, 5) == "this."){
4639 return tpl.call(format.substr(5), values[name], values);
4642 // quoted values are required for strings in compiled templates,
4643 // but for non compiled we need to strip them
4644 // quoted reversed for jsmin
4645 var re = /^\s*['"](.*)["']\s*$/;
4646 args = args.split(',');
4647 for(var i = 0, len = args.length; i < len; i++){
4648 args[i] = args[i].replace(re, "$1");
4650 args = [values[name]].concat(args);
4652 args = [values[name]];
4654 return fm[format].apply(fm, args);
4657 return values[name] !== undefined ? values[name] : "";
4660 return this.html.replace(this.re, fn);
4678 this.loading = true;
4679 this.compiled = false;
4681 var cx = new Roo.data.Connection();
4685 success : function (response) {
4687 _t.html = response.responseText;
4691 failure : function(response) {
4692 Roo.log("Template failed to load from " + _t.url);
4699 * Sets the HTML used as the template and optionally compiles it.
4700 * @param {String} html
4701 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4702 * @return {Roo.Template} this
4704 set : function(html, compile){
4706 this.compiled = null;
4714 * True to disable format functions (defaults to false)
4717 disableFormats : false,
4720 * The regular expression used to match template variables
4724 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4727 * Compiles the template into an internal function, eliminating the RegEx overhead.
4728 * @return {Roo.Template} this
4730 compile : function(){
4731 var fm = Roo.util.Format;
4732 var useF = this.disableFormats !== true;
4733 var sep = Roo.isGecko ? "+" : ",";
4734 var fn = function(m, name, format, args){
4736 args = args ? ',' + args : "";
4737 if(format.substr(0, 5) != "this."){
4738 format = "fm." + format + '(';
4740 format = 'this.call("'+ format.substr(5) + '", ';
4744 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4746 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4749 // branched to use + in gecko and [].join() in others
4751 body = "this.compiled = function(values){ return '" +
4752 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4755 body = ["this.compiled = function(values){ return ['"];
4756 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4757 body.push("'].join('');};");
4758 body = body.join('');
4768 // private function used to call members
4769 call : function(fnName, value, allValues){
4770 return this[fnName](value, allValues);
4774 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4775 * @param {String/HTMLElement/Roo.Element} el The context element
4776 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4777 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4778 * @return {HTMLElement/Roo.Element} The new node or Element
4780 insertFirst: function(el, values, returnElement){
4781 return this.doInsert('afterBegin', el, values, returnElement);
4785 * Applies the supplied values to the template and inserts the new node(s) before el.
4786 * @param {String/HTMLElement/Roo.Element} el The context element
4787 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4788 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4789 * @return {HTMLElement/Roo.Element} The new node or Element
4791 insertBefore: function(el, values, returnElement){
4792 return this.doInsert('beforeBegin', el, values, returnElement);
4796 * Applies the supplied values to the template and inserts the new node(s) after el.
4797 * @param {String/HTMLElement/Roo.Element} el The context element
4798 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4799 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4800 * @return {HTMLElement/Roo.Element} The new node or Element
4802 insertAfter : function(el, values, returnElement){
4803 return this.doInsert('afterEnd', el, values, returnElement);
4807 * Applies the supplied values to the template and appends the new node(s) to el.
4808 * @param {String/HTMLElement/Roo.Element} el The context element
4809 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4810 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4811 * @return {HTMLElement/Roo.Element} The new node or Element
4813 append : function(el, values, returnElement){
4814 return this.doInsert('beforeEnd', el, values, returnElement);
4817 doInsert : function(where, el, values, returnEl){
4818 el = Roo.getDom(el);
4819 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4820 return returnEl ? Roo.get(newNode, true) : newNode;
4824 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4825 * @param {String/HTMLElement/Roo.Element} el The context element
4826 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4827 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4828 * @return {HTMLElement/Roo.Element} The new node or Element
4830 overwrite : function(el, values, returnElement){
4831 el = Roo.getDom(el);
4832 el.innerHTML = this.applyTemplate(values);
4833 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4837 * Alias for {@link #applyTemplate}
4840 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4843 Roo.DomHelper.Template = Roo.Template;
4846 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4847 * @param {String/HTMLElement} el A DOM element or its id
4848 * @returns {Roo.Template} The created template
4851 Roo.Template.from = function(el){
4852 el = Roo.getDom(el);
4853 return new Roo.Template(el.value || el.innerHTML);
4856 * Ext JS Library 1.1.1
4857 * Copyright(c) 2006-2007, Ext JS, LLC.
4859 * Originally Released Under LGPL - original licence link has changed is not relivant.
4862 * <script type="text/javascript">
4867 * This is code is also distributed under MIT license for use
4868 * with jQuery and prototype JavaScript libraries.
4871 * @class Roo.DomQuery
4872 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4874 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4877 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4879 <h4>Element Selectors:</h4>
4881 <li> <b>*</b> any element</li>
4882 <li> <b>E</b> an element with the tag E</li>
4883 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4884 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4885 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4886 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4888 <h4>Attribute Selectors:</h4>
4889 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4891 <li> <b>E[foo]</b> has an attribute "foo"</li>
4892 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4893 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4894 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4895 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4896 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4897 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4899 <h4>Pseudo Classes:</h4>
4901 <li> <b>E:first-child</b> E is the first child of its parent</li>
4902 <li> <b>E:last-child</b> E is the last child of its parent</li>
4903 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4904 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4905 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4906 <li> <b>E:only-child</b> E is the only child of its parent</li>
4907 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4908 <li> <b>E:first</b> the first E in the resultset</li>
4909 <li> <b>E:last</b> the last E in the resultset</li>
4910 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4911 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4912 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4913 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4914 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4915 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4916 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4917 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4918 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4920 <h4>CSS Value Selectors:</h4>
4922 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4923 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4924 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4925 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4926 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4927 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4931 Roo.DomQuery = function(){
4932 var cache = {}, simpleCache = {}, valueCache = {};
4933 var nonSpace = /\S/;
4934 var trimRe = /^\s+|\s+$/g;
4935 var tplRe = /\{(\d+)\}/g;
4936 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4937 var tagTokenRe = /^(#)?([\w-\*]+)/;
4938 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4940 function child(p, index){
4942 var n = p.firstChild;
4944 if(n.nodeType == 1){
4955 while((n = n.nextSibling) && n.nodeType != 1);
4960 while((n = n.previousSibling) && n.nodeType != 1);
4964 function children(d){
4965 var n = d.firstChild, ni = -1;
4967 var nx = n.nextSibling;
4968 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4978 function byClassName(c, a, v){
4982 var r = [], ri = -1, cn;
4983 for(var i = 0, ci; ci = c[i]; i++){
4984 if((' '+ci.className+' ').indexOf(v) != -1){
4991 function attrValue(n, attr){
4992 if(!n.tagName && typeof n.length != "undefined"){
5001 if(attr == "class" || attr == "className"){
5004 return n.getAttribute(attr) || n[attr];
5008 function getNodes(ns, mode, tagName){
5009 var result = [], ri = -1, cs;
5013 tagName = tagName || "*";
5014 if(typeof ns.getElementsByTagName != "undefined"){
5018 for(var i = 0, ni; ni = ns[i]; i++){
5019 cs = ni.getElementsByTagName(tagName);
5020 for(var j = 0, ci; ci = cs[j]; j++){
5024 }else if(mode == "/" || mode == ">"){
5025 var utag = tagName.toUpperCase();
5026 for(var i = 0, ni, cn; ni = ns[i]; i++){
5027 cn = ni.children || ni.childNodes;
5028 for(var j = 0, cj; cj = cn[j]; j++){
5029 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5034 }else if(mode == "+"){
5035 var utag = tagName.toUpperCase();
5036 for(var i = 0, n; n = ns[i]; i++){
5037 while((n = n.nextSibling) && n.nodeType != 1);
5038 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5042 }else if(mode == "~"){
5043 for(var i = 0, n; n = ns[i]; i++){
5044 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5053 function concat(a, b){
5057 for(var i = 0, l = b.length; i < l; i++){
5063 function byTag(cs, tagName){
5064 if(cs.tagName || cs == document){
5070 var r = [], ri = -1;
5071 tagName = tagName.toLowerCase();
5072 for(var i = 0, ci; ci = cs[i]; i++){
5073 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5080 function byId(cs, attr, id){
5081 if(cs.tagName || cs == document){
5087 var r = [], ri = -1;
5088 for(var i = 0,ci; ci = cs[i]; i++){
5089 if(ci && ci.id == id){
5097 function byAttribute(cs, attr, value, op, custom){
5098 var r = [], ri = -1, st = custom=="{";
5099 var f = Roo.DomQuery.operators[op];
5100 for(var i = 0, ci; ci = cs[i]; i++){
5103 a = Roo.DomQuery.getStyle(ci, attr);
5105 else if(attr == "class" || attr == "className"){
5107 }else if(attr == "for"){
5109 }else if(attr == "href"){
5110 a = ci.getAttribute("href", 2);
5112 a = ci.getAttribute(attr);
5114 if((f && f(a, value)) || (!f && a)){
5121 function byPseudo(cs, name, value){
5122 return Roo.DomQuery.pseudos[name](cs, value);
5125 // This is for IE MSXML which does not support expandos.
5126 // IE runs the same speed using setAttribute, however FF slows way down
5127 // and Safari completely fails so they need to continue to use expandos.
5128 var isIE = window.ActiveXObject ? true : false;
5130 // this eval is stop the compressor from
5131 // renaming the variable to something shorter
5133 /** eval:var:batch */
5138 function nodupIEXml(cs){
5140 cs[0].setAttribute("_nodup", d);
5142 for(var i = 1, len = cs.length; i < len; i++){
5144 if(!c.getAttribute("_nodup") != d){
5145 c.setAttribute("_nodup", d);
5149 for(var i = 0, len = cs.length; i < len; i++){
5150 cs[i].removeAttribute("_nodup");
5159 var len = cs.length, c, i, r = cs, cj, ri = -1;
5160 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5163 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5164 return nodupIEXml(cs);
5168 for(i = 1; c = cs[i]; i++){
5173 for(var j = 0; j < i; j++){
5176 for(j = i+1; cj = cs[j]; j++){
5188 function quickDiffIEXml(c1, c2){
5190 for(var i = 0, len = c1.length; i < len; i++){
5191 c1[i].setAttribute("_qdiff", d);
5194 for(var i = 0, len = c2.length; i < len; i++){
5195 if(c2[i].getAttribute("_qdiff") != d){
5196 r[r.length] = c2[i];
5199 for(var i = 0, len = c1.length; i < len; i++){
5200 c1[i].removeAttribute("_qdiff");
5205 function quickDiff(c1, c2){
5206 var len1 = c1.length;
5210 if(isIE && c1[0].selectSingleNode){
5211 return quickDiffIEXml(c1, c2);
5214 for(var i = 0; i < len1; i++){
5218 for(var i = 0, len = c2.length; i < len; i++){
5219 if(c2[i]._qdiff != d){
5220 r[r.length] = c2[i];
5226 function quickId(ns, mode, root, id){
5228 var d = root.ownerDocument || root;
5229 return d.getElementById(id);
5231 ns = getNodes(ns, mode, "*");
5232 return byId(ns, null, id);
5236 getStyle : function(el, name){
5237 return Roo.fly(el).getStyle(name);
5240 * Compiles a selector/xpath query into a reusable function. The returned function
5241 * takes one parameter "root" (optional), which is the context node from where the query should start.
5242 * @param {String} selector The selector/xpath query
5243 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5244 * @return {Function}
5246 compile : function(path, type){
5247 type = type || "select";
5249 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5250 var q = path, mode, lq;
5251 var tk = Roo.DomQuery.matchers;
5252 var tklen = tk.length;
5255 // accept leading mode switch
5256 var lmode = q.match(modeRe);
5257 if(lmode && lmode[1]){
5258 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5259 q = q.replace(lmode[1], "");
5261 // strip leading slashes
5262 while(path.substr(0, 1)=="/"){
5263 path = path.substr(1);
5266 while(q && lq != q){
5268 var tm = q.match(tagTokenRe);
5269 if(type == "select"){
5272 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5274 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5276 q = q.replace(tm[0], "");
5277 }else if(q.substr(0, 1) != '@'){
5278 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5283 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5285 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5287 q = q.replace(tm[0], "");
5290 while(!(mm = q.match(modeRe))){
5291 var matched = false;
5292 for(var j = 0; j < tklen; j++){
5294 var m = q.match(t.re);
5296 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5299 q = q.replace(m[0], "");
5304 // prevent infinite loop on bad selector
5306 throw 'Error parsing selector, parsing failed at "' + q + '"';
5310 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5311 q = q.replace(mm[1], "");
5314 fn[fn.length] = "return nodup(n);\n}";
5317 * list of variables that need from compression as they are used by eval.
5327 * eval:var:byClassName
5329 * eval:var:byAttribute
5330 * eval:var:attrValue
5338 * Selects a group of elements.
5339 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5340 * @param {Node} root (optional) The start of the query (defaults to document).
5343 select : function(path, root, type){
5344 if(!root || root == document){
5347 if(typeof root == "string"){
5348 root = document.getElementById(root);
5350 var paths = path.split(",");
5352 for(var i = 0, len = paths.length; i < len; i++){
5353 var p = paths[i].replace(trimRe, "");
5355 cache[p] = Roo.DomQuery.compile(p);
5357 throw p + " is not a valid selector";
5360 var result = cache[p](root);
5361 if(result && result != document){
5362 results = results.concat(result);
5365 if(paths.length > 1){
5366 return nodup(results);
5372 * Selects a single element.
5373 * @param {String} selector The selector/xpath query
5374 * @param {Node} root (optional) The start of the query (defaults to document).
5377 selectNode : function(path, root){
5378 return Roo.DomQuery.select(path, root)[0];
5382 * Selects the value of a node, optionally replacing null with the defaultValue.
5383 * @param {String} selector The selector/xpath query
5384 * @param {Node} root (optional) The start of the query (defaults to document).
5385 * @param {String} defaultValue
5387 selectValue : function(path, root, defaultValue){
5388 path = path.replace(trimRe, "");
5389 if(!valueCache[path]){
5390 valueCache[path] = Roo.DomQuery.compile(path, "select");
5392 var n = valueCache[path](root);
5393 n = n[0] ? n[0] : n;
5394 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5395 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5399 * Selects the value of a node, parsing integers and floats.
5400 * @param {String} selector The selector/xpath query
5401 * @param {Node} root (optional) The start of the query (defaults to document).
5402 * @param {Number} defaultValue
5405 selectNumber : function(path, root, defaultValue){
5406 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5407 return parseFloat(v);
5411 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5412 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5413 * @param {String} selector The simple selector to test
5416 is : function(el, ss){
5417 if(typeof el == "string"){
5418 el = document.getElementById(el);
5420 var isArray = (el instanceof Array);
5421 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5422 return isArray ? (result.length == el.length) : (result.length > 0);
5426 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5427 * @param {Array} el An array of elements to filter
5428 * @param {String} selector The simple selector to test
5429 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5430 * the selector instead of the ones that match
5433 filter : function(els, ss, nonMatches){
5434 ss = ss.replace(trimRe, "");
5435 if(!simpleCache[ss]){
5436 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5438 var result = simpleCache[ss](els);
5439 return nonMatches ? quickDiff(result, els) : result;
5443 * Collection of matching regular expressions and code snippets.
5447 select: 'n = byClassName(n, null, " {1} ");'
5449 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5450 select: 'n = byPseudo(n, "{1}", "{2}");'
5452 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5453 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5456 select: 'n = byId(n, null, "{1}");'
5459 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5464 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5465 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5468 "=" : function(a, v){
5471 "!=" : function(a, v){
5474 "^=" : function(a, v){
5475 return a && a.substr(0, v.length) == v;
5477 "$=" : function(a, v){
5478 return a && a.substr(a.length-v.length) == v;
5480 "*=" : function(a, v){
5481 return a && a.indexOf(v) !== -1;
5483 "%=" : function(a, v){
5484 return (a % v) == 0;
5486 "|=" : function(a, v){
5487 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5489 "~=" : function(a, v){
5490 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5495 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5496 * and the argument (if any) supplied in the selector.
5499 "first-child" : function(c){
5500 var r = [], ri = -1, n;
5501 for(var i = 0, ci; ci = n = c[i]; i++){
5502 while((n = n.previousSibling) && n.nodeType != 1);
5510 "last-child" : function(c){
5511 var r = [], ri = -1, n;
5512 for(var i = 0, ci; ci = n = c[i]; i++){
5513 while((n = n.nextSibling) && n.nodeType != 1);
5521 "nth-child" : function(c, a) {
5522 var r = [], ri = -1;
5523 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5524 var f = (m[1] || 1) - 0, l = m[2] - 0;
5525 for(var i = 0, n; n = c[i]; i++){
5526 var pn = n.parentNode;
5527 if (batch != pn._batch) {
5529 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5530 if(cn.nodeType == 1){
5537 if (l == 0 || n.nodeIndex == l){
5540 } else if ((n.nodeIndex + l) % f == 0){
5548 "only-child" : function(c){
5549 var r = [], ri = -1;;
5550 for(var i = 0, ci; ci = c[i]; i++){
5551 if(!prev(ci) && !next(ci)){
5558 "empty" : function(c){
5559 var r = [], ri = -1;
5560 for(var i = 0, ci; ci = c[i]; i++){
5561 var cns = ci.childNodes, j = 0, cn, empty = true;
5564 if(cn.nodeType == 1 || cn.nodeType == 3){
5576 "contains" : function(c, v){
5577 var r = [], ri = -1;
5578 for(var i = 0, ci; ci = c[i]; i++){
5579 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5586 "nodeValue" : function(c, v){
5587 var r = [], ri = -1;
5588 for(var i = 0, ci; ci = c[i]; i++){
5589 if(ci.firstChild && ci.firstChild.nodeValue == v){
5596 "checked" : function(c){
5597 var r = [], ri = -1;
5598 for(var i = 0, ci; ci = c[i]; i++){
5599 if(ci.checked == true){
5606 "not" : function(c, ss){
5607 return Roo.DomQuery.filter(c, ss, true);
5610 "odd" : function(c){
5611 return this["nth-child"](c, "odd");
5614 "even" : function(c){
5615 return this["nth-child"](c, "even");
5618 "nth" : function(c, a){
5619 return c[a-1] || [];
5622 "first" : function(c){
5626 "last" : function(c){
5627 return c[c.length-1] || [];
5630 "has" : function(c, ss){
5631 var s = Roo.DomQuery.select;
5632 var r = [], ri = -1;
5633 for(var i = 0, ci; ci = c[i]; i++){
5634 if(s(ss, ci).length > 0){
5641 "next" : function(c, ss){
5642 var is = Roo.DomQuery.is;
5643 var r = [], ri = -1;
5644 for(var i = 0, ci; ci = c[i]; i++){
5653 "prev" : function(c, ss){
5654 var is = Roo.DomQuery.is;
5655 var r = [], ri = -1;
5656 for(var i = 0, ci; ci = c[i]; i++){
5669 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5670 * @param {String} path The selector/xpath query
5671 * @param {Node} root (optional) The start of the query (defaults to document).
5676 Roo.query = Roo.DomQuery.select;
5679 * Ext JS Library 1.1.1
5680 * Copyright(c) 2006-2007, Ext JS, LLC.
5682 * Originally Released Under LGPL - original licence link has changed is not relivant.
5685 * <script type="text/javascript">
5689 * @class Roo.util.Observable
5690 * Base class that provides a common interface for publishing events. Subclasses are expected to
5691 * to have a property "events" with all the events defined.<br>
5694 Employee = function(name){
5701 Roo.extend(Employee, Roo.util.Observable);
5703 * @param {Object} config properties to use (incuding events / listeners)
5706 Roo.util.Observable = function(cfg){
5709 this.addEvents(cfg.events || {});
5711 delete cfg.events; // make sure
5714 Roo.apply(this, cfg);
5717 this.on(this.listeners);
5718 delete this.listeners;
5721 Roo.util.Observable.prototype = {
5723 * @cfg {Object} listeners list of events and functions to call for this object,
5727 'click' : function(e) {
5737 * Fires the specified event with the passed parameters (minus the event name).
5738 * @param {String} eventName
5739 * @param {Object...} args Variable number of parameters are passed to handlers
5740 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5742 fireEvent : function(){
5743 var ce = this.events[arguments[0].toLowerCase()];
5744 if(typeof ce == "object"){
5745 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5752 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5755 * Appends an event handler to this component
5756 * @param {String} eventName The type of event to listen for
5757 * @param {Function} handler The method the event invokes
5758 * @param {Object} scope (optional) The scope in which to execute the handler
5759 * function. The handler function's "this" context.
5760 * @param {Object} options (optional) An object containing handler configuration
5761 * properties. This may contain any of the following properties:<ul>
5762 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5763 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5764 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5765 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5766 * by the specified number of milliseconds. If the event fires again within that time, the original
5767 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5770 * <b>Combining Options</b><br>
5771 * Using the options argument, it is possible to combine different types of listeners:<br>
5773 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5775 el.on('click', this.onClick, this, {
5782 * <b>Attaching multiple handlers in 1 call</b><br>
5783 * The method also allows for a single argument to be passed which is a config object containing properties
5784 * which specify multiple handlers.
5793 fn: this.onMouseOver,
5797 fn: this.onMouseOut,
5803 * Or a shorthand syntax which passes the same scope object to all handlers:
5806 'click': this.onClick,
5807 'mouseover': this.onMouseOver,
5808 'mouseout': this.onMouseOut,
5813 addListener : function(eventName, fn, scope, o){
5814 if(typeof eventName == "object"){
5817 if(this.filterOptRe.test(e)){
5820 if(typeof o[e] == "function"){
5822 this.addListener(e, o[e], o.scope, o);
5824 // individual options
5825 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5830 o = (!o || typeof o == "boolean") ? {} : o;
5831 eventName = eventName.toLowerCase();
5832 var ce = this.events[eventName] || true;
5833 if(typeof ce == "boolean"){
5834 ce = new Roo.util.Event(this, eventName);
5835 this.events[eventName] = ce;
5837 ce.addListener(fn, scope, o);
5841 * Removes a listener
5842 * @param {String} eventName The type of event to listen for
5843 * @param {Function} handler The handler to remove
5844 * @param {Object} scope (optional) The scope (this object) for the handler
5846 removeListener : function(eventName, fn, scope){
5847 var ce = this.events[eventName.toLowerCase()];
5848 if(typeof ce == "object"){
5849 ce.removeListener(fn, scope);
5854 * Removes all listeners for this object
5856 purgeListeners : function(){
5857 for(var evt in this.events){
5858 if(typeof this.events[evt] == "object"){
5859 this.events[evt].clearListeners();
5864 relayEvents : function(o, events){
5865 var createHandler = function(ename){
5867 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5870 for(var i = 0, len = events.length; i < len; i++){
5871 var ename = events[i];
5872 if(!this.events[ename]){ this.events[ename] = true; };
5873 o.on(ename, createHandler(ename), this);
5878 * Used to define events on this Observable
5879 * @param {Object} object The object with the events defined
5881 addEvents : function(o){
5885 Roo.applyIf(this.events, o);
5889 * Checks to see if this object has any listeners for a specified event
5890 * @param {String} eventName The name of the event to check for
5891 * @return {Boolean} True if the event is being listened for, else false
5893 hasListener : function(eventName){
5894 var e = this.events[eventName];
5895 return typeof e == "object" && e.listeners.length > 0;
5899 * Appends an event handler to this element (shorthand for addListener)
5900 * @param {String} eventName The type of event to listen for
5901 * @param {Function} handler The method the event invokes
5902 * @param {Object} scope (optional) The scope in which to execute the handler
5903 * function. The handler function's "this" context.
5904 * @param {Object} options (optional)
5907 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5909 * Removes a listener (shorthand for removeListener)
5910 * @param {String} eventName The type of event to listen for
5911 * @param {Function} handler The handler to remove
5912 * @param {Object} scope (optional) The scope (this object) for the handler
5915 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5918 * Starts capture on the specified Observable. All events will be passed
5919 * to the supplied function with the event name + standard signature of the event
5920 * <b>before</b> the event is fired. If the supplied function returns false,
5921 * the event will not fire.
5922 * @param {Observable} o The Observable to capture
5923 * @param {Function} fn The function to call
5924 * @param {Object} scope (optional) The scope (this object) for the fn
5927 Roo.util.Observable.capture = function(o, fn, scope){
5928 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5932 * Removes <b>all</b> added captures from the Observable.
5933 * @param {Observable} o The Observable to release
5936 Roo.util.Observable.releaseCapture = function(o){
5937 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5942 var createBuffered = function(h, o, scope){
5943 var task = new Roo.util.DelayedTask();
5945 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5949 var createSingle = function(h, e, fn, scope){
5951 e.removeListener(fn, scope);
5952 return h.apply(scope, arguments);
5956 var createDelayed = function(h, o, scope){
5958 var args = Array.prototype.slice.call(arguments, 0);
5959 setTimeout(function(){
5960 h.apply(scope, args);
5965 Roo.util.Event = function(obj, name){
5968 this.listeners = [];
5971 Roo.util.Event.prototype = {
5972 addListener : function(fn, scope, options){
5973 var o = options || {};
5974 scope = scope || this.obj;
5975 if(!this.isListening(fn, scope)){
5976 var l = {fn: fn, scope: scope, options: o};
5979 h = createDelayed(h, o, scope);
5982 h = createSingle(h, this, fn, scope);
5985 h = createBuffered(h, o, scope);
5988 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5989 this.listeners.push(l);
5991 this.listeners = this.listeners.slice(0);
5992 this.listeners.push(l);
5997 findListener : function(fn, scope){
5998 scope = scope || this.obj;
5999 var ls = this.listeners;
6000 for(var i = 0, len = ls.length; i < len; i++){
6002 if(l.fn == fn && l.scope == scope){
6009 isListening : function(fn, scope){
6010 return this.findListener(fn, scope) != -1;
6013 removeListener : function(fn, scope){
6015 if((index = this.findListener(fn, scope)) != -1){
6017 this.listeners.splice(index, 1);
6019 this.listeners = this.listeners.slice(0);
6020 this.listeners.splice(index, 1);
6027 clearListeners : function(){
6028 this.listeners = [];
6032 var ls = this.listeners, scope, len = ls.length;
6035 var args = Array.prototype.slice.call(arguments, 0);
6036 for(var i = 0; i < len; i++){
6038 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6039 this.firing = false;
6043 this.firing = false;
6050 * Ext JS Library 1.1.1
6051 * Copyright(c) 2006-2007, Ext JS, LLC.
6053 * Originally Released Under LGPL - original licence link has changed is not relivant.
6056 * <script type="text/javascript">
6060 * @class Roo.EventManager
6061 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6062 * several useful events directly.
6063 * See {@link Roo.EventObject} for more details on normalized event objects.
6066 Roo.EventManager = function(){
6067 var docReadyEvent, docReadyProcId, docReadyState = false;
6068 var resizeEvent, resizeTask, textEvent, textSize;
6069 var E = Roo.lib.Event;
6070 var D = Roo.lib.Dom;
6075 var fireDocReady = function(){
6077 docReadyState = true;
6080 clearInterval(docReadyProcId);
6082 if(Roo.isGecko || Roo.isOpera) {
6083 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6086 var defer = document.getElementById("ie-deferred-loader");
6088 defer.onreadystatechange = null;
6089 defer.parentNode.removeChild(defer);
6093 docReadyEvent.fire();
6094 docReadyEvent.clearListeners();
6099 var initDocReady = function(){
6100 docReadyEvent = new Roo.util.Event();
6101 if(Roo.isGecko || Roo.isOpera) {
6102 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6104 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6105 var defer = document.getElementById("ie-deferred-loader");
6106 defer.onreadystatechange = function(){
6107 if(this.readyState == "complete"){
6111 }else if(Roo.isSafari){
6112 docReadyProcId = setInterval(function(){
6113 var rs = document.readyState;
6114 if(rs == "complete") {
6119 // no matter what, make sure it fires on load
6120 E.on(window, "load", fireDocReady);
6123 var createBuffered = function(h, o){
6124 var task = new Roo.util.DelayedTask(h);
6126 // create new event object impl so new events don't wipe out properties
6127 e = new Roo.EventObjectImpl(e);
6128 task.delay(o.buffer, h, null, [e]);
6132 var createSingle = function(h, el, ename, fn){
6134 Roo.EventManager.removeListener(el, ename, fn);
6139 var createDelayed = function(h, o){
6141 // create new event object impl so new events don't wipe out properties
6142 e = new Roo.EventObjectImpl(e);
6143 setTimeout(function(){
6148 var transitionEndVal = false;
6150 var transitionEnd = function()
6152 if (transitionEndVal) {
6153 return transitionEndVal;
6155 var el = document.createElement('div');
6157 var transEndEventNames = {
6158 WebkitTransition : 'webkitTransitionEnd',
6159 MozTransition : 'transitionend',
6160 OTransition : 'oTransitionEnd otransitionend',
6161 transition : 'transitionend'
6164 for (var name in transEndEventNames) {
6165 if (el.style[name] !== undefined) {
6166 transitionEndVal = transEndEventNames[name];
6167 return transitionEndVal ;
6173 var listen = function(element, ename, opt, fn, scope){
6174 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6175 fn = fn || o.fn; scope = scope || o.scope;
6176 var el = Roo.getDom(element);
6180 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6183 if (ename == 'transitionend') {
6184 ename = transitionEnd();
6186 var h = function(e){
6187 e = Roo.EventObject.setEvent(e);
6190 t = e.getTarget(o.delegate, el);
6197 if(o.stopEvent === true){
6200 if(o.preventDefault === true){
6203 if(o.stopPropagation === true){
6204 e.stopPropagation();
6207 if(o.normalized === false){
6211 fn.call(scope || el, e, t, o);
6214 h = createDelayed(h, o);
6217 h = createSingle(h, el, ename, fn);
6220 h = createBuffered(h, o);
6222 fn._handlers = fn._handlers || [];
6225 fn._handlers.push([Roo.id(el), ename, h]);
6230 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6231 el.addEventListener("DOMMouseScroll", h, false);
6232 E.on(window, 'unload', function(){
6233 el.removeEventListener("DOMMouseScroll", h, false);
6236 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6237 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6242 var stopListening = function(el, ename, fn){
6243 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6245 for(var i = 0, len = hds.length; i < len; i++){
6247 if(h[0] == id && h[1] == ename){
6254 E.un(el, ename, hd);
6255 el = Roo.getDom(el);
6256 if(ename == "mousewheel" && el.addEventListener){
6257 el.removeEventListener("DOMMouseScroll", hd, false);
6259 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6260 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6264 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6271 * @scope Roo.EventManager
6276 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6277 * object with a Roo.EventObject
6278 * @param {Function} fn The method the event invokes
6279 * @param {Object} scope An object that becomes the scope of the handler
6280 * @param {boolean} override If true, the obj passed in becomes
6281 * the execution scope of the listener
6282 * @return {Function} The wrapped function
6285 wrap : function(fn, scope, override){
6287 Roo.EventObject.setEvent(e);
6288 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6293 * Appends an event handler to an element (shorthand for addListener)
6294 * @param {String/HTMLElement} element The html element or id to assign the
6295 * @param {String} eventName The type of event to listen for
6296 * @param {Function} handler The method the event invokes
6297 * @param {Object} scope (optional) The scope in which to execute the handler
6298 * function. The handler function's "this" context.
6299 * @param {Object} options (optional) An object containing handler configuration
6300 * properties. This may contain any of the following properties:<ul>
6301 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6302 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6303 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6304 * <li>preventDefault {Boolean} True to prevent the default action</li>
6305 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6306 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6307 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6308 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6309 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6310 * by the specified number of milliseconds. If the event fires again within that time, the original
6311 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6314 * <b>Combining Options</b><br>
6315 * Using the options argument, it is possible to combine different types of listeners:<br>
6317 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6319 el.on('click', this.onClick, this, {
6326 * <b>Attaching multiple handlers in 1 call</b><br>
6327 * The method also allows for a single argument to be passed which is a config object containing properties
6328 * which specify multiple handlers.
6338 fn: this.onMouseOver
6347 * Or a shorthand syntax:<br>
6350 'click' : this.onClick,
6351 'mouseover' : this.onMouseOver,
6352 'mouseout' : this.onMouseOut
6356 addListener : function(element, eventName, fn, scope, options){
6357 if(typeof eventName == "object"){
6363 if(typeof o[e] == "function"){
6365 listen(element, e, o, o[e], o.scope);
6367 // individual options
6368 listen(element, e, o[e]);
6373 return listen(element, eventName, options, fn, scope);
6377 * Removes an event handler
6379 * @param {String/HTMLElement} element The id or html element to remove the
6381 * @param {String} eventName The type of event
6382 * @param {Function} fn
6383 * @return {Boolean} True if a listener was actually removed
6385 removeListener : function(element, eventName, fn){
6386 return stopListening(element, eventName, fn);
6390 * Fires when the document is ready (before onload and before images are loaded). Can be
6391 * accessed shorthanded Roo.onReady().
6392 * @param {Function} fn The method the event invokes
6393 * @param {Object} scope An object that becomes the scope of the handler
6394 * @param {boolean} options
6396 onDocumentReady : function(fn, scope, options){
6397 if(docReadyState){ // if it already fired
6398 docReadyEvent.addListener(fn, scope, options);
6399 docReadyEvent.fire();
6400 docReadyEvent.clearListeners();
6406 docReadyEvent.addListener(fn, scope, options);
6410 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6411 * @param {Function} fn The method the event invokes
6412 * @param {Object} scope An object that becomes the scope of the handler
6413 * @param {boolean} options
6415 onWindowResize : function(fn, scope, options){
6417 resizeEvent = new Roo.util.Event();
6418 resizeTask = new Roo.util.DelayedTask(function(){
6419 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6421 E.on(window, "resize", function(){
6423 resizeTask.delay(50);
6425 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6429 resizeEvent.addListener(fn, scope, options);
6433 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6434 * @param {Function} fn The method the event invokes
6435 * @param {Object} scope An object that becomes the scope of the handler
6436 * @param {boolean} options
6438 onTextResize : function(fn, scope, options){
6440 textEvent = new Roo.util.Event();
6441 var textEl = new Roo.Element(document.createElement('div'));
6442 textEl.dom.className = 'x-text-resize';
6443 textEl.dom.innerHTML = 'X';
6444 textEl.appendTo(document.body);
6445 textSize = textEl.dom.offsetHeight;
6446 setInterval(function(){
6447 if(textEl.dom.offsetHeight != textSize){
6448 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6450 }, this.textResizeInterval);
6452 textEvent.addListener(fn, scope, options);
6456 * Removes the passed window resize listener.
6457 * @param {Function} fn The method the event invokes
6458 * @param {Object} scope The scope of handler
6460 removeResizeListener : function(fn, scope){
6462 resizeEvent.removeListener(fn, scope);
6467 fireResize : function(){
6469 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6473 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6477 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6479 textResizeInterval : 50
6484 * @scopeAlias pub=Roo.EventManager
6488 * Appends an event handler to an element (shorthand for addListener)
6489 * @param {String/HTMLElement} element The html element or id to assign the
6490 * @param {String} eventName The type of event to listen for
6491 * @param {Function} handler The method the event invokes
6492 * @param {Object} scope (optional) The scope in which to execute the handler
6493 * function. The handler function's "this" context.
6494 * @param {Object} options (optional) An object containing handler configuration
6495 * properties. This may contain any of the following properties:<ul>
6496 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6497 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6498 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6499 * <li>preventDefault {Boolean} True to prevent the default action</li>
6500 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6501 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6502 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6503 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6504 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6505 * by the specified number of milliseconds. If the event fires again within that time, the original
6506 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6509 * <b>Combining Options</b><br>
6510 * Using the options argument, it is possible to combine different types of listeners:<br>
6512 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6514 el.on('click', this.onClick, this, {
6521 * <b>Attaching multiple handlers in 1 call</b><br>
6522 * The method also allows for a single argument to be passed which is a config object containing properties
6523 * which specify multiple handlers.
6533 fn: this.onMouseOver
6542 * Or a shorthand syntax:<br>
6545 'click' : this.onClick,
6546 'mouseover' : this.onMouseOver,
6547 'mouseout' : this.onMouseOut
6551 pub.on = pub.addListener;
6552 pub.un = pub.removeListener;
6554 pub.stoppedMouseDownEvent = new Roo.util.Event();
6558 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6559 * @param {Function} fn The method the event invokes
6560 * @param {Object} scope An object that becomes the scope of the handler
6561 * @param {boolean} override If true, the obj passed in becomes
6562 * the execution scope of the listener
6566 Roo.onReady = Roo.EventManager.onDocumentReady;
6568 Roo.onReady(function(){
6569 var bd = Roo.get(document.body);
6574 : Roo.isGecko ? "roo-gecko"
6575 : Roo.isOpera ? "roo-opera"
6576 : Roo.isSafari ? "roo-safari" : ""];
6579 cls.push("roo-mac");
6582 cls.push("roo-linux");
6585 cls.push("roo-ios");
6587 if(Roo.isBorderBox){
6588 cls.push('roo-border-box');
6590 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6591 var p = bd.dom.parentNode;
6593 p.className += ' roo-strict';
6596 bd.addClass(cls.join(' '));
6600 * @class Roo.EventObject
6601 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6602 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6605 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6607 var target = e.getTarget();
6610 var myDiv = Roo.get("myDiv");
6611 myDiv.on("click", handleClick);
6613 Roo.EventManager.on("myDiv", 'click', handleClick);
6614 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6618 Roo.EventObject = function(){
6620 var E = Roo.lib.Event;
6622 // safari keypress events for special keys return bad keycodes
6625 63235 : 39, // right
6628 63276 : 33, // page up
6629 63277 : 34, // page down
6630 63272 : 46, // delete
6635 // normalize button clicks
6636 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6637 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6639 Roo.EventObjectImpl = function(e){
6641 this.setEvent(e.browserEvent || e);
6644 Roo.EventObjectImpl.prototype = {
6646 * Used to fix doc tools.
6647 * @scope Roo.EventObject.prototype
6653 /** The normal browser event */
6654 browserEvent : null,
6655 /** The button pressed in a mouse event */
6657 /** True if the shift key was down during the event */
6659 /** True if the control key was down during the event */
6661 /** True if the alt key was down during the event */
6720 setEvent : function(e){
6721 if(e == this || (e && e.browserEvent)){ // already wrapped
6724 this.browserEvent = e;
6726 // normalize buttons
6727 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6728 if(e.type == 'click' && this.button == -1){
6732 this.shiftKey = e.shiftKey;
6733 // mac metaKey behaves like ctrlKey
6734 this.ctrlKey = e.ctrlKey || e.metaKey;
6735 this.altKey = e.altKey;
6736 // in getKey these will be normalized for the mac
6737 this.keyCode = e.keyCode;
6738 // keyup warnings on firefox.
6739 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6740 // cache the target for the delayed and or buffered events
6741 this.target = E.getTarget(e);
6743 this.xy = E.getXY(e);
6746 this.shiftKey = false;
6747 this.ctrlKey = false;
6748 this.altKey = false;
6758 * Stop the event (preventDefault and stopPropagation)
6760 stopEvent : function(){
6761 if(this.browserEvent){
6762 if(this.browserEvent.type == 'mousedown'){
6763 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6765 E.stopEvent(this.browserEvent);
6770 * Prevents the browsers default handling of the event.
6772 preventDefault : function(){
6773 if(this.browserEvent){
6774 E.preventDefault(this.browserEvent);
6779 isNavKeyPress : function(){
6780 var k = this.keyCode;
6781 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6782 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6785 isSpecialKey : function(){
6786 var k = this.keyCode;
6787 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6788 (k == 16) || (k == 17) ||
6789 (k >= 18 && k <= 20) ||
6790 (k >= 33 && k <= 35) ||
6791 (k >= 36 && k <= 39) ||
6792 (k >= 44 && k <= 45);
6795 * Cancels bubbling of the event.
6797 stopPropagation : function(){
6798 if(this.browserEvent){
6799 if(this.type == 'mousedown'){
6800 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6802 E.stopPropagation(this.browserEvent);
6807 * Gets the key code for the event.
6810 getCharCode : function(){
6811 return this.charCode || this.keyCode;
6815 * Returns a normalized keyCode for the event.
6816 * @return {Number} The key code
6818 getKey : function(){
6819 var k = this.keyCode || this.charCode;
6820 return Roo.isSafari ? (safariKeys[k] || k) : k;
6824 * Gets the x coordinate of the event.
6827 getPageX : function(){
6832 * Gets the y coordinate of the event.
6835 getPageY : function(){
6840 * Gets the time of the event.
6843 getTime : function(){
6844 if(this.browserEvent){
6845 return E.getTime(this.browserEvent);
6851 * Gets the page coordinates of the event.
6852 * @return {Array} The xy values like [x, y]
6859 * Gets the target for the event.
6860 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6861 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6862 search as a number or element (defaults to 10 || document.body)
6863 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6864 * @return {HTMLelement}
6866 getTarget : function(selector, maxDepth, returnEl){
6867 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6870 * Gets the related target.
6871 * @return {HTMLElement}
6873 getRelatedTarget : function(){
6874 if(this.browserEvent){
6875 return E.getRelatedTarget(this.browserEvent);
6881 * Normalizes mouse wheel delta across browsers
6882 * @return {Number} The delta
6884 getWheelDelta : function(){
6885 var e = this.browserEvent;
6887 if(e.wheelDelta){ /* IE/Opera. */
6888 delta = e.wheelDelta/120;
6889 }else if(e.detail){ /* Mozilla case. */
6890 delta = -e.detail/3;
6896 * Returns true if the control, meta, shift or alt key was pressed during this event.
6899 hasModifier : function(){
6900 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6904 * Returns true if the target of this event equals el or is a child of el
6905 * @param {String/HTMLElement/Element} el
6906 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6909 within : function(el, related){
6910 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6911 return t && Roo.fly(el).contains(t);
6914 getPoint : function(){
6915 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6919 return new Roo.EventObjectImpl();
6924 * Ext JS Library 1.1.1
6925 * Copyright(c) 2006-2007, Ext JS, LLC.
6927 * Originally Released Under LGPL - original licence link has changed is not relivant.
6930 * <script type="text/javascript">
6934 // was in Composite Element!??!?!
6937 var D = Roo.lib.Dom;
6938 var E = Roo.lib.Event;
6939 var A = Roo.lib.Anim;
6941 // local style camelizing for speed
6943 var camelRe = /(-[a-z])/gi;
6944 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6945 var view = document.defaultView;
6948 * @class Roo.Element
6949 * Represents an Element in the DOM.<br><br>
6952 var el = Roo.get("my-div");
6955 var el = getEl("my-div");
6957 // or with a DOM element
6958 var el = Roo.get(myDivElement);
6960 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6961 * each call instead of constructing a new one.<br><br>
6962 * <b>Animations</b><br />
6963 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6964 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6966 Option Default Description
6967 --------- -------- ---------------------------------------------
6968 duration .35 The duration of the animation in seconds
6969 easing easeOut The YUI easing method
6970 callback none A function to execute when the anim completes
6971 scope this The scope (this) of the callback function
6973 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6974 * manipulate the animation. Here's an example:
6976 var el = Roo.get("my-div");
6981 // default animation
6982 el.setWidth(100, true);
6984 // animation with some options set
6991 // using the "anim" property to get the Anim object
6997 el.setWidth(100, opt);
6999 if(opt.anim.isAnimated()){
7003 * <b> Composite (Collections of) Elements</b><br />
7004 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7005 * @constructor Create a new Element directly.
7006 * @param {String/HTMLElement} element
7007 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
7009 Roo.Element = function(element, forceNew){
7010 var dom = typeof element == "string" ?
7011 document.getElementById(element) : element;
7012 if(!dom){ // invalid id/element
7016 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7017 return Roo.Element.cache[id];
7027 * The DOM element ID
7030 this.id = id || Roo.id(dom);
7033 var El = Roo.Element;
7037 * The element's default display mode (defaults to "")
7040 originalDisplay : "",
7044 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7049 pxReg : '/^\d+(?:\.\d*)?px$/i',
7051 * Sets the element's visibility mode. When setVisible() is called it
7052 * will use this to determine whether to set the visibility or the display property.
7053 * @param visMode Element.VISIBILITY or Element.DISPLAY
7054 * @return {Roo.Element} this
7056 setVisibilityMode : function(visMode){
7057 this.visibilityMode = visMode;
7061 * Convenience method for setVisibilityMode(Element.DISPLAY)
7062 * @param {String} display (optional) What to set display to when visible
7063 * @return {Roo.Element} this
7065 enableDisplayMode : function(display){
7066 this.setVisibilityMode(El.DISPLAY);
7067 if(typeof display != "undefined") this.originalDisplay = display;
7072 * 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)
7073 * @param {String} selector The simple selector to test
7074 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7075 search as a number or element (defaults to 10 || document.body)
7076 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7077 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7079 findParent : function(simpleSelector, maxDepth, returnEl){
7080 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7081 maxDepth = maxDepth || 50;
7082 if(typeof maxDepth != "number"){
7083 stopEl = Roo.getDom(maxDepth);
7086 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7087 if(dq.is(p, simpleSelector)){
7088 return returnEl ? Roo.get(p) : p;
7098 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7099 * @param {String} selector The simple selector to test
7100 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7101 search as a number or element (defaults to 10 || document.body)
7102 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7103 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7105 findParentNode : function(simpleSelector, maxDepth, returnEl){
7106 var p = Roo.fly(this.dom.parentNode, '_internal');
7107 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7111 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7112 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7113 * @param {String} selector The simple selector to test
7114 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7115 search as a number or element (defaults to 10 || document.body)
7116 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7118 up : function(simpleSelector, maxDepth){
7119 return this.findParentNode(simpleSelector, maxDepth, true);
7125 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7126 * @param {String} selector The simple selector to test
7127 * @return {Boolean} True if this element matches the selector, else false
7129 is : function(simpleSelector){
7130 return Roo.DomQuery.is(this.dom, simpleSelector);
7134 * Perform animation on this element.
7135 * @param {Object} args The YUI animation control args
7136 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7137 * @param {Function} onComplete (optional) Function to call when animation completes
7138 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7139 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7140 * @return {Roo.Element} this
7142 animate : function(args, duration, onComplete, easing, animType){
7143 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7148 * @private Internal animation call
7150 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7151 animType = animType || 'run';
7153 var anim = Roo.lib.Anim[animType](
7155 (opt.duration || defaultDur) || .35,
7156 (opt.easing || defaultEase) || 'easeOut',
7158 Roo.callback(cb, this);
7159 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7167 // private legacy anim prep
7168 preanim : function(a, i){
7169 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7173 * Removes worthless text nodes
7174 * @param {Boolean} forceReclean (optional) By default the element
7175 * keeps track if it has been cleaned already so
7176 * you can call this over and over. However, if you update the element and
7177 * need to force a reclean, you can pass true.
7179 clean : function(forceReclean){
7180 if(this.isCleaned && forceReclean !== true){
7184 var d = this.dom, n = d.firstChild, ni = -1;
7186 var nx = n.nextSibling;
7187 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7194 this.isCleaned = true;
7199 calcOffsetsTo : function(el){
7202 var restorePos = false;
7203 if(el.getStyle('position') == 'static'){
7204 el.position('relative');
7209 while(op && op != d && op.tagName != 'HTML'){
7212 op = op.offsetParent;
7215 el.position('static');
7221 * Scrolls this element into view within the passed container.
7222 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7223 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7224 * @return {Roo.Element} this
7226 scrollIntoView : function(container, hscroll){
7227 var c = Roo.getDom(container) || document.body;
7230 var o = this.calcOffsetsTo(c),
7233 b = t+el.offsetHeight,
7234 r = l+el.offsetWidth;
7236 var ch = c.clientHeight;
7237 var ct = parseInt(c.scrollTop, 10);
7238 var cl = parseInt(c.scrollLeft, 10);
7240 var cr = cl + c.clientWidth;
7248 if(hscroll !== false){
7252 c.scrollLeft = r-c.clientWidth;
7259 scrollChildIntoView : function(child, hscroll){
7260 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7264 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7265 * the new height may not be available immediately.
7266 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7267 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7268 * @param {Function} onComplete (optional) Function to call when animation completes
7269 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7270 * @return {Roo.Element} this
7272 autoHeight : function(animate, duration, onComplete, easing){
7273 var oldHeight = this.getHeight();
7275 this.setHeight(1); // force clipping
7276 setTimeout(function(){
7277 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7279 this.setHeight(height);
7281 if(typeof onComplete == "function"){
7285 this.setHeight(oldHeight); // restore original height
7286 this.setHeight(height, animate, duration, function(){
7288 if(typeof onComplete == "function") onComplete();
7289 }.createDelegate(this), easing);
7291 }.createDelegate(this), 0);
7296 * Returns true if this element is an ancestor of the passed element
7297 * @param {HTMLElement/String} el The element to check
7298 * @return {Boolean} True if this element is an ancestor of el, else false
7300 contains : function(el){
7301 if(!el){return false;}
7302 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7306 * Checks whether the element is currently visible using both visibility and display properties.
7307 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7308 * @return {Boolean} True if the element is currently visible, else false
7310 isVisible : function(deep) {
7311 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7312 if(deep !== true || !vis){
7315 var p = this.dom.parentNode;
7316 while(p && p.tagName.toLowerCase() != "body"){
7317 if(!Roo.fly(p, '_isVisible').isVisible()){
7326 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7327 * @param {String} selector The CSS selector
7328 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7329 * @return {CompositeElement/CompositeElementLite} The composite element
7331 select : function(selector, unique){
7332 return El.select(selector, unique, this.dom);
7336 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7337 * @param {String} selector The CSS selector
7338 * @return {Array} An array of the matched nodes
7340 query : function(selector, unique){
7341 return Roo.DomQuery.select(selector, this.dom);
7345 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7346 * @param {String} selector The CSS selector
7347 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7348 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7350 child : function(selector, returnDom){
7351 var n = Roo.DomQuery.selectNode(selector, this.dom);
7352 return returnDom ? n : Roo.get(n);
7356 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7357 * @param {String} selector The CSS selector
7358 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7359 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7361 down : function(selector, returnDom){
7362 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7363 return returnDom ? n : Roo.get(n);
7367 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7368 * @param {String} group The group the DD object is member of
7369 * @param {Object} config The DD config object
7370 * @param {Object} overrides An object containing methods to override/implement on the DD object
7371 * @return {Roo.dd.DD} The DD object
7373 initDD : function(group, config, overrides){
7374 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7375 return Roo.apply(dd, overrides);
7379 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7380 * @param {String} group The group the DDProxy object is member of
7381 * @param {Object} config The DDProxy config object
7382 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7383 * @return {Roo.dd.DDProxy} The DDProxy object
7385 initDDProxy : function(group, config, overrides){
7386 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7387 return Roo.apply(dd, overrides);
7391 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7392 * @param {String} group The group the DDTarget object is member of
7393 * @param {Object} config The DDTarget config object
7394 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7395 * @return {Roo.dd.DDTarget} The DDTarget object
7397 initDDTarget : function(group, config, overrides){
7398 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7399 return Roo.apply(dd, overrides);
7403 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7404 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7405 * @param {Boolean} visible Whether the element is visible
7406 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7407 * @return {Roo.Element} this
7409 setVisible : function(visible, animate){
7411 if(this.visibilityMode == El.DISPLAY){
7412 this.setDisplayed(visible);
7415 this.dom.style.visibility = visible ? "visible" : "hidden";
7418 // closure for composites
7420 var visMode = this.visibilityMode;
7422 this.setOpacity(.01);
7423 this.setVisible(true);
7425 this.anim({opacity: { to: (visible?1:0) }},
7426 this.preanim(arguments, 1),
7427 null, .35, 'easeIn', function(){
7429 if(visMode == El.DISPLAY){
7430 dom.style.display = "none";
7432 dom.style.visibility = "hidden";
7434 Roo.get(dom).setOpacity(1);
7442 * Returns true if display is not "none"
7445 isDisplayed : function() {
7446 return this.getStyle("display") != "none";
7450 * Toggles the element's visibility or display, depending on visibility mode.
7451 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7452 * @return {Roo.Element} this
7454 toggle : function(animate){
7455 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7460 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7461 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7462 * @return {Roo.Element} this
7464 setDisplayed : function(value) {
7465 if(typeof value == "boolean"){
7466 value = value ? this.originalDisplay : "none";
7468 this.setStyle("display", value);
7473 * Tries to focus the element. Any exceptions are caught and ignored.
7474 * @return {Roo.Element} this
7476 focus : function() {
7484 * Tries to blur the element. Any exceptions are caught and ignored.
7485 * @return {Roo.Element} this
7495 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7496 * @param {String/Array} className The CSS class to add, or an array of classes
7497 * @return {Roo.Element} this
7499 addClass : function(className){
7500 if(className instanceof Array){
7501 for(var i = 0, len = className.length; i < len; i++) {
7502 this.addClass(className[i]);
7505 if(className && !this.hasClass(className)){
7506 this.dom.className = this.dom.className + " " + className;
7513 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7514 * @param {String/Array} className The CSS class to add, or an array of classes
7515 * @return {Roo.Element} this
7517 radioClass : function(className){
7518 var siblings = this.dom.parentNode.childNodes;
7519 for(var i = 0; i < siblings.length; i++) {
7520 var s = siblings[i];
7521 if(s.nodeType == 1){
7522 Roo.get(s).removeClass(className);
7525 this.addClass(className);
7530 * Removes one or more CSS classes from the element.
7531 * @param {String/Array} className The CSS class to remove, or an array of classes
7532 * @return {Roo.Element} this
7534 removeClass : function(className){
7535 if(!className || !this.dom.className){
7538 if(className instanceof Array){
7539 for(var i = 0, len = className.length; i < len; i++) {
7540 this.removeClass(className[i]);
7543 if(this.hasClass(className)){
7544 var re = this.classReCache[className];
7546 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7547 this.classReCache[className] = re;
7549 this.dom.className =
7550 this.dom.className.replace(re, " ");
7560 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7561 * @param {String} className The CSS class to toggle
7562 * @return {Roo.Element} this
7564 toggleClass : function(className){
7565 if(this.hasClass(className)){
7566 this.removeClass(className);
7568 this.addClass(className);
7574 * Checks if the specified CSS class exists on this element's DOM node.
7575 * @param {String} className The CSS class to check for
7576 * @return {Boolean} True if the class exists, else false
7578 hasClass : function(className){
7579 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7583 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7584 * @param {String} oldClassName The CSS class to replace
7585 * @param {String} newClassName The replacement CSS class
7586 * @return {Roo.Element} this
7588 replaceClass : function(oldClassName, newClassName){
7589 this.removeClass(oldClassName);
7590 this.addClass(newClassName);
7595 * Returns an object with properties matching the styles requested.
7596 * For example, el.getStyles('color', 'font-size', 'width') might return
7597 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7598 * @param {String} style1 A style name
7599 * @param {String} style2 A style name
7600 * @param {String} etc.
7601 * @return {Object} The style object
7603 getStyles : function(){
7604 var a = arguments, len = a.length, r = {};
7605 for(var i = 0; i < len; i++){
7606 r[a[i]] = this.getStyle(a[i]);
7612 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7613 * @param {String} property The style property whose value is returned.
7614 * @return {String} The current value of the style property for this element.
7616 getStyle : function(){
7617 return view && view.getComputedStyle ?
7619 var el = this.dom, v, cs, camel;
7620 if(prop == 'float'){
7623 if(el.style && (v = el.style[prop])){
7626 if(cs = view.getComputedStyle(el, "")){
7627 if(!(camel = propCache[prop])){
7628 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7635 var el = this.dom, v, cs, camel;
7636 if(prop == 'opacity'){
7637 if(typeof el.style.filter == 'string'){
7638 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7640 var fv = parseFloat(m[1]);
7642 return fv ? fv / 100 : 0;
7647 }else if(prop == 'float'){
7648 prop = "styleFloat";
7650 if(!(camel = propCache[prop])){
7651 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7653 if(v = el.style[camel]){
7656 if(cs = el.currentStyle){
7664 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7665 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7666 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7667 * @return {Roo.Element} this
7669 setStyle : function(prop, value){
7670 if(typeof prop == "string"){
7672 if (prop == 'float') {
7673 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7678 if(!(camel = propCache[prop])){
7679 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7682 if(camel == 'opacity') {
7683 this.setOpacity(value);
7685 this.dom.style[camel] = value;
7688 for(var style in prop){
7689 if(typeof prop[style] != "function"){
7690 this.setStyle(style, prop[style]);
7698 * More flexible version of {@link #setStyle} for setting style properties.
7699 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7700 * a function which returns such a specification.
7701 * @return {Roo.Element} this
7703 applyStyles : function(style){
7704 Roo.DomHelper.applyStyles(this.dom, style);
7709 * 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).
7710 * @return {Number} The X position of the element
7713 return D.getX(this.dom);
7717 * 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).
7718 * @return {Number} The Y position of the element
7721 return D.getY(this.dom);
7725 * 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).
7726 * @return {Array} The XY position of the element
7729 return D.getXY(this.dom);
7733 * 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).
7734 * @param {Number} The X position of the element
7735 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7736 * @return {Roo.Element} this
7738 setX : function(x, animate){
7740 D.setX(this.dom, x);
7742 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7748 * 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).
7749 * @param {Number} The Y position of the element
7750 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7751 * @return {Roo.Element} this
7753 setY : function(y, animate){
7755 D.setY(this.dom, y);
7757 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7763 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7764 * @param {String} left The left CSS property value
7765 * @return {Roo.Element} this
7767 setLeft : function(left){
7768 this.setStyle("left", this.addUnits(left));
7773 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7774 * @param {String} top The top CSS property value
7775 * @return {Roo.Element} this
7777 setTop : function(top){
7778 this.setStyle("top", this.addUnits(top));
7783 * Sets the element's CSS right style.
7784 * @param {String} right The right CSS property value
7785 * @return {Roo.Element} this
7787 setRight : function(right){
7788 this.setStyle("right", this.addUnits(right));
7793 * Sets the element's CSS bottom style.
7794 * @param {String} bottom The bottom CSS property value
7795 * @return {Roo.Element} this
7797 setBottom : function(bottom){
7798 this.setStyle("bottom", this.addUnits(bottom));
7803 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7804 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7805 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7806 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7807 * @return {Roo.Element} this
7809 setXY : function(pos, animate){
7811 D.setXY(this.dom, pos);
7813 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7819 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7820 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7821 * @param {Number} x X value for new position (coordinates are page-based)
7822 * @param {Number} y Y value for new position (coordinates are page-based)
7823 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7824 * @return {Roo.Element} this
7826 setLocation : function(x, y, animate){
7827 this.setXY([x, y], this.preanim(arguments, 2));
7832 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7833 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7834 * @param {Number} x X value for new position (coordinates are page-based)
7835 * @param {Number} y Y value for new position (coordinates are page-based)
7836 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7837 * @return {Roo.Element} this
7839 moveTo : function(x, y, animate){
7840 this.setXY([x, y], this.preanim(arguments, 2));
7845 * Returns the region of the given element.
7846 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7847 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7849 getRegion : function(){
7850 return D.getRegion(this.dom);
7854 * Returns the offset height of the element
7855 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7856 * @return {Number} The element's height
7858 getHeight : function(contentHeight){
7859 var h = this.dom.offsetHeight || 0;
7860 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7864 * Returns the offset width of the element
7865 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7866 * @return {Number} The element's width
7868 getWidth : function(contentWidth){
7869 var w = this.dom.offsetWidth || 0;
7870 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7874 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7875 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7876 * if a height has not been set using CSS.
7879 getComputedHeight : function(){
7880 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7882 h = parseInt(this.getStyle('height'), 10) || 0;
7883 if(!this.isBorderBox()){
7884 h += this.getFrameWidth('tb');
7891 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7892 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7893 * if a width has not been set using CSS.
7896 getComputedWidth : function(){
7897 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7899 w = parseInt(this.getStyle('width'), 10) || 0;
7900 if(!this.isBorderBox()){
7901 w += this.getFrameWidth('lr');
7908 * Returns the size of the element.
7909 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7910 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7912 getSize : function(contentSize){
7913 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7917 * Returns the width and height of the viewport.
7918 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7920 getViewSize : function(){
7921 var d = this.dom, doc = document, aw = 0, ah = 0;
7922 if(d == doc || d == doc.body){
7923 return {width : D.getViewWidth(), height: D.getViewHeight()};
7926 width : d.clientWidth,
7927 height: d.clientHeight
7933 * Returns the value of the "value" attribute
7934 * @param {Boolean} asNumber true to parse the value as a number
7935 * @return {String/Number}
7937 getValue : function(asNumber){
7938 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7942 adjustWidth : function(width){
7943 if(typeof width == "number"){
7944 if(this.autoBoxAdjust && !this.isBorderBox()){
7945 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7955 adjustHeight : function(height){
7956 if(typeof height == "number"){
7957 if(this.autoBoxAdjust && !this.isBorderBox()){
7958 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7968 * Set the width of the element
7969 * @param {Number} width The new width
7970 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7971 * @return {Roo.Element} this
7973 setWidth : function(width, animate){
7974 width = this.adjustWidth(width);
7976 this.dom.style.width = this.addUnits(width);
7978 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7984 * Set the height of the element
7985 * @param {Number} height The new height
7986 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7987 * @return {Roo.Element} this
7989 setHeight : function(height, animate){
7990 height = this.adjustHeight(height);
7992 this.dom.style.height = this.addUnits(height);
7994 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8000 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8001 * @param {Number} width The new width
8002 * @param {Number} height The new height
8003 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8004 * @return {Roo.Element} this
8006 setSize : function(width, height, animate){
8007 if(typeof width == "object"){ // in case of object from getSize()
8008 height = width.height; width = width.width;
8010 width = this.adjustWidth(width); height = this.adjustHeight(height);
8012 this.dom.style.width = this.addUnits(width);
8013 this.dom.style.height = this.addUnits(height);
8015 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8021 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8022 * @param {Number} x X value for new position (coordinates are page-based)
8023 * @param {Number} y Y value for new position (coordinates are page-based)
8024 * @param {Number} width The new width
8025 * @param {Number} height The new height
8026 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8027 * @return {Roo.Element} this
8029 setBounds : function(x, y, width, height, animate){
8031 this.setSize(width, height);
8032 this.setLocation(x, y);
8034 width = this.adjustWidth(width); height = this.adjustHeight(height);
8035 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8036 this.preanim(arguments, 4), 'motion');
8042 * 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.
8043 * @param {Roo.lib.Region} region The region to fill
8044 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8045 * @return {Roo.Element} this
8047 setRegion : function(region, animate){
8048 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8053 * Appends an event handler
8055 * @param {String} eventName The type of event to append
8056 * @param {Function} fn The method the event invokes
8057 * @param {Object} scope (optional) The scope (this object) of the fn
8058 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8060 addListener : function(eventName, fn, scope, options){
8062 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8067 * Removes an event handler from this element
8068 * @param {String} eventName the type of event to remove
8069 * @param {Function} fn the method the event invokes
8070 * @return {Roo.Element} this
8072 removeListener : function(eventName, fn){
8073 Roo.EventManager.removeListener(this.dom, eventName, fn);
8078 * Removes all previous added listeners from this element
8079 * @return {Roo.Element} this
8081 removeAllListeners : function(){
8082 E.purgeElement(this.dom);
8086 relayEvent : function(eventName, observable){
8087 this.on(eventName, function(e){
8088 observable.fireEvent(eventName, e);
8093 * Set the opacity of the element
8094 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8095 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8096 * @return {Roo.Element} this
8098 setOpacity : function(opacity, animate){
8100 var s = this.dom.style;
8103 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8104 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8106 s.opacity = opacity;
8109 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8115 * Gets the left X coordinate
8116 * @param {Boolean} local True to get the local css position instead of page coordinate
8119 getLeft : function(local){
8123 var x = this.getStyle("left");
8125 if(!x || x === 'AUTO'){
8129 if(this.pxReg.test(x)){
8130 return parseFloat(x);
8135 var par = this.dom.offsetParent ? Roo.fly(this.dom.offsetParent) : false;
8137 if (par !== false) {
8146 * Gets the right X coordinate of the element (element X position + element width)
8147 * @param {Boolean} local True to get the local css position instead of page coordinate
8150 getRight : function(local){
8152 return this.getX() + this.getWidth();
8154 return (this.getLeft(true) + this.getWidth()) || 0;
8159 * Gets the top Y coordinate
8160 * @param {Boolean} local True to get the local css position instead of page coordinate
8163 getTop : function(local) {
8167 return parseInt(this.getStyle("top"), 10) || 0;
8172 * Gets the bottom Y coordinate of the element (element Y position + element height)
8173 * @param {Boolean} local True to get the local css position instead of page coordinate
8176 getBottom : function(local){
8178 return this.getY() + this.getHeight();
8180 return (this.getTop(true) + this.getHeight()) || 0;
8185 * Initializes positioning on this element. If a desired position is not passed, it will make the
8186 * the element positioned relative IF it is not already positioned.
8187 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8188 * @param {Number} zIndex (optional) The zIndex to apply
8189 * @param {Number} x (optional) Set the page X position
8190 * @param {Number} y (optional) Set the page Y position
8192 position : function(pos, zIndex, x, y){
8194 if(this.getStyle('position') == 'static'){
8195 this.setStyle('position', 'relative');
8198 this.setStyle("position", pos);
8201 this.setStyle("z-index", zIndex);
8203 if(x !== undefined && y !== undefined){
8205 }else if(x !== undefined){
8207 }else if(y !== undefined){
8213 * Clear positioning back to the default when the document was loaded
8214 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8215 * @return {Roo.Element} this
8217 clearPositioning : function(value){
8225 "position" : "static"
8231 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8232 * snapshot before performing an update and then restoring the element.
8235 getPositioning : function(){
8236 var l = this.getStyle("left");
8237 var t = this.getStyle("top");
8239 "position" : this.getStyle("position"),
8241 "right" : l ? "" : this.getStyle("right"),
8243 "bottom" : t ? "" : this.getStyle("bottom"),
8244 "z-index" : this.getStyle("z-index")
8249 * Gets the width of the border(s) for the specified side(s)
8250 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8251 * passing lr would get the border (l)eft width + the border (r)ight width.
8252 * @return {Number} The width of the sides passed added together
8254 getBorderWidth : function(side){
8255 return this.addStyles(side, El.borders);
8259 * Gets the width of the padding(s) for the specified side(s)
8260 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8261 * passing lr would get the padding (l)eft + the padding (r)ight.
8262 * @return {Number} The padding of the sides passed added together
8264 getPadding : function(side){
8265 return this.addStyles(side, El.paddings);
8269 * Set positioning with an object returned by getPositioning().
8270 * @param {Object} posCfg
8271 * @return {Roo.Element} this
8273 setPositioning : function(pc){
8274 this.applyStyles(pc);
8275 if(pc.right == "auto"){
8276 this.dom.style.right = "";
8278 if(pc.bottom == "auto"){
8279 this.dom.style.bottom = "";
8285 fixDisplay : function(){
8286 if(this.getStyle("display") == "none"){
8287 this.setStyle("visibility", "hidden");
8288 this.setStyle("display", this.originalDisplay); // first try reverting to default
8289 if(this.getStyle("display") == "none"){ // if that fails, default to block
8290 this.setStyle("display", "block");
8296 * Quick set left and top adding default units
8297 * @param {String} left The left CSS property value
8298 * @param {String} top The top CSS property value
8299 * @return {Roo.Element} this
8301 setLeftTop : function(left, top){
8302 this.dom.style.left = this.addUnits(left);
8303 this.dom.style.top = this.addUnits(top);
8308 * Move this element relative to its current position.
8309 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8310 * @param {Number} distance How far to move the element in pixels
8311 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8312 * @return {Roo.Element} this
8314 move : function(direction, distance, animate){
8315 var xy = this.getXY();
8316 direction = direction.toLowerCase();
8320 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8324 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8329 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8334 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8341 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8342 * @return {Roo.Element} this
8345 if(!this.isClipped){
8346 this.isClipped = true;
8347 this.originalClip = {
8348 "o": this.getStyle("overflow"),
8349 "x": this.getStyle("overflow-x"),
8350 "y": this.getStyle("overflow-y")
8352 this.setStyle("overflow", "hidden");
8353 this.setStyle("overflow-x", "hidden");
8354 this.setStyle("overflow-y", "hidden");
8360 * Return clipping (overflow) to original clipping before clip() was called
8361 * @return {Roo.Element} this
8363 unclip : function(){
8365 this.isClipped = false;
8366 var o = this.originalClip;
8367 if(o.o){this.setStyle("overflow", o.o);}
8368 if(o.x){this.setStyle("overflow-x", o.x);}
8369 if(o.y){this.setStyle("overflow-y", o.y);}
8376 * Gets the x,y coordinates specified by the anchor position on the element.
8377 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8378 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8379 * {width: (target width), height: (target height)} (defaults to the element's current size)
8380 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8381 * @return {Array} [x, y] An array containing the element's x and y coordinates
8383 getAnchorXY : function(anchor, local, s){
8384 //Passing a different size is useful for pre-calculating anchors,
8385 //especially for anchored animations that change the el size.
8387 var w, h, vp = false;
8390 if(d == document.body || d == document){
8392 w = D.getViewWidth(); h = D.getViewHeight();
8394 w = this.getWidth(); h = this.getHeight();
8397 w = s.width; h = s.height;
8399 var x = 0, y = 0, r = Math.round;
8400 switch((anchor || "tl").toLowerCase()){
8442 var sc = this.getScroll();
8443 return [x + sc.left, y + sc.top];
8445 //Add the element's offset xy
8446 var o = this.getXY();
8447 return [x+o[0], y+o[1]];
8451 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8452 * supported position values.
8453 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8454 * @param {String} position The position to align to.
8455 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8456 * @return {Array} [x, y]
8458 getAlignToXY : function(el, p, o){
8462 throw "Element.alignTo with an element that doesn't exist";
8464 var c = false; //constrain to viewport
8465 var p1 = "", p2 = "";
8472 }else if(p.indexOf("-") == -1){
8475 p = p.toLowerCase();
8476 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8478 throw "Element.alignTo with an invalid alignment " + p;
8480 p1 = m[1]; p2 = m[2]; c = !!m[3];
8482 //Subtract the aligned el's internal xy from the target's offset xy
8483 //plus custom offset to get the aligned el's new offset xy
8484 var a1 = this.getAnchorXY(p1, true);
8485 var a2 = el.getAnchorXY(p2, false);
8486 var x = a2[0] - a1[0] + o[0];
8487 var y = a2[1] - a1[1] + o[1];
8489 //constrain the aligned el to viewport if necessary
8490 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8491 // 5px of margin for ie
8492 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8494 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8495 //perpendicular to the vp border, allow the aligned el to slide on that border,
8496 //otherwise swap the aligned el to the opposite border of the target.
8497 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8498 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8499 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8500 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8503 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8504 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8506 if((x+w) > dw + scrollX){
8507 x = swapX ? r.left-w : dw+scrollX-w;
8510 x = swapX ? r.right : scrollX;
8512 if((y+h) > dh + scrollY){
8513 y = swapY ? r.top-h : dh+scrollY-h;
8516 y = swapY ? r.bottom : scrollY;
8523 getConstrainToXY : function(){
8524 var os = {top:0, left:0, bottom:0, right: 0};
8526 return function(el, local, offsets, proposedXY){
8528 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8530 var vw, vh, vx = 0, vy = 0;
8531 if(el.dom == document.body || el.dom == document){
8532 vw = Roo.lib.Dom.getViewWidth();
8533 vh = Roo.lib.Dom.getViewHeight();
8535 vw = el.dom.clientWidth;
8536 vh = el.dom.clientHeight;
8538 var vxy = el.getXY();
8544 var s = el.getScroll();
8546 vx += offsets.left + s.left;
8547 vy += offsets.top + s.top;
8549 vw -= offsets.right;
8550 vh -= offsets.bottom;
8555 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8556 var x = xy[0], y = xy[1];
8557 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8559 // only move it if it needs it
8562 // first validate right/bottom
8571 // then make sure top/left isn't negative
8580 return moved ? [x, y] : false;
8585 adjustForConstraints : function(xy, parent, offsets){
8586 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8590 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8591 * document it aligns it to the viewport.
8592 * The position parameter is optional, and can be specified in any one of the following formats:
8594 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8595 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8596 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8597 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8598 * <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
8599 * element's anchor point, and the second value is used as the target's anchor point.</li>
8601 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8602 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8603 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8604 * that specified in order to enforce the viewport constraints.
8605 * Following are all of the supported anchor positions:
8608 ----- -----------------------------
8609 tl The top left corner (default)
8610 t The center of the top edge
8611 tr The top right corner
8612 l The center of the left edge
8613 c In the center of the element
8614 r The center of the right edge
8615 bl The bottom left corner
8616 b The center of the bottom edge
8617 br The bottom right corner
8621 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8622 el.alignTo("other-el");
8624 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8625 el.alignTo("other-el", "tr?");
8627 // align the bottom right corner of el with the center left edge of other-el
8628 el.alignTo("other-el", "br-l?");
8630 // align the center of el with the bottom left corner of other-el and
8631 // adjust the x position by -6 pixels (and the y position by 0)
8632 el.alignTo("other-el", "c-bl", [-6, 0]);
8634 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8635 * @param {String} position The position to align to.
8636 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8637 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8638 * @return {Roo.Element} this
8640 alignTo : function(element, position, offsets, animate){
8641 var xy = this.getAlignToXY(element, position, offsets);
8642 this.setXY(xy, this.preanim(arguments, 3));
8647 * Anchors an element to another element and realigns it when the window is resized.
8648 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8649 * @param {String} position The position to align to.
8650 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8651 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8652 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8653 * is a number, it is used as the buffer delay (defaults to 50ms).
8654 * @param {Function} callback The function to call after the animation finishes
8655 * @return {Roo.Element} this
8657 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8658 var action = function(){
8659 this.alignTo(el, alignment, offsets, animate);
8660 Roo.callback(callback, this);
8662 Roo.EventManager.onWindowResize(action, this);
8663 var tm = typeof monitorScroll;
8664 if(tm != 'undefined'){
8665 Roo.EventManager.on(window, 'scroll', action, this,
8666 {buffer: tm == 'number' ? monitorScroll : 50});
8668 action.call(this); // align immediately
8672 * Clears any opacity settings from this element. Required in some cases for IE.
8673 * @return {Roo.Element} this
8675 clearOpacity : function(){
8676 if (window.ActiveXObject) {
8677 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8678 this.dom.style.filter = "";
8681 this.dom.style.opacity = "";
8682 this.dom.style["-moz-opacity"] = "";
8683 this.dom.style["-khtml-opacity"] = "";
8689 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8690 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8691 * @return {Roo.Element} this
8693 hide : function(animate){
8694 this.setVisible(false, this.preanim(arguments, 0));
8699 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8700 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8701 * @return {Roo.Element} this
8703 show : function(animate){
8704 this.setVisible(true, this.preanim(arguments, 0));
8709 * @private Test if size has a unit, otherwise appends the default
8711 addUnits : function(size){
8712 return Roo.Element.addUnits(size, this.defaultUnit);
8716 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8717 * @return {Roo.Element} this
8719 beginMeasure : function(){
8721 if(el.offsetWidth || el.offsetHeight){
8722 return this; // offsets work already
8725 var p = this.dom, b = document.body; // start with this element
8726 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8727 var pe = Roo.get(p);
8728 if(pe.getStyle('display') == 'none'){
8729 changed.push({el: p, visibility: pe.getStyle("visibility")});
8730 p.style.visibility = "hidden";
8731 p.style.display = "block";
8735 this._measureChanged = changed;
8741 * Restores displays to before beginMeasure was called
8742 * @return {Roo.Element} this
8744 endMeasure : function(){
8745 var changed = this._measureChanged;
8747 for(var i = 0, len = changed.length; i < len; i++) {
8749 r.el.style.visibility = r.visibility;
8750 r.el.style.display = "none";
8752 this._measureChanged = null;
8758 * Update the innerHTML of this element, optionally searching for and processing scripts
8759 * @param {String} html The new HTML
8760 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8761 * @param {Function} callback For async script loading you can be noticed when the update completes
8762 * @return {Roo.Element} this
8764 update : function(html, loadScripts, callback){
8765 if(typeof html == "undefined"){
8768 if(loadScripts !== true){
8769 this.dom.innerHTML = html;
8770 if(typeof callback == "function"){
8778 html += '<span id="' + id + '"></span>';
8780 E.onAvailable(id, function(){
8781 var hd = document.getElementsByTagName("head")[0];
8782 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8783 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8784 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8787 while(match = re.exec(html)){
8788 var attrs = match[1];
8789 var srcMatch = attrs ? attrs.match(srcRe) : false;
8790 if(srcMatch && srcMatch[2]){
8791 var s = document.createElement("script");
8792 s.src = srcMatch[2];
8793 var typeMatch = attrs.match(typeRe);
8794 if(typeMatch && typeMatch[2]){
8795 s.type = typeMatch[2];
8798 }else if(match[2] && match[2].length > 0){
8799 if(window.execScript) {
8800 window.execScript(match[2]);
8808 window.eval(match[2]);
8812 var el = document.getElementById(id);
8813 if(el){el.parentNode.removeChild(el);}
8814 if(typeof callback == "function"){
8818 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8823 * Direct access to the UpdateManager update() method (takes the same parameters).
8824 * @param {String/Function} url The url for this request or a function to call to get the url
8825 * @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}
8826 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8827 * @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.
8828 * @return {Roo.Element} this
8831 var um = this.getUpdateManager();
8832 um.update.apply(um, arguments);
8837 * Gets this element's UpdateManager
8838 * @return {Roo.UpdateManager} The UpdateManager
8840 getUpdateManager : function(){
8841 if(!this.updateManager){
8842 this.updateManager = new Roo.UpdateManager(this);
8844 return this.updateManager;
8848 * Disables text selection for this element (normalized across browsers)
8849 * @return {Roo.Element} this
8851 unselectable : function(){
8852 this.dom.unselectable = "on";
8853 this.swallowEvent("selectstart", true);
8854 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8855 this.addClass("x-unselectable");
8860 * Calculates the x, y to center this element on the screen
8861 * @return {Array} The x, y values [x, y]
8863 getCenterXY : function(){
8864 return this.getAlignToXY(document, 'c-c');
8868 * Centers the Element in either the viewport, or another Element.
8869 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8871 center : function(centerIn){
8872 this.alignTo(centerIn || document, 'c-c');
8877 * Tests various css rules/browsers to determine if this element uses a border box
8880 isBorderBox : function(){
8881 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8885 * Return a box {x, y, width, height} that can be used to set another elements
8886 * size/location to match this element.
8887 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8888 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8889 * @return {Object} box An object in the format {x, y, width, height}
8891 getBox : function(contentBox, local){
8896 var left = parseInt(this.getStyle("left"), 10) || 0;
8897 var top = parseInt(this.getStyle("top"), 10) || 0;
8900 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8902 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8904 var l = this.getBorderWidth("l")+this.getPadding("l");
8905 var r = this.getBorderWidth("r")+this.getPadding("r");
8906 var t = this.getBorderWidth("t")+this.getPadding("t");
8907 var b = this.getBorderWidth("b")+this.getPadding("b");
8908 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)};
8910 bx.right = bx.x + bx.width;
8911 bx.bottom = bx.y + bx.height;
8916 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8917 for more information about the sides.
8918 * @param {String} sides
8921 getFrameWidth : function(sides, onlyContentBox){
8922 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8926 * 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.
8927 * @param {Object} box The box to fill {x, y, width, height}
8928 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8929 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8930 * @return {Roo.Element} this
8932 setBox : function(box, adjust, animate){
8933 var w = box.width, h = box.height;
8934 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8935 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8936 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8938 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8943 * Forces the browser to repaint this element
8944 * @return {Roo.Element} this
8946 repaint : function(){
8948 this.addClass("x-repaint");
8949 setTimeout(function(){
8950 Roo.get(dom).removeClass("x-repaint");
8956 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8957 * then it returns the calculated width of the sides (see getPadding)
8958 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8959 * @return {Object/Number}
8961 getMargins : function(side){
8964 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8965 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8966 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8967 right: parseInt(this.getStyle("margin-right"), 10) || 0
8970 return this.addStyles(side, El.margins);
8975 addStyles : function(sides, styles){
8977 for(var i = 0, len = sides.length; i < len; i++){
8978 v = this.getStyle(styles[sides.charAt(i)]);
8980 w = parseInt(v, 10);
8988 * Creates a proxy element of this element
8989 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8990 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8991 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8992 * @return {Roo.Element} The new proxy element
8994 createProxy : function(config, renderTo, matchBox){
8996 renderTo = Roo.getDom(renderTo);
8998 renderTo = document.body;
9000 config = typeof config == "object" ?
9001 config : {tag : "div", cls: config};
9002 var proxy = Roo.DomHelper.append(renderTo, config, true);
9004 proxy.setBox(this.getBox());
9010 * Puts a mask over this element to disable user interaction. Requires core.css.
9011 * This method can only be applied to elements which accept child nodes.
9012 * @param {String} msg (optional) A message to display in the mask
9013 * @param {String} msgCls (optional) A css class to apply to the msg element
9014 * @return {Element} The mask element
9016 mask : function(msg, msgCls)
9018 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9019 this.setStyle("position", "relative");
9022 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9024 this.addClass("x-masked");
9025 this._mask.setDisplayed(true);
9030 while (dom && dom.style) {
9031 if (!isNaN(parseInt(dom.style.zIndex))) {
9032 z = Math.max(z, parseInt(dom.style.zIndex));
9034 dom = dom.parentNode;
9036 // if we are masking the body - then it hides everything..
9037 if (this.dom == document.body) {
9039 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9040 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9043 if(typeof msg == 'string'){
9045 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9047 var mm = this._maskMsg;
9048 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9049 if (mm.dom.firstChild) { // weird IE issue?
9050 mm.dom.firstChild.innerHTML = msg;
9052 mm.setDisplayed(true);
9054 mm.setStyle('z-index', z + 102);
9056 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9057 this._mask.setHeight(this.getHeight());
9059 this._mask.setStyle('z-index', z + 100);
9065 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9066 * it is cached for reuse.
9068 unmask : function(removeEl){
9070 if(removeEl === true){
9071 this._mask.remove();
9074 this._maskMsg.remove();
9075 delete this._maskMsg;
9078 this._mask.setDisplayed(false);
9080 this._maskMsg.setDisplayed(false);
9084 this.removeClass("x-masked");
9088 * Returns true if this element is masked
9091 isMasked : function(){
9092 return this._mask && this._mask.isVisible();
9096 * Creates an iframe shim for this element to keep selects and other windowed objects from
9098 * @return {Roo.Element} The new shim element
9100 createShim : function(){
9101 var el = document.createElement('iframe');
9102 el.frameBorder = 'no';
9103 el.className = 'roo-shim';
9104 if(Roo.isIE && Roo.isSecure){
9105 el.src = Roo.SSL_SECURE_URL;
9107 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9108 shim.autoBoxAdjust = false;
9113 * Removes this element from the DOM and deletes it from the cache
9115 remove : function(){
9116 if(this.dom.parentNode){
9117 this.dom.parentNode.removeChild(this.dom);
9119 delete El.cache[this.dom.id];
9123 * Sets up event handlers to add and remove a css class when the mouse is over this element
9124 * @param {String} className
9125 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9126 * mouseout events for children elements
9127 * @return {Roo.Element} this
9129 addClassOnOver : function(className, preventFlicker){
9130 this.on("mouseover", function(){
9131 Roo.fly(this, '_internal').addClass(className);
9133 var removeFn = function(e){
9134 if(preventFlicker !== true || !e.within(this, true)){
9135 Roo.fly(this, '_internal').removeClass(className);
9138 this.on("mouseout", removeFn, this.dom);
9143 * Sets up event handlers to add and remove a css class when this element has the focus
9144 * @param {String} className
9145 * @return {Roo.Element} this
9147 addClassOnFocus : function(className){
9148 this.on("focus", function(){
9149 Roo.fly(this, '_internal').addClass(className);
9151 this.on("blur", function(){
9152 Roo.fly(this, '_internal').removeClass(className);
9157 * 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)
9158 * @param {String} className
9159 * @return {Roo.Element} this
9161 addClassOnClick : function(className){
9163 this.on("mousedown", function(){
9164 Roo.fly(dom, '_internal').addClass(className);
9165 var d = Roo.get(document);
9166 var fn = function(){
9167 Roo.fly(dom, '_internal').removeClass(className);
9168 d.removeListener("mouseup", fn);
9170 d.on("mouseup", fn);
9176 * Stops the specified event from bubbling and optionally prevents the default action
9177 * @param {String} eventName
9178 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9179 * @return {Roo.Element} this
9181 swallowEvent : function(eventName, preventDefault){
9182 var fn = function(e){
9183 e.stopPropagation();
9188 if(eventName instanceof Array){
9189 for(var i = 0, len = eventName.length; i < len; i++){
9190 this.on(eventName[i], fn);
9194 this.on(eventName, fn);
9201 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9204 * Sizes this element to its parent element's dimensions performing
9205 * neccessary box adjustments.
9206 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9207 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9208 * @return {Roo.Element} this
9210 fitToParent : function(monitorResize, targetParent) {
9211 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9212 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9213 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9216 var p = Roo.get(targetParent || this.dom.parentNode);
9217 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9218 if (monitorResize === true) {
9219 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9220 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9226 * Gets the next sibling, skipping text nodes
9227 * @return {HTMLElement} The next sibling or null
9229 getNextSibling : function(){
9230 var n = this.dom.nextSibling;
9231 while(n && n.nodeType != 1){
9238 * Gets the previous sibling, skipping text nodes
9239 * @return {HTMLElement} The previous sibling or null
9241 getPrevSibling : function(){
9242 var n = this.dom.previousSibling;
9243 while(n && n.nodeType != 1){
9244 n = n.previousSibling;
9251 * Appends the passed element(s) to this element
9252 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9253 * @return {Roo.Element} this
9255 appendChild: function(el){
9262 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9263 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9264 * automatically generated with the specified attributes.
9265 * @param {HTMLElement} insertBefore (optional) a child element of this element
9266 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9267 * @return {Roo.Element} The new child element
9269 createChild: function(config, insertBefore, returnDom){
9270 config = config || {tag:'div'};
9272 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9274 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9278 * Appends this element to the passed element
9279 * @param {String/HTMLElement/Element} el The new parent element
9280 * @return {Roo.Element} this
9282 appendTo: function(el){
9283 el = Roo.getDom(el);
9284 el.appendChild(this.dom);
9289 * Inserts this element before the passed element in the DOM
9290 * @param {String/HTMLElement/Element} el The element to insert before
9291 * @return {Roo.Element} this
9293 insertBefore: function(el){
9294 el = Roo.getDom(el);
9295 el.parentNode.insertBefore(this.dom, el);
9300 * Inserts this element after the passed element in the DOM
9301 * @param {String/HTMLElement/Element} el The element to insert after
9302 * @return {Roo.Element} this
9304 insertAfter: function(el){
9305 el = Roo.getDom(el);
9306 el.parentNode.insertBefore(this.dom, el.nextSibling);
9311 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9312 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9313 * @return {Roo.Element} The new child
9315 insertFirst: function(el, returnDom){
9317 if(typeof el == 'object' && !el.nodeType){ // dh config
9318 return this.createChild(el, this.dom.firstChild, returnDom);
9320 el = Roo.getDom(el);
9321 this.dom.insertBefore(el, this.dom.firstChild);
9322 return !returnDom ? Roo.get(el) : el;
9327 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9328 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9329 * @param {String} where (optional) 'before' or 'after' defaults to before
9330 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9331 * @return {Roo.Element} the inserted Element
9333 insertSibling: function(el, where, returnDom){
9334 where = where ? where.toLowerCase() : 'before';
9336 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9338 if(typeof el == 'object' && !el.nodeType){ // dh config
9339 if(where == 'after' && !this.dom.nextSibling){
9340 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9342 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9346 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9347 where == 'before' ? this.dom : this.dom.nextSibling);
9356 * Creates and wraps this element with another element
9357 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9358 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9359 * @return {HTMLElement/Element} The newly created wrapper element
9361 wrap: function(config, returnDom){
9363 config = {tag: "div"};
9365 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9366 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9371 * Replaces the passed element with this element
9372 * @param {String/HTMLElement/Element} el The element to replace
9373 * @return {Roo.Element} this
9375 replace: function(el){
9377 this.insertBefore(el);
9383 * Inserts an html fragment into this element
9384 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9385 * @param {String} html The HTML fragment
9386 * @param {Boolean} returnEl True to return an Roo.Element
9387 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9389 insertHtml : function(where, html, returnEl){
9390 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9391 return returnEl ? Roo.get(el) : el;
9395 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9396 * @param {Object} o The object with the attributes
9397 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9398 * @return {Roo.Element} this
9400 set : function(o, useSet){
9402 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9404 if(attr == "style" || typeof o[attr] == "function") continue;
9406 el.className = o["cls"];
9408 if(useSet) el.setAttribute(attr, o[attr]);
9409 else el[attr] = o[attr];
9413 Roo.DomHelper.applyStyles(el, o.style);
9419 * Convenience method for constructing a KeyMap
9420 * @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:
9421 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9422 * @param {Function} fn The function to call
9423 * @param {Object} scope (optional) The scope of the function
9424 * @return {Roo.KeyMap} The KeyMap created
9426 addKeyListener : function(key, fn, scope){
9428 if(typeof key != "object" || key instanceof Array){
9444 return new Roo.KeyMap(this, config);
9448 * Creates a KeyMap for this element
9449 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9450 * @return {Roo.KeyMap} The KeyMap created
9452 addKeyMap : function(config){
9453 return new Roo.KeyMap(this, config);
9457 * Returns true if this element is scrollable.
9460 isScrollable : function(){
9462 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9466 * 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().
9467 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9468 * @param {Number} value The new scroll value
9469 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9470 * @return {Element} this
9473 scrollTo : function(side, value, animate){
9474 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9476 this.dom[prop] = value;
9478 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9479 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9485 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9486 * within this element's scrollable range.
9487 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9488 * @param {Number} distance How far to scroll the element in pixels
9489 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9490 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9491 * was scrolled as far as it could go.
9493 scroll : function(direction, distance, animate){
9494 if(!this.isScrollable()){
9498 var l = el.scrollLeft, t = el.scrollTop;
9499 var w = el.scrollWidth, h = el.scrollHeight;
9500 var cw = el.clientWidth, ch = el.clientHeight;
9501 direction = direction.toLowerCase();
9502 var scrolled = false;
9503 var a = this.preanim(arguments, 2);
9508 var v = Math.min(l + distance, w-cw);
9509 this.scrollTo("left", v, a);
9516 var v = Math.max(l - distance, 0);
9517 this.scrollTo("left", v, a);
9525 var v = Math.max(t - distance, 0);
9526 this.scrollTo("top", v, a);
9534 var v = Math.min(t + distance, h-ch);
9535 this.scrollTo("top", v, a);
9544 * Translates the passed page coordinates into left/top css values for this element
9545 * @param {Number/Array} x The page x or an array containing [x, y]
9546 * @param {Number} y The page y
9547 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9549 translatePoints : function(x, y){
9550 if(typeof x == 'object' || x instanceof Array){
9553 var p = this.getStyle('position');
9554 var o = this.getXY();
9556 var l = parseInt(this.getStyle('left'), 10);
9557 var t = parseInt(this.getStyle('top'), 10);
9560 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9563 t = (p == "relative") ? 0 : this.dom.offsetTop;
9566 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9570 * Returns the current scroll position of the element.
9571 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9573 getScroll : function(){
9574 var d = this.dom, doc = document;
9575 if(d == doc || d == doc.body){
9576 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9577 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9578 return {left: l, top: t};
9580 return {left: d.scrollLeft, top: d.scrollTop};
9585 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9586 * are convert to standard 6 digit hex color.
9587 * @param {String} attr The css attribute
9588 * @param {String} defaultValue The default value to use when a valid color isn't found
9589 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9592 getColor : function(attr, defaultValue, prefix){
9593 var v = this.getStyle(attr);
9594 if(!v || v == "transparent" || v == "inherit") {
9595 return defaultValue;
9597 var color = typeof prefix == "undefined" ? "#" : prefix;
9598 if(v.substr(0, 4) == "rgb("){
9599 var rvs = v.slice(4, v.length -1).split(",");
9600 for(var i = 0; i < 3; i++){
9601 var h = parseInt(rvs[i]).toString(16);
9608 if(v.substr(0, 1) == "#"){
9610 for(var i = 1; i < 4; i++){
9611 var c = v.charAt(i);
9614 }else if(v.length == 7){
9615 color += v.substr(1);
9619 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9623 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9624 * gradient background, rounded corners and a 4-way shadow.
9625 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9626 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9627 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9628 * @return {Roo.Element} this
9630 boxWrap : function(cls){
9631 cls = cls || 'x-box';
9632 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9633 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9638 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9639 * @param {String} namespace The namespace in which to look for the attribute
9640 * @param {String} name The attribute name
9641 * @return {String} The attribute value
9643 getAttributeNS : Roo.isIE ? function(ns, name){
9645 var type = typeof d[ns+":"+name];
9646 if(type != 'undefined' && type != 'unknown'){
9647 return d[ns+":"+name];
9650 } : function(ns, name){
9652 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9657 * Sets or Returns the value the dom attribute value
9658 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9659 * @param {String} value (optional) The value to set the attribute to
9660 * @return {String} The attribute value
9662 attr : function(name){
9663 if (arguments.length > 1) {
9664 this.dom.setAttribute(name, arguments[1]);
9665 return arguments[1];
9667 if (typeof(name) == 'object') {
9668 for(var i in name) {
9669 this.attr(i, name[i]);
9675 if (!this.dom.hasAttribute(name)) {
9678 return this.dom.getAttribute(name);
9685 var ep = El.prototype;
9688 * Appends an event handler (Shorthand for addListener)
9689 * @param {String} eventName The type of event to append
9690 * @param {Function} fn The method the event invokes
9691 * @param {Object} scope (optional) The scope (this object) of the fn
9692 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9695 ep.on = ep.addListener;
9697 ep.mon = ep.addListener;
9700 * Removes an event handler from this element (shorthand for removeListener)
9701 * @param {String} eventName the type of event to remove
9702 * @param {Function} fn the method the event invokes
9703 * @return {Roo.Element} this
9706 ep.un = ep.removeListener;
9709 * true to automatically adjust width and height settings for box-model issues (default to true)
9711 ep.autoBoxAdjust = true;
9714 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9717 El.addUnits = function(v, defaultUnit){
9718 if(v === "" || v == "auto"){
9721 if(v === undefined){
9724 if(typeof v == "number" || !El.unitPattern.test(v)){
9725 return v + (defaultUnit || 'px');
9730 // special markup used throughout Roo when box wrapping elements
9731 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>';
9733 * Visibility mode constant - Use visibility to hide element
9739 * Visibility mode constant - Use display to hide element
9745 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9746 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9747 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9759 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9760 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9761 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9762 * @return {Element} The Element object
9765 El.get = function(el){
9767 if(!el){ return null; }
9768 if(typeof el == "string"){ // element id
9769 if(!(elm = document.getElementById(el))){
9772 if(ex = El.cache[el]){
9775 ex = El.cache[el] = new El(elm);
9778 }else if(el.tagName){ // dom element
9782 if(ex = El.cache[id]){
9785 ex = El.cache[id] = new El(el);
9788 }else if(el instanceof El){
9790 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9791 // catch case where it hasn't been appended
9792 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9795 }else if(el.isComposite){
9797 }else if(el instanceof Array){
9798 return El.select(el);
9799 }else if(el == document){
9800 // create a bogus element object representing the document object
9802 var f = function(){};
9803 f.prototype = El.prototype;
9805 docEl.dom = document;
9813 El.uncache = function(el){
9814 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9816 delete El.cache[a[i].id || a[i]];
9822 // Garbage collection - uncache elements/purge listeners on orphaned elements
9823 // so we don't hold a reference and cause the browser to retain them
9824 El.garbageCollect = function(){
9825 if(!Roo.enableGarbageCollector){
9826 clearInterval(El.collectorThread);
9829 for(var eid in El.cache){
9830 var el = El.cache[eid], d = el.dom;
9831 // -------------------------------------------------------
9832 // Determining what is garbage:
9833 // -------------------------------------------------------
9835 // dom node is null, definitely garbage
9836 // -------------------------------------------------------
9838 // no parentNode == direct orphan, definitely garbage
9839 // -------------------------------------------------------
9840 // !d.offsetParent && !document.getElementById(eid)
9841 // display none elements have no offsetParent so we will
9842 // also try to look it up by it's id. However, check
9843 // offsetParent first so we don't do unneeded lookups.
9844 // This enables collection of elements that are not orphans
9845 // directly, but somewhere up the line they have an orphan
9847 // -------------------------------------------------------
9848 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9849 delete El.cache[eid];
9850 if(d && Roo.enableListenerCollection){
9856 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9860 El.Flyweight = function(dom){
9863 El.Flyweight.prototype = El.prototype;
9865 El._flyweights = {};
9867 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9868 * the dom node can be overwritten by other code.
9869 * @param {String/HTMLElement} el The dom node or id
9870 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9871 * prevent conflicts (e.g. internally Roo uses "_internal")
9873 * @return {Element} The shared Element object
9875 El.fly = function(el, named){
9876 named = named || '_global';
9877 el = Roo.getDom(el);
9881 if(!El._flyweights[named]){
9882 El._flyweights[named] = new El.Flyweight();
9884 El._flyweights[named].dom = el;
9885 return El._flyweights[named];
9889 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9890 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9891 * Shorthand of {@link Roo.Element#get}
9892 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9893 * @return {Element} The Element object
9899 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9900 * the dom node can be overwritten by other code.
9901 * Shorthand of {@link Roo.Element#fly}
9902 * @param {String/HTMLElement} el The dom node or id
9903 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9904 * prevent conflicts (e.g. internally Roo uses "_internal")
9906 * @return {Element} The shared Element object
9912 // speedy lookup for elements never to box adjust
9913 var noBoxAdjust = Roo.isStrict ? {
9916 input:1, select:1, textarea:1
9918 if(Roo.isIE || Roo.isGecko){
9919 noBoxAdjust['button'] = 1;
9923 Roo.EventManager.on(window, 'unload', function(){
9925 delete El._flyweights;
9933 Roo.Element.selectorFunction = Roo.DomQuery.select;
9936 Roo.Element.select = function(selector, unique, root){
9938 if(typeof selector == "string"){
9939 els = Roo.Element.selectorFunction(selector, root);
9940 }else if(selector.length !== undefined){
9943 throw "Invalid selector";
9945 if(unique === true){
9946 return new Roo.CompositeElement(els);
9948 return new Roo.CompositeElementLite(els);
9952 * Selects elements based on the passed CSS selector to enable working on them as 1.
9953 * @param {String/Array} selector The CSS selector or an array of elements
9954 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9955 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9956 * @return {CompositeElementLite/CompositeElement}
9960 Roo.select = Roo.Element.select;
9977 * Ext JS Library 1.1.1
9978 * Copyright(c) 2006-2007, Ext JS, LLC.
9980 * Originally Released Under LGPL - original licence link has changed is not relivant.
9983 * <script type="text/javascript">
9988 //Notifies Element that fx methods are available
9989 Roo.enableFx = true;
9993 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9994 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9995 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9996 * Element effects to work.</p><br/>
9998 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9999 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10000 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10001 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10002 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10003 * expected results and should be done with care.</p><br/>
10005 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10006 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10009 ----- -----------------------------
10010 tl The top left corner
10011 t The center of the top edge
10012 tr The top right corner
10013 l The center of the left edge
10014 r The center of the right edge
10015 bl The bottom left corner
10016 b The center of the bottom edge
10017 br The bottom right corner
10019 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10020 * below are common options that can be passed to any Fx method.</b>
10021 * @cfg {Function} callback A function called when the effect is finished
10022 * @cfg {Object} scope The scope of the effect function
10023 * @cfg {String} easing A valid Easing value for the effect
10024 * @cfg {String} afterCls A css class to apply after the effect
10025 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10026 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10027 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10028 * effects that end with the element being visually hidden, ignored otherwise)
10029 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10030 * a function which returns such a specification that will be applied to the Element after the effect finishes
10031 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10032 * @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
10033 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10037 * Slides the element into view. An anchor point can be optionally passed to set the point of
10038 * origin for the slide effect. This function automatically handles wrapping the element with
10039 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10042 // default: slide the element in from the top
10045 // custom: slide the element in from the right with a 2-second duration
10046 el.slideIn('r', { duration: 2 });
10048 // common config options shown with default values
10054 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10055 * @param {Object} options (optional) Object literal with any of the Fx config options
10056 * @return {Roo.Element} The Element
10058 slideIn : function(anchor, o){
10059 var el = this.getFxEl();
10062 el.queueFx(o, function(){
10064 anchor = anchor || "t";
10066 // fix display to visibility
10069 // restore values after effect
10070 var r = this.getFxRestore();
10071 var b = this.getBox();
10072 // fixed size for slide
10076 var wrap = this.fxWrap(r.pos, o, "hidden");
10078 var st = this.dom.style;
10079 st.visibility = "visible";
10080 st.position = "absolute";
10082 // clear out temp styles after slide and unwrap
10083 var after = function(){
10084 el.fxUnwrap(wrap, r.pos, o);
10085 st.width = r.width;
10086 st.height = r.height;
10089 // time to calc the positions
10090 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10092 switch(anchor.toLowerCase()){
10094 wrap.setSize(b.width, 0);
10095 st.left = st.bottom = "0";
10099 wrap.setSize(0, b.height);
10100 st.right = st.top = "0";
10104 wrap.setSize(0, b.height);
10105 wrap.setX(b.right);
10106 st.left = st.top = "0";
10107 a = {width: bw, points: pt};
10110 wrap.setSize(b.width, 0);
10111 wrap.setY(b.bottom);
10112 st.left = st.top = "0";
10113 a = {height: bh, points: pt};
10116 wrap.setSize(0, 0);
10117 st.right = st.bottom = "0";
10118 a = {width: bw, height: bh};
10121 wrap.setSize(0, 0);
10122 wrap.setY(b.y+b.height);
10123 st.right = st.top = "0";
10124 a = {width: bw, height: bh, points: pt};
10127 wrap.setSize(0, 0);
10128 wrap.setXY([b.right, b.bottom]);
10129 st.left = st.top = "0";
10130 a = {width: bw, height: bh, points: pt};
10133 wrap.setSize(0, 0);
10134 wrap.setX(b.x+b.width);
10135 st.left = st.bottom = "0";
10136 a = {width: bw, height: bh, points: pt};
10139 this.dom.style.visibility = "visible";
10142 arguments.callee.anim = wrap.fxanim(a,
10152 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10153 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10154 * 'hidden') but block elements will still take up space in the document. The element must be removed
10155 * from the DOM using the 'remove' config option if desired. This function automatically handles
10156 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10159 // default: slide the element out to the top
10162 // custom: slide the element out to the right with a 2-second duration
10163 el.slideOut('r', { duration: 2 });
10165 // common config options shown with default values
10173 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10174 * @param {Object} options (optional) Object literal with any of the Fx config options
10175 * @return {Roo.Element} The Element
10177 slideOut : function(anchor, o){
10178 var el = this.getFxEl();
10181 el.queueFx(o, function(){
10183 anchor = anchor || "t";
10185 // restore values after effect
10186 var r = this.getFxRestore();
10188 var b = this.getBox();
10189 // fixed size for slide
10193 var wrap = this.fxWrap(r.pos, o, "visible");
10195 var st = this.dom.style;
10196 st.visibility = "visible";
10197 st.position = "absolute";
10201 var after = function(){
10203 el.setDisplayed(false);
10208 el.fxUnwrap(wrap, r.pos, o);
10210 st.width = r.width;
10211 st.height = r.height;
10216 var a, zero = {to: 0};
10217 switch(anchor.toLowerCase()){
10219 st.left = st.bottom = "0";
10220 a = {height: zero};
10223 st.right = st.top = "0";
10227 st.left = st.top = "0";
10228 a = {width: zero, points: {to:[b.right, b.y]}};
10231 st.left = st.top = "0";
10232 a = {height: zero, points: {to:[b.x, b.bottom]}};
10235 st.right = st.bottom = "0";
10236 a = {width: zero, height: zero};
10239 st.right = st.top = "0";
10240 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10243 st.left = st.top = "0";
10244 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10247 st.left = st.bottom = "0";
10248 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10252 arguments.callee.anim = wrap.fxanim(a,
10262 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10263 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10264 * The element must be removed from the DOM using the 'remove' config option if desired.
10270 // common config options shown with default values
10278 * @param {Object} options (optional) Object literal with any of the Fx config options
10279 * @return {Roo.Element} The Element
10281 puff : function(o){
10282 var el = this.getFxEl();
10285 el.queueFx(o, function(){
10286 this.clearOpacity();
10289 // restore values after effect
10290 var r = this.getFxRestore();
10291 var st = this.dom.style;
10293 var after = function(){
10295 el.setDisplayed(false);
10302 el.setPositioning(r.pos);
10303 st.width = r.width;
10304 st.height = r.height;
10309 var width = this.getWidth();
10310 var height = this.getHeight();
10312 arguments.callee.anim = this.fxanim({
10313 width : {to: this.adjustWidth(width * 2)},
10314 height : {to: this.adjustHeight(height * 2)},
10315 points : {by: [-(width * .5), -(height * .5)]},
10317 fontSize: {to:200, unit: "%"}
10328 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10329 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10330 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10336 // all config options shown with default values
10344 * @param {Object} options (optional) Object literal with any of the Fx config options
10345 * @return {Roo.Element} The Element
10347 switchOff : function(o){
10348 var el = this.getFxEl();
10351 el.queueFx(o, function(){
10352 this.clearOpacity();
10355 // restore values after effect
10356 var r = this.getFxRestore();
10357 var st = this.dom.style;
10359 var after = function(){
10361 el.setDisplayed(false);
10367 el.setPositioning(r.pos);
10368 st.width = r.width;
10369 st.height = r.height;
10374 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10375 this.clearOpacity();
10379 points:{by:[0, this.getHeight() * .5]}
10380 }, o, 'motion', 0.3, 'easeIn', after);
10381 }).defer(100, this);
10388 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10389 * changed using the "attr" config option) and then fading back to the original color. If no original
10390 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10393 // default: highlight background to yellow
10396 // custom: highlight foreground text to blue for 2 seconds
10397 el.highlight("0000ff", { attr: 'color', duration: 2 });
10399 // common config options shown with default values
10400 el.highlight("ffff9c", {
10401 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10402 endColor: (current color) or "ffffff",
10407 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10408 * @param {Object} options (optional) Object literal with any of the Fx config options
10409 * @return {Roo.Element} The Element
10411 highlight : function(color, o){
10412 var el = this.getFxEl();
10415 el.queueFx(o, function(){
10416 color = color || "ffff9c";
10417 attr = o.attr || "backgroundColor";
10419 this.clearOpacity();
10422 var origColor = this.getColor(attr);
10423 var restoreColor = this.dom.style[attr];
10424 endColor = (o.endColor || origColor) || "ffffff";
10426 var after = function(){
10427 el.dom.style[attr] = restoreColor;
10432 a[attr] = {from: color, to: endColor};
10433 arguments.callee.anim = this.fxanim(a,
10443 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10446 // default: a single light blue ripple
10449 // custom: 3 red ripples lasting 3 seconds total
10450 el.frame("ff0000", 3, { duration: 3 });
10452 // common config options shown with default values
10453 el.frame("C3DAF9", 1, {
10454 duration: 1 //duration of entire animation (not each individual ripple)
10455 // Note: Easing is not configurable and will be ignored if included
10458 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10459 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10460 * @param {Object} options (optional) Object literal with any of the Fx config options
10461 * @return {Roo.Element} The Element
10463 frame : function(color, count, o){
10464 var el = this.getFxEl();
10467 el.queueFx(o, function(){
10468 color = color || "#C3DAF9";
10469 if(color.length == 6){
10470 color = "#" + color;
10472 count = count || 1;
10473 duration = o.duration || 1;
10476 var b = this.getBox();
10477 var animFn = function(){
10478 var proxy = this.createProxy({
10481 visbility:"hidden",
10482 position:"absolute",
10483 "z-index":"35000", // yee haw
10484 border:"0px solid " + color
10487 var scale = Roo.isBorderBox ? 2 : 1;
10489 top:{from:b.y, to:b.y - 20},
10490 left:{from:b.x, to:b.x - 20},
10491 borderWidth:{from:0, to:10},
10492 opacity:{from:1, to:0},
10493 height:{from:b.height, to:(b.height + (20*scale))},
10494 width:{from:b.width, to:(b.width + (20*scale))}
10495 }, duration, function(){
10499 animFn.defer((duration/2)*1000, this);
10510 * Creates a pause before any subsequent queued effects begin. If there are
10511 * no effects queued after the pause it will have no effect.
10516 * @param {Number} seconds The length of time to pause (in seconds)
10517 * @return {Roo.Element} The Element
10519 pause : function(seconds){
10520 var el = this.getFxEl();
10523 el.queueFx(o, function(){
10524 setTimeout(function(){
10526 }, seconds * 1000);
10532 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10533 * using the "endOpacity" config option.
10536 // default: fade in from opacity 0 to 100%
10539 // custom: fade in from opacity 0 to 75% over 2 seconds
10540 el.fadeIn({ endOpacity: .75, duration: 2});
10542 // common config options shown with default values
10544 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10549 * @param {Object} options (optional) Object literal with any of the Fx config options
10550 * @return {Roo.Element} The Element
10552 fadeIn : function(o){
10553 var el = this.getFxEl();
10555 el.queueFx(o, function(){
10556 this.setOpacity(0);
10558 this.dom.style.visibility = 'visible';
10559 var to = o.endOpacity || 1;
10560 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10561 o, null, .5, "easeOut", function(){
10563 this.clearOpacity();
10572 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10573 * using the "endOpacity" config option.
10576 // default: fade out from the element's current opacity to 0
10579 // custom: fade out from the element's current opacity to 25% over 2 seconds
10580 el.fadeOut({ endOpacity: .25, duration: 2});
10582 // common config options shown with default values
10584 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10591 * @param {Object} options (optional) Object literal with any of the Fx config options
10592 * @return {Roo.Element} The Element
10594 fadeOut : function(o){
10595 var el = this.getFxEl();
10597 el.queueFx(o, function(){
10598 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10599 o, null, .5, "easeOut", function(){
10600 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10601 this.dom.style.display = "none";
10603 this.dom.style.visibility = "hidden";
10605 this.clearOpacity();
10613 * Animates the transition of an element's dimensions from a starting height/width
10614 * to an ending height/width.
10617 // change height and width to 100x100 pixels
10618 el.scale(100, 100);
10620 // common config options shown with default values. The height and width will default to
10621 // the element's existing values if passed as null.
10624 [element's height], {
10629 * @param {Number} width The new width (pass undefined to keep the original width)
10630 * @param {Number} height The new height (pass undefined to keep the original height)
10631 * @param {Object} options (optional) Object literal with any of the Fx config options
10632 * @return {Roo.Element} The Element
10634 scale : function(w, h, o){
10635 this.shift(Roo.apply({}, o, {
10643 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10644 * Any of these properties not specified in the config object will not be changed. This effect
10645 * requires that at least one new dimension, position or opacity setting must be passed in on
10646 * the config object in order for the function to have any effect.
10649 // slide the element horizontally to x position 200 while changing the height and opacity
10650 el.shift({ x: 200, height: 50, opacity: .8 });
10652 // common config options shown with default values.
10654 width: [element's width],
10655 height: [element's height],
10656 x: [element's x position],
10657 y: [element's y position],
10658 opacity: [element's opacity],
10663 * @param {Object} options Object literal with any of the Fx config options
10664 * @return {Roo.Element} The Element
10666 shift : function(o){
10667 var el = this.getFxEl();
10669 el.queueFx(o, function(){
10670 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10671 if(w !== undefined){
10672 a.width = {to: this.adjustWidth(w)};
10674 if(h !== undefined){
10675 a.height = {to: this.adjustHeight(h)};
10677 if(x !== undefined || y !== undefined){
10679 x !== undefined ? x : this.getX(),
10680 y !== undefined ? y : this.getY()
10683 if(op !== undefined){
10684 a.opacity = {to: op};
10686 if(o.xy !== undefined){
10687 a.points = {to: o.xy};
10689 arguments.callee.anim = this.fxanim(a,
10690 o, 'motion', .35, "easeOut", function(){
10698 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10699 * ending point of the effect.
10702 // default: slide the element downward while fading out
10705 // custom: slide the element out to the right with a 2-second duration
10706 el.ghost('r', { duration: 2 });
10708 // common config options shown with default values
10716 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10717 * @param {Object} options (optional) Object literal with any of the Fx config options
10718 * @return {Roo.Element} The Element
10720 ghost : function(anchor, o){
10721 var el = this.getFxEl();
10724 el.queueFx(o, function(){
10725 anchor = anchor || "b";
10727 // restore values after effect
10728 var r = this.getFxRestore();
10729 var w = this.getWidth(),
10730 h = this.getHeight();
10732 var st = this.dom.style;
10734 var after = function(){
10736 el.setDisplayed(false);
10742 el.setPositioning(r.pos);
10743 st.width = r.width;
10744 st.height = r.height;
10749 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10750 switch(anchor.toLowerCase()){
10777 arguments.callee.anim = this.fxanim(a,
10787 * Ensures that all effects queued after syncFx is called on the element are
10788 * run concurrently. This is the opposite of {@link #sequenceFx}.
10789 * @return {Roo.Element} The Element
10791 syncFx : function(){
10792 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10801 * Ensures that all effects queued after sequenceFx is called on the element are
10802 * run in sequence. This is the opposite of {@link #syncFx}.
10803 * @return {Roo.Element} The Element
10805 sequenceFx : function(){
10806 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10808 concurrent : false,
10815 nextFx : function(){
10816 var ef = this.fxQueue[0];
10823 * Returns true if the element has any effects actively running or queued, else returns false.
10824 * @return {Boolean} True if element has active effects, else false
10826 hasActiveFx : function(){
10827 return this.fxQueue && this.fxQueue[0];
10831 * Stops any running effects and clears the element's internal effects queue if it contains
10832 * any additional effects that haven't started yet.
10833 * @return {Roo.Element} The Element
10835 stopFx : function(){
10836 if(this.hasActiveFx()){
10837 var cur = this.fxQueue[0];
10838 if(cur && cur.anim && cur.anim.isAnimated()){
10839 this.fxQueue = [cur]; // clear out others
10840 cur.anim.stop(true);
10847 beforeFx : function(o){
10848 if(this.hasActiveFx() && !o.concurrent){
10859 * Returns true if the element is currently blocking so that no other effect can be queued
10860 * until this effect is finished, else returns false if blocking is not set. This is commonly
10861 * used to ensure that an effect initiated by a user action runs to completion prior to the
10862 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10863 * @return {Boolean} True if blocking, else false
10865 hasFxBlock : function(){
10866 var q = this.fxQueue;
10867 return q && q[0] && q[0].block;
10871 queueFx : function(o, fn){
10875 if(!this.hasFxBlock()){
10876 Roo.applyIf(o, this.fxDefaults);
10878 var run = this.beforeFx(o);
10879 fn.block = o.block;
10880 this.fxQueue.push(fn);
10892 fxWrap : function(pos, o, vis){
10894 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10897 wrapXY = this.getXY();
10899 var div = document.createElement("div");
10900 div.style.visibility = vis;
10901 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10902 wrap.setPositioning(pos);
10903 if(wrap.getStyle("position") == "static"){
10904 wrap.position("relative");
10906 this.clearPositioning('auto');
10908 wrap.dom.appendChild(this.dom);
10910 wrap.setXY(wrapXY);
10917 fxUnwrap : function(wrap, pos, o){
10918 this.clearPositioning();
10919 this.setPositioning(pos);
10921 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10927 getFxRestore : function(){
10928 var st = this.dom.style;
10929 return {pos: this.getPositioning(), width: st.width, height : st.height};
10933 afterFx : function(o){
10935 this.applyStyles(o.afterStyle);
10938 this.addClass(o.afterCls);
10940 if(o.remove === true){
10943 Roo.callback(o.callback, o.scope, [this]);
10945 this.fxQueue.shift();
10951 getFxEl : function(){ // support for composite element fx
10952 return Roo.get(this.dom);
10956 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10957 animType = animType || 'run';
10959 var anim = Roo.lib.Anim[animType](
10961 (opt.duration || defaultDur) || .35,
10962 (opt.easing || defaultEase) || 'easeOut',
10964 Roo.callback(cb, this);
10973 // backwords compat
10974 Roo.Fx.resize = Roo.Fx.scale;
10976 //When included, Roo.Fx is automatically applied to Element so that all basic
10977 //effects are available directly via the Element API
10978 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10980 * Ext JS Library 1.1.1
10981 * Copyright(c) 2006-2007, Ext JS, LLC.
10983 * Originally Released Under LGPL - original licence link has changed is not relivant.
10986 * <script type="text/javascript">
10991 * @class Roo.CompositeElement
10992 * Standard composite class. Creates a Roo.Element for every element in the collection.
10994 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10995 * actions will be performed on all the elements in this collection.</b>
10997 * All methods return <i>this</i> and can be chained.
10999 var els = Roo.select("#some-el div.some-class", true);
11000 // or select directly from an existing element
11001 var el = Roo.get('some-el');
11002 el.select('div.some-class', true);
11004 els.setWidth(100); // all elements become 100 width
11005 els.hide(true); // all elements fade out and hide
11007 els.setWidth(100).hide(true);
11010 Roo.CompositeElement = function(els){
11011 this.elements = [];
11012 this.addElements(els);
11014 Roo.CompositeElement.prototype = {
11016 addElements : function(els){
11017 if(!els) return this;
11018 if(typeof els == "string"){
11019 els = Roo.Element.selectorFunction(els);
11021 var yels = this.elements;
11022 var index = yels.length-1;
11023 for(var i = 0, len = els.length; i < len; i++) {
11024 yels[++index] = Roo.get(els[i]);
11030 * Clears this composite and adds the elements returned by the passed selector.
11031 * @param {String/Array} els A string CSS selector, an array of elements or an element
11032 * @return {CompositeElement} this
11034 fill : function(els){
11035 this.elements = [];
11041 * Filters this composite to only elements that match the passed selector.
11042 * @param {String} selector A string CSS selector
11043 * @param {Boolean} inverse return inverse filter (not matches)
11044 * @return {CompositeElement} this
11046 filter : function(selector, inverse){
11048 inverse = inverse || false;
11049 this.each(function(el){
11050 var match = inverse ? !el.is(selector) : el.is(selector);
11052 els[els.length] = el.dom;
11059 invoke : function(fn, args){
11060 var els = this.elements;
11061 for(var i = 0, len = els.length; i < len; i++) {
11062 Roo.Element.prototype[fn].apply(els[i], args);
11067 * Adds elements to this composite.
11068 * @param {String/Array} els A string CSS selector, an array of elements or an element
11069 * @return {CompositeElement} this
11071 add : function(els){
11072 if(typeof els == "string"){
11073 this.addElements(Roo.Element.selectorFunction(els));
11074 }else if(els.length !== undefined){
11075 this.addElements(els);
11077 this.addElements([els]);
11082 * Calls the passed function passing (el, this, index) for each element in this composite.
11083 * @param {Function} fn The function to call
11084 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11085 * @return {CompositeElement} this
11087 each : function(fn, scope){
11088 var els = this.elements;
11089 for(var i = 0, len = els.length; i < len; i++){
11090 if(fn.call(scope || els[i], els[i], this, i) === false) {
11098 * Returns the Element object at the specified index
11099 * @param {Number} index
11100 * @return {Roo.Element}
11102 item : function(index){
11103 return this.elements[index] || null;
11107 * Returns the first Element
11108 * @return {Roo.Element}
11110 first : function(){
11111 return this.item(0);
11115 * Returns the last Element
11116 * @return {Roo.Element}
11119 return this.item(this.elements.length-1);
11123 * Returns the number of elements in this composite
11126 getCount : function(){
11127 return this.elements.length;
11131 * Returns true if this composite contains the passed element
11134 contains : function(el){
11135 return this.indexOf(el) !== -1;
11139 * Returns true if this composite contains the passed element
11142 indexOf : function(el){
11143 return this.elements.indexOf(Roo.get(el));
11148 * Removes the specified element(s).
11149 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11150 * or an array of any of those.
11151 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11152 * @return {CompositeElement} this
11154 removeElement : function(el, removeDom){
11155 if(el instanceof Array){
11156 for(var i = 0, len = el.length; i < len; i++){
11157 this.removeElement(el[i]);
11161 var index = typeof el == 'number' ? el : this.indexOf(el);
11164 var d = this.elements[index];
11168 d.parentNode.removeChild(d);
11171 this.elements.splice(index, 1);
11177 * Replaces the specified element with the passed element.
11178 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11180 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11181 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11182 * @return {CompositeElement} this
11184 replaceElement : function(el, replacement, domReplace){
11185 var index = typeof el == 'number' ? el : this.indexOf(el);
11188 this.elements[index].replaceWith(replacement);
11190 this.elements.splice(index, 1, Roo.get(replacement))
11197 * Removes all elements.
11199 clear : function(){
11200 this.elements = [];
11204 Roo.CompositeElement.createCall = function(proto, fnName){
11205 if(!proto[fnName]){
11206 proto[fnName] = function(){
11207 return this.invoke(fnName, arguments);
11211 for(var fnName in Roo.Element.prototype){
11212 if(typeof Roo.Element.prototype[fnName] == "function"){
11213 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11219 * Ext JS Library 1.1.1
11220 * Copyright(c) 2006-2007, Ext JS, LLC.
11222 * Originally Released Under LGPL - original licence link has changed is not relivant.
11225 * <script type="text/javascript">
11229 * @class Roo.CompositeElementLite
11230 * @extends Roo.CompositeElement
11231 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11233 var els = Roo.select("#some-el div.some-class");
11234 // or select directly from an existing element
11235 var el = Roo.get('some-el');
11236 el.select('div.some-class');
11238 els.setWidth(100); // all elements become 100 width
11239 els.hide(true); // all elements fade out and hide
11241 els.setWidth(100).hide(true);
11242 </code></pre><br><br>
11243 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11244 * actions will be performed on all the elements in this collection.</b>
11246 Roo.CompositeElementLite = function(els){
11247 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11248 this.el = new Roo.Element.Flyweight();
11250 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11251 addElements : function(els){
11253 if(els instanceof Array){
11254 this.elements = this.elements.concat(els);
11256 var yels = this.elements;
11257 var index = yels.length-1;
11258 for(var i = 0, len = els.length; i < len; i++) {
11259 yels[++index] = els[i];
11265 invoke : function(fn, args){
11266 var els = this.elements;
11268 for(var i = 0, len = els.length; i < len; i++) {
11270 Roo.Element.prototype[fn].apply(el, args);
11275 * Returns a flyweight Element of the dom element object at the specified index
11276 * @param {Number} index
11277 * @return {Roo.Element}
11279 item : function(index){
11280 if(!this.elements[index]){
11283 this.el.dom = this.elements[index];
11287 // fixes scope with flyweight
11288 addListener : function(eventName, handler, scope, opt){
11289 var els = this.elements;
11290 for(var i = 0, len = els.length; i < len; i++) {
11291 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11297 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11298 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11299 * a reference to the dom node, use el.dom.</b>
11300 * @param {Function} fn The function to call
11301 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11302 * @return {CompositeElement} this
11304 each : function(fn, scope){
11305 var els = this.elements;
11307 for(var i = 0, len = els.length; i < len; i++){
11309 if(fn.call(scope || el, el, this, i) === false){
11316 indexOf : function(el){
11317 return this.elements.indexOf(Roo.getDom(el));
11320 replaceElement : function(el, replacement, domReplace){
11321 var index = typeof el == 'number' ? el : this.indexOf(el);
11323 replacement = Roo.getDom(replacement);
11325 var d = this.elements[index];
11326 d.parentNode.insertBefore(replacement, d);
11327 d.parentNode.removeChild(d);
11329 this.elements.splice(index, 1, replacement);
11334 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11338 * Ext JS Library 1.1.1
11339 * Copyright(c) 2006-2007, Ext JS, LLC.
11341 * Originally Released Under LGPL - original licence link has changed is not relivant.
11344 * <script type="text/javascript">
11350 * @class Roo.data.Connection
11351 * @extends Roo.util.Observable
11352 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11353 * either to a configured URL, or to a URL specified at request time.<br><br>
11355 * Requests made by this class are asynchronous, and will return immediately. No data from
11356 * the server will be available to the statement immediately following the {@link #request} call.
11357 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11359 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11360 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11361 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11362 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11363 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11364 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11365 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11366 * standard DOM methods.
11368 * @param {Object} config a configuration object.
11370 Roo.data.Connection = function(config){
11371 Roo.apply(this, config);
11374 * @event beforerequest
11375 * Fires before a network request is made to retrieve a data object.
11376 * @param {Connection} conn This Connection object.
11377 * @param {Object} options The options config object passed to the {@link #request} method.
11379 "beforerequest" : true,
11381 * @event requestcomplete
11382 * Fires if the request was successfully completed.
11383 * @param {Connection} conn This Connection object.
11384 * @param {Object} response The XHR object containing the response data.
11385 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11386 * @param {Object} options The options config object passed to the {@link #request} method.
11388 "requestcomplete" : true,
11390 * @event requestexception
11391 * Fires if an error HTTP status was returned from the server.
11392 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11393 * @param {Connection} conn This Connection object.
11394 * @param {Object} response The XHR object containing the response data.
11395 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11396 * @param {Object} options The options config object passed to the {@link #request} method.
11398 "requestexception" : true
11400 Roo.data.Connection.superclass.constructor.call(this);
11403 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11405 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11408 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11409 * extra parameters to each request made by this object. (defaults to undefined)
11412 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11413 * to each request made by this object. (defaults to undefined)
11416 * @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)
11419 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11423 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11429 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11432 disableCaching: true,
11435 * Sends an HTTP request to a remote server.
11436 * @param {Object} options An object which may contain the following properties:<ul>
11437 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11438 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11439 * request, a url encoded string or a function to call to get either.</li>
11440 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11441 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11442 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11443 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11444 * <li>options {Object} The parameter to the request call.</li>
11445 * <li>success {Boolean} True if the request succeeded.</li>
11446 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11448 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11449 * The callback is passed the following parameters:<ul>
11450 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11451 * <li>options {Object} The parameter to the request call.</li>
11453 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11454 * The callback is passed the following parameters:<ul>
11455 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11456 * <li>options {Object} The parameter to the request call.</li>
11458 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11459 * for the callback function. Defaults to the browser window.</li>
11460 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11461 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11462 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11463 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11464 * params for the post data. Any params will be appended to the URL.</li>
11465 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11467 * @return {Number} transactionId
11469 request : function(o){
11470 if(this.fireEvent("beforerequest", this, o) !== false){
11473 if(typeof p == "function"){
11474 p = p.call(o.scope||window, o);
11476 if(typeof p == "object"){
11477 p = Roo.urlEncode(o.params);
11479 if(this.extraParams){
11480 var extras = Roo.urlEncode(this.extraParams);
11481 p = p ? (p + '&' + extras) : extras;
11484 var url = o.url || this.url;
11485 if(typeof url == 'function'){
11486 url = url.call(o.scope||window, o);
11490 var form = Roo.getDom(o.form);
11491 url = url || form.action;
11493 var enctype = form.getAttribute("enctype");
11494 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11495 return this.doFormUpload(o, p, url);
11497 var f = Roo.lib.Ajax.serializeForm(form);
11498 p = p ? (p + '&' + f) : f;
11501 var hs = o.headers;
11502 if(this.defaultHeaders){
11503 hs = Roo.apply(hs || {}, this.defaultHeaders);
11510 success: this.handleResponse,
11511 failure: this.handleFailure,
11513 argument: {options: o},
11514 timeout : o.timeout || this.timeout
11517 var method = o.method||this.method||(p ? "POST" : "GET");
11519 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11520 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11523 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11527 }else if(this.autoAbort !== false){
11531 if((method == 'GET' && p) || o.xmlData){
11532 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11535 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11536 return this.transId;
11538 Roo.callback(o.callback, o.scope, [o, null, null]);
11544 * Determine whether this object has a request outstanding.
11545 * @param {Number} transactionId (Optional) defaults to the last transaction
11546 * @return {Boolean} True if there is an outstanding request.
11548 isLoading : function(transId){
11550 return Roo.lib.Ajax.isCallInProgress(transId);
11552 return this.transId ? true : false;
11557 * Aborts any outstanding request.
11558 * @param {Number} transactionId (Optional) defaults to the last transaction
11560 abort : function(transId){
11561 if(transId || this.isLoading()){
11562 Roo.lib.Ajax.abort(transId || this.transId);
11567 handleResponse : function(response){
11568 this.transId = false;
11569 var options = response.argument.options;
11570 response.argument = options ? options.argument : null;
11571 this.fireEvent("requestcomplete", this, response, options);
11572 Roo.callback(options.success, options.scope, [response, options]);
11573 Roo.callback(options.callback, options.scope, [options, true, response]);
11577 handleFailure : function(response, e){
11578 this.transId = false;
11579 var options = response.argument.options;
11580 response.argument = options ? options.argument : null;
11581 this.fireEvent("requestexception", this, response, options, e);
11582 Roo.callback(options.failure, options.scope, [response, options]);
11583 Roo.callback(options.callback, options.scope, [options, false, response]);
11587 doFormUpload : function(o, ps, url){
11589 var frame = document.createElement('iframe');
11592 frame.className = 'x-hidden';
11594 frame.src = Roo.SSL_SECURE_URL;
11596 document.body.appendChild(frame);
11599 document.frames[id].name = id;
11602 var form = Roo.getDom(o.form);
11604 form.method = 'POST';
11605 form.enctype = form.encoding = 'multipart/form-data';
11611 if(ps){ // add dynamic params
11613 ps = Roo.urlDecode(ps, false);
11615 if(ps.hasOwnProperty(k)){
11616 hd = document.createElement('input');
11617 hd.type = 'hidden';
11620 form.appendChild(hd);
11627 var r = { // bogus response object
11632 r.argument = o ? o.argument : null;
11637 doc = frame.contentWindow.document;
11639 doc = (frame.contentDocument || window.frames[id].document);
11641 if(doc && doc.body){
11642 r.responseText = doc.body.innerHTML;
11644 if(doc && doc.XMLDocument){
11645 r.responseXML = doc.XMLDocument;
11647 r.responseXML = doc;
11654 Roo.EventManager.removeListener(frame, 'load', cb, this);
11656 this.fireEvent("requestcomplete", this, r, o);
11657 Roo.callback(o.success, o.scope, [r, o]);
11658 Roo.callback(o.callback, o.scope, [o, true, r]);
11660 setTimeout(function(){document.body.removeChild(frame);}, 100);
11663 Roo.EventManager.on(frame, 'load', cb, this);
11666 if(hiddens){ // remove dynamic params
11667 for(var i = 0, len = hiddens.length; i < len; i++){
11668 form.removeChild(hiddens[i]);
11675 * Ext JS Library 1.1.1
11676 * Copyright(c) 2006-2007, Ext JS, LLC.
11678 * Originally Released Under LGPL - original licence link has changed is not relivant.
11681 * <script type="text/javascript">
11685 * Global Ajax request class.
11688 * @extends Roo.data.Connection
11691 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11692 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11693 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11694 * @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)
11695 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11696 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11697 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11699 Roo.Ajax = new Roo.data.Connection({
11708 * Serialize the passed form into a url encoded string
11710 * @param {String/HTMLElement} form
11713 serializeForm : function(form){
11714 return Roo.lib.Ajax.serializeForm(form);
11718 * Ext JS Library 1.1.1
11719 * Copyright(c) 2006-2007, Ext JS, LLC.
11721 * Originally Released Under LGPL - original licence link has changed is not relivant.
11724 * <script type="text/javascript">
11729 * @class Roo.UpdateManager
11730 * @extends Roo.util.Observable
11731 * Provides AJAX-style update for Element object.<br><br>
11734 * // Get it from a Roo.Element object
11735 * var el = Roo.get("foo");
11736 * var mgr = el.getUpdateManager();
11737 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11739 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11741 * // or directly (returns the same UpdateManager instance)
11742 * var mgr = new Roo.UpdateManager("myElementId");
11743 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11744 * mgr.on("update", myFcnNeedsToKnow);
11746 // short handed call directly from the element object
11747 Roo.get("foo").load({
11751 text: "Loading Foo..."
11755 * Create new UpdateManager directly.
11756 * @param {String/HTMLElement/Roo.Element} el The element to update
11757 * @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).
11759 Roo.UpdateManager = function(el, forceNew){
11761 if(!forceNew && el.updateManager){
11762 return el.updateManager;
11765 * The Element object
11766 * @type Roo.Element
11770 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11773 this.defaultUrl = null;
11777 * @event beforeupdate
11778 * Fired before an update is made, return false from your handler and the update is cancelled.
11779 * @param {Roo.Element} el
11780 * @param {String/Object/Function} url
11781 * @param {String/Object} params
11783 "beforeupdate": true,
11786 * Fired after successful update is made.
11787 * @param {Roo.Element} el
11788 * @param {Object} oResponseObject The response Object
11793 * Fired on update failure.
11794 * @param {Roo.Element} el
11795 * @param {Object} oResponseObject The response Object
11799 var d = Roo.UpdateManager.defaults;
11801 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11804 this.sslBlankUrl = d.sslBlankUrl;
11806 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11809 this.disableCaching = d.disableCaching;
11811 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11814 this.indicatorText = d.indicatorText;
11816 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11819 this.showLoadIndicator = d.showLoadIndicator;
11821 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11824 this.timeout = d.timeout;
11827 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11830 this.loadScripts = d.loadScripts;
11833 * Transaction object of current executing transaction
11835 this.transaction = null;
11840 this.autoRefreshProcId = null;
11842 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11845 this.refreshDelegate = this.refresh.createDelegate(this);
11847 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11850 this.updateDelegate = this.update.createDelegate(this);
11852 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11855 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11859 this.successDelegate = this.processSuccess.createDelegate(this);
11863 this.failureDelegate = this.processFailure.createDelegate(this);
11865 if(!this.renderer){
11867 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11869 this.renderer = new Roo.UpdateManager.BasicRenderer();
11872 Roo.UpdateManager.superclass.constructor.call(this);
11875 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11877 * Get the Element this UpdateManager is bound to
11878 * @return {Roo.Element} The element
11880 getEl : function(){
11884 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11885 * @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:
11888 url: "your-url.php",<br/>
11889 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11890 callback: yourFunction,<br/>
11891 scope: yourObject, //(optional scope) <br/>
11892 discardUrl: false, <br/>
11893 nocache: false,<br/>
11894 text: "Loading...",<br/>
11896 scripts: false<br/>
11899 * The only required property is url. The optional properties nocache, text and scripts
11900 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11901 * @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}
11902 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11903 * @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.
11905 update : function(url, params, callback, discardUrl){
11906 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11907 var method = this.method,
11909 if(typeof url == "object"){ // must be config object
11912 params = params || cfg.params;
11913 callback = callback || cfg.callback;
11914 discardUrl = discardUrl || cfg.discardUrl;
11915 if(callback && cfg.scope){
11916 callback = callback.createDelegate(cfg.scope);
11918 if(typeof cfg.method != "undefined"){method = cfg.method;};
11919 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11920 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11921 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11922 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11924 this.showLoading();
11926 this.defaultUrl = url;
11928 if(typeof url == "function"){
11929 url = url.call(this);
11932 method = method || (params ? "POST" : "GET");
11933 if(method == "GET"){
11934 url = this.prepareUrl(url);
11937 var o = Roo.apply(cfg ||{}, {
11940 success: this.successDelegate,
11941 failure: this.failureDelegate,
11942 callback: undefined,
11943 timeout: (this.timeout*1000),
11944 argument: {"url": url, "form": null, "callback": callback, "params": params}
11946 Roo.log("updated manager called with timeout of " + o.timeout);
11947 this.transaction = Roo.Ajax.request(o);
11952 * 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.
11953 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11954 * @param {String/HTMLElement} form The form Id or form element
11955 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11956 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11957 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11959 formUpdate : function(form, url, reset, callback){
11960 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11961 if(typeof url == "function"){
11962 url = url.call(this);
11964 form = Roo.getDom(form);
11965 this.transaction = Roo.Ajax.request({
11968 success: this.successDelegate,
11969 failure: this.failureDelegate,
11970 timeout: (this.timeout*1000),
11971 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11973 this.showLoading.defer(1, this);
11978 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11979 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11981 refresh : function(callback){
11982 if(this.defaultUrl == null){
11985 this.update(this.defaultUrl, null, callback, true);
11989 * Set this element to auto refresh.
11990 * @param {Number} interval How often to update (in seconds).
11991 * @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)
11992 * @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}
11993 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11994 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11996 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11998 this.update(url || this.defaultUrl, params, callback, true);
12000 if(this.autoRefreshProcId){
12001 clearInterval(this.autoRefreshProcId);
12003 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12007 * Stop auto refresh on this element.
12009 stopAutoRefresh : function(){
12010 if(this.autoRefreshProcId){
12011 clearInterval(this.autoRefreshProcId);
12012 delete this.autoRefreshProcId;
12016 isAutoRefreshing : function(){
12017 return this.autoRefreshProcId ? true : false;
12020 * Called to update the element to "Loading" state. Override to perform custom action.
12022 showLoading : function(){
12023 if(this.showLoadIndicator){
12024 this.el.update(this.indicatorText);
12029 * Adds unique parameter to query string if disableCaching = true
12032 prepareUrl : function(url){
12033 if(this.disableCaching){
12034 var append = "_dc=" + (new Date().getTime());
12035 if(url.indexOf("?") !== -1){
12036 url += "&" + append;
12038 url += "?" + append;
12047 processSuccess : function(response){
12048 this.transaction = null;
12049 if(response.argument.form && response.argument.reset){
12050 try{ // put in try/catch since some older FF releases had problems with this
12051 response.argument.form.reset();
12054 if(this.loadScripts){
12055 this.renderer.render(this.el, response, this,
12056 this.updateComplete.createDelegate(this, [response]));
12058 this.renderer.render(this.el, response, this);
12059 this.updateComplete(response);
12063 updateComplete : function(response){
12064 this.fireEvent("update", this.el, response);
12065 if(typeof response.argument.callback == "function"){
12066 response.argument.callback(this.el, true, response);
12073 processFailure : function(response){
12074 this.transaction = null;
12075 this.fireEvent("failure", this.el, response);
12076 if(typeof response.argument.callback == "function"){
12077 response.argument.callback(this.el, false, response);
12082 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12083 * @param {Object} renderer The object implementing the render() method
12085 setRenderer : function(renderer){
12086 this.renderer = renderer;
12089 getRenderer : function(){
12090 return this.renderer;
12094 * Set the defaultUrl used for updates
12095 * @param {String/Function} defaultUrl The url or a function to call to get the url
12097 setDefaultUrl : function(defaultUrl){
12098 this.defaultUrl = defaultUrl;
12102 * Aborts the executing transaction
12104 abort : function(){
12105 if(this.transaction){
12106 Roo.Ajax.abort(this.transaction);
12111 * Returns true if an update is in progress
12112 * @return {Boolean}
12114 isUpdating : function(){
12115 if(this.transaction){
12116 return Roo.Ajax.isLoading(this.transaction);
12123 * @class Roo.UpdateManager.defaults
12124 * @static (not really - but it helps the doc tool)
12125 * The defaults collection enables customizing the default properties of UpdateManager
12127 Roo.UpdateManager.defaults = {
12129 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12135 * True to process scripts by default (Defaults to false).
12138 loadScripts : false,
12141 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12144 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12146 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12149 disableCaching : false,
12151 * Whether to show indicatorText when loading (Defaults to true).
12154 showLoadIndicator : true,
12156 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12159 indicatorText : '<div class="loading-indicator">Loading...</div>'
12163 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12165 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12166 * @param {String/HTMLElement/Roo.Element} el The element to update
12167 * @param {String} url The url
12168 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12169 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12172 * @member Roo.UpdateManager
12174 Roo.UpdateManager.updateElement = function(el, url, params, options){
12175 var um = Roo.get(el, true).getUpdateManager();
12176 Roo.apply(um, options);
12177 um.update(url, params, options ? options.callback : null);
12179 // alias for backwards compat
12180 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12182 * @class Roo.UpdateManager.BasicRenderer
12183 * Default Content renderer. Updates the elements innerHTML with the responseText.
12185 Roo.UpdateManager.BasicRenderer = function(){};
12187 Roo.UpdateManager.BasicRenderer.prototype = {
12189 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12190 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12191 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12192 * @param {Roo.Element} el The element being rendered
12193 * @param {Object} response The YUI Connect response object
12194 * @param {UpdateManager} updateManager The calling update manager
12195 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12197 render : function(el, response, updateManager, callback){
12198 el.update(response.responseText, updateManager.loadScripts, callback);
12204 * (c)) Alan Knowles
12210 * @class Roo.DomTemplate
12211 * @extends Roo.Template
12212 * An effort at a dom based template engine..
12214 * Similar to XTemplate, except it uses dom parsing to create the template..
12216 * Supported features:
12221 {a_variable} - output encoded.
12222 {a_variable.format:("Y-m-d")} - call a method on the variable
12223 {a_variable:raw} - unencoded output
12224 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12225 {a_variable:this.method_on_template(...)} - call a method on the template object.
12230 <div roo-for="a_variable or condition.."></div>
12231 <div roo-if="a_variable or condition"></div>
12232 <div roo-exec="some javascript"></div>
12233 <div roo-name="named_template"></div>
12238 Roo.DomTemplate = function()
12240 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12247 Roo.extend(Roo.DomTemplate, Roo.Template, {
12249 * id counter for sub templates.
12253 * flag to indicate if dom parser is inside a pre,
12254 * it will strip whitespace if not.
12259 * The various sub templates
12267 * basic tag replacing syntax
12270 * // you can fake an object call by doing this
12274 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12275 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12277 iterChild : function (node, method) {
12279 var oldPre = this.inPre;
12280 if (node.tagName == 'PRE') {
12283 for( var i = 0; i < node.childNodes.length; i++) {
12284 method.call(this, node.childNodes[i]);
12286 this.inPre = oldPre;
12292 * compile the template
12294 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12297 compile: function()
12301 // covert the html into DOM...
12305 doc = document.implementation.createHTMLDocument("");
12306 doc.documentElement.innerHTML = this.html ;
12307 div = doc.documentElement;
12309 // old IE... - nasty -- it causes all sorts of issues.. with
12310 // images getting pulled from server..
12311 div = document.createElement('div');
12312 div.innerHTML = this.html;
12314 //doc.documentElement.innerHTML = htmlBody
12320 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12322 var tpls = this.tpls;
12324 // create a top level template from the snippet..
12326 //Roo.log(div.innerHTML);
12333 body : div.innerHTML,
12346 Roo.each(tpls, function(tp){
12347 this.compileTpl(tp);
12348 this.tpls[tp.id] = tp;
12351 this.master = tpls[0];
12357 compileNode : function(node, istop) {
12362 // skip anything not a tag..
12363 if (node.nodeType != 1) {
12364 if (node.nodeType == 3 && !this.inPre) {
12365 // reduce white space..
12366 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12389 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12390 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12391 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12392 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12398 // just itterate children..
12399 this.iterChild(node,this.compileNode);
12402 tpl.uid = this.id++;
12403 tpl.value = node.getAttribute('roo-' + tpl.attr);
12404 node.removeAttribute('roo-'+ tpl.attr);
12405 if (tpl.attr != 'name') {
12406 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12407 node.parentNode.replaceChild(placeholder, node);
12410 var placeholder = document.createElement('span');
12411 placeholder.className = 'roo-tpl-' + tpl.value;
12412 node.parentNode.replaceChild(placeholder, node);
12415 // parent now sees '{domtplXXXX}
12416 this.iterChild(node,this.compileNode);
12418 // we should now have node body...
12419 var div = document.createElement('div');
12420 div.appendChild(node);
12422 // this has the unfortunate side effect of converting tagged attributes
12423 // eg. href="{...}" into %7C...%7D
12424 // this has been fixed by searching for those combo's although it's a bit hacky..
12427 tpl.body = div.innerHTML;
12434 switch (tpl.value) {
12435 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12436 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12437 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12442 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12446 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12450 tpl.id = tpl.value; // replace non characters???
12456 this.tpls.push(tpl);
12466 * Compile a segment of the template into a 'sub-template'
12472 compileTpl : function(tpl)
12474 var fm = Roo.util.Format;
12475 var useF = this.disableFormats !== true;
12477 var sep = Roo.isGecko ? "+\n" : ",\n";
12479 var undef = function(str) {
12480 Roo.debug && Roo.log("Property not found :" + str);
12484 //Roo.log(tpl.body);
12488 var fn = function(m, lbrace, name, format, args)
12491 //Roo.log(arguments);
12492 args = args ? args.replace(/\\'/g,"'") : args;
12493 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12494 if (typeof(format) == 'undefined') {
12495 format = 'htmlEncode';
12497 if (format == 'raw' ) {
12501 if(name.substr(0, 6) == 'domtpl'){
12502 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12505 // build an array of options to determine if value is undefined..
12507 // basically get 'xxxx.yyyy' then do
12508 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12509 // (function () { Roo.log("Property not found"); return ''; })() :
12514 Roo.each(name.split('.'), function(st) {
12515 lookfor += (lookfor.length ? '.': '') + st;
12516 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12519 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12522 if(format && useF){
12524 args = args ? ',' + args : "";
12526 if(format.substr(0, 5) != "this."){
12527 format = "fm." + format + '(';
12529 format = 'this.call("'+ format.substr(5) + '", ';
12533 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12536 if (args && args.length) {
12537 // called with xxyx.yuu:(test,test)
12539 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12541 // raw.. - :raw modifier..
12542 return "'"+ sep + udef_st + name + ")"+sep+"'";
12546 // branched to use + in gecko and [].join() in others
12548 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12549 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12552 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12553 body.push(tpl.body.replace(/(\r\n|\n)/g,
12554 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12555 body.push("'].join('');};};");
12556 body = body.join('');
12559 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12561 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12568 * same as applyTemplate, except it's done to one of the subTemplates
12569 * when using named templates, you can do:
12571 * var str = pl.applySubTemplate('your-name', values);
12574 * @param {Number} id of the template
12575 * @param {Object} values to apply to template
12576 * @param {Object} parent (normaly the instance of this object)
12578 applySubTemplate : function(id, values, parent)
12582 var t = this.tpls[id];
12586 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12587 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12591 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12598 if(t.execCall && t.execCall.call(this, values, parent)){
12602 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12608 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12609 parent = t.target ? values : parent;
12610 if(t.forCall && vs instanceof Array){
12612 for(var i = 0, len = vs.length; i < len; i++){
12614 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12616 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12618 //Roo.log(t.compiled);
12622 return buf.join('');
12625 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12630 return t.compiled.call(this, vs, parent);
12632 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12634 //Roo.log(t.compiled);
12642 applyTemplate : function(values){
12643 return this.master.compiled.call(this, values, {});
12644 //var s = this.subs;
12647 apply : function(){
12648 return this.applyTemplate.apply(this, arguments);
12653 Roo.DomTemplate.from = function(el){
12654 el = Roo.getDom(el);
12655 return new Roo.Domtemplate(el.value || el.innerHTML);
12658 * Ext JS Library 1.1.1
12659 * Copyright(c) 2006-2007, Ext JS, LLC.
12661 * Originally Released Under LGPL - original licence link has changed is not relivant.
12664 * <script type="text/javascript">
12668 * @class Roo.util.DelayedTask
12669 * Provides a convenient method of performing setTimeout where a new
12670 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12671 * You can use this class to buffer
12672 * the keypress events for a certain number of milliseconds, and perform only if they stop
12673 * for that amount of time.
12674 * @constructor The parameters to this constructor serve as defaults and are not required.
12675 * @param {Function} fn (optional) The default function to timeout
12676 * @param {Object} scope (optional) The default scope of that timeout
12677 * @param {Array} args (optional) The default Array of arguments
12679 Roo.util.DelayedTask = function(fn, scope, args){
12680 var id = null, d, t;
12682 var call = function(){
12683 var now = new Date().getTime();
12687 fn.apply(scope, args || []);
12691 * Cancels any pending timeout and queues a new one
12692 * @param {Number} delay The milliseconds to delay
12693 * @param {Function} newFn (optional) Overrides function passed to constructor
12694 * @param {Object} newScope (optional) Overrides scope passed to constructor
12695 * @param {Array} newArgs (optional) Overrides args passed to constructor
12697 this.delay = function(delay, newFn, newScope, newArgs){
12698 if(id && delay != d){
12702 t = new Date().getTime();
12704 scope = newScope || scope;
12705 args = newArgs || args;
12707 id = setInterval(call, d);
12712 * Cancel the last queued timeout
12714 this.cancel = function(){
12722 * Ext JS Library 1.1.1
12723 * Copyright(c) 2006-2007, Ext JS, LLC.
12725 * Originally Released Under LGPL - original licence link has changed is not relivant.
12728 * <script type="text/javascript">
12732 Roo.util.TaskRunner = function(interval){
12733 interval = interval || 10;
12734 var tasks = [], removeQueue = [];
12736 var running = false;
12738 var stopThread = function(){
12744 var startThread = function(){
12747 id = setInterval(runTasks, interval);
12751 var removeTask = function(task){
12752 removeQueue.push(task);
12758 var runTasks = function(){
12759 if(removeQueue.length > 0){
12760 for(var i = 0, len = removeQueue.length; i < len; i++){
12761 tasks.remove(removeQueue[i]);
12764 if(tasks.length < 1){
12769 var now = new Date().getTime();
12770 for(var i = 0, len = tasks.length; i < len; ++i){
12772 var itime = now - t.taskRunTime;
12773 if(t.interval <= itime){
12774 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12775 t.taskRunTime = now;
12776 if(rt === false || t.taskRunCount === t.repeat){
12781 if(t.duration && t.duration <= (now - t.taskStartTime)){
12788 * Queues a new task.
12789 * @param {Object} task
12791 this.start = function(task){
12793 task.taskStartTime = new Date().getTime();
12794 task.taskRunTime = 0;
12795 task.taskRunCount = 0;
12800 this.stop = function(task){
12805 this.stopAll = function(){
12807 for(var i = 0, len = tasks.length; i < len; i++){
12808 if(tasks[i].onStop){
12817 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12819 * Ext JS Library 1.1.1
12820 * Copyright(c) 2006-2007, Ext JS, LLC.
12822 * Originally Released Under LGPL - original licence link has changed is not relivant.
12825 * <script type="text/javascript">
12830 * @class Roo.util.MixedCollection
12831 * @extends Roo.util.Observable
12832 * A Collection class that maintains both numeric indexes and keys and exposes events.
12834 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12835 * collection (defaults to false)
12836 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12837 * and return the key value for that item. This is used when available to look up the key on items that
12838 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12839 * equivalent to providing an implementation for the {@link #getKey} method.
12841 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12849 * Fires when the collection is cleared.
12854 * Fires when an item is added to the collection.
12855 * @param {Number} index The index at which the item was added.
12856 * @param {Object} o The item added.
12857 * @param {String} key The key associated with the added item.
12862 * Fires when an item is replaced in the collection.
12863 * @param {String} key he key associated with the new added.
12864 * @param {Object} old The item being replaced.
12865 * @param {Object} new The new item.
12870 * Fires when an item is removed from the collection.
12871 * @param {Object} o The item being removed.
12872 * @param {String} key (optional) The key associated with the removed item.
12877 this.allowFunctions = allowFunctions === true;
12879 this.getKey = keyFn;
12881 Roo.util.MixedCollection.superclass.constructor.call(this);
12884 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12885 allowFunctions : false,
12888 * Adds an item to the collection.
12889 * @param {String} key The key to associate with the item
12890 * @param {Object} o The item to add.
12891 * @return {Object} The item added.
12893 add : function(key, o){
12894 if(arguments.length == 1){
12896 key = this.getKey(o);
12898 if(typeof key == "undefined" || key === null){
12900 this.items.push(o);
12901 this.keys.push(null);
12903 var old = this.map[key];
12905 return this.replace(key, o);
12908 this.items.push(o);
12910 this.keys.push(key);
12912 this.fireEvent("add", this.length-1, o, key);
12917 * MixedCollection has a generic way to fetch keys if you implement getKey.
12920 var mc = new Roo.util.MixedCollection();
12921 mc.add(someEl.dom.id, someEl);
12922 mc.add(otherEl.dom.id, otherEl);
12926 var mc = new Roo.util.MixedCollection();
12927 mc.getKey = function(el){
12933 // or via the constructor
12934 var mc = new Roo.util.MixedCollection(false, function(el){
12940 * @param o {Object} The item for which to find the key.
12941 * @return {Object} The key for the passed item.
12943 getKey : function(o){
12948 * Replaces an item in the collection.
12949 * @param {String} key The key associated with the item to replace, or the item to replace.
12950 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12951 * @return {Object} The new item.
12953 replace : function(key, o){
12954 if(arguments.length == 1){
12956 key = this.getKey(o);
12958 var old = this.item(key);
12959 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12960 return this.add(key, o);
12962 var index = this.indexOfKey(key);
12963 this.items[index] = o;
12965 this.fireEvent("replace", key, old, o);
12970 * Adds all elements of an Array or an Object to the collection.
12971 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12972 * an Array of values, each of which are added to the collection.
12974 addAll : function(objs){
12975 if(arguments.length > 1 || objs instanceof Array){
12976 var args = arguments.length > 1 ? arguments : objs;
12977 for(var i = 0, len = args.length; i < len; i++){
12981 for(var key in objs){
12982 if(this.allowFunctions || typeof objs[key] != "function"){
12983 this.add(key, objs[key]);
12990 * Executes the specified function once for every item in the collection, passing each
12991 * item as the first and only parameter. returning false from the function will stop the iteration.
12992 * @param {Function} fn The function to execute for each item.
12993 * @param {Object} scope (optional) The scope in which to execute the function.
12995 each : function(fn, scope){
12996 var items = [].concat(this.items); // each safe for removal
12997 for(var i = 0, len = items.length; i < len; i++){
12998 if(fn.call(scope || items[i], items[i], i, len) === false){
13005 * Executes the specified function once for every key in the collection, passing each
13006 * key, and its associated item as the first two parameters.
13007 * @param {Function} fn The function to execute for each item.
13008 * @param {Object} scope (optional) The scope in which to execute the function.
13010 eachKey : function(fn, scope){
13011 for(var i = 0, len = this.keys.length; i < len; i++){
13012 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13017 * Returns the first item in the collection which elicits a true return value from the
13018 * passed selection function.
13019 * @param {Function} fn The selection function to execute for each item.
13020 * @param {Object} scope (optional) The scope in which to execute the function.
13021 * @return {Object} The first item in the collection which returned true from the selection function.
13023 find : function(fn, scope){
13024 for(var i = 0, len = this.items.length; i < len; i++){
13025 if(fn.call(scope || window, this.items[i], this.keys[i])){
13026 return this.items[i];
13033 * Inserts an item at the specified index in the collection.
13034 * @param {Number} index The index to insert the item at.
13035 * @param {String} key The key to associate with the new item, or the item itself.
13036 * @param {Object} o (optional) If the second parameter was a key, the new item.
13037 * @return {Object} The item inserted.
13039 insert : function(index, key, o){
13040 if(arguments.length == 2){
13042 key = this.getKey(o);
13044 if(index >= this.length){
13045 return this.add(key, o);
13048 this.items.splice(index, 0, o);
13049 if(typeof key != "undefined" && key != null){
13052 this.keys.splice(index, 0, key);
13053 this.fireEvent("add", index, o, key);
13058 * Removed an item from the collection.
13059 * @param {Object} o The item to remove.
13060 * @return {Object} The item removed.
13062 remove : function(o){
13063 return this.removeAt(this.indexOf(o));
13067 * Remove an item from a specified index in the collection.
13068 * @param {Number} index The index within the collection of the item to remove.
13070 removeAt : function(index){
13071 if(index < this.length && index >= 0){
13073 var o = this.items[index];
13074 this.items.splice(index, 1);
13075 var key = this.keys[index];
13076 if(typeof key != "undefined"){
13077 delete this.map[key];
13079 this.keys.splice(index, 1);
13080 this.fireEvent("remove", o, key);
13085 * Removed an item associated with the passed key fom the collection.
13086 * @param {String} key The key of the item to remove.
13088 removeKey : function(key){
13089 return this.removeAt(this.indexOfKey(key));
13093 * Returns the number of items in the collection.
13094 * @return {Number} the number of items in the collection.
13096 getCount : function(){
13097 return this.length;
13101 * Returns index within the collection of the passed Object.
13102 * @param {Object} o The item to find the index of.
13103 * @return {Number} index of the item.
13105 indexOf : function(o){
13106 if(!this.items.indexOf){
13107 for(var i = 0, len = this.items.length; i < len; i++){
13108 if(this.items[i] == o) return i;
13112 return this.items.indexOf(o);
13117 * Returns index within the collection of the passed key.
13118 * @param {String} key The key to find the index of.
13119 * @return {Number} index of the key.
13121 indexOfKey : function(key){
13122 if(!this.keys.indexOf){
13123 for(var i = 0, len = this.keys.length; i < len; i++){
13124 if(this.keys[i] == key) return i;
13128 return this.keys.indexOf(key);
13133 * Returns the item associated with the passed key OR index. Key has priority over index.
13134 * @param {String/Number} key The key or index of the item.
13135 * @return {Object} The item associated with the passed key.
13137 item : function(key){
13138 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13139 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13143 * Returns the item at the specified index.
13144 * @param {Number} index The index of the item.
13147 itemAt : function(index){
13148 return this.items[index];
13152 * Returns the item associated with the passed key.
13153 * @param {String/Number} key The key of the item.
13154 * @return {Object} The item associated with the passed key.
13156 key : function(key){
13157 return this.map[key];
13161 * Returns true if the collection contains the passed Object as an item.
13162 * @param {Object} o The Object to look for in the collection.
13163 * @return {Boolean} True if the collection contains the Object as an item.
13165 contains : function(o){
13166 return this.indexOf(o) != -1;
13170 * Returns true if the collection contains the passed Object as a key.
13171 * @param {String} key The key to look for in the collection.
13172 * @return {Boolean} True if the collection contains the Object as a key.
13174 containsKey : function(key){
13175 return typeof this.map[key] != "undefined";
13179 * Removes all items from the collection.
13181 clear : function(){
13186 this.fireEvent("clear");
13190 * Returns the first item in the collection.
13191 * @return {Object} the first item in the collection..
13193 first : function(){
13194 return this.items[0];
13198 * Returns the last item in the collection.
13199 * @return {Object} the last item in the collection..
13202 return this.items[this.length-1];
13205 _sort : function(property, dir, fn){
13206 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13207 fn = fn || function(a, b){
13210 var c = [], k = this.keys, items = this.items;
13211 for(var i = 0, len = items.length; i < len; i++){
13212 c[c.length] = {key: k[i], value: items[i], index: i};
13214 c.sort(function(a, b){
13215 var v = fn(a[property], b[property]) * dsc;
13217 v = (a.index < b.index ? -1 : 1);
13221 for(var i = 0, len = c.length; i < len; i++){
13222 items[i] = c[i].value;
13225 this.fireEvent("sort", this);
13229 * Sorts this collection with the passed comparison function
13230 * @param {String} direction (optional) "ASC" or "DESC"
13231 * @param {Function} fn (optional) comparison function
13233 sort : function(dir, fn){
13234 this._sort("value", dir, fn);
13238 * Sorts this collection by keys
13239 * @param {String} direction (optional) "ASC" or "DESC"
13240 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13242 keySort : function(dir, fn){
13243 this._sort("key", dir, fn || function(a, b){
13244 return String(a).toUpperCase()-String(b).toUpperCase();
13249 * Returns a range of items in this collection
13250 * @param {Number} startIndex (optional) defaults to 0
13251 * @param {Number} endIndex (optional) default to the last item
13252 * @return {Array} An array of items
13254 getRange : function(start, end){
13255 var items = this.items;
13256 if(items.length < 1){
13259 start = start || 0;
13260 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13263 for(var i = start; i <= end; i++) {
13264 r[r.length] = items[i];
13267 for(var i = start; i >= end; i--) {
13268 r[r.length] = items[i];
13275 * Filter the <i>objects</i> in this collection by a specific property.
13276 * Returns a new collection that has been filtered.
13277 * @param {String} property A property on your objects
13278 * @param {String/RegExp} value Either string that the property values
13279 * should start with or a RegExp to test against the property
13280 * @return {MixedCollection} The new filtered collection
13282 filter : function(property, value){
13283 if(!value.exec){ // not a regex
13284 value = String(value);
13285 if(value.length == 0){
13286 return this.clone();
13288 value = new RegExp("^" + Roo.escapeRe(value), "i");
13290 return this.filterBy(function(o){
13291 return o && value.test(o[property]);
13296 * Filter by a function. * Returns a new collection that has been filtered.
13297 * The passed function will be called with each
13298 * object in the collection. If the function returns true, the value is included
13299 * otherwise it is filtered.
13300 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13301 * @param {Object} scope (optional) The scope of the function (defaults to this)
13302 * @return {MixedCollection} The new filtered collection
13304 filterBy : function(fn, scope){
13305 var r = new Roo.util.MixedCollection();
13306 r.getKey = this.getKey;
13307 var k = this.keys, it = this.items;
13308 for(var i = 0, len = it.length; i < len; i++){
13309 if(fn.call(scope||this, it[i], k[i])){
13310 r.add(k[i], it[i]);
13317 * Creates a duplicate of this collection
13318 * @return {MixedCollection}
13320 clone : function(){
13321 var r = new Roo.util.MixedCollection();
13322 var k = this.keys, it = this.items;
13323 for(var i = 0, len = it.length; i < len; i++){
13324 r.add(k[i], it[i]);
13326 r.getKey = this.getKey;
13331 * Returns the item associated with the passed key or index.
13333 * @param {String/Number} key The key or index of the item.
13334 * @return {Object} The item associated with the passed key.
13336 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13338 * Ext JS Library 1.1.1
13339 * Copyright(c) 2006-2007, Ext JS, LLC.
13341 * Originally Released Under LGPL - original licence link has changed is not relivant.
13344 * <script type="text/javascript">
13347 * @class Roo.util.JSON
13348 * Modified version of Douglas Crockford"s json.js that doesn"t
13349 * mess with the Object prototype
13350 * http://www.json.org/js.html
13353 Roo.util.JSON = new (function(){
13354 var useHasOwn = {}.hasOwnProperty ? true : false;
13356 // crashes Safari in some instances
13357 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13359 var pad = function(n) {
13360 return n < 10 ? "0" + n : n;
13373 var encodeString = function(s){
13374 if (/["\\\x00-\x1f]/.test(s)) {
13375 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13380 c = b.charCodeAt();
13382 Math.floor(c / 16).toString(16) +
13383 (c % 16).toString(16);
13386 return '"' + s + '"';
13389 var encodeArray = function(o){
13390 var a = ["["], b, i, l = o.length, v;
13391 for (i = 0; i < l; i += 1) {
13393 switch (typeof v) {
13402 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13410 var encodeDate = function(o){
13411 return '"' + o.getFullYear() + "-" +
13412 pad(o.getMonth() + 1) + "-" +
13413 pad(o.getDate()) + "T" +
13414 pad(o.getHours()) + ":" +
13415 pad(o.getMinutes()) + ":" +
13416 pad(o.getSeconds()) + '"';
13420 * Encodes an Object, Array or other value
13421 * @param {Mixed} o The variable to encode
13422 * @return {String} The JSON string
13424 this.encode = function(o)
13426 // should this be extended to fully wrap stringify..
13428 if(typeof o == "undefined" || o === null){
13430 }else if(o instanceof Array){
13431 return encodeArray(o);
13432 }else if(o instanceof Date){
13433 return encodeDate(o);
13434 }else if(typeof o == "string"){
13435 return encodeString(o);
13436 }else if(typeof o == "number"){
13437 return isFinite(o) ? String(o) : "null";
13438 }else if(typeof o == "boolean"){
13441 var a = ["{"], b, i, v;
13443 if(!useHasOwn || o.hasOwnProperty(i)) {
13445 switch (typeof v) {
13454 a.push(this.encode(i), ":",
13455 v === null ? "null" : this.encode(v));
13466 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13467 * @param {String} json The JSON string
13468 * @return {Object} The resulting object
13470 this.decode = function(json){
13472 return /** eval:var:json */ eval("(" + json + ')');
13476 * Shorthand for {@link Roo.util.JSON#encode}
13477 * @member Roo encode
13479 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13481 * Shorthand for {@link Roo.util.JSON#decode}
13482 * @member Roo decode
13484 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13487 * Ext JS Library 1.1.1
13488 * Copyright(c) 2006-2007, Ext JS, LLC.
13490 * Originally Released Under LGPL - original licence link has changed is not relivant.
13493 * <script type="text/javascript">
13497 * @class Roo.util.Format
13498 * Reusable data formatting functions
13501 Roo.util.Format = function(){
13502 var trimRe = /^\s+|\s+$/g;
13505 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13506 * @param {String} value The string to truncate
13507 * @param {Number} length The maximum length to allow before truncating
13508 * @return {String} The converted text
13510 ellipsis : function(value, len){
13511 if(value && value.length > len){
13512 return value.substr(0, len-3)+"...";
13518 * Checks a reference and converts it to empty string if it is undefined
13519 * @param {Mixed} value Reference to check
13520 * @return {Mixed} Empty string if converted, otherwise the original value
13522 undef : function(value){
13523 return typeof value != "undefined" ? value : "";
13527 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13528 * @param {String} value The string to encode
13529 * @return {String} The encoded text
13531 htmlEncode : function(value){
13532 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13536 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13537 * @param {String} value The string to decode
13538 * @return {String} The decoded text
13540 htmlDecode : function(value){
13541 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13545 * Trims any whitespace from either side of a string
13546 * @param {String} value The text to trim
13547 * @return {String} The trimmed text
13549 trim : function(value){
13550 return String(value).replace(trimRe, "");
13554 * Returns a substring from within an original string
13555 * @param {String} value The original text
13556 * @param {Number} start The start index of the substring
13557 * @param {Number} length The length of the substring
13558 * @return {String} The substring
13560 substr : function(value, start, length){
13561 return String(value).substr(start, length);
13565 * Converts a string to all lower case letters
13566 * @param {String} value The text to convert
13567 * @return {String} The converted text
13569 lowercase : function(value){
13570 return String(value).toLowerCase();
13574 * Converts a string to all upper case letters
13575 * @param {String} value The text to convert
13576 * @return {String} The converted text
13578 uppercase : function(value){
13579 return String(value).toUpperCase();
13583 * Converts the first character only of a string to upper case
13584 * @param {String} value The text to convert
13585 * @return {String} The converted text
13587 capitalize : function(value){
13588 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13592 call : function(value, fn){
13593 if(arguments.length > 2){
13594 var args = Array.prototype.slice.call(arguments, 2);
13595 args.unshift(value);
13597 return /** eval:var:value */ eval(fn).apply(window, args);
13599 /** eval:var:value */
13600 return /** eval:var:value */ eval(fn).call(window, value);
13606 * safer version of Math.toFixed..??/
13607 * @param {Number/String} value The numeric value to format
13608 * @param {Number/String} value Decimal places
13609 * @return {String} The formatted currency string
13611 toFixed : function(v, n)
13613 // why not use to fixed - precision is buggered???
13615 return Math.round(v-0);
13617 var fact = Math.pow(10,n+1);
13618 v = (Math.round((v-0)*fact))/fact;
13619 var z = (''+fact).substring(2);
13620 if (v == Math.floor(v)) {
13621 return Math.floor(v) + '.' + z;
13624 // now just padd decimals..
13625 var ps = String(v).split('.');
13626 var fd = (ps[1] + z);
13627 var r = fd.substring(0,n);
13628 var rm = fd.substring(n);
13630 return ps[0] + '.' + r;
13632 r*=1; // turn it into a number;
13634 if (String(r).length != n) {
13637 r = String(r).substring(1); // chop the end off.
13640 return ps[0] + '.' + r;
13645 * Format a number as US currency
13646 * @param {Number/String} value The numeric value to format
13647 * @return {String} The formatted currency string
13649 usMoney : function(v){
13650 return '$' + Roo.util.Format.number(v);
13655 * eventually this should probably emulate php's number_format
13656 * @param {Number/String} value The numeric value to format
13657 * @param {Number} decimals number of decimal places
13658 * @return {String} The formatted currency string
13660 number : function(v,decimals)
13662 // multiply and round.
13663 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13664 var mul = Math.pow(10, decimals);
13665 var zero = String(mul).substring(1);
13666 v = (Math.round((v-0)*mul))/mul;
13668 // if it's '0' number.. then
13670 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13672 var ps = v.split('.');
13676 var r = /(\d+)(\d{3})/;
13678 while (r.test(whole)) {
13679 whole = whole.replace(r, '$1' + ',' + '$2');
13685 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13686 // does not have decimals
13687 (decimals ? ('.' + zero) : '');
13690 return whole + sub ;
13694 * Parse a value into a formatted date using the specified format pattern.
13695 * @param {Mixed} value The value to format
13696 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13697 * @return {String} The formatted date string
13699 date : function(v, format){
13703 if(!(v instanceof Date)){
13704 v = new Date(Date.parse(v));
13706 return v.dateFormat(format || Roo.util.Format.defaults.date);
13710 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13711 * @param {String} format Any valid date format string
13712 * @return {Function} The date formatting function
13714 dateRenderer : function(format){
13715 return function(v){
13716 return Roo.util.Format.date(v, format);
13721 stripTagsRE : /<\/?[^>]+>/gi,
13724 * Strips all HTML tags
13725 * @param {Mixed} value The text from which to strip tags
13726 * @return {String} The stripped text
13728 stripTags : function(v){
13729 return !v ? v : String(v).replace(this.stripTagsRE, "");
13733 Roo.util.Format.defaults = {
13737 * Ext JS Library 1.1.1
13738 * Copyright(c) 2006-2007, Ext JS, LLC.
13740 * Originally Released Under LGPL - original licence link has changed is not relivant.
13743 * <script type="text/javascript">
13750 * @class Roo.MasterTemplate
13751 * @extends Roo.Template
13752 * Provides a template that can have child templates. The syntax is:
13754 var t = new Roo.MasterTemplate(
13755 '<select name="{name}">',
13756 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13759 t.add('options', {value: 'foo', text: 'bar'});
13760 // or you can add multiple child elements in one shot
13761 t.addAll('options', [
13762 {value: 'foo', text: 'bar'},
13763 {value: 'foo2', text: 'bar2'},
13764 {value: 'foo3', text: 'bar3'}
13766 // then append, applying the master template values
13767 t.append('my-form', {name: 'my-select'});
13769 * A name attribute for the child template is not required if you have only one child
13770 * template or you want to refer to them by index.
13772 Roo.MasterTemplate = function(){
13773 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13774 this.originalHtml = this.html;
13776 var m, re = this.subTemplateRe;
13779 while(m = re.exec(this.html)){
13780 var name = m[1], content = m[2];
13785 tpl : new Roo.Template(content)
13788 st[name] = st[subIndex];
13790 st[subIndex].tpl.compile();
13791 st[subIndex].tpl.call = this.call.createDelegate(this);
13794 this.subCount = subIndex;
13797 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13799 * The regular expression used to match sub templates
13803 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13806 * Applies the passed values to a child template.
13807 * @param {String/Number} name (optional) The name or index of the child template
13808 * @param {Array/Object} values The values to be applied to the template
13809 * @return {MasterTemplate} this
13811 add : function(name, values){
13812 if(arguments.length == 1){
13813 values = arguments[0];
13816 var s = this.subs[name];
13817 s.buffer[s.buffer.length] = s.tpl.apply(values);
13822 * Applies all the passed values to a child template.
13823 * @param {String/Number} name (optional) The name or index of the child template
13824 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13825 * @param {Boolean} reset (optional) True to reset the template first
13826 * @return {MasterTemplate} this
13828 fill : function(name, values, reset){
13830 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13838 for(var i = 0, len = values.length; i < len; i++){
13839 this.add(name, values[i]);
13845 * Resets the template for reuse
13846 * @return {MasterTemplate} this
13848 reset : function(){
13850 for(var i = 0; i < this.subCount; i++){
13856 applyTemplate : function(values){
13858 var replaceIndex = -1;
13859 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13860 return s[++replaceIndex].buffer.join("");
13862 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13865 apply : function(){
13866 return this.applyTemplate.apply(this, arguments);
13869 compile : function(){return this;}
13873 * Alias for fill().
13876 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13878 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13879 * var tpl = Roo.MasterTemplate.from('element-id');
13880 * @param {String/HTMLElement} el
13881 * @param {Object} config
13884 Roo.MasterTemplate.from = function(el, config){
13885 el = Roo.getDom(el);
13886 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13889 * Ext JS Library 1.1.1
13890 * Copyright(c) 2006-2007, Ext JS, LLC.
13892 * Originally Released Under LGPL - original licence link has changed is not relivant.
13895 * <script type="text/javascript">
13900 * @class Roo.util.CSS
13901 * Utility class for manipulating CSS rules
13904 Roo.util.CSS = function(){
13906 var doc = document;
13908 var camelRe = /(-[a-z])/gi;
13909 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13913 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13914 * tag and appended to the HEAD of the document.
13915 * @param {String|Object} cssText The text containing the css rules
13916 * @param {String} id An id to add to the stylesheet for later removal
13917 * @return {StyleSheet}
13919 createStyleSheet : function(cssText, id){
13921 var head = doc.getElementsByTagName("head")[0];
13922 var nrules = doc.createElement("style");
13923 nrules.setAttribute("type", "text/css");
13925 nrules.setAttribute("id", id);
13927 if (typeof(cssText) != 'string') {
13928 // support object maps..
13929 // not sure if this a good idea..
13930 // perhaps it should be merged with the general css handling
13931 // and handle js style props.
13932 var cssTextNew = [];
13933 for(var n in cssText) {
13935 for(var k in cssText[n]) {
13936 citems.push( k + ' : ' +cssText[n][k] + ';' );
13938 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13941 cssText = cssTextNew.join("\n");
13947 head.appendChild(nrules);
13948 ss = nrules.styleSheet;
13949 ss.cssText = cssText;
13952 nrules.appendChild(doc.createTextNode(cssText));
13954 nrules.cssText = cssText;
13956 head.appendChild(nrules);
13957 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13959 this.cacheStyleSheet(ss);
13964 * Removes a style or link tag by id
13965 * @param {String} id The id of the tag
13967 removeStyleSheet : function(id){
13968 var existing = doc.getElementById(id);
13970 existing.parentNode.removeChild(existing);
13975 * Dynamically swaps an existing stylesheet reference for a new one
13976 * @param {String} id The id of an existing link tag to remove
13977 * @param {String} url The href of the new stylesheet to include
13979 swapStyleSheet : function(id, url){
13980 this.removeStyleSheet(id);
13981 var ss = doc.createElement("link");
13982 ss.setAttribute("rel", "stylesheet");
13983 ss.setAttribute("type", "text/css");
13984 ss.setAttribute("id", id);
13985 ss.setAttribute("href", url);
13986 doc.getElementsByTagName("head")[0].appendChild(ss);
13990 * Refresh the rule cache if you have dynamically added stylesheets
13991 * @return {Object} An object (hash) of rules indexed by selector
13993 refreshCache : function(){
13994 return this.getRules(true);
13998 cacheStyleSheet : function(stylesheet){
14002 try{// try catch for cross domain access issue
14003 var ssRules = stylesheet.cssRules || stylesheet.rules;
14004 for(var j = ssRules.length-1; j >= 0; --j){
14005 rules[ssRules[j].selectorText] = ssRules[j];
14011 * Gets all css rules for the document
14012 * @param {Boolean} refreshCache true to refresh the internal cache
14013 * @return {Object} An object (hash) of rules indexed by selector
14015 getRules : function(refreshCache){
14016 if(rules == null || refreshCache){
14018 var ds = doc.styleSheets;
14019 for(var i =0, len = ds.length; i < len; i++){
14021 this.cacheStyleSheet(ds[i]);
14029 * Gets an an individual CSS rule by selector(s)
14030 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14031 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14032 * @return {CSSRule} The CSS rule or null if one is not found
14034 getRule : function(selector, refreshCache){
14035 var rs = this.getRules(refreshCache);
14036 if(!(selector instanceof Array)){
14037 return rs[selector];
14039 for(var i = 0; i < selector.length; i++){
14040 if(rs[selector[i]]){
14041 return rs[selector[i]];
14049 * Updates a rule property
14050 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14051 * @param {String} property The css property
14052 * @param {String} value The new value for the property
14053 * @return {Boolean} true If a rule was found and updated
14055 updateRule : function(selector, property, value){
14056 if(!(selector instanceof Array)){
14057 var rule = this.getRule(selector);
14059 rule.style[property.replace(camelRe, camelFn)] = value;
14063 for(var i = 0; i < selector.length; i++){
14064 if(this.updateRule(selector[i], property, value)){
14074 * Ext JS Library 1.1.1
14075 * Copyright(c) 2006-2007, Ext JS, LLC.
14077 * Originally Released Under LGPL - original licence link has changed is not relivant.
14080 * <script type="text/javascript">
14086 * @class Roo.util.ClickRepeater
14087 * @extends Roo.util.Observable
14089 * A wrapper class which can be applied to any element. Fires a "click" event while the
14090 * mouse is pressed. The interval between firings may be specified in the config but
14091 * defaults to 10 milliseconds.
14093 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14095 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14096 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14097 * Similar to an autorepeat key delay.
14098 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14099 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14100 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14101 * "interval" and "delay" are ignored. "immediate" is honored.
14102 * @cfg {Boolean} preventDefault True to prevent the default click event
14103 * @cfg {Boolean} stopDefault True to stop the default click event
14106 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14107 * 2007-02-02 jvs Renamed to ClickRepeater
14108 * 2007-02-03 jvs Modifications for FF Mac and Safari
14111 * @param {String/HTMLElement/Element} el The element to listen on
14112 * @param {Object} config
14114 Roo.util.ClickRepeater = function(el, config)
14116 this.el = Roo.get(el);
14117 this.el.unselectable();
14119 Roo.apply(this, config);
14124 * Fires when the mouse button is depressed.
14125 * @param {Roo.util.ClickRepeater} this
14127 "mousedown" : true,
14130 * Fires on a specified interval during the time the element is pressed.
14131 * @param {Roo.util.ClickRepeater} this
14136 * Fires when the mouse key is released.
14137 * @param {Roo.util.ClickRepeater} this
14142 this.el.on("mousedown", this.handleMouseDown, this);
14143 if(this.preventDefault || this.stopDefault){
14144 this.el.on("click", function(e){
14145 if(this.preventDefault){
14146 e.preventDefault();
14148 if(this.stopDefault){
14154 // allow inline handler
14156 this.on("click", this.handler, this.scope || this);
14159 Roo.util.ClickRepeater.superclass.constructor.call(this);
14162 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14165 preventDefault : true,
14166 stopDefault : false,
14170 handleMouseDown : function(){
14171 clearTimeout(this.timer);
14173 if(this.pressClass){
14174 this.el.addClass(this.pressClass);
14176 this.mousedownTime = new Date();
14178 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14179 this.el.on("mouseout", this.handleMouseOut, this);
14181 this.fireEvent("mousedown", this);
14182 this.fireEvent("click", this);
14184 this.timer = this.click.defer(this.delay || this.interval, this);
14188 click : function(){
14189 this.fireEvent("click", this);
14190 this.timer = this.click.defer(this.getInterval(), this);
14194 getInterval: function(){
14195 if(!this.accelerate){
14196 return this.interval;
14198 var pressTime = this.mousedownTime.getElapsed();
14199 if(pressTime < 500){
14201 }else if(pressTime < 1700){
14203 }else if(pressTime < 2600){
14205 }else if(pressTime < 3500){
14207 }else if(pressTime < 4400){
14209 }else if(pressTime < 5300){
14211 }else if(pressTime < 6200){
14219 handleMouseOut : function(){
14220 clearTimeout(this.timer);
14221 if(this.pressClass){
14222 this.el.removeClass(this.pressClass);
14224 this.el.on("mouseover", this.handleMouseReturn, this);
14228 handleMouseReturn : function(){
14229 this.el.un("mouseover", this.handleMouseReturn);
14230 if(this.pressClass){
14231 this.el.addClass(this.pressClass);
14237 handleMouseUp : function(){
14238 clearTimeout(this.timer);
14239 this.el.un("mouseover", this.handleMouseReturn);
14240 this.el.un("mouseout", this.handleMouseOut);
14241 Roo.get(document).un("mouseup", this.handleMouseUp);
14242 this.el.removeClass(this.pressClass);
14243 this.fireEvent("mouseup", this);
14247 * Ext JS Library 1.1.1
14248 * Copyright(c) 2006-2007, Ext JS, LLC.
14250 * Originally Released Under LGPL - original licence link has changed is not relivant.
14253 * <script type="text/javascript">
14258 * @class Roo.KeyNav
14259 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14260 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14261 * way to implement custom navigation schemes for any UI component.</p>
14262 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14263 * pageUp, pageDown, del, home, end. Usage:</p>
14265 var nav = new Roo.KeyNav("my-element", {
14266 "left" : function(e){
14267 this.moveLeft(e.ctrlKey);
14269 "right" : function(e){
14270 this.moveRight(e.ctrlKey);
14272 "enter" : function(e){
14279 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14280 * @param {Object} config The config
14282 Roo.KeyNav = function(el, config){
14283 this.el = Roo.get(el);
14284 Roo.apply(this, config);
14285 if(!this.disabled){
14286 this.disabled = true;
14291 Roo.KeyNav.prototype = {
14293 * @cfg {Boolean} disabled
14294 * True to disable this KeyNav instance (defaults to false)
14298 * @cfg {String} defaultEventAction
14299 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14300 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14301 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14303 defaultEventAction: "stopEvent",
14305 * @cfg {Boolean} forceKeyDown
14306 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14307 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14308 * handle keydown instead of keypress.
14310 forceKeyDown : false,
14313 prepareEvent : function(e){
14314 var k = e.getKey();
14315 var h = this.keyToHandler[k];
14316 //if(h && this[h]){
14317 // e.stopPropagation();
14319 if(Roo.isSafari && h && k >= 37 && k <= 40){
14325 relay : function(e){
14326 var k = e.getKey();
14327 var h = this.keyToHandler[k];
14329 if(this.doRelay(e, this[h], h) !== true){
14330 e[this.defaultEventAction]();
14336 doRelay : function(e, h, hname){
14337 return h.call(this.scope || this, e);
14340 // possible handlers
14354 // quick lookup hash
14371 * Enable this KeyNav
14373 enable: function(){
14375 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14376 // the EventObject will normalize Safari automatically
14377 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14378 this.el.on("keydown", this.relay, this);
14380 this.el.on("keydown", this.prepareEvent, this);
14381 this.el.on("keypress", this.relay, this);
14383 this.disabled = false;
14388 * Disable this KeyNav
14390 disable: function(){
14391 if(!this.disabled){
14392 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14393 this.el.un("keydown", this.relay);
14395 this.el.un("keydown", this.prepareEvent);
14396 this.el.un("keypress", this.relay);
14398 this.disabled = true;
14403 * Ext JS Library 1.1.1
14404 * Copyright(c) 2006-2007, Ext JS, LLC.
14406 * Originally Released Under LGPL - original licence link has changed is not relivant.
14409 * <script type="text/javascript">
14414 * @class Roo.KeyMap
14415 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14416 * The constructor accepts the same config object as defined by {@link #addBinding}.
14417 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14418 * combination it will call the function with this signature (if the match is a multi-key
14419 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14420 * A KeyMap can also handle a string representation of keys.<br />
14423 // map one key by key code
14424 var map = new Roo.KeyMap("my-element", {
14425 key: 13, // or Roo.EventObject.ENTER
14430 // map multiple keys to one action by string
14431 var map = new Roo.KeyMap("my-element", {
14437 // map multiple keys to multiple actions by strings and array of codes
14438 var map = new Roo.KeyMap("my-element", [
14441 fn: function(){ alert("Return was pressed"); }
14444 fn: function(){ alert('a, b or c was pressed'); }
14449 fn: function(){ alert('Control + shift + tab was pressed.'); }
14453 * <b>Note: A KeyMap starts enabled</b>
14455 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14456 * @param {Object} config The config (see {@link #addBinding})
14457 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14459 Roo.KeyMap = function(el, config, eventName){
14460 this.el = Roo.get(el);
14461 this.eventName = eventName || "keydown";
14462 this.bindings = [];
14464 this.addBinding(config);
14469 Roo.KeyMap.prototype = {
14471 * True to stop the event from bubbling and prevent the default browser action if the
14472 * key was handled by the KeyMap (defaults to false)
14478 * Add a new binding to this KeyMap. The following config object properties are supported:
14480 Property Type Description
14481 ---------- --------------- ----------------------------------------------------------------------
14482 key String/Array A single keycode or an array of keycodes to handle
14483 shift Boolean True to handle key only when shift is pressed (defaults to false)
14484 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14485 alt Boolean True to handle key only when alt is pressed (defaults to false)
14486 fn Function The function to call when KeyMap finds the expected key combination
14487 scope Object The scope of the callback function
14493 var map = new Roo.KeyMap(document, {
14494 key: Roo.EventObject.ENTER,
14499 //Add a new binding to the existing KeyMap later
14507 * @param {Object/Array} config A single KeyMap config or an array of configs
14509 addBinding : function(config){
14510 if(config instanceof Array){
14511 for(var i = 0, len = config.length; i < len; i++){
14512 this.addBinding(config[i]);
14516 var keyCode = config.key,
14517 shift = config.shift,
14518 ctrl = config.ctrl,
14521 scope = config.scope;
14522 if(typeof keyCode == "string"){
14524 var keyString = keyCode.toUpperCase();
14525 for(var j = 0, len = keyString.length; j < len; j++){
14526 ks.push(keyString.charCodeAt(j));
14530 var keyArray = keyCode instanceof Array;
14531 var handler = function(e){
14532 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14533 var k = e.getKey();
14535 for(var i = 0, len = keyCode.length; i < len; i++){
14536 if(keyCode[i] == k){
14537 if(this.stopEvent){
14540 fn.call(scope || window, k, e);
14546 if(this.stopEvent){
14549 fn.call(scope || window, k, e);
14554 this.bindings.push(handler);
14558 * Shorthand for adding a single key listener
14559 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14560 * following options:
14561 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14562 * @param {Function} fn The function to call
14563 * @param {Object} scope (optional) The scope of the function
14565 on : function(key, fn, scope){
14566 var keyCode, shift, ctrl, alt;
14567 if(typeof key == "object" && !(key instanceof Array)){
14586 handleKeyDown : function(e){
14587 if(this.enabled){ //just in case
14588 var b = this.bindings;
14589 for(var i = 0, len = b.length; i < len; i++){
14590 b[i].call(this, e);
14596 * Returns true if this KeyMap is enabled
14597 * @return {Boolean}
14599 isEnabled : function(){
14600 return this.enabled;
14604 * Enables this KeyMap
14606 enable: function(){
14608 this.el.on(this.eventName, this.handleKeyDown, this);
14609 this.enabled = true;
14614 * Disable this KeyMap
14616 disable: function(){
14618 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14619 this.enabled = false;
14624 * Ext JS Library 1.1.1
14625 * Copyright(c) 2006-2007, Ext JS, LLC.
14627 * Originally Released Under LGPL - original licence link has changed is not relivant.
14630 * <script type="text/javascript">
14635 * @class Roo.util.TextMetrics
14636 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14637 * wide, in pixels, a given block of text will be.
14640 Roo.util.TextMetrics = function(){
14644 * Measures the size of the specified text
14645 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14646 * that can affect the size of the rendered text
14647 * @param {String} text The text to measure
14648 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14649 * in order to accurately measure the text height
14650 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14652 measure : function(el, text, fixedWidth){
14654 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14657 shared.setFixedWidth(fixedWidth || 'auto');
14658 return shared.getSize(text);
14662 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14663 * the overhead of multiple calls to initialize the style properties on each measurement.
14664 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14665 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14666 * in order to accurately measure the text height
14667 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14669 createInstance : function(el, fixedWidth){
14670 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14677 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14678 var ml = new Roo.Element(document.createElement('div'));
14679 document.body.appendChild(ml.dom);
14680 ml.position('absolute');
14681 ml.setLeftTop(-1000, -1000);
14685 ml.setWidth(fixedWidth);
14690 * Returns the size of the specified text based on the internal element's style and width properties
14691 * @memberOf Roo.util.TextMetrics.Instance#
14692 * @param {String} text The text to measure
14693 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14695 getSize : function(text){
14697 var s = ml.getSize();
14703 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14704 * that can affect the size of the rendered text
14705 * @memberOf Roo.util.TextMetrics.Instance#
14706 * @param {String/HTMLElement} el The element, dom node or id
14708 bind : function(el){
14710 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14715 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14716 * to set a fixed width in order to accurately measure the text height.
14717 * @memberOf Roo.util.TextMetrics.Instance#
14718 * @param {Number} width The width to set on the element
14720 setFixedWidth : function(width){
14721 ml.setWidth(width);
14725 * Returns the measured width of the specified text
14726 * @memberOf Roo.util.TextMetrics.Instance#
14727 * @param {String} text The text to measure
14728 * @return {Number} width The width in pixels
14730 getWidth : function(text){
14731 ml.dom.style.width = 'auto';
14732 return this.getSize(text).width;
14736 * Returns the measured height of the specified text. For multiline text, be sure to call
14737 * {@link #setFixedWidth} if necessary.
14738 * @memberOf Roo.util.TextMetrics.Instance#
14739 * @param {String} text The text to measure
14740 * @return {Number} height The height in pixels
14742 getHeight : function(text){
14743 return this.getSize(text).height;
14747 instance.bind(bindTo);
14752 // backwards compat
14753 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14755 * Ext JS Library 1.1.1
14756 * Copyright(c) 2006-2007, Ext JS, LLC.
14758 * Originally Released Under LGPL - original licence link has changed is not relivant.
14761 * <script type="text/javascript">
14765 * @class Roo.state.Provider
14766 * Abstract base class for state provider implementations. This class provides methods
14767 * for encoding and decoding <b>typed</b> variables including dates and defines the
14768 * Provider interface.
14770 Roo.state.Provider = function(){
14772 * @event statechange
14773 * Fires when a state change occurs.
14774 * @param {Provider} this This state provider
14775 * @param {String} key The state key which was changed
14776 * @param {String} value The encoded value for the state
14779 "statechange": true
14782 Roo.state.Provider.superclass.constructor.call(this);
14784 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14786 * Returns the current value for a key
14787 * @param {String} name The key name
14788 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14789 * @return {Mixed} The state data
14791 get : function(name, defaultValue){
14792 return typeof this.state[name] == "undefined" ?
14793 defaultValue : this.state[name];
14797 * Clears a value from the state
14798 * @param {String} name The key name
14800 clear : function(name){
14801 delete this.state[name];
14802 this.fireEvent("statechange", this, name, null);
14806 * Sets the value for a key
14807 * @param {String} name The key name
14808 * @param {Mixed} value The value to set
14810 set : function(name, value){
14811 this.state[name] = value;
14812 this.fireEvent("statechange", this, name, value);
14816 * Decodes a string previously encoded with {@link #encodeValue}.
14817 * @param {String} value The value to decode
14818 * @return {Mixed} The decoded value
14820 decodeValue : function(cookie){
14821 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14822 var matches = re.exec(unescape(cookie));
14823 if(!matches || !matches[1]) return; // non state cookie
14824 var type = matches[1];
14825 var v = matches[2];
14828 return parseFloat(v);
14830 return new Date(Date.parse(v));
14835 var values = v.split("^");
14836 for(var i = 0, len = values.length; i < len; i++){
14837 all.push(this.decodeValue(values[i]));
14842 var values = v.split("^");
14843 for(var i = 0, len = values.length; i < len; i++){
14844 var kv = values[i].split("=");
14845 all[kv[0]] = this.decodeValue(kv[1]);
14854 * Encodes a value including type information. Decode with {@link #decodeValue}.
14855 * @param {Mixed} value The value to encode
14856 * @return {String} The encoded value
14858 encodeValue : function(v){
14860 if(typeof v == "number"){
14862 }else if(typeof v == "boolean"){
14863 enc = "b:" + (v ? "1" : "0");
14864 }else if(v instanceof Date){
14865 enc = "d:" + v.toGMTString();
14866 }else if(v instanceof Array){
14868 for(var i = 0, len = v.length; i < len; i++){
14869 flat += this.encodeValue(v[i]);
14870 if(i != len-1) flat += "^";
14873 }else if(typeof v == "object"){
14876 if(typeof v[key] != "function"){
14877 flat += key + "=" + this.encodeValue(v[key]) + "^";
14880 enc = "o:" + flat.substring(0, flat.length-1);
14884 return escape(enc);
14890 * Ext JS Library 1.1.1
14891 * Copyright(c) 2006-2007, Ext JS, LLC.
14893 * Originally Released Under LGPL - original licence link has changed is not relivant.
14896 * <script type="text/javascript">
14899 * @class Roo.state.Manager
14900 * This is the global state manager. By default all components that are "state aware" check this class
14901 * for state information if you don't pass them a custom state provider. In order for this class
14902 * to be useful, it must be initialized with a provider when your application initializes.
14904 // in your initialization function
14906 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14908 // supposed you have a {@link Roo.BorderLayout}
14909 var layout = new Roo.BorderLayout(...);
14910 layout.restoreState();
14911 // or a {Roo.BasicDialog}
14912 var dialog = new Roo.BasicDialog(...);
14913 dialog.restoreState();
14917 Roo.state.Manager = function(){
14918 var provider = new Roo.state.Provider();
14922 * Configures the default state provider for your application
14923 * @param {Provider} stateProvider The state provider to set
14925 setProvider : function(stateProvider){
14926 provider = stateProvider;
14930 * Returns the current value for a key
14931 * @param {String} name The key name
14932 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14933 * @return {Mixed} The state data
14935 get : function(key, defaultValue){
14936 return provider.get(key, defaultValue);
14940 * Sets the value for a key
14941 * @param {String} name The key name
14942 * @param {Mixed} value The state data
14944 set : function(key, value){
14945 provider.set(key, value);
14949 * Clears a value from the state
14950 * @param {String} name The key name
14952 clear : function(key){
14953 provider.clear(key);
14957 * Gets the currently configured state provider
14958 * @return {Provider} The state provider
14960 getProvider : function(){
14967 * Ext JS Library 1.1.1
14968 * Copyright(c) 2006-2007, Ext JS, LLC.
14970 * Originally Released Under LGPL - original licence link has changed is not relivant.
14973 * <script type="text/javascript">
14976 * @class Roo.state.CookieProvider
14977 * @extends Roo.state.Provider
14978 * The default Provider implementation which saves state via cookies.
14981 var cp = new Roo.state.CookieProvider({
14983 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14984 domain: "roojs.com"
14986 Roo.state.Manager.setProvider(cp);
14988 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14989 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14990 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14991 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14992 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14993 * domain the page is running on including the 'www' like 'www.roojs.com')
14994 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14996 * Create a new CookieProvider
14997 * @param {Object} config The configuration object
14999 Roo.state.CookieProvider = function(config){
15000 Roo.state.CookieProvider.superclass.constructor.call(this);
15002 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15003 this.domain = null;
15004 this.secure = false;
15005 Roo.apply(this, config);
15006 this.state = this.readCookies();
15009 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15011 set : function(name, value){
15012 if(typeof value == "undefined" || value === null){
15016 this.setCookie(name, value);
15017 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15021 clear : function(name){
15022 this.clearCookie(name);
15023 Roo.state.CookieProvider.superclass.clear.call(this, name);
15027 readCookies : function(){
15029 var c = document.cookie + ";";
15030 var re = /\s?(.*?)=(.*?);/g;
15032 while((matches = re.exec(c)) != null){
15033 var name = matches[1];
15034 var value = matches[2];
15035 if(name && name.substring(0,3) == "ys-"){
15036 cookies[name.substr(3)] = this.decodeValue(value);
15043 setCookie : function(name, value){
15044 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15045 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15046 ((this.path == null) ? "" : ("; path=" + this.path)) +
15047 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15048 ((this.secure == true) ? "; secure" : "");
15052 clearCookie : function(name){
15053 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15054 ((this.path == null) ? "" : ("; path=" + this.path)) +
15055 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15056 ((this.secure == true) ? "; secure" : "");
15060 * Ext JS Library 1.1.1
15061 * Copyright(c) 2006-2007, Ext JS, LLC.
15063 * Originally Released Under LGPL - original licence link has changed is not relivant.
15066 * <script type="text/javascript">
15071 * @class Roo.ComponentMgr
15072 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15075 Roo.ComponentMgr = function(){
15076 var all = new Roo.util.MixedCollection();
15080 * Registers a component.
15081 * @param {Roo.Component} c The component
15083 register : function(c){
15088 * Unregisters a component.
15089 * @param {Roo.Component} c The component
15091 unregister : function(c){
15096 * Returns a component by id
15097 * @param {String} id The component id
15099 get : function(id){
15100 return all.get(id);
15104 * Registers a function that will be called when a specified component is added to ComponentMgr
15105 * @param {String} id The component id
15106 * @param {Funtction} fn The callback function
15107 * @param {Object} scope The scope of the callback
15109 onAvailable : function(id, fn, scope){
15110 all.on("add", function(index, o){
15112 fn.call(scope || o, o);
15113 all.un("add", fn, scope);
15120 * Ext JS Library 1.1.1
15121 * Copyright(c) 2006-2007, Ext JS, LLC.
15123 * Originally Released Under LGPL - original licence link has changed is not relivant.
15126 * <script type="text/javascript">
15130 * @class Roo.Component
15131 * @extends Roo.util.Observable
15132 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15133 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15134 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15135 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15136 * All visual components (widgets) that require rendering into a layout should subclass Component.
15138 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15139 * 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
15140 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15142 Roo.Component = function(config){
15143 config = config || {};
15144 if(config.tagName || config.dom || typeof config == "string"){ // element object
15145 config = {el: config, id: config.id || config};
15147 this.initialConfig = config;
15149 Roo.apply(this, config);
15153 * Fires after the component is disabled.
15154 * @param {Roo.Component} this
15159 * Fires after the component is enabled.
15160 * @param {Roo.Component} this
15164 * @event beforeshow
15165 * Fires before the component is shown. Return false to stop the show.
15166 * @param {Roo.Component} this
15171 * Fires after the component is shown.
15172 * @param {Roo.Component} this
15176 * @event beforehide
15177 * Fires before the component is hidden. Return false to stop the hide.
15178 * @param {Roo.Component} this
15183 * Fires after the component is hidden.
15184 * @param {Roo.Component} this
15188 * @event beforerender
15189 * Fires before the component is rendered. Return false to stop the render.
15190 * @param {Roo.Component} this
15192 beforerender : true,
15195 * Fires after the component is rendered.
15196 * @param {Roo.Component} this
15200 * @event beforedestroy
15201 * Fires before the component is destroyed. Return false to stop the destroy.
15202 * @param {Roo.Component} this
15204 beforedestroy : true,
15207 * Fires after the component is destroyed.
15208 * @param {Roo.Component} this
15213 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15215 Roo.ComponentMgr.register(this);
15216 Roo.Component.superclass.constructor.call(this);
15217 this.initComponent();
15218 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15219 this.render(this.renderTo);
15220 delete this.renderTo;
15225 Roo.Component.AUTO_ID = 1000;
15227 Roo.extend(Roo.Component, Roo.util.Observable, {
15229 * @scope Roo.Component.prototype
15231 * true if this component is hidden. Read-only.
15236 * true if this component is disabled. Read-only.
15241 * true if this component has been rendered. Read-only.
15245 /** @cfg {String} disableClass
15246 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15248 disabledClass : "x-item-disabled",
15249 /** @cfg {Boolean} allowDomMove
15250 * Whether the component can move the Dom node when rendering (defaults to true).
15252 allowDomMove : true,
15253 /** @cfg {String} hideMode (display|visibility)
15254 * How this component should hidden. Supported values are
15255 * "visibility" (css visibility), "offsets" (negative offset position) and
15256 * "display" (css display) - defaults to "display".
15258 hideMode: 'display',
15261 ctype : "Roo.Component",
15264 * @cfg {String} actionMode
15265 * which property holds the element that used for hide() / show() / disable() / enable()
15271 getActionEl : function(){
15272 return this[this.actionMode];
15275 initComponent : Roo.emptyFn,
15277 * If this is a lazy rendering component, render it to its container element.
15278 * @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.
15280 render : function(container, position){
15281 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15282 if(!container && this.el){
15283 this.el = Roo.get(this.el);
15284 container = this.el.dom.parentNode;
15285 this.allowDomMove = false;
15287 this.container = Roo.get(container);
15288 this.rendered = true;
15289 if(position !== undefined){
15290 if(typeof position == 'number'){
15291 position = this.container.dom.childNodes[position];
15293 position = Roo.getDom(position);
15296 this.onRender(this.container, position || null);
15298 this.el.addClass(this.cls);
15302 this.el.applyStyles(this.style);
15305 this.fireEvent("render", this);
15306 this.afterRender(this.container);
15318 // default function is not really useful
15319 onRender : function(ct, position){
15321 this.el = Roo.get(this.el);
15322 if(this.allowDomMove !== false){
15323 ct.dom.insertBefore(this.el.dom, position);
15329 getAutoCreate : function(){
15330 var cfg = typeof this.autoCreate == "object" ?
15331 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15332 if(this.id && !cfg.id){
15339 afterRender : Roo.emptyFn,
15342 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15343 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15345 destroy : function(){
15346 if(this.fireEvent("beforedestroy", this) !== false){
15347 this.purgeListeners();
15348 this.beforeDestroy();
15350 this.el.removeAllListeners();
15352 if(this.actionMode == "container"){
15353 this.container.remove();
15357 Roo.ComponentMgr.unregister(this);
15358 this.fireEvent("destroy", this);
15363 beforeDestroy : function(){
15368 onDestroy : function(){
15373 * Returns the underlying {@link Roo.Element}.
15374 * @return {Roo.Element} The element
15376 getEl : function(){
15381 * Returns the id of this component.
15384 getId : function(){
15389 * Try to focus this component.
15390 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15391 * @return {Roo.Component} this
15393 focus : function(selectText){
15396 if(selectText === true){
15397 this.el.dom.select();
15412 * Disable this component.
15413 * @return {Roo.Component} this
15415 disable : function(){
15419 this.disabled = true;
15420 this.fireEvent("disable", this);
15425 onDisable : function(){
15426 this.getActionEl().addClass(this.disabledClass);
15427 this.el.dom.disabled = true;
15431 * Enable this component.
15432 * @return {Roo.Component} this
15434 enable : function(){
15438 this.disabled = false;
15439 this.fireEvent("enable", this);
15444 onEnable : function(){
15445 this.getActionEl().removeClass(this.disabledClass);
15446 this.el.dom.disabled = false;
15450 * Convenience function for setting disabled/enabled by boolean.
15451 * @param {Boolean} disabled
15453 setDisabled : function(disabled){
15454 this[disabled ? "disable" : "enable"]();
15458 * Show this component.
15459 * @return {Roo.Component} this
15462 if(this.fireEvent("beforeshow", this) !== false){
15463 this.hidden = false;
15467 this.fireEvent("show", this);
15473 onShow : function(){
15474 var ae = this.getActionEl();
15475 if(this.hideMode == 'visibility'){
15476 ae.dom.style.visibility = "visible";
15477 }else if(this.hideMode == 'offsets'){
15478 ae.removeClass('x-hidden');
15480 ae.dom.style.display = "";
15485 * Hide this component.
15486 * @return {Roo.Component} this
15489 if(this.fireEvent("beforehide", this) !== false){
15490 this.hidden = true;
15494 this.fireEvent("hide", this);
15500 onHide : function(){
15501 var ae = this.getActionEl();
15502 if(this.hideMode == 'visibility'){
15503 ae.dom.style.visibility = "hidden";
15504 }else if(this.hideMode == 'offsets'){
15505 ae.addClass('x-hidden');
15507 ae.dom.style.display = "none";
15512 * Convenience function to hide or show this component by boolean.
15513 * @param {Boolean} visible True to show, false to hide
15514 * @return {Roo.Component} this
15516 setVisible: function(visible){
15526 * Returns true if this component is visible.
15528 isVisible : function(){
15529 return this.getActionEl().isVisible();
15532 cloneConfig : function(overrides){
15533 overrides = overrides || {};
15534 var id = overrides.id || Roo.id();
15535 var cfg = Roo.applyIf(overrides, this.initialConfig);
15536 cfg.id = id; // prevent dup id
15537 return new this.constructor(cfg);
15541 * Ext JS Library 1.1.1
15542 * Copyright(c) 2006-2007, Ext JS, LLC.
15544 * Originally Released Under LGPL - original licence link has changed is not relivant.
15547 * <script type="text/javascript">
15551 * @class Roo.BoxComponent
15552 * @extends Roo.Component
15553 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15554 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15555 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15556 * layout containers.
15558 * @param {Roo.Element/String/Object} config The configuration options.
15560 Roo.BoxComponent = function(config){
15561 Roo.Component.call(this, config);
15565 * Fires after the component is resized.
15566 * @param {Roo.Component} this
15567 * @param {Number} adjWidth The box-adjusted width that was set
15568 * @param {Number} adjHeight The box-adjusted height that was set
15569 * @param {Number} rawWidth The width that was originally specified
15570 * @param {Number} rawHeight The height that was originally specified
15575 * Fires after the component is moved.
15576 * @param {Roo.Component} this
15577 * @param {Number} x The new x position
15578 * @param {Number} y The new y position
15584 Roo.extend(Roo.BoxComponent, Roo.Component, {
15585 // private, set in afterRender to signify that the component has been rendered
15587 // private, used to defer height settings to subclasses
15588 deferHeight: false,
15589 /** @cfg {Number} width
15590 * width (optional) size of component
15592 /** @cfg {Number} height
15593 * height (optional) size of component
15597 * Sets the width and height of the component. This method fires the resize event. This method can accept
15598 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15599 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15600 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15601 * @return {Roo.BoxComponent} this
15603 setSize : function(w, h){
15604 // support for standard size objects
15605 if(typeof w == 'object'){
15610 if(!this.boxReady){
15616 // prevent recalcs when not needed
15617 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15620 this.lastSize = {width: w, height: h};
15622 var adj = this.adjustSize(w, h);
15623 var aw = adj.width, ah = adj.height;
15624 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15625 var rz = this.getResizeEl();
15626 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15627 rz.setSize(aw, ah);
15628 }else if(!this.deferHeight && ah !== undefined){
15630 }else if(aw !== undefined){
15633 this.onResize(aw, ah, w, h);
15634 this.fireEvent('resize', this, aw, ah, w, h);
15640 * Gets the current size of the component's underlying element.
15641 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15643 getSize : function(){
15644 return this.el.getSize();
15648 * Gets the current XY position of the component's underlying element.
15649 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15650 * @return {Array} The XY position of the element (e.g., [100, 200])
15652 getPosition : function(local){
15653 if(local === true){
15654 return [this.el.getLeft(true), this.el.getTop(true)];
15656 return this.xy || this.el.getXY();
15660 * Gets the current box measurements of the component's underlying element.
15661 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15662 * @returns {Object} box An object in the format {x, y, width, height}
15664 getBox : function(local){
15665 var s = this.el.getSize();
15667 s.x = this.el.getLeft(true);
15668 s.y = this.el.getTop(true);
15670 var xy = this.xy || this.el.getXY();
15678 * Sets the current box measurements of the component's underlying element.
15679 * @param {Object} box An object in the format {x, y, width, height}
15680 * @returns {Roo.BoxComponent} this
15682 updateBox : function(box){
15683 this.setSize(box.width, box.height);
15684 this.setPagePosition(box.x, box.y);
15689 getResizeEl : function(){
15690 return this.resizeEl || this.el;
15694 getPositionEl : function(){
15695 return this.positionEl || this.el;
15699 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15700 * This method fires the move event.
15701 * @param {Number} left The new left
15702 * @param {Number} top The new top
15703 * @returns {Roo.BoxComponent} this
15705 setPosition : function(x, y){
15708 if(!this.boxReady){
15711 var adj = this.adjustPosition(x, y);
15712 var ax = adj.x, ay = adj.y;
15714 var el = this.getPositionEl();
15715 if(ax !== undefined || ay !== undefined){
15716 if(ax !== undefined && ay !== undefined){
15717 el.setLeftTop(ax, ay);
15718 }else if(ax !== undefined){
15720 }else if(ay !== undefined){
15723 this.onPosition(ax, ay);
15724 this.fireEvent('move', this, ax, ay);
15730 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15731 * This method fires the move event.
15732 * @param {Number} x The new x position
15733 * @param {Number} y The new y position
15734 * @returns {Roo.BoxComponent} this
15736 setPagePosition : function(x, y){
15739 if(!this.boxReady){
15742 if(x === undefined || y === undefined){ // cannot translate undefined points
15745 var p = this.el.translatePoints(x, y);
15746 this.setPosition(p.left, p.top);
15751 onRender : function(ct, position){
15752 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15754 this.resizeEl = Roo.get(this.resizeEl);
15756 if(this.positionEl){
15757 this.positionEl = Roo.get(this.positionEl);
15762 afterRender : function(){
15763 Roo.BoxComponent.superclass.afterRender.call(this);
15764 this.boxReady = true;
15765 this.setSize(this.width, this.height);
15766 if(this.x || this.y){
15767 this.setPosition(this.x, this.y);
15769 if(this.pageX || this.pageY){
15770 this.setPagePosition(this.pageX, this.pageY);
15775 * Force the component's size to recalculate based on the underlying element's current height and width.
15776 * @returns {Roo.BoxComponent} this
15778 syncSize : function(){
15779 delete this.lastSize;
15780 this.setSize(this.el.getWidth(), this.el.getHeight());
15785 * Called after the component is resized, this method is empty by default but can be implemented by any
15786 * subclass that needs to perform custom logic after a resize occurs.
15787 * @param {Number} adjWidth The box-adjusted width that was set
15788 * @param {Number} adjHeight The box-adjusted height that was set
15789 * @param {Number} rawWidth The width that was originally specified
15790 * @param {Number} rawHeight The height that was originally specified
15792 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15797 * Called after the component is moved, this method is empty by default but can be implemented by any
15798 * subclass that needs to perform custom logic after a move occurs.
15799 * @param {Number} x The new x position
15800 * @param {Number} y The new y position
15802 onPosition : function(x, y){
15807 adjustSize : function(w, h){
15808 if(this.autoWidth){
15811 if(this.autoHeight){
15814 return {width : w, height: h};
15818 adjustPosition : function(x, y){
15819 return {x : x, y: y};
15822 * Original code for Roojs - LGPL
15823 * <script type="text/javascript">
15827 * @class Roo.XComponent
15828 * A delayed Element creator...
15829 * Or a way to group chunks of interface together.
15830 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15831 * used in conjunction with XComponent.build() it will create an instance of each element,
15832 * then call addxtype() to build the User interface.
15834 * Mypart.xyx = new Roo.XComponent({
15836 parent : 'Mypart.xyz', // empty == document.element.!!
15840 disabled : function() {}
15842 tree : function() { // return an tree of xtype declared components
15846 xtype : 'NestedLayoutPanel',
15853 * It can be used to build a big heiracy, with parent etc.
15854 * or you can just use this to render a single compoent to a dom element
15855 * MYPART.render(Roo.Element | String(id) | dom_element )
15862 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15863 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15865 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15867 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15868 * - if mulitple topModules exist, the last one is defined as the top module.
15872 * When the top level or multiple modules are to embedded into a existing HTML page,
15873 * the parent element can container '#id' of the element where the module will be drawn.
15877 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15878 * it relies more on a include mechanism, where sub modules are included into an outer page.
15879 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15881 * Bootstrap Roo Included elements
15883 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15884 * hence confusing the component builder as it thinks there are multiple top level elements.
15888 * @extends Roo.util.Observable
15890 * @param cfg {Object} configuration of component
15893 Roo.XComponent = function(cfg) {
15894 Roo.apply(this, cfg);
15898 * Fires when this the componnt is built
15899 * @param {Roo.XComponent} c the component
15904 this.region = this.region || 'center'; // default..
15905 Roo.XComponent.register(this);
15906 this.modules = false;
15907 this.el = false; // where the layout goes..
15911 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15914 * The created element (with Roo.factory())
15915 * @type {Roo.Layout}
15921 * for BC - use el in new code
15922 * @type {Roo.Layout}
15928 * for BC - use el in new code
15929 * @type {Roo.Layout}
15934 * @cfg {Function|boolean} disabled
15935 * If this module is disabled by some rule, return true from the funtion
15940 * @cfg {String} parent
15941 * Name of parent element which it get xtype added to..
15946 * @cfg {String} order
15947 * Used to set the order in which elements are created (usefull for multiple tabs)
15952 * @cfg {String} name
15953 * String to display while loading.
15957 * @cfg {String} region
15958 * Region to render component to (defaults to center)
15963 * @cfg {Array} items
15964 * A single item array - the first element is the root of the tree..
15965 * It's done this way to stay compatible with the Xtype system...
15971 * The method that retuns the tree of parts that make up this compoennt
15978 * render element to dom or tree
15979 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15982 render : function(el)
15986 var hp = this.parent ? 1 : 0;
15987 Roo.debug && Roo.log(this);
15989 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15990 // if parent is a '#.....' string, then let's use that..
15991 var ename = this.parent.substr(1);
15992 this.parent = false;
15993 Roo.debug && Roo.log(ename);
15995 case 'bootstrap-body' :
15996 if (typeof(Roo.bootstrap.Body) != 'undefined') {
15997 this.parent = { el : new Roo.bootstrap.Body() };
15998 Roo.debug && Roo.log("setting el to doc body");
16001 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16005 this.parent = { el : true};
16008 el = Roo.get(ename);
16013 if (!el && !this.parent) {
16014 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16018 Roo.debug && Roo.log("EL:");
16019 Roo.debug && Roo.log(el);
16020 Roo.debug && Roo.log("this.parent.el:");
16021 Roo.debug && Roo.log(this.parent.el);
16023 var tree = this._tree ? this._tree() : this.tree();
16025 // altertive root elements ??? - we need a better way to indicate these.
16026 var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16027 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16029 if (!this.parent && is_alt) {
16030 //el = Roo.get(document.body);
16031 this.parent = { el : true };
16036 if (!this.parent) {
16038 Roo.debug && Roo.log("no parent - creating one");
16040 el = el ? Roo.get(el) : false;
16042 // it's a top level one..
16044 el : new Roo.BorderLayout(el || document.body, {
16050 tabPosition: 'top',
16051 //resizeTabs: true,
16052 alwaysShowTabs: el && hp? false : true,
16053 hideTabs: el || !hp ? true : false,
16060 if (!this.parent.el) {
16061 // probably an old style ctor, which has been disabled.
16065 // The 'tree' method is '_tree now'
16067 tree.region = tree.region || this.region;
16069 if (this.parent.el === true) {
16070 // bootstrap... - body..
16071 this.parent.el = Roo.factory(tree);
16074 this.el = this.parent.el.addxtype(tree);
16075 this.fireEvent('built', this);
16077 this.panel = this.el;
16078 this.layout = this.panel.layout;
16079 this.parentLayout = this.parent.layout || false;
16085 Roo.apply(Roo.XComponent, {
16087 * @property hideProgress
16088 * true to disable the building progress bar.. usefull on single page renders.
16091 hideProgress : false,
16093 * @property buildCompleted
16094 * True when the builder has completed building the interface.
16097 buildCompleted : false,
16100 * @property topModule
16101 * the upper most module - uses document.element as it's constructor.
16108 * @property modules
16109 * array of modules to be created by registration system.
16110 * @type {Array} of Roo.XComponent
16115 * @property elmodules
16116 * array of modules to be created by which use #ID
16117 * @type {Array} of Roo.XComponent
16123 * @property build_from_html
16124 * Build elements from html - used by bootstrap HTML stuff
16125 * - this is cleared after build is completed
16126 * @type {boolean} true (default false)
16129 build_from_html : false,
16132 * Register components to be built later.
16134 * This solves the following issues
16135 * - Building is not done on page load, but after an authentication process has occured.
16136 * - Interface elements are registered on page load
16137 * - Parent Interface elements may not be loaded before child, so this handles that..
16144 module : 'Pman.Tab.projectMgr',
16146 parent : 'Pman.layout',
16147 disabled : false, // or use a function..
16150 * * @param {Object} details about module
16152 register : function(obj) {
16154 Roo.XComponent.event.fireEvent('register', obj);
16155 switch(typeof(obj.disabled) ) {
16161 if ( obj.disabled() ) {
16167 if (obj.disabled) {
16173 this.modules.push(obj);
16177 * convert a string to an object..
16178 * eg. 'AAA.BBB' -> finds AAA.BBB
16182 toObject : function(str)
16184 if (!str || typeof(str) == 'object') {
16187 if (str.substring(0,1) == '#') {
16191 var ar = str.split('.');
16196 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16198 throw "Module not found : " + str;
16202 throw "Module not found : " + str;
16204 Roo.each(ar, function(e) {
16205 if (typeof(o[e]) == 'undefined') {
16206 throw "Module not found : " + str;
16217 * move modules into their correct place in the tree..
16220 preBuild : function ()
16223 Roo.each(this.modules , function (obj)
16225 Roo.XComponent.event.fireEvent('beforebuild', obj);
16227 var opar = obj.parent;
16229 obj.parent = this.toObject(opar);
16231 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16236 Roo.debug && Roo.log("GOT top level module");
16237 Roo.debug && Roo.log(obj);
16238 obj.modules = new Roo.util.MixedCollection(false,
16239 function(o) { return o.order + '' }
16241 this.topModule = obj;
16244 // parent is a string (usually a dom element name..)
16245 if (typeof(obj.parent) == 'string') {
16246 this.elmodules.push(obj);
16249 if (obj.parent.constructor != Roo.XComponent) {
16250 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16252 if (!obj.parent.modules) {
16253 obj.parent.modules = new Roo.util.MixedCollection(false,
16254 function(o) { return o.order + '' }
16257 if (obj.parent.disabled) {
16258 obj.disabled = true;
16260 obj.parent.modules.add(obj);
16265 * make a list of modules to build.
16266 * @return {Array} list of modules.
16269 buildOrder : function()
16272 var cmp = function(a,b) {
16273 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16275 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16276 throw "No top level modules to build";
16279 // make a flat list in order of modules to build.
16280 var mods = this.topModule ? [ this.topModule ] : [];
16283 // elmodules (is a list of DOM based modules )
16284 Roo.each(this.elmodules, function(e) {
16286 if (!this.topModule &&
16287 typeof(e.parent) == 'string' &&
16288 e.parent.substring(0,1) == '#' &&
16289 Roo.get(e.parent.substr(1))
16292 _this.topModule = e;
16298 // add modules to their parents..
16299 var addMod = function(m) {
16300 Roo.debug && Roo.log("build Order: add: " + m.name);
16303 if (m.modules && !m.disabled) {
16304 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16305 m.modules.keySort('ASC', cmp );
16306 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16308 m.modules.each(addMod);
16310 Roo.debug && Roo.log("build Order: no child modules");
16312 // not sure if this is used any more..
16314 m.finalize.name = m.name + " (clean up) ";
16315 mods.push(m.finalize);
16319 if (this.topModule && this.topModule.modules) {
16320 this.topModule.modules.keySort('ASC', cmp );
16321 this.topModule.modules.each(addMod);
16327 * Build the registered modules.
16328 * @param {Object} parent element.
16329 * @param {Function} optional method to call after module has been added.
16333 build : function(opts)
16336 if (typeof(opts) != 'undefined') {
16337 Roo.apply(this,opts);
16341 var mods = this.buildOrder();
16343 //this.allmods = mods;
16344 //Roo.debug && Roo.log(mods);
16346 if (!mods.length) { // should not happen
16347 throw "NO modules!!!";
16351 var msg = "Building Interface...";
16352 // flash it up as modal - so we store the mask!?
16353 if (!this.hideProgress && Roo.MessageBox) {
16354 Roo.MessageBox.show({ title: 'loading' });
16355 Roo.MessageBox.show({
16356 title: "Please wait...",
16365 var total = mods.length;
16368 var progressRun = function() {
16369 if (!mods.length) {
16370 Roo.debug && Roo.log('hide?');
16371 if (!this.hideProgress && Roo.MessageBox) {
16372 Roo.MessageBox.hide();
16374 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16376 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16382 var m = mods.shift();
16385 Roo.debug && Roo.log(m);
16386 // not sure if this is supported any more.. - modules that are are just function
16387 if (typeof(m) == 'function') {
16389 return progressRun.defer(10, _this);
16393 msg = "Building Interface " + (total - mods.length) +
16395 (m.name ? (' - ' + m.name) : '');
16396 Roo.debug && Roo.log(msg);
16397 if (!this.hideProgress && Roo.MessageBox) {
16398 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16402 // is the module disabled?
16403 var disabled = (typeof(m.disabled) == 'function') ?
16404 m.disabled.call(m.module.disabled) : m.disabled;
16408 return progressRun(); // we do not update the display!
16416 // it's 10 on top level, and 1 on others??? why...
16417 return progressRun.defer(10, _this);
16420 progressRun.defer(1, _this);
16434 * wrapper for event.on - aliased later..
16435 * Typically use to register a event handler for register:
16437 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16446 Roo.XComponent.event = new Roo.util.Observable({
16450 * Fires when an Component is registered,
16451 * set the disable property on the Component to stop registration.
16452 * @param {Roo.XComponent} c the component being registerd.
16457 * @event beforebuild
16458 * Fires before each Component is built
16459 * can be used to apply permissions.
16460 * @param {Roo.XComponent} c the component being registerd.
16463 'beforebuild' : true,
16465 * @event buildcomplete
16466 * Fires on the top level element when all elements have been built
16467 * @param {Roo.XComponent} the top level component.
16469 'buildcomplete' : true
16474 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16477 * Ext JS Library 1.1.1
16478 * Copyright(c) 2006-2007, Ext JS, LLC.
16480 * Originally Released Under LGPL - original licence link has changed is not relivant.
16483 * <script type="text/javascript">
16489 * These classes are derivatives of the similarly named classes in the YUI Library.
16490 * The original license:
16491 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16492 * Code licensed under the BSD License:
16493 * http://developer.yahoo.net/yui/license.txt
16498 var Event=Roo.EventManager;
16499 var Dom=Roo.lib.Dom;
16502 * @class Roo.dd.DragDrop
16503 * @extends Roo.util.Observable
16504 * Defines the interface and base operation of items that that can be
16505 * dragged or can be drop targets. It was designed to be extended, overriding
16506 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16507 * Up to three html elements can be associated with a DragDrop instance:
16509 * <li>linked element: the element that is passed into the constructor.
16510 * This is the element which defines the boundaries for interaction with
16511 * other DragDrop objects.</li>
16512 * <li>handle element(s): The drag operation only occurs if the element that
16513 * was clicked matches a handle element. By default this is the linked
16514 * element, but there are times that you will want only a portion of the
16515 * linked element to initiate the drag operation, and the setHandleElId()
16516 * method provides a way to define this.</li>
16517 * <li>drag element: this represents the element that would be moved along
16518 * with the cursor during a drag operation. By default, this is the linked
16519 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16520 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16523 * This class should not be instantiated until the onload event to ensure that
16524 * the associated elements are available.
16525 * The following would define a DragDrop obj that would interact with any
16526 * other DragDrop obj in the "group1" group:
16528 * dd = new Roo.dd.DragDrop("div1", "group1");
16530 * Since none of the event handlers have been implemented, nothing would
16531 * actually happen if you were to run the code above. Normally you would
16532 * override this class or one of the default implementations, but you can
16533 * also override the methods you want on an instance of the class...
16535 * dd.onDragDrop = function(e, id) {
16536 * alert("dd was dropped on " + id);
16540 * @param {String} id of the element that is linked to this instance
16541 * @param {String} sGroup the group of related DragDrop objects
16542 * @param {object} config an object containing configurable attributes
16543 * Valid properties for DragDrop:
16544 * padding, isTarget, maintainOffset, primaryButtonOnly
16546 Roo.dd.DragDrop = function(id, sGroup, config) {
16548 this.init(id, sGroup, config);
16553 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16556 * The id of the element associated with this object. This is what we
16557 * refer to as the "linked element" because the size and position of
16558 * this element is used to determine when the drag and drop objects have
16566 * Configuration attributes passed into the constructor
16573 * The id of the element that will be dragged. By default this is same
16574 * as the linked element , but could be changed to another element. Ex:
16576 * @property dragElId
16583 * the id of the element that initiates the drag operation. By default
16584 * this is the linked element, but could be changed to be a child of this
16585 * element. This lets us do things like only starting the drag when the
16586 * header element within the linked html element is clicked.
16587 * @property handleElId
16594 * An associative array of HTML tags that will be ignored if clicked.
16595 * @property invalidHandleTypes
16596 * @type {string: string}
16598 invalidHandleTypes: null,
16601 * An associative array of ids for elements that will be ignored if clicked
16602 * @property invalidHandleIds
16603 * @type {string: string}
16605 invalidHandleIds: null,
16608 * An indexted array of css class names for elements that will be ignored
16610 * @property invalidHandleClasses
16613 invalidHandleClasses: null,
16616 * The linked element's absolute X position at the time the drag was
16618 * @property startPageX
16625 * The linked element's absolute X position at the time the drag was
16627 * @property startPageY
16634 * The group defines a logical collection of DragDrop objects that are
16635 * related. Instances only get events when interacting with other
16636 * DragDrop object in the same group. This lets us define multiple
16637 * groups using a single DragDrop subclass if we want.
16639 * @type {string: string}
16644 * Individual drag/drop instances can be locked. This will prevent
16645 * onmousedown start drag.
16653 * Lock this instance
16656 lock: function() { this.locked = true; },
16659 * Unlock this instace
16662 unlock: function() { this.locked = false; },
16665 * By default, all insances can be a drop target. This can be disabled by
16666 * setting isTarget to false.
16673 * The padding configured for this drag and drop object for calculating
16674 * the drop zone intersection with this object.
16681 * Cached reference to the linked element
16682 * @property _domRef
16688 * Internal typeof flag
16689 * @property __ygDragDrop
16692 __ygDragDrop: true,
16695 * Set to true when horizontal contraints are applied
16696 * @property constrainX
16703 * Set to true when vertical contraints are applied
16704 * @property constrainY
16711 * The left constraint
16719 * The right constraint
16727 * The up constraint
16736 * The down constraint
16744 * Maintain offsets when we resetconstraints. Set to true when you want
16745 * the position of the element relative to its parent to stay the same
16746 * when the page changes
16748 * @property maintainOffset
16751 maintainOffset: false,
16754 * Array of pixel locations the element will snap to if we specified a
16755 * horizontal graduation/interval. This array is generated automatically
16756 * when you define a tick interval.
16763 * Array of pixel locations the element will snap to if we specified a
16764 * vertical graduation/interval. This array is generated automatically
16765 * when you define a tick interval.
16772 * By default the drag and drop instance will only respond to the primary
16773 * button click (left button for a right-handed mouse). Set to true to
16774 * allow drag and drop to start with any mouse click that is propogated
16776 * @property primaryButtonOnly
16779 primaryButtonOnly: true,
16782 * The availabe property is false until the linked dom element is accessible.
16783 * @property available
16789 * By default, drags can only be initiated if the mousedown occurs in the
16790 * region the linked element is. This is done in part to work around a
16791 * bug in some browsers that mis-report the mousedown if the previous
16792 * mouseup happened outside of the window. This property is set to true
16793 * if outer handles are defined.
16795 * @property hasOuterHandles
16799 hasOuterHandles: false,
16802 * Code that executes immediately before the startDrag event
16803 * @method b4StartDrag
16806 b4StartDrag: function(x, y) { },
16809 * Abstract method called after a drag/drop object is clicked
16810 * and the drag or mousedown time thresholds have beeen met.
16811 * @method startDrag
16812 * @param {int} X click location
16813 * @param {int} Y click location
16815 startDrag: function(x, y) { /* override this */ },
16818 * Code that executes immediately before the onDrag event
16822 b4Drag: function(e) { },
16825 * Abstract method called during the onMouseMove event while dragging an
16828 * @param {Event} e the mousemove event
16830 onDrag: function(e) { /* override this */ },
16833 * Abstract method called when this element fist begins hovering over
16834 * another DragDrop obj
16835 * @method onDragEnter
16836 * @param {Event} e the mousemove event
16837 * @param {String|DragDrop[]} id In POINT mode, the element
16838 * id this is hovering over. In INTERSECT mode, an array of one or more
16839 * dragdrop items being hovered over.
16841 onDragEnter: function(e, id) { /* override this */ },
16844 * Code that executes immediately before the onDragOver event
16845 * @method b4DragOver
16848 b4DragOver: function(e) { },
16851 * Abstract method called when this element is hovering over another
16853 * @method onDragOver
16854 * @param {Event} e the mousemove event
16855 * @param {String|DragDrop[]} id In POINT mode, the element
16856 * id this is hovering over. In INTERSECT mode, an array of dd items
16857 * being hovered over.
16859 onDragOver: function(e, id) { /* override this */ },
16862 * Code that executes immediately before the onDragOut event
16863 * @method b4DragOut
16866 b4DragOut: function(e) { },
16869 * Abstract method called when we are no longer hovering over an element
16870 * @method onDragOut
16871 * @param {Event} e the mousemove event
16872 * @param {String|DragDrop[]} id In POINT mode, the element
16873 * id this was hovering over. In INTERSECT mode, an array of dd items
16874 * that the mouse is no longer over.
16876 onDragOut: function(e, id) { /* override this */ },
16879 * Code that executes immediately before the onDragDrop event
16880 * @method b4DragDrop
16883 b4DragDrop: function(e) { },
16886 * Abstract method called when this item is dropped on another DragDrop
16888 * @method onDragDrop
16889 * @param {Event} e the mouseup event
16890 * @param {String|DragDrop[]} id In POINT mode, the element
16891 * id this was dropped on. In INTERSECT mode, an array of dd items this
16894 onDragDrop: function(e, id) { /* override this */ },
16897 * Abstract method called when this item is dropped on an area with no
16899 * @method onInvalidDrop
16900 * @param {Event} e the mouseup event
16902 onInvalidDrop: function(e) { /* override this */ },
16905 * Code that executes immediately before the endDrag event
16906 * @method b4EndDrag
16909 b4EndDrag: function(e) { },
16912 * Fired when we are done dragging the object
16914 * @param {Event} e the mouseup event
16916 endDrag: function(e) { /* override this */ },
16919 * Code executed immediately before the onMouseDown event
16920 * @method b4MouseDown
16921 * @param {Event} e the mousedown event
16924 b4MouseDown: function(e) { },
16927 * Event handler that fires when a drag/drop obj gets a mousedown
16928 * @method onMouseDown
16929 * @param {Event} e the mousedown event
16931 onMouseDown: function(e) { /* override this */ },
16934 * Event handler that fires when a drag/drop obj gets a mouseup
16935 * @method onMouseUp
16936 * @param {Event} e the mouseup event
16938 onMouseUp: function(e) { /* override this */ },
16941 * Override the onAvailable method to do what is needed after the initial
16942 * position was determined.
16943 * @method onAvailable
16945 onAvailable: function () {
16949 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16952 defaultPadding : {left:0, right:0, top:0, bottom:0},
16955 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16959 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16960 { dragElId: "existingProxyDiv" });
16961 dd.startDrag = function(){
16962 this.constrainTo("parent-id");
16965 * Or you can initalize it using the {@link Roo.Element} object:
16967 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16968 startDrag : function(){
16969 this.constrainTo("parent-id");
16973 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16974 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16975 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16976 * an object containing the sides to pad. For example: {right:10, bottom:10}
16977 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16979 constrainTo : function(constrainTo, pad, inContent){
16980 if(typeof pad == "number"){
16981 pad = {left: pad, right:pad, top:pad, bottom:pad};
16983 pad = pad || this.defaultPadding;
16984 var b = Roo.get(this.getEl()).getBox();
16985 var ce = Roo.get(constrainTo);
16986 var s = ce.getScroll();
16987 var c, cd = ce.dom;
16988 if(cd == document.body){
16989 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16992 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16996 var topSpace = b.y - c.y;
16997 var leftSpace = b.x - c.x;
16999 this.resetConstraints();
17000 this.setXConstraint(leftSpace - (pad.left||0), // left
17001 c.width - leftSpace - b.width - (pad.right||0) //right
17003 this.setYConstraint(topSpace - (pad.top||0), //top
17004 c.height - topSpace - b.height - (pad.bottom||0) //bottom
17009 * Returns a reference to the linked element
17011 * @return {HTMLElement} the html element
17013 getEl: function() {
17014 if (!this._domRef) {
17015 this._domRef = Roo.getDom(this.id);
17018 return this._domRef;
17022 * Returns a reference to the actual element to drag. By default this is
17023 * the same as the html element, but it can be assigned to another
17024 * element. An example of this can be found in Roo.dd.DDProxy
17025 * @method getDragEl
17026 * @return {HTMLElement} the html element
17028 getDragEl: function() {
17029 return Roo.getDom(this.dragElId);
17033 * Sets up the DragDrop object. Must be called in the constructor of any
17034 * Roo.dd.DragDrop subclass
17036 * @param id the id of the linked element
17037 * @param {String} sGroup the group of related items
17038 * @param {object} config configuration attributes
17040 init: function(id, sGroup, config) {
17041 this.initTarget(id, sGroup, config);
17042 if (!Roo.isTouch) {
17043 Event.on(this.id, "mousedown", this.handleMouseDown, this);
17045 Event.on(this.id, "touchstart", this.handleMouseDown, this);
17046 // Event.on(this.id, "selectstart", Event.preventDefault);
17050 * Initializes Targeting functionality only... the object does not
17051 * get a mousedown handler.
17052 * @method initTarget
17053 * @param id the id of the linked element
17054 * @param {String} sGroup the group of related items
17055 * @param {object} config configuration attributes
17057 initTarget: function(id, sGroup, config) {
17059 // configuration attributes
17060 this.config = config || {};
17062 // create a local reference to the drag and drop manager
17063 this.DDM = Roo.dd.DDM;
17064 // initialize the groups array
17067 // assume that we have an element reference instead of an id if the
17068 // parameter is not a string
17069 if (typeof id !== "string") {
17076 // add to an interaction group
17077 this.addToGroup((sGroup) ? sGroup : "default");
17079 // We don't want to register this as the handle with the manager
17080 // so we just set the id rather than calling the setter.
17081 this.handleElId = id;
17083 // the linked element is the element that gets dragged by default
17084 this.setDragElId(id);
17086 // by default, clicked anchors will not start drag operations.
17087 this.invalidHandleTypes = { A: "A" };
17088 this.invalidHandleIds = {};
17089 this.invalidHandleClasses = [];
17091 this.applyConfig();
17093 this.handleOnAvailable();
17097 * Applies the configuration parameters that were passed into the constructor.
17098 * This is supposed to happen at each level through the inheritance chain. So
17099 * a DDProxy implentation will execute apply config on DDProxy, DD, and
17100 * DragDrop in order to get all of the parameters that are available in
17102 * @method applyConfig
17104 applyConfig: function() {
17106 // configurable properties:
17107 // padding, isTarget, maintainOffset, primaryButtonOnly
17108 this.padding = this.config.padding || [0, 0, 0, 0];
17109 this.isTarget = (this.config.isTarget !== false);
17110 this.maintainOffset = (this.config.maintainOffset);
17111 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
17116 * Executed when the linked element is available
17117 * @method handleOnAvailable
17120 handleOnAvailable: function() {
17121 this.available = true;
17122 this.resetConstraints();
17123 this.onAvailable();
17127 * Configures the padding for the target zone in px. Effectively expands
17128 * (or reduces) the virtual object size for targeting calculations.
17129 * Supports css-style shorthand; if only one parameter is passed, all sides
17130 * will have that padding, and if only two are passed, the top and bottom
17131 * will have the first param, the left and right the second.
17132 * @method setPadding
17133 * @param {int} iTop Top pad
17134 * @param {int} iRight Right pad
17135 * @param {int} iBot Bot pad
17136 * @param {int} iLeft Left pad
17138 setPadding: function(iTop, iRight, iBot, iLeft) {
17139 // this.padding = [iLeft, iRight, iTop, iBot];
17140 if (!iRight && 0 !== iRight) {
17141 this.padding = [iTop, iTop, iTop, iTop];
17142 } else if (!iBot && 0 !== iBot) {
17143 this.padding = [iTop, iRight, iTop, iRight];
17145 this.padding = [iTop, iRight, iBot, iLeft];
17150 * Stores the initial placement of the linked element.
17151 * @method setInitialPosition
17152 * @param {int} diffX the X offset, default 0
17153 * @param {int} diffY the Y offset, default 0
17155 setInitPosition: function(diffX, diffY) {
17156 var el = this.getEl();
17158 if (!this.DDM.verifyEl(el)) {
17162 var dx = diffX || 0;
17163 var dy = diffY || 0;
17165 var p = Dom.getXY( el );
17167 this.initPageX = p[0] - dx;
17168 this.initPageY = p[1] - dy;
17170 this.lastPageX = p[0];
17171 this.lastPageY = p[1];
17174 this.setStartPosition(p);
17178 * Sets the start position of the element. This is set when the obj
17179 * is initialized, the reset when a drag is started.
17180 * @method setStartPosition
17181 * @param pos current position (from previous lookup)
17184 setStartPosition: function(pos) {
17185 var p = pos || Dom.getXY( this.getEl() );
17186 this.deltaSetXY = null;
17188 this.startPageX = p[0];
17189 this.startPageY = p[1];
17193 * Add this instance to a group of related drag/drop objects. All
17194 * instances belong to at least one group, and can belong to as many
17195 * groups as needed.
17196 * @method addToGroup
17197 * @param sGroup {string} the name of the group
17199 addToGroup: function(sGroup) {
17200 this.groups[sGroup] = true;
17201 this.DDM.regDragDrop(this, sGroup);
17205 * Remove's this instance from the supplied interaction group
17206 * @method removeFromGroup
17207 * @param {string} sGroup The group to drop
17209 removeFromGroup: function(sGroup) {
17210 if (this.groups[sGroup]) {
17211 delete this.groups[sGroup];
17214 this.DDM.removeDDFromGroup(this, sGroup);
17218 * Allows you to specify that an element other than the linked element
17219 * will be moved with the cursor during a drag
17220 * @method setDragElId
17221 * @param id {string} the id of the element that will be used to initiate the drag
17223 setDragElId: function(id) {
17224 this.dragElId = id;
17228 * Allows you to specify a child of the linked element that should be
17229 * used to initiate the drag operation. An example of this would be if
17230 * you have a content div with text and links. Clicking anywhere in the
17231 * content area would normally start the drag operation. Use this method
17232 * to specify that an element inside of the content div is the element
17233 * that starts the drag operation.
17234 * @method setHandleElId
17235 * @param id {string} the id of the element that will be used to
17236 * initiate the drag.
17238 setHandleElId: function(id) {
17239 if (typeof id !== "string") {
17242 this.handleElId = id;
17243 this.DDM.regHandle(this.id, id);
17247 * Allows you to set an element outside of the linked element as a drag
17249 * @method setOuterHandleElId
17250 * @param id the id of the element that will be used to initiate the drag
17252 setOuterHandleElId: function(id) {
17253 if (typeof id !== "string") {
17256 Event.on(id, "mousedown",
17257 this.handleMouseDown, this);
17258 this.setHandleElId(id);
17260 this.hasOuterHandles = true;
17264 * Remove all drag and drop hooks for this element
17267 unreg: function() {
17268 Event.un(this.id, "mousedown",
17269 this.handleMouseDown);
17270 Event.un(this.id, "touchstart",
17271 this.handleMouseDown);
17272 this._domRef = null;
17273 this.DDM._remove(this);
17276 destroy : function(){
17281 * Returns true if this instance is locked, or the drag drop mgr is locked
17282 * (meaning that all drag/drop is disabled on the page.)
17284 * @return {boolean} true if this obj or all drag/drop is locked, else
17287 isLocked: function() {
17288 return (this.DDM.isLocked() || this.locked);
17292 * Fired when this object is clicked
17293 * @method handleMouseDown
17295 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17298 handleMouseDown: function(e, oDD){
17300 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17301 //Roo.log('not touch/ button !=0');
17304 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17305 return; // double touch..
17309 if (this.isLocked()) {
17310 //Roo.log('locked');
17314 this.DDM.refreshCache(this.groups);
17315 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17316 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17317 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17318 //Roo.log('no outer handes or not over target');
17321 // Roo.log('check validator');
17322 if (this.clickValidator(e)) {
17323 // Roo.log('validate success');
17324 // set the initial element position
17325 this.setStartPosition();
17328 this.b4MouseDown(e);
17329 this.onMouseDown(e);
17331 this.DDM.handleMouseDown(e, this);
17333 this.DDM.stopEvent(e);
17341 clickValidator: function(e) {
17342 var target = e.getTarget();
17343 return ( this.isValidHandleChild(target) &&
17344 (this.id == this.handleElId ||
17345 this.DDM.handleWasClicked(target, this.id)) );
17349 * Allows you to specify a tag name that should not start a drag operation
17350 * when clicked. This is designed to facilitate embedding links within a
17351 * drag handle that do something other than start the drag.
17352 * @method addInvalidHandleType
17353 * @param {string} tagName the type of element to exclude
17355 addInvalidHandleType: function(tagName) {
17356 var type = tagName.toUpperCase();
17357 this.invalidHandleTypes[type] = type;
17361 * Lets you to specify an element id for a child of a drag handle
17362 * that should not initiate a drag
17363 * @method addInvalidHandleId
17364 * @param {string} id the element id of the element you wish to ignore
17366 addInvalidHandleId: function(id) {
17367 if (typeof id !== "string") {
17370 this.invalidHandleIds[id] = id;
17374 * Lets you specify a css class of elements that will not initiate a drag
17375 * @method addInvalidHandleClass
17376 * @param {string} cssClass the class of the elements you wish to ignore
17378 addInvalidHandleClass: function(cssClass) {
17379 this.invalidHandleClasses.push(cssClass);
17383 * Unsets an excluded tag name set by addInvalidHandleType
17384 * @method removeInvalidHandleType
17385 * @param {string} tagName the type of element to unexclude
17387 removeInvalidHandleType: function(tagName) {
17388 var type = tagName.toUpperCase();
17389 // this.invalidHandleTypes[type] = null;
17390 delete this.invalidHandleTypes[type];
17394 * Unsets an invalid handle id
17395 * @method removeInvalidHandleId
17396 * @param {string} id the id of the element to re-enable
17398 removeInvalidHandleId: function(id) {
17399 if (typeof id !== "string") {
17402 delete this.invalidHandleIds[id];
17406 * Unsets an invalid css class
17407 * @method removeInvalidHandleClass
17408 * @param {string} cssClass the class of the element(s) you wish to
17411 removeInvalidHandleClass: function(cssClass) {
17412 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17413 if (this.invalidHandleClasses[i] == cssClass) {
17414 delete this.invalidHandleClasses[i];
17420 * Checks the tag exclusion list to see if this click should be ignored
17421 * @method isValidHandleChild
17422 * @param {HTMLElement} node the HTMLElement to evaluate
17423 * @return {boolean} true if this is a valid tag type, false if not
17425 isValidHandleChild: function(node) {
17428 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17431 nodeName = node.nodeName.toUpperCase();
17433 nodeName = node.nodeName;
17435 valid = valid && !this.invalidHandleTypes[nodeName];
17436 valid = valid && !this.invalidHandleIds[node.id];
17438 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17439 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17448 * Create the array of horizontal tick marks if an interval was specified
17449 * in setXConstraint().
17450 * @method setXTicks
17453 setXTicks: function(iStartX, iTickSize) {
17455 this.xTickSize = iTickSize;
17459 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17461 this.xTicks[this.xTicks.length] = i;
17466 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17468 this.xTicks[this.xTicks.length] = i;
17473 this.xTicks.sort(this.DDM.numericSort) ;
17477 * Create the array of vertical tick marks if an interval was specified in
17478 * setYConstraint().
17479 * @method setYTicks
17482 setYTicks: function(iStartY, iTickSize) {
17484 this.yTickSize = iTickSize;
17488 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17490 this.yTicks[this.yTicks.length] = i;
17495 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17497 this.yTicks[this.yTicks.length] = i;
17502 this.yTicks.sort(this.DDM.numericSort) ;
17506 * By default, the element can be dragged any place on the screen. Use
17507 * this method to limit the horizontal travel of the element. Pass in
17508 * 0,0 for the parameters if you want to lock the drag to the y axis.
17509 * @method setXConstraint
17510 * @param {int} iLeft the number of pixels the element can move to the left
17511 * @param {int} iRight the number of pixels the element can move to the
17513 * @param {int} iTickSize optional parameter for specifying that the
17515 * should move iTickSize pixels at a time.
17517 setXConstraint: function(iLeft, iRight, iTickSize) {
17518 this.leftConstraint = iLeft;
17519 this.rightConstraint = iRight;
17521 this.minX = this.initPageX - iLeft;
17522 this.maxX = this.initPageX + iRight;
17523 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17525 this.constrainX = true;
17529 * Clears any constraints applied to this instance. Also clears ticks
17530 * since they can't exist independent of a constraint at this time.
17531 * @method clearConstraints
17533 clearConstraints: function() {
17534 this.constrainX = false;
17535 this.constrainY = false;
17540 * Clears any tick interval defined for this instance
17541 * @method clearTicks
17543 clearTicks: function() {
17544 this.xTicks = null;
17545 this.yTicks = null;
17546 this.xTickSize = 0;
17547 this.yTickSize = 0;
17551 * By default, the element can be dragged any place on the screen. Set
17552 * this to limit the vertical travel of the element. Pass in 0,0 for the
17553 * parameters if you want to lock the drag to the x axis.
17554 * @method setYConstraint
17555 * @param {int} iUp the number of pixels the element can move up
17556 * @param {int} iDown the number of pixels the element can move down
17557 * @param {int} iTickSize optional parameter for specifying that the
17558 * element should move iTickSize pixels at a time.
17560 setYConstraint: function(iUp, iDown, iTickSize) {
17561 this.topConstraint = iUp;
17562 this.bottomConstraint = iDown;
17564 this.minY = this.initPageY - iUp;
17565 this.maxY = this.initPageY + iDown;
17566 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17568 this.constrainY = true;
17573 * resetConstraints must be called if you manually reposition a dd element.
17574 * @method resetConstraints
17575 * @param {boolean} maintainOffset
17577 resetConstraints: function() {
17580 // Maintain offsets if necessary
17581 if (this.initPageX || this.initPageX === 0) {
17582 // figure out how much this thing has moved
17583 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17584 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17586 this.setInitPosition(dx, dy);
17588 // This is the first time we have detected the element's position
17590 this.setInitPosition();
17593 if (this.constrainX) {
17594 this.setXConstraint( this.leftConstraint,
17595 this.rightConstraint,
17599 if (this.constrainY) {
17600 this.setYConstraint( this.topConstraint,
17601 this.bottomConstraint,
17607 * Normally the drag element is moved pixel by pixel, but we can specify
17608 * that it move a number of pixels at a time. This method resolves the
17609 * location when we have it set up like this.
17611 * @param {int} val where we want to place the object
17612 * @param {int[]} tickArray sorted array of valid points
17613 * @return {int} the closest tick
17616 getTick: function(val, tickArray) {
17619 // If tick interval is not defined, it is effectively 1 pixel,
17620 // so we return the value passed to us.
17622 } else if (tickArray[0] >= val) {
17623 // The value is lower than the first tick, so we return the first
17625 return tickArray[0];
17627 for (var i=0, len=tickArray.length; i<len; ++i) {
17629 if (tickArray[next] && tickArray[next] >= val) {
17630 var diff1 = val - tickArray[i];
17631 var diff2 = tickArray[next] - val;
17632 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17636 // The value is larger than the last tick, so we return the last
17638 return tickArray[tickArray.length - 1];
17645 * @return {string} string representation of the dd obj
17647 toString: function() {
17648 return ("DragDrop " + this.id);
17656 * Ext JS Library 1.1.1
17657 * Copyright(c) 2006-2007, Ext JS, LLC.
17659 * Originally Released Under LGPL - original licence link has changed is not relivant.
17662 * <script type="text/javascript">
17667 * The drag and drop utility provides a framework for building drag and drop
17668 * applications. In addition to enabling drag and drop for specific elements,
17669 * the drag and drop elements are tracked by the manager class, and the
17670 * interactions between the various elements are tracked during the drag and
17671 * the implementing code is notified about these important moments.
17674 // Only load the library once. Rewriting the manager class would orphan
17675 // existing drag and drop instances.
17676 if (!Roo.dd.DragDropMgr) {
17679 * @class Roo.dd.DragDropMgr
17680 * DragDropMgr is a singleton that tracks the element interaction for
17681 * all DragDrop items in the window. Generally, you will not call
17682 * this class directly, but it does have helper methods that could
17683 * be useful in your DragDrop implementations.
17686 Roo.dd.DragDropMgr = function() {
17688 var Event = Roo.EventManager;
17693 * Two dimensional Array of registered DragDrop objects. The first
17694 * dimension is the DragDrop item group, the second the DragDrop
17697 * @type {string: string}
17704 * Array of element ids defined as drag handles. Used to determine
17705 * if the element that generated the mousedown event is actually the
17706 * handle and not the html element itself.
17707 * @property handleIds
17708 * @type {string: string}
17715 * the DragDrop object that is currently being dragged
17716 * @property dragCurrent
17724 * the DragDrop object(s) that are being hovered over
17725 * @property dragOvers
17733 * the X distance between the cursor and the object being dragged
17742 * the Y distance between the cursor and the object being dragged
17751 * Flag to determine if we should prevent the default behavior of the
17752 * events we define. By default this is true, but this can be set to
17753 * false if you need the default behavior (not recommended)
17754 * @property preventDefault
17758 preventDefault: true,
17761 * Flag to determine if we should stop the propagation of the events
17762 * we generate. This is true by default but you may want to set it to
17763 * false if the html element contains other features that require the
17765 * @property stopPropagation
17769 stopPropagation: true,
17772 * Internal flag that is set to true when drag and drop has been
17774 * @property initialized
17781 * All drag and drop can be disabled.
17789 * Called the first time an element is registered.
17795 this.initialized = true;
17799 * In point mode, drag and drop interaction is defined by the
17800 * location of the cursor during the drag/drop
17808 * In intersect mode, drag and drop interactio nis defined by the
17809 * overlap of two or more drag and drop objects.
17810 * @property INTERSECT
17817 * The current drag and drop mode. Default: POINT
17825 * Runs method on all drag and drop objects
17826 * @method _execOnAll
17830 _execOnAll: function(sMethod, args) {
17831 for (var i in this.ids) {
17832 for (var j in this.ids[i]) {
17833 var oDD = this.ids[i][j];
17834 if (! this.isTypeOfDD(oDD)) {
17837 oDD[sMethod].apply(oDD, args);
17843 * Drag and drop initialization. Sets up the global event handlers
17848 _onLoad: function() {
17852 if (!Roo.isTouch) {
17853 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17854 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17856 Event.on(document, "touchend", this.handleMouseUp, this, true);
17857 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17859 Event.on(window, "unload", this._onUnload, this, true);
17860 Event.on(window, "resize", this._onResize, this, true);
17861 // Event.on(window, "mouseout", this._test);
17866 * Reset constraints on all drag and drop objs
17867 * @method _onResize
17871 _onResize: function(e) {
17872 this._execOnAll("resetConstraints", []);
17876 * Lock all drag and drop functionality
17880 lock: function() { this.locked = true; },
17883 * Unlock all drag and drop functionality
17887 unlock: function() { this.locked = false; },
17890 * Is drag and drop locked?
17892 * @return {boolean} True if drag and drop is locked, false otherwise.
17895 isLocked: function() { return this.locked; },
17898 * Location cache that is set for all drag drop objects when a drag is
17899 * initiated, cleared when the drag is finished.
17900 * @property locationCache
17907 * Set useCache to false if you want to force object the lookup of each
17908 * drag and drop linked element constantly during a drag.
17909 * @property useCache
17916 * The number of pixels that the mouse needs to move after the
17917 * mousedown before the drag is initiated. Default=3;
17918 * @property clickPixelThresh
17922 clickPixelThresh: 3,
17925 * The number of milliseconds after the mousedown event to initiate the
17926 * drag if we don't get a mouseup event. Default=1000
17927 * @property clickTimeThresh
17931 clickTimeThresh: 350,
17934 * Flag that indicates that either the drag pixel threshold or the
17935 * mousdown time threshold has been met
17936 * @property dragThreshMet
17941 dragThreshMet: false,
17944 * Timeout used for the click time threshold
17945 * @property clickTimeout
17950 clickTimeout: null,
17953 * The X position of the mousedown event stored for later use when a
17954 * drag threshold is met.
17963 * The Y position of the mousedown event stored for later use when a
17964 * drag threshold is met.
17973 * Each DragDrop instance must be registered with the DragDropMgr.
17974 * This is executed in DragDrop.init()
17975 * @method regDragDrop
17976 * @param {DragDrop} oDD the DragDrop object to register
17977 * @param {String} sGroup the name of the group this element belongs to
17980 regDragDrop: function(oDD, sGroup) {
17981 if (!this.initialized) { this.init(); }
17983 if (!this.ids[sGroup]) {
17984 this.ids[sGroup] = {};
17986 this.ids[sGroup][oDD.id] = oDD;
17990 * Removes the supplied dd instance from the supplied group. Executed
17991 * by DragDrop.removeFromGroup, so don't call this function directly.
17992 * @method removeDDFromGroup
17996 removeDDFromGroup: function(oDD, sGroup) {
17997 if (!this.ids[sGroup]) {
17998 this.ids[sGroup] = {};
18001 var obj = this.ids[sGroup];
18002 if (obj && obj[oDD.id]) {
18003 delete obj[oDD.id];
18008 * Unregisters a drag and drop item. This is executed in
18009 * DragDrop.unreg, use that method instead of calling this directly.
18014 _remove: function(oDD) {
18015 for (var g in oDD.groups) {
18016 if (g && this.ids[g][oDD.id]) {
18017 delete this.ids[g][oDD.id];
18020 delete this.handleIds[oDD.id];
18024 * Each DragDrop handle element must be registered. This is done
18025 * automatically when executing DragDrop.setHandleElId()
18026 * @method regHandle
18027 * @param {String} sDDId the DragDrop id this element is a handle for
18028 * @param {String} sHandleId the id of the element that is the drag
18032 regHandle: function(sDDId, sHandleId) {
18033 if (!this.handleIds[sDDId]) {
18034 this.handleIds[sDDId] = {};
18036 this.handleIds[sDDId][sHandleId] = sHandleId;
18040 * Utility function to determine if a given element has been
18041 * registered as a drag drop item.
18042 * @method isDragDrop
18043 * @param {String} id the element id to check
18044 * @return {boolean} true if this element is a DragDrop item,
18048 isDragDrop: function(id) {
18049 return ( this.getDDById(id) ) ? true : false;
18053 * Returns the drag and drop instances that are in all groups the
18054 * passed in instance belongs to.
18055 * @method getRelated
18056 * @param {DragDrop} p_oDD the obj to get related data for
18057 * @param {boolean} bTargetsOnly if true, only return targetable objs
18058 * @return {DragDrop[]} the related instances
18061 getRelated: function(p_oDD, bTargetsOnly) {
18063 for (var i in p_oDD.groups) {
18064 for (j in this.ids[i]) {
18065 var dd = this.ids[i][j];
18066 if (! this.isTypeOfDD(dd)) {
18069 if (!bTargetsOnly || dd.isTarget) {
18070 oDDs[oDDs.length] = dd;
18079 * Returns true if the specified dd target is a legal target for
18080 * the specifice drag obj
18081 * @method isLegalTarget
18082 * @param {DragDrop} the drag obj
18083 * @param {DragDrop} the target
18084 * @return {boolean} true if the target is a legal target for the
18088 isLegalTarget: function (oDD, oTargetDD) {
18089 var targets = this.getRelated(oDD, true);
18090 for (var i=0, len=targets.length;i<len;++i) {
18091 if (targets[i].id == oTargetDD.id) {
18100 * My goal is to be able to transparently determine if an object is
18101 * typeof DragDrop, and the exact subclass of DragDrop. typeof
18102 * returns "object", oDD.constructor.toString() always returns
18103 * "DragDrop" and not the name of the subclass. So for now it just
18104 * evaluates a well-known variable in DragDrop.
18105 * @method isTypeOfDD
18106 * @param {Object} the object to evaluate
18107 * @return {boolean} true if typeof oDD = DragDrop
18110 isTypeOfDD: function (oDD) {
18111 return (oDD && oDD.__ygDragDrop);
18115 * Utility function to determine if a given element has been
18116 * registered as a drag drop handle for the given Drag Drop object.
18118 * @param {String} id the element id to check
18119 * @return {boolean} true if this element is a DragDrop handle, false
18123 isHandle: function(sDDId, sHandleId) {
18124 return ( this.handleIds[sDDId] &&
18125 this.handleIds[sDDId][sHandleId] );
18129 * Returns the DragDrop instance for a given id
18130 * @method getDDById
18131 * @param {String} id the id of the DragDrop object
18132 * @return {DragDrop} the drag drop object, null if it is not found
18135 getDDById: function(id) {
18136 for (var i in this.ids) {
18137 if (this.ids[i][id]) {
18138 return this.ids[i][id];
18145 * Fired after a registered DragDrop object gets the mousedown event.
18146 * Sets up the events required to track the object being dragged
18147 * @method handleMouseDown
18148 * @param {Event} e the event
18149 * @param oDD the DragDrop object being dragged
18153 handleMouseDown: function(e, oDD) {
18155 Roo.QuickTips.disable();
18157 this.currentTarget = e.getTarget();
18159 this.dragCurrent = oDD;
18161 var el = oDD.getEl();
18163 // track start position
18164 this.startX = e.getPageX();
18165 this.startY = e.getPageY();
18167 this.deltaX = this.startX - el.offsetLeft;
18168 this.deltaY = this.startY - el.offsetTop;
18170 this.dragThreshMet = false;
18172 this.clickTimeout = setTimeout(
18174 var DDM = Roo.dd.DDM;
18175 DDM.startDrag(DDM.startX, DDM.startY);
18177 this.clickTimeThresh );
18181 * Fired when either the drag pixel threshol or the mousedown hold
18182 * time threshold has been met.
18183 * @method startDrag
18184 * @param x {int} the X position of the original mousedown
18185 * @param y {int} the Y position of the original mousedown
18188 startDrag: function(x, y) {
18189 clearTimeout(this.clickTimeout);
18190 if (this.dragCurrent) {
18191 this.dragCurrent.b4StartDrag(x, y);
18192 this.dragCurrent.startDrag(x, y);
18194 this.dragThreshMet = true;
18198 * Internal function to handle the mouseup event. Will be invoked
18199 * from the context of the document.
18200 * @method handleMouseUp
18201 * @param {Event} e the event
18205 handleMouseUp: function(e) {
18208 Roo.QuickTips.enable();
18210 if (! this.dragCurrent) {
18214 clearTimeout(this.clickTimeout);
18216 if (this.dragThreshMet) {
18217 this.fireEvents(e, true);
18227 * Utility to stop event propagation and event default, if these
18228 * features are turned on.
18229 * @method stopEvent
18230 * @param {Event} e the event as returned by this.getEvent()
18233 stopEvent: function(e){
18234 if(this.stopPropagation) {
18235 e.stopPropagation();
18238 if (this.preventDefault) {
18239 e.preventDefault();
18244 * Internal function to clean up event handlers after the drag
18245 * operation is complete
18247 * @param {Event} e the event
18251 stopDrag: function(e) {
18252 // Fire the drag end event for the item that was dragged
18253 if (this.dragCurrent) {
18254 if (this.dragThreshMet) {
18255 this.dragCurrent.b4EndDrag(e);
18256 this.dragCurrent.endDrag(e);
18259 this.dragCurrent.onMouseUp(e);
18262 this.dragCurrent = null;
18263 this.dragOvers = {};
18267 * Internal function to handle the mousemove event. Will be invoked
18268 * from the context of the html element.
18270 * @TODO figure out what we can do about mouse events lost when the
18271 * user drags objects beyond the window boundary. Currently we can
18272 * detect this in internet explorer by verifying that the mouse is
18273 * down during the mousemove event. Firefox doesn't give us the
18274 * button state on the mousemove event.
18275 * @method handleMouseMove
18276 * @param {Event} e the event
18280 handleMouseMove: function(e) {
18281 if (! this.dragCurrent) {
18285 // var button = e.which || e.button;
18287 // check for IE mouseup outside of page boundary
18288 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18290 return this.handleMouseUp(e);
18293 if (!this.dragThreshMet) {
18294 var diffX = Math.abs(this.startX - e.getPageX());
18295 var diffY = Math.abs(this.startY - e.getPageY());
18296 if (diffX > this.clickPixelThresh ||
18297 diffY > this.clickPixelThresh) {
18298 this.startDrag(this.startX, this.startY);
18302 if (this.dragThreshMet) {
18303 this.dragCurrent.b4Drag(e);
18304 this.dragCurrent.onDrag(e);
18305 if(!this.dragCurrent.moveOnly){
18306 this.fireEvents(e, false);
18316 * Iterates over all of the DragDrop elements to find ones we are
18317 * hovering over or dropping on
18318 * @method fireEvents
18319 * @param {Event} e the event
18320 * @param {boolean} isDrop is this a drop op or a mouseover op?
18324 fireEvents: function(e, isDrop) {
18325 var dc = this.dragCurrent;
18327 // If the user did the mouse up outside of the window, we could
18328 // get here even though we have ended the drag.
18329 if (!dc || dc.isLocked()) {
18333 var pt = e.getPoint();
18335 // cache the previous dragOver array
18341 var enterEvts = [];
18343 // Check to see if the object(s) we were hovering over is no longer
18344 // being hovered over so we can fire the onDragOut event
18345 for (var i in this.dragOvers) {
18347 var ddo = this.dragOvers[i];
18349 if (! this.isTypeOfDD(ddo)) {
18353 if (! this.isOverTarget(pt, ddo, this.mode)) {
18354 outEvts.push( ddo );
18357 oldOvers[i] = true;
18358 delete this.dragOvers[i];
18361 for (var sGroup in dc.groups) {
18363 if ("string" != typeof sGroup) {
18367 for (i in this.ids[sGroup]) {
18368 var oDD = this.ids[sGroup][i];
18369 if (! this.isTypeOfDD(oDD)) {
18373 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18374 if (this.isOverTarget(pt, oDD, this.mode)) {
18375 // look for drop interactions
18377 dropEvts.push( oDD );
18378 // look for drag enter and drag over interactions
18381 // initial drag over: dragEnter fires
18382 if (!oldOvers[oDD.id]) {
18383 enterEvts.push( oDD );
18384 // subsequent drag overs: dragOver fires
18386 overEvts.push( oDD );
18389 this.dragOvers[oDD.id] = oDD;
18397 if (outEvts.length) {
18398 dc.b4DragOut(e, outEvts);
18399 dc.onDragOut(e, outEvts);
18402 if (enterEvts.length) {
18403 dc.onDragEnter(e, enterEvts);
18406 if (overEvts.length) {
18407 dc.b4DragOver(e, overEvts);
18408 dc.onDragOver(e, overEvts);
18411 if (dropEvts.length) {
18412 dc.b4DragDrop(e, dropEvts);
18413 dc.onDragDrop(e, dropEvts);
18417 // fire dragout events
18419 for (i=0, len=outEvts.length; i<len; ++i) {
18420 dc.b4DragOut(e, outEvts[i].id);
18421 dc.onDragOut(e, outEvts[i].id);
18424 // fire enter events
18425 for (i=0,len=enterEvts.length; i<len; ++i) {
18426 // dc.b4DragEnter(e, oDD.id);
18427 dc.onDragEnter(e, enterEvts[i].id);
18430 // fire over events
18431 for (i=0,len=overEvts.length; i<len; ++i) {
18432 dc.b4DragOver(e, overEvts[i].id);
18433 dc.onDragOver(e, overEvts[i].id);
18436 // fire drop events
18437 for (i=0, len=dropEvts.length; i<len; ++i) {
18438 dc.b4DragDrop(e, dropEvts[i].id);
18439 dc.onDragDrop(e, dropEvts[i].id);
18444 // notify about a drop that did not find a target
18445 if (isDrop && !dropEvts.length) {
18446 dc.onInvalidDrop(e);
18452 * Helper function for getting the best match from the list of drag
18453 * and drop objects returned by the drag and drop events when we are
18454 * in INTERSECT mode. It returns either the first object that the
18455 * cursor is over, or the object that has the greatest overlap with
18456 * the dragged element.
18457 * @method getBestMatch
18458 * @param {DragDrop[]} dds The array of drag and drop objects
18460 * @return {DragDrop} The best single match
18463 getBestMatch: function(dds) {
18465 // Return null if the input is not what we expect
18466 //if (!dds || !dds.length || dds.length == 0) {
18468 // If there is only one item, it wins
18469 //} else if (dds.length == 1) {
18471 var len = dds.length;
18476 // Loop through the targeted items
18477 for (var i=0; i<len; ++i) {
18479 // If the cursor is over the object, it wins. If the
18480 // cursor is over multiple matches, the first one we come
18482 if (dd.cursorIsOver) {
18485 // Otherwise the object with the most overlap wins
18488 winner.overlap.getArea() < dd.overlap.getArea()) {
18499 * Refreshes the cache of the top-left and bottom-right points of the
18500 * drag and drop objects in the specified group(s). This is in the
18501 * format that is stored in the drag and drop instance, so typical
18504 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18508 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18510 * @TODO this really should be an indexed array. Alternatively this
18511 * method could accept both.
18512 * @method refreshCache
18513 * @param {Object} groups an associative array of groups to refresh
18516 refreshCache: function(groups) {
18517 for (var sGroup in groups) {
18518 if ("string" != typeof sGroup) {
18521 for (var i in this.ids[sGroup]) {
18522 var oDD = this.ids[sGroup][i];
18524 if (this.isTypeOfDD(oDD)) {
18525 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18526 var loc = this.getLocation(oDD);
18528 this.locationCache[oDD.id] = loc;
18530 delete this.locationCache[oDD.id];
18531 // this will unregister the drag and drop object if
18532 // the element is not in a usable state
18541 * This checks to make sure an element exists and is in the DOM. The
18542 * main purpose is to handle cases where innerHTML is used to remove
18543 * drag and drop objects from the DOM. IE provides an 'unspecified
18544 * error' when trying to access the offsetParent of such an element
18546 * @param {HTMLElement} el the element to check
18547 * @return {boolean} true if the element looks usable
18550 verifyEl: function(el) {
18555 parent = el.offsetParent;
18558 parent = el.offsetParent;
18569 * Returns a Region object containing the drag and drop element's position
18570 * and size, including the padding configured for it
18571 * @method getLocation
18572 * @param {DragDrop} oDD the drag and drop object to get the
18574 * @return {Roo.lib.Region} a Region object representing the total area
18575 * the element occupies, including any padding
18576 * the instance is configured for.
18579 getLocation: function(oDD) {
18580 if (! this.isTypeOfDD(oDD)) {
18584 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18587 pos= Roo.lib.Dom.getXY(el);
18595 x2 = x1 + el.offsetWidth;
18597 y2 = y1 + el.offsetHeight;
18599 t = y1 - oDD.padding[0];
18600 r = x2 + oDD.padding[1];
18601 b = y2 + oDD.padding[2];
18602 l = x1 - oDD.padding[3];
18604 return new Roo.lib.Region( t, r, b, l );
18608 * Checks the cursor location to see if it over the target
18609 * @method isOverTarget
18610 * @param {Roo.lib.Point} pt The point to evaluate
18611 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18612 * @return {boolean} true if the mouse is over the target
18616 isOverTarget: function(pt, oTarget, intersect) {
18617 // use cache if available
18618 var loc = this.locationCache[oTarget.id];
18619 if (!loc || !this.useCache) {
18620 loc = this.getLocation(oTarget);
18621 this.locationCache[oTarget.id] = loc;
18629 oTarget.cursorIsOver = loc.contains( pt );
18631 // DragDrop is using this as a sanity check for the initial mousedown
18632 // in this case we are done. In POINT mode, if the drag obj has no
18633 // contraints, we are also done. Otherwise we need to evaluate the
18634 // location of the target as related to the actual location of the
18635 // dragged element.
18636 var dc = this.dragCurrent;
18637 if (!dc || !dc.getTargetCoord ||
18638 (!intersect && !dc.constrainX && !dc.constrainY)) {
18639 return oTarget.cursorIsOver;
18642 oTarget.overlap = null;
18644 // Get the current location of the drag element, this is the
18645 // location of the mouse event less the delta that represents
18646 // where the original mousedown happened on the element. We
18647 // need to consider constraints and ticks as well.
18648 var pos = dc.getTargetCoord(pt.x, pt.y);
18650 var el = dc.getDragEl();
18651 var curRegion = new Roo.lib.Region( pos.y,
18652 pos.x + el.offsetWidth,
18653 pos.y + el.offsetHeight,
18656 var overlap = curRegion.intersect(loc);
18659 oTarget.overlap = overlap;
18660 return (intersect) ? true : oTarget.cursorIsOver;
18667 * unload event handler
18668 * @method _onUnload
18672 _onUnload: function(e, me) {
18673 Roo.dd.DragDropMgr.unregAll();
18677 * Cleans up the drag and drop events and objects.
18682 unregAll: function() {
18684 if (this.dragCurrent) {
18686 this.dragCurrent = null;
18689 this._execOnAll("unreg", []);
18691 for (i in this.elementCache) {
18692 delete this.elementCache[i];
18695 this.elementCache = {};
18700 * A cache of DOM elements
18701 * @property elementCache
18708 * Get the wrapper for the DOM element specified
18709 * @method getElWrapper
18710 * @param {String} id the id of the element to get
18711 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18713 * @deprecated This wrapper isn't that useful
18716 getElWrapper: function(id) {
18717 var oWrapper = this.elementCache[id];
18718 if (!oWrapper || !oWrapper.el) {
18719 oWrapper = this.elementCache[id] =
18720 new this.ElementWrapper(Roo.getDom(id));
18726 * Returns the actual DOM element
18727 * @method getElement
18728 * @param {String} id the id of the elment to get
18729 * @return {Object} The element
18730 * @deprecated use Roo.getDom instead
18733 getElement: function(id) {
18734 return Roo.getDom(id);
18738 * Returns the style property for the DOM element (i.e.,
18739 * document.getElById(id).style)
18741 * @param {String} id the id of the elment to get
18742 * @return {Object} The style property of the element
18743 * @deprecated use Roo.getDom instead
18746 getCss: function(id) {
18747 var el = Roo.getDom(id);
18748 return (el) ? el.style : null;
18752 * Inner class for cached elements
18753 * @class DragDropMgr.ElementWrapper
18758 ElementWrapper: function(el) {
18763 this.el = el || null;
18768 this.id = this.el && el.id;
18770 * A reference to the style property
18773 this.css = this.el && el.style;
18777 * Returns the X position of an html element
18779 * @param el the element for which to get the position
18780 * @return {int} the X coordinate
18782 * @deprecated use Roo.lib.Dom.getX instead
18785 getPosX: function(el) {
18786 return Roo.lib.Dom.getX(el);
18790 * Returns the Y position of an html element
18792 * @param el the element for which to get the position
18793 * @return {int} the Y coordinate
18794 * @deprecated use Roo.lib.Dom.getY instead
18797 getPosY: function(el) {
18798 return Roo.lib.Dom.getY(el);
18802 * Swap two nodes. In IE, we use the native method, for others we
18803 * emulate the IE behavior
18805 * @param n1 the first node to swap
18806 * @param n2 the other node to swap
18809 swapNode: function(n1, n2) {
18813 var p = n2.parentNode;
18814 var s = n2.nextSibling;
18817 p.insertBefore(n1, n2);
18818 } else if (n2 == n1.nextSibling) {
18819 p.insertBefore(n2, n1);
18821 n1.parentNode.replaceChild(n2, n1);
18822 p.insertBefore(n1, s);
18828 * Returns the current scroll position
18829 * @method getScroll
18833 getScroll: function () {
18834 var t, l, dde=document.documentElement, db=document.body;
18835 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18837 l = dde.scrollLeft;
18844 return { top: t, left: l };
18848 * Returns the specified element style property
18850 * @param {HTMLElement} el the element
18851 * @param {string} styleProp the style property
18852 * @return {string} The value of the style property
18853 * @deprecated use Roo.lib.Dom.getStyle
18856 getStyle: function(el, styleProp) {
18857 return Roo.fly(el).getStyle(styleProp);
18861 * Gets the scrollTop
18862 * @method getScrollTop
18863 * @return {int} the document's scrollTop
18866 getScrollTop: function () { return this.getScroll().top; },
18869 * Gets the scrollLeft
18870 * @method getScrollLeft
18871 * @return {int} the document's scrollTop
18874 getScrollLeft: function () { return this.getScroll().left; },
18877 * Sets the x/y position of an element to the location of the
18880 * @param {HTMLElement} moveEl The element to move
18881 * @param {HTMLElement} targetEl The position reference element
18884 moveToEl: function (moveEl, targetEl) {
18885 var aCoord = Roo.lib.Dom.getXY(targetEl);
18886 Roo.lib.Dom.setXY(moveEl, aCoord);
18890 * Numeric array sort function
18891 * @method numericSort
18894 numericSort: function(a, b) { return (a - b); },
18898 * @property _timeoutCount
18905 * Trying to make the load order less important. Without this we get
18906 * an error if this file is loaded before the Event Utility.
18907 * @method _addListeners
18911 _addListeners: function() {
18912 var DDM = Roo.dd.DDM;
18913 if ( Roo.lib.Event && document ) {
18916 if (DDM._timeoutCount > 2000) {
18918 setTimeout(DDM._addListeners, 10);
18919 if (document && document.body) {
18920 DDM._timeoutCount += 1;
18927 * Recursively searches the immediate parent and all child nodes for
18928 * the handle element in order to determine wheter or not it was
18930 * @method handleWasClicked
18931 * @param node the html element to inspect
18934 handleWasClicked: function(node, id) {
18935 if (this.isHandle(id, node.id)) {
18938 // check to see if this is a text node child of the one we want
18939 var p = node.parentNode;
18942 if (this.isHandle(id, p.id)) {
18957 // shorter alias, save a few bytes
18958 Roo.dd.DDM = Roo.dd.DragDropMgr;
18959 Roo.dd.DDM._addListeners();
18963 * Ext JS Library 1.1.1
18964 * Copyright(c) 2006-2007, Ext JS, LLC.
18966 * Originally Released Under LGPL - original licence link has changed is not relivant.
18969 * <script type="text/javascript">
18974 * A DragDrop implementation where the linked element follows the
18975 * mouse cursor during a drag.
18976 * @extends Roo.dd.DragDrop
18978 * @param {String} id the id of the linked element
18979 * @param {String} sGroup the group of related DragDrop items
18980 * @param {object} config an object containing configurable attributes
18981 * Valid properties for DD:
18984 Roo.dd.DD = function(id, sGroup, config) {
18986 this.init(id, sGroup, config);
18990 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18993 * When set to true, the utility automatically tries to scroll the browser
18994 * window wehn a drag and drop element is dragged near the viewport boundary.
18995 * Defaults to true.
19002 * Sets the pointer offset to the distance between the linked element's top
19003 * left corner and the location the element was clicked
19004 * @method autoOffset
19005 * @param {int} iPageX the X coordinate of the click
19006 * @param {int} iPageY the Y coordinate of the click
19008 autoOffset: function(iPageX, iPageY) {
19009 var x = iPageX - this.startPageX;
19010 var y = iPageY - this.startPageY;
19011 this.setDelta(x, y);
19015 * Sets the pointer offset. You can call this directly to force the
19016 * offset to be in a particular location (e.g., pass in 0,0 to set it
19017 * to the center of the object)
19019 * @param {int} iDeltaX the distance from the left
19020 * @param {int} iDeltaY the distance from the top
19022 setDelta: function(iDeltaX, iDeltaY) {
19023 this.deltaX = iDeltaX;
19024 this.deltaY = iDeltaY;
19028 * Sets the drag element to the location of the mousedown or click event,
19029 * maintaining the cursor location relative to the location on the element
19030 * that was clicked. Override this if you want to place the element in a
19031 * location other than where the cursor is.
19032 * @method setDragElPos
19033 * @param {int} iPageX the X coordinate of the mousedown or drag event
19034 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19036 setDragElPos: function(iPageX, iPageY) {
19037 // the first time we do this, we are going to check to make sure
19038 // the element has css positioning
19040 var el = this.getDragEl();
19041 this.alignElWithMouse(el, iPageX, iPageY);
19045 * Sets the element to the location of the mousedown or click event,
19046 * maintaining the cursor location relative to the location on the element
19047 * that was clicked. Override this if you want to place the element in a
19048 * location other than where the cursor is.
19049 * @method alignElWithMouse
19050 * @param {HTMLElement} el the element to move
19051 * @param {int} iPageX the X coordinate of the mousedown or drag event
19052 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19054 alignElWithMouse: function(el, iPageX, iPageY) {
19055 var oCoord = this.getTargetCoord(iPageX, iPageY);
19056 var fly = el.dom ? el : Roo.fly(el);
19057 if (!this.deltaSetXY) {
19058 var aCoord = [oCoord.x, oCoord.y];
19060 var newLeft = fly.getLeft(true);
19061 var newTop = fly.getTop(true);
19062 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
19064 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
19067 this.cachePosition(oCoord.x, oCoord.y);
19068 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
19073 * Saves the most recent position so that we can reset the constraints and
19074 * tick marks on-demand. We need to know this so that we can calculate the
19075 * number of pixels the element is offset from its original position.
19076 * @method cachePosition
19077 * @param iPageX the current x position (optional, this just makes it so we
19078 * don't have to look it up again)
19079 * @param iPageY the current y position (optional, this just makes it so we
19080 * don't have to look it up again)
19082 cachePosition: function(iPageX, iPageY) {
19084 this.lastPageX = iPageX;
19085 this.lastPageY = iPageY;
19087 var aCoord = Roo.lib.Dom.getXY(this.getEl());
19088 this.lastPageX = aCoord[0];
19089 this.lastPageY = aCoord[1];
19094 * Auto-scroll the window if the dragged object has been moved beyond the
19095 * visible window boundary.
19096 * @method autoScroll
19097 * @param {int} x the drag element's x position
19098 * @param {int} y the drag element's y position
19099 * @param {int} h the height of the drag element
19100 * @param {int} w the width of the drag element
19103 autoScroll: function(x, y, h, w) {
19106 // The client height
19107 var clientH = Roo.lib.Dom.getViewWidth();
19109 // The client width
19110 var clientW = Roo.lib.Dom.getViewHeight();
19112 // The amt scrolled down
19113 var st = this.DDM.getScrollTop();
19115 // The amt scrolled right
19116 var sl = this.DDM.getScrollLeft();
19118 // Location of the bottom of the element
19121 // Location of the right of the element
19124 // The distance from the cursor to the bottom of the visible area,
19125 // adjusted so that we don't scroll if the cursor is beyond the
19126 // element drag constraints
19127 var toBot = (clientH + st - y - this.deltaY);
19129 // The distance from the cursor to the right of the visible area
19130 var toRight = (clientW + sl - x - this.deltaX);
19133 // How close to the edge the cursor must be before we scroll
19134 // var thresh = (document.all) ? 100 : 40;
19137 // How many pixels to scroll per autoscroll op. This helps to reduce
19138 // clunky scrolling. IE is more sensitive about this ... it needs this
19139 // value to be higher.
19140 var scrAmt = (document.all) ? 80 : 30;
19142 // Scroll down if we are near the bottom of the visible page and the
19143 // obj extends below the crease
19144 if ( bot > clientH && toBot < thresh ) {
19145 window.scrollTo(sl, st + scrAmt);
19148 // Scroll up if the window is scrolled down and the top of the object
19149 // goes above the top border
19150 if ( y < st && st > 0 && y - st < thresh ) {
19151 window.scrollTo(sl, st - scrAmt);
19154 // Scroll right if the obj is beyond the right border and the cursor is
19155 // near the border.
19156 if ( right > clientW && toRight < thresh ) {
19157 window.scrollTo(sl + scrAmt, st);
19160 // Scroll left if the window has been scrolled to the right and the obj
19161 // extends past the left border
19162 if ( x < sl && sl > 0 && x - sl < thresh ) {
19163 window.scrollTo(sl - scrAmt, st);
19169 * Finds the location the element should be placed if we want to move
19170 * it to where the mouse location less the click offset would place us.
19171 * @method getTargetCoord
19172 * @param {int} iPageX the X coordinate of the click
19173 * @param {int} iPageY the Y coordinate of the click
19174 * @return an object that contains the coordinates (Object.x and Object.y)
19177 getTargetCoord: function(iPageX, iPageY) {
19180 var x = iPageX - this.deltaX;
19181 var y = iPageY - this.deltaY;
19183 if (this.constrainX) {
19184 if (x < this.minX) { x = this.minX; }
19185 if (x > this.maxX) { x = this.maxX; }
19188 if (this.constrainY) {
19189 if (y < this.minY) { y = this.minY; }
19190 if (y > this.maxY) { y = this.maxY; }
19193 x = this.getTick(x, this.xTicks);
19194 y = this.getTick(y, this.yTicks);
19201 * Sets up config options specific to this class. Overrides
19202 * Roo.dd.DragDrop, but all versions of this method through the
19203 * inheritance chain are called
19205 applyConfig: function() {
19206 Roo.dd.DD.superclass.applyConfig.call(this);
19207 this.scroll = (this.config.scroll !== false);
19211 * Event that fires prior to the onMouseDown event. Overrides
19214 b4MouseDown: function(e) {
19215 // this.resetConstraints();
19216 this.autoOffset(e.getPageX(),
19221 * Event that fires prior to the onDrag event. Overrides
19224 b4Drag: function(e) {
19225 this.setDragElPos(e.getPageX(),
19229 toString: function() {
19230 return ("DD " + this.id);
19233 //////////////////////////////////////////////////////////////////////////
19234 // Debugging ygDragDrop events that can be overridden
19235 //////////////////////////////////////////////////////////////////////////
19237 startDrag: function(x, y) {
19240 onDrag: function(e) {
19243 onDragEnter: function(e, id) {
19246 onDragOver: function(e, id) {
19249 onDragOut: function(e, id) {
19252 onDragDrop: function(e, id) {
19255 endDrag: function(e) {
19262 * Ext JS Library 1.1.1
19263 * Copyright(c) 2006-2007, Ext JS, LLC.
19265 * Originally Released Under LGPL - original licence link has changed is not relivant.
19268 * <script type="text/javascript">
19272 * @class Roo.dd.DDProxy
19273 * A DragDrop implementation that inserts an empty, bordered div into
19274 * the document that follows the cursor during drag operations. At the time of
19275 * the click, the frame div is resized to the dimensions of the linked html
19276 * element, and moved to the exact location of the linked element.
19278 * References to the "frame" element refer to the single proxy element that
19279 * was created to be dragged in place of all DDProxy elements on the
19282 * @extends Roo.dd.DD
19284 * @param {String} id the id of the linked html element
19285 * @param {String} sGroup the group of related DragDrop objects
19286 * @param {object} config an object containing configurable attributes
19287 * Valid properties for DDProxy in addition to those in DragDrop:
19288 * resizeFrame, centerFrame, dragElId
19290 Roo.dd.DDProxy = function(id, sGroup, config) {
19292 this.init(id, sGroup, config);
19298 * The default drag frame div id
19299 * @property Roo.dd.DDProxy.dragElId
19303 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19305 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19308 * By default we resize the drag frame to be the same size as the element
19309 * we want to drag (this is to get the frame effect). We can turn it off
19310 * if we want a different behavior.
19311 * @property resizeFrame
19317 * By default the frame is positioned exactly where the drag element is, so
19318 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19319 * you do not have constraints on the obj is to have the drag frame centered
19320 * around the cursor. Set centerFrame to true for this effect.
19321 * @property centerFrame
19324 centerFrame: false,
19327 * Creates the proxy element if it does not yet exist
19328 * @method createFrame
19330 createFrame: function() {
19332 var body = document.body;
19334 if (!body || !body.firstChild) {
19335 setTimeout( function() { self.createFrame(); }, 50 );
19339 var div = this.getDragEl();
19342 div = document.createElement("div");
19343 div.id = this.dragElId;
19346 s.position = "absolute";
19347 s.visibility = "hidden";
19349 s.border = "2px solid #aaa";
19352 // appendChild can blow up IE if invoked prior to the window load event
19353 // while rendering a table. It is possible there are other scenarios
19354 // that would cause this to happen as well.
19355 body.insertBefore(div, body.firstChild);
19360 * Initialization for the drag frame element. Must be called in the
19361 * constructor of all subclasses
19362 * @method initFrame
19364 initFrame: function() {
19365 this.createFrame();
19368 applyConfig: function() {
19369 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19371 this.resizeFrame = (this.config.resizeFrame !== false);
19372 this.centerFrame = (this.config.centerFrame);
19373 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19377 * Resizes the drag frame to the dimensions of the clicked object, positions
19378 * it over the object, and finally displays it
19379 * @method showFrame
19380 * @param {int} iPageX X click position
19381 * @param {int} iPageY Y click position
19384 showFrame: function(iPageX, iPageY) {
19385 var el = this.getEl();
19386 var dragEl = this.getDragEl();
19387 var s = dragEl.style;
19389 this._resizeProxy();
19391 if (this.centerFrame) {
19392 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19393 Math.round(parseInt(s.height, 10)/2) );
19396 this.setDragElPos(iPageX, iPageY);
19398 Roo.fly(dragEl).show();
19402 * The proxy is automatically resized to the dimensions of the linked
19403 * element when a drag is initiated, unless resizeFrame is set to false
19404 * @method _resizeProxy
19407 _resizeProxy: function() {
19408 if (this.resizeFrame) {
19409 var el = this.getEl();
19410 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19414 // overrides Roo.dd.DragDrop
19415 b4MouseDown: function(e) {
19416 var x = e.getPageX();
19417 var y = e.getPageY();
19418 this.autoOffset(x, y);
19419 this.setDragElPos(x, y);
19422 // overrides Roo.dd.DragDrop
19423 b4StartDrag: function(x, y) {
19424 // show the drag frame
19425 this.showFrame(x, y);
19428 // overrides Roo.dd.DragDrop
19429 b4EndDrag: function(e) {
19430 Roo.fly(this.getDragEl()).hide();
19433 // overrides Roo.dd.DragDrop
19434 // By default we try to move the element to the last location of the frame.
19435 // This is so that the default behavior mirrors that of Roo.dd.DD.
19436 endDrag: function(e) {
19438 var lel = this.getEl();
19439 var del = this.getDragEl();
19441 // Show the drag frame briefly so we can get its position
19442 del.style.visibility = "";
19445 // Hide the linked element before the move to get around a Safari
19447 lel.style.visibility = "hidden";
19448 Roo.dd.DDM.moveToEl(lel, del);
19449 del.style.visibility = "hidden";
19450 lel.style.visibility = "";
19455 beforeMove : function(){
19459 afterDrag : function(){
19463 toString: function() {
19464 return ("DDProxy " + this.id);
19470 * Ext JS Library 1.1.1
19471 * Copyright(c) 2006-2007, Ext JS, LLC.
19473 * Originally Released Under LGPL - original licence link has changed is not relivant.
19476 * <script type="text/javascript">
19480 * @class Roo.dd.DDTarget
19481 * A DragDrop implementation that does not move, but can be a drop
19482 * target. You would get the same result by simply omitting implementation
19483 * for the event callbacks, but this way we reduce the processing cost of the
19484 * event listener and the callbacks.
19485 * @extends Roo.dd.DragDrop
19487 * @param {String} id the id of the element that is a drop target
19488 * @param {String} sGroup the group of related DragDrop objects
19489 * @param {object} config an object containing configurable attributes
19490 * Valid properties for DDTarget in addition to those in
19494 Roo.dd.DDTarget = function(id, sGroup, config) {
19496 this.initTarget(id, sGroup, config);
19498 if (config.listeners || config.events) {
19499 Roo.dd.DragDrop.superclass.constructor.call(this, {
19500 listeners : config.listeners || {},
19501 events : config.events || {}
19506 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19507 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19508 toString: function() {
19509 return ("DDTarget " + this.id);
19514 * Ext JS Library 1.1.1
19515 * Copyright(c) 2006-2007, Ext JS, LLC.
19517 * Originally Released Under LGPL - original licence link has changed is not relivant.
19520 * <script type="text/javascript">
19525 * @class Roo.dd.ScrollManager
19526 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19527 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19530 Roo.dd.ScrollManager = function(){
19531 var ddm = Roo.dd.DragDropMgr;
19538 var onStop = function(e){
19543 var triggerRefresh = function(){
19544 if(ddm.dragCurrent){
19545 ddm.refreshCache(ddm.dragCurrent.groups);
19549 var doScroll = function(){
19550 if(ddm.dragCurrent){
19551 var dds = Roo.dd.ScrollManager;
19553 if(proc.el.scroll(proc.dir, dds.increment)){
19557 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19562 var clearProc = function(){
19564 clearInterval(proc.id);
19571 var startProc = function(el, dir){
19572 Roo.log('scroll startproc');
19576 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19579 var onFire = function(e, isDrop){
19581 if(isDrop || !ddm.dragCurrent){ return; }
19582 var dds = Roo.dd.ScrollManager;
19583 if(!dragEl || dragEl != ddm.dragCurrent){
19584 dragEl = ddm.dragCurrent;
19585 // refresh regions on drag start
19586 dds.refreshCache();
19589 var xy = Roo.lib.Event.getXY(e);
19590 var pt = new Roo.lib.Point(xy[0], xy[1]);
19591 for(var id in els){
19592 var el = els[id], r = el._region;
19593 if(r && r.contains(pt) && el.isScrollable()){
19594 if(r.bottom - pt.y <= dds.thresh){
19596 startProc(el, "down");
19599 }else if(r.right - pt.x <= dds.thresh){
19601 startProc(el, "left");
19604 }else if(pt.y - r.top <= dds.thresh){
19606 startProc(el, "up");
19609 }else if(pt.x - r.left <= dds.thresh){
19611 startProc(el, "right");
19620 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19621 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19625 * Registers new overflow element(s) to auto scroll
19626 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19628 register : function(el){
19629 if(el instanceof Array){
19630 for(var i = 0, len = el.length; i < len; i++) {
19631 this.register(el[i]);
19637 Roo.dd.ScrollManager.els = els;
19641 * Unregisters overflow element(s) so they are no longer scrolled
19642 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19644 unregister : function(el){
19645 if(el instanceof Array){
19646 for(var i = 0, len = el.length; i < len; i++) {
19647 this.unregister(el[i]);
19656 * The number of pixels from the edge of a container the pointer needs to be to
19657 * trigger scrolling (defaults to 25)
19663 * The number of pixels to scroll in each scroll increment (defaults to 50)
19669 * The frequency of scrolls in milliseconds (defaults to 500)
19675 * True to animate the scroll (defaults to true)
19681 * The animation duration in seconds -
19682 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19688 * Manually trigger a cache refresh.
19690 refreshCache : function(){
19691 for(var id in els){
19692 if(typeof els[id] == 'object'){ // for people extending the object prototype
19693 els[id]._region = els[id].getRegion();
19700 * Ext JS Library 1.1.1
19701 * Copyright(c) 2006-2007, Ext JS, LLC.
19703 * Originally Released Under LGPL - original licence link has changed is not relivant.
19706 * <script type="text/javascript">
19711 * @class Roo.dd.Registry
19712 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19713 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19716 Roo.dd.Registry = function(){
19719 var autoIdSeed = 0;
19721 var getId = function(el, autogen){
19722 if(typeof el == "string"){
19726 if(!id && autogen !== false){
19727 id = "roodd-" + (++autoIdSeed);
19735 * Register a drag drop element
19736 * @param {String|HTMLElement} element The id or DOM node to register
19737 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19738 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19739 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19740 * populated in the data object (if applicable):
19742 Value Description<br />
19743 --------- ------------------------------------------<br />
19744 handles Array of DOM nodes that trigger dragging<br />
19745 for the element being registered<br />
19746 isHandle True if the element passed in triggers<br />
19747 dragging itself, else false
19750 register : function(el, data){
19752 if(typeof el == "string"){
19753 el = document.getElementById(el);
19756 elements[getId(el)] = data;
19757 if(data.isHandle !== false){
19758 handles[data.ddel.id] = data;
19761 var hs = data.handles;
19762 for(var i = 0, len = hs.length; i < len; i++){
19763 handles[getId(hs[i])] = data;
19769 * Unregister a drag drop element
19770 * @param {String|HTMLElement} element The id or DOM node to unregister
19772 unregister : function(el){
19773 var id = getId(el, false);
19774 var data = elements[id];
19776 delete elements[id];
19778 var hs = data.handles;
19779 for(var i = 0, len = hs.length; i < len; i++){
19780 delete handles[getId(hs[i], false)];
19787 * Returns the handle registered for a DOM Node by id
19788 * @param {String|HTMLElement} id The DOM node or id to look up
19789 * @return {Object} handle The custom handle data
19791 getHandle : function(id){
19792 if(typeof id != "string"){ // must be element?
19795 return handles[id];
19799 * Returns the handle that is registered for the DOM node that is the target of the event
19800 * @param {Event} e The event
19801 * @return {Object} handle The custom handle data
19803 getHandleFromEvent : function(e){
19804 var t = Roo.lib.Event.getTarget(e);
19805 return t ? handles[t.id] : null;
19809 * Returns a custom data object that is registered for a DOM node by id
19810 * @param {String|HTMLElement} id The DOM node or id to look up
19811 * @return {Object} data The custom data
19813 getTarget : function(id){
19814 if(typeof id != "string"){ // must be element?
19817 return elements[id];
19821 * Returns a custom data object that is registered for the DOM node that is the target of the event
19822 * @param {Event} e The event
19823 * @return {Object} data The custom data
19825 getTargetFromEvent : function(e){
19826 var t = Roo.lib.Event.getTarget(e);
19827 return t ? elements[t.id] || handles[t.id] : null;
19832 * Ext JS Library 1.1.1
19833 * Copyright(c) 2006-2007, Ext JS, LLC.
19835 * Originally Released Under LGPL - original licence link has changed is not relivant.
19838 * <script type="text/javascript">
19843 * @class Roo.dd.StatusProxy
19844 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19845 * default drag proxy used by all Roo.dd components.
19847 * @param {Object} config
19849 Roo.dd.StatusProxy = function(config){
19850 Roo.apply(this, config);
19851 this.id = this.id || Roo.id();
19852 this.el = new Roo.Layer({
19854 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19855 {tag: "div", cls: "x-dd-drop-icon"},
19856 {tag: "div", cls: "x-dd-drag-ghost"}
19859 shadow: !config || config.shadow !== false
19861 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19862 this.dropStatus = this.dropNotAllowed;
19865 Roo.dd.StatusProxy.prototype = {
19867 * @cfg {String} dropAllowed
19868 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19870 dropAllowed : "x-dd-drop-ok",
19872 * @cfg {String} dropNotAllowed
19873 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19875 dropNotAllowed : "x-dd-drop-nodrop",
19878 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19879 * over the current target element.
19880 * @param {String} cssClass The css class for the new drop status indicator image
19882 setStatus : function(cssClass){
19883 cssClass = cssClass || this.dropNotAllowed;
19884 if(this.dropStatus != cssClass){
19885 this.el.replaceClass(this.dropStatus, cssClass);
19886 this.dropStatus = cssClass;
19891 * Resets the status indicator to the default dropNotAllowed value
19892 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19894 reset : function(clearGhost){
19895 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19896 this.dropStatus = this.dropNotAllowed;
19898 this.ghost.update("");
19903 * Updates the contents of the ghost element
19904 * @param {String} html The html that will replace the current innerHTML of the ghost element
19906 update : function(html){
19907 if(typeof html == "string"){
19908 this.ghost.update(html);
19910 this.ghost.update("");
19911 html.style.margin = "0";
19912 this.ghost.dom.appendChild(html);
19914 // ensure float = none set?? cant remember why though.
19915 var el = this.ghost.dom.firstChild;
19917 Roo.fly(el).setStyle('float', 'none');
19922 * Returns the underlying proxy {@link Roo.Layer}
19923 * @return {Roo.Layer} el
19925 getEl : function(){
19930 * Returns the ghost element
19931 * @return {Roo.Element} el
19933 getGhost : function(){
19939 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19941 hide : function(clear){
19949 * Stops the repair animation if it's currently running
19952 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19958 * Displays this proxy
19965 * Force the Layer to sync its shadow and shim positions to the element
19972 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19973 * invalid drop operation by the item being dragged.
19974 * @param {Array} xy The XY position of the element ([x, y])
19975 * @param {Function} callback The function to call after the repair is complete
19976 * @param {Object} scope The scope in which to execute the callback
19978 repair : function(xy, callback, scope){
19979 this.callback = callback;
19980 this.scope = scope;
19981 if(xy && this.animRepair !== false){
19982 this.el.addClass("x-dd-drag-repair");
19983 this.el.hideUnders(true);
19984 this.anim = this.el.shift({
19985 duration: this.repairDuration || .5,
19989 callback: this.afterRepair,
19993 this.afterRepair();
19998 afterRepair : function(){
20000 if(typeof this.callback == "function"){
20001 this.callback.call(this.scope || this);
20003 this.callback = null;
20008 * Ext JS Library 1.1.1
20009 * Copyright(c) 2006-2007, Ext JS, LLC.
20011 * Originally Released Under LGPL - original licence link has changed is not relivant.
20014 * <script type="text/javascript">
20018 * @class Roo.dd.DragSource
20019 * @extends Roo.dd.DDProxy
20020 * A simple class that provides the basic implementation needed to make any element draggable.
20022 * @param {String/HTMLElement/Element} el The container element
20023 * @param {Object} config
20025 Roo.dd.DragSource = function(el, config){
20026 this.el = Roo.get(el);
20027 this.dragData = {};
20029 Roo.apply(this, config);
20032 this.proxy = new Roo.dd.StatusProxy();
20035 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
20036 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
20038 this.dragging = false;
20041 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
20043 * @cfg {String} dropAllowed
20044 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20046 dropAllowed : "x-dd-drop-ok",
20048 * @cfg {String} dropNotAllowed
20049 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20051 dropNotAllowed : "x-dd-drop-nodrop",
20054 * Returns the data object associated with this drag source
20055 * @return {Object} data An object containing arbitrary data
20057 getDragData : function(e){
20058 return this.dragData;
20062 onDragEnter : function(e, id){
20063 var target = Roo.dd.DragDropMgr.getDDById(id);
20064 this.cachedTarget = target;
20065 if(this.beforeDragEnter(target, e, id) !== false){
20066 if(target.isNotifyTarget){
20067 var status = target.notifyEnter(this, e, this.dragData);
20068 this.proxy.setStatus(status);
20070 this.proxy.setStatus(this.dropAllowed);
20073 if(this.afterDragEnter){
20075 * An empty function by default, but provided so that you can perform a custom action
20076 * when the dragged item enters the drop target by providing an implementation.
20077 * @param {Roo.dd.DragDrop} target The drop target
20078 * @param {Event} e The event object
20079 * @param {String} id The id of the dragged element
20080 * @method afterDragEnter
20082 this.afterDragEnter(target, e, id);
20088 * An empty function by default, but provided so that you can perform a custom action
20089 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
20090 * @param {Roo.dd.DragDrop} target The drop target
20091 * @param {Event} e The event object
20092 * @param {String} id The id of the dragged element
20093 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20095 beforeDragEnter : function(target, e, id){
20100 alignElWithMouse: function() {
20101 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
20106 onDragOver : function(e, id){
20107 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20108 if(this.beforeDragOver(target, e, id) !== false){
20109 if(target.isNotifyTarget){
20110 var status = target.notifyOver(this, e, this.dragData);
20111 this.proxy.setStatus(status);
20114 if(this.afterDragOver){
20116 * An empty function by default, but provided so that you can perform a custom action
20117 * while the dragged item is over the drop target by providing an implementation.
20118 * @param {Roo.dd.DragDrop} target The drop target
20119 * @param {Event} e The event object
20120 * @param {String} id The id of the dragged element
20121 * @method afterDragOver
20123 this.afterDragOver(target, e, id);
20129 * An empty function by default, but provided so that you can perform a custom action
20130 * while the dragged item is over the drop target and optionally cancel the onDragOver.
20131 * @param {Roo.dd.DragDrop} target The drop target
20132 * @param {Event} e The event object
20133 * @param {String} id The id of the dragged element
20134 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20136 beforeDragOver : function(target, e, id){
20141 onDragOut : function(e, id){
20142 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20143 if(this.beforeDragOut(target, e, id) !== false){
20144 if(target.isNotifyTarget){
20145 target.notifyOut(this, e, this.dragData);
20147 this.proxy.reset();
20148 if(this.afterDragOut){
20150 * An empty function by default, but provided so that you can perform a custom action
20151 * after the dragged item is dragged out of the target without dropping.
20152 * @param {Roo.dd.DragDrop} target The drop target
20153 * @param {Event} e The event object
20154 * @param {String} id The id of the dragged element
20155 * @method afterDragOut
20157 this.afterDragOut(target, e, id);
20160 this.cachedTarget = null;
20164 * An empty function by default, but provided so that you can perform a custom action before the dragged
20165 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20166 * @param {Roo.dd.DragDrop} target The drop target
20167 * @param {Event} e The event object
20168 * @param {String} id The id of the dragged element
20169 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20171 beforeDragOut : function(target, e, id){
20176 onDragDrop : function(e, id){
20177 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20178 if(this.beforeDragDrop(target, e, id) !== false){
20179 if(target.isNotifyTarget){
20180 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20181 this.onValidDrop(target, e, id);
20183 this.onInvalidDrop(target, e, id);
20186 this.onValidDrop(target, e, id);
20189 if(this.afterDragDrop){
20191 * An empty function by default, but provided so that you can perform a custom action
20192 * after a valid drag drop has occurred by providing an implementation.
20193 * @param {Roo.dd.DragDrop} target The drop target
20194 * @param {Event} e The event object
20195 * @param {String} id The id of the dropped element
20196 * @method afterDragDrop
20198 this.afterDragDrop(target, e, id);
20201 delete this.cachedTarget;
20205 * An empty function by default, but provided so that you can perform a custom action before the dragged
20206 * item is dropped onto the target and optionally cancel the onDragDrop.
20207 * @param {Roo.dd.DragDrop} target The drop target
20208 * @param {Event} e The event object
20209 * @param {String} id The id of the dragged element
20210 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20212 beforeDragDrop : function(target, e, id){
20217 onValidDrop : function(target, e, id){
20219 if(this.afterValidDrop){
20221 * An empty function by default, but provided so that you can perform a custom action
20222 * after a valid drop has occurred by providing an implementation.
20223 * @param {Object} target The target DD
20224 * @param {Event} e The event object
20225 * @param {String} id The id of the dropped element
20226 * @method afterInvalidDrop
20228 this.afterValidDrop(target, e, id);
20233 getRepairXY : function(e, data){
20234 return this.el.getXY();
20238 onInvalidDrop : function(target, e, id){
20239 this.beforeInvalidDrop(target, e, id);
20240 if(this.cachedTarget){
20241 if(this.cachedTarget.isNotifyTarget){
20242 this.cachedTarget.notifyOut(this, e, this.dragData);
20244 this.cacheTarget = null;
20246 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20248 if(this.afterInvalidDrop){
20250 * An empty function by default, but provided so that you can perform a custom action
20251 * after an invalid drop has occurred by providing an implementation.
20252 * @param {Event} e The event object
20253 * @param {String} id The id of the dropped element
20254 * @method afterInvalidDrop
20256 this.afterInvalidDrop(e, id);
20261 afterRepair : function(){
20263 this.el.highlight(this.hlColor || "c3daf9");
20265 this.dragging = false;
20269 * An empty function by default, but provided so that you can perform a custom action after an invalid
20270 * drop has occurred.
20271 * @param {Roo.dd.DragDrop} target The drop target
20272 * @param {Event} e The event object
20273 * @param {String} id The id of the dragged element
20274 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20276 beforeInvalidDrop : function(target, e, id){
20281 handleMouseDown : function(e){
20282 if(this.dragging) {
20285 var data = this.getDragData(e);
20286 if(data && this.onBeforeDrag(data, e) !== false){
20287 this.dragData = data;
20289 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20294 * An empty function by default, but provided so that you can perform a custom action before the initial
20295 * drag event begins and optionally cancel it.
20296 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20297 * @param {Event} e The event object
20298 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20300 onBeforeDrag : function(data, e){
20305 * An empty function by default, but provided so that you can perform a custom action once the initial
20306 * drag event has begun. The drag cannot be canceled from this function.
20307 * @param {Number} x The x position of the click on the dragged object
20308 * @param {Number} y The y position of the click on the dragged object
20310 onStartDrag : Roo.emptyFn,
20312 // private - YUI override
20313 startDrag : function(x, y){
20314 this.proxy.reset();
20315 this.dragging = true;
20316 this.proxy.update("");
20317 this.onInitDrag(x, y);
20322 onInitDrag : function(x, y){
20323 var clone = this.el.dom.cloneNode(true);
20324 clone.id = Roo.id(); // prevent duplicate ids
20325 this.proxy.update(clone);
20326 this.onStartDrag(x, y);
20331 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20332 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20334 getProxy : function(){
20339 * Hides the drag source's {@link Roo.dd.StatusProxy}
20341 hideProxy : function(){
20343 this.proxy.reset(true);
20344 this.dragging = false;
20348 triggerCacheRefresh : function(){
20349 Roo.dd.DDM.refreshCache(this.groups);
20352 // private - override to prevent hiding
20353 b4EndDrag: function(e) {
20356 // private - override to prevent moving
20357 endDrag : function(e){
20358 this.onEndDrag(this.dragData, e);
20362 onEndDrag : function(data, e){
20365 // private - pin to cursor
20366 autoOffset : function(x, y) {
20367 this.setDelta(-12, -20);
20371 * Ext JS Library 1.1.1
20372 * Copyright(c) 2006-2007, Ext JS, LLC.
20374 * Originally Released Under LGPL - original licence link has changed is not relivant.
20377 * <script type="text/javascript">
20382 * @class Roo.dd.DropTarget
20383 * @extends Roo.dd.DDTarget
20384 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20385 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20387 * @param {String/HTMLElement/Element} el The container element
20388 * @param {Object} config
20390 Roo.dd.DropTarget = function(el, config){
20391 this.el = Roo.get(el);
20393 var listeners = false; ;
20394 if (config && config.listeners) {
20395 listeners= config.listeners;
20396 delete config.listeners;
20398 Roo.apply(this, config);
20400 if(this.containerScroll){
20401 Roo.dd.ScrollManager.register(this.el);
20405 * @scope Roo.dd.DropTarget
20410 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20411 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20412 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20414 * IMPORTANT : it should set this.overClass and this.dropAllowed
20416 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20417 * @param {Event} e The event
20418 * @param {Object} data An object containing arbitrary data supplied by the drag source
20424 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20425 * This method will be called on every mouse movement while the drag source is over the drop target.
20426 * This default implementation simply returns the dropAllowed config value.
20428 * IMPORTANT : it should set this.dropAllowed
20430 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20431 * @param {Event} e The event
20432 * @param {Object} data An object containing arbitrary data supplied by the drag source
20438 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20439 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20440 * overClass (if any) from the drop element.
20442 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20443 * @param {Event} e The event
20444 * @param {Object} data An object containing arbitrary data supplied by the drag source
20450 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20451 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20452 * implementation that does something to process the drop event and returns true so that the drag source's
20453 * repair action does not run.
20455 * IMPORTANT : it should set this.success
20457 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20458 * @param {Event} e The event
20459 * @param {Object} data An object containing arbitrary data supplied by the drag source
20465 Roo.dd.DropTarget.superclass.constructor.call( this,
20467 this.ddGroup || this.group,
20470 listeners : listeners || {}
20478 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20480 * @cfg {String} overClass
20481 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20484 * @cfg {String} ddGroup
20485 * The drag drop group to handle drop events for
20489 * @cfg {String} dropAllowed
20490 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20492 dropAllowed : "x-dd-drop-ok",
20494 * @cfg {String} dropNotAllowed
20495 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20497 dropNotAllowed : "x-dd-drop-nodrop",
20499 * @cfg {boolean} success
20500 * set this after drop listener..
20504 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20505 * if the drop point is valid for over/enter..
20512 isNotifyTarget : true,
20517 notifyEnter : function(dd, e, data)
20520 this.fireEvent('enter', dd, e, data);
20521 if(this.overClass){
20522 this.el.addClass(this.overClass);
20524 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20525 this.valid ? this.dropAllowed : this.dropNotAllowed
20532 notifyOver : function(dd, e, data)
20535 this.fireEvent('over', dd, e, data);
20536 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20537 this.valid ? this.dropAllowed : this.dropNotAllowed
20544 notifyOut : function(dd, e, data)
20546 this.fireEvent('out', dd, e, data);
20547 if(this.overClass){
20548 this.el.removeClass(this.overClass);
20555 notifyDrop : function(dd, e, data)
20557 this.success = false;
20558 this.fireEvent('drop', dd, e, data);
20559 return this.success;
20563 * Ext JS Library 1.1.1
20564 * Copyright(c) 2006-2007, Ext JS, LLC.
20566 * Originally Released Under LGPL - original licence link has changed is not relivant.
20569 * <script type="text/javascript">
20574 * @class Roo.dd.DragZone
20575 * @extends Roo.dd.DragSource
20576 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20577 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20579 * @param {String/HTMLElement/Element} el The container element
20580 * @param {Object} config
20582 Roo.dd.DragZone = function(el, config){
20583 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20584 if(this.containerScroll){
20585 Roo.dd.ScrollManager.register(this.el);
20589 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20591 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20592 * for auto scrolling during drag operations.
20595 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20596 * method after a failed drop (defaults to "c3daf9" - light blue)
20600 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20601 * for a valid target to drag based on the mouse down. Override this method
20602 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20603 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20604 * @param {EventObject} e The mouse down event
20605 * @return {Object} The dragData
20607 getDragData : function(e){
20608 return Roo.dd.Registry.getHandleFromEvent(e);
20612 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20613 * this.dragData.ddel
20614 * @param {Number} x The x position of the click on the dragged object
20615 * @param {Number} y The y position of the click on the dragged object
20616 * @return {Boolean} true to continue the drag, false to cancel
20618 onInitDrag : function(x, y){
20619 this.proxy.update(this.dragData.ddel.cloneNode(true));
20620 this.onStartDrag(x, y);
20625 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20627 afterRepair : function(){
20629 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20631 this.dragging = false;
20635 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20636 * the XY of this.dragData.ddel
20637 * @param {EventObject} e The mouse up event
20638 * @return {Array} The xy location (e.g. [100, 200])
20640 getRepairXY : function(e){
20641 return Roo.Element.fly(this.dragData.ddel).getXY();
20645 * Ext JS Library 1.1.1
20646 * Copyright(c) 2006-2007, Ext JS, LLC.
20648 * Originally Released Under LGPL - original licence link has changed is not relivant.
20651 * <script type="text/javascript">
20654 * @class Roo.dd.DropZone
20655 * @extends Roo.dd.DropTarget
20656 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20657 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20659 * @param {String/HTMLElement/Element} el The container element
20660 * @param {Object} config
20662 Roo.dd.DropZone = function(el, config){
20663 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20666 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20668 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20669 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20670 * provide your own custom lookup.
20671 * @param {Event} e The event
20672 * @return {Object} data The custom data
20674 getTargetFromEvent : function(e){
20675 return Roo.dd.Registry.getTargetFromEvent(e);
20679 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20680 * that it has registered. This method has no default implementation and should be overridden to provide
20681 * node-specific processing if necessary.
20682 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20683 * {@link #getTargetFromEvent} for this node)
20684 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20685 * @param {Event} e The event
20686 * @param {Object} data An object containing arbitrary data supplied by the drag source
20688 onNodeEnter : function(n, dd, e, data){
20693 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20694 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20695 * overridden to provide the proper feedback.
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
20701 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20702 * underlying {@link Roo.dd.StatusProxy} can be updated
20704 onNodeOver : function(n, dd, e, data){
20705 return this.dropAllowed;
20709 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20710 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20711 * node-specific processing if necessary.
20712 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20713 * {@link #getTargetFromEvent} for this node)
20714 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20715 * @param {Event} e The event
20716 * @param {Object} data An object containing arbitrary data supplied by the drag source
20718 onNodeOut : function(n, dd, e, data){
20723 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20724 * the drop node. The default implementation returns false, so it should be overridden to provide the
20725 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20726 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20727 * {@link #getTargetFromEvent} for this node)
20728 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20729 * @param {Event} e The event
20730 * @param {Object} data An object containing arbitrary data supplied by the drag source
20731 * @return {Boolean} True if the drop was valid, else false
20733 onNodeDrop : function(n, dd, e, data){
20738 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20739 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20740 * it should be overridden to provide the proper feedback if necessary.
20741 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20742 * @param {Event} e The event
20743 * @param {Object} data An object containing arbitrary data supplied by the drag source
20744 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20745 * underlying {@link Roo.dd.StatusProxy} can be updated
20747 onContainerOver : function(dd, e, data){
20748 return this.dropNotAllowed;
20752 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20753 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20754 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20755 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20756 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20757 * @param {Event} e The event
20758 * @param {Object} data An object containing arbitrary data supplied by the drag source
20759 * @return {Boolean} True if the drop was valid, else false
20761 onContainerDrop : function(dd, e, data){
20766 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20767 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20768 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20769 * you should override this method and provide a custom implementation.
20770 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20771 * @param {Event} e The event
20772 * @param {Object} data An object containing arbitrary data supplied by the drag source
20773 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20774 * underlying {@link Roo.dd.StatusProxy} can be updated
20776 notifyEnter : function(dd, e, data){
20777 return this.dropNotAllowed;
20781 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20782 * This method will be called on every mouse movement while the drag source is over the drop zone.
20783 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20784 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20785 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20786 * registered node, it will call {@link #onContainerOver}.
20787 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20788 * @param {Event} e The event
20789 * @param {Object} data An object containing arbitrary data supplied by the drag source
20790 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20791 * underlying {@link Roo.dd.StatusProxy} can be updated
20793 notifyOver : function(dd, e, data){
20794 var n = this.getTargetFromEvent(e);
20795 if(!n){ // not over valid drop target
20796 if(this.lastOverNode){
20797 this.onNodeOut(this.lastOverNode, dd, e, data);
20798 this.lastOverNode = null;
20800 return this.onContainerOver(dd, e, data);
20802 if(this.lastOverNode != n){
20803 if(this.lastOverNode){
20804 this.onNodeOut(this.lastOverNode, dd, e, data);
20806 this.onNodeEnter(n, dd, e, data);
20807 this.lastOverNode = n;
20809 return this.onNodeOver(n, dd, e, data);
20813 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20814 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20815 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20816 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20817 * @param {Event} e The event
20818 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20820 notifyOut : function(dd, e, data){
20821 if(this.lastOverNode){
20822 this.onNodeOut(this.lastOverNode, dd, e, data);
20823 this.lastOverNode = null;
20828 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20829 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20830 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20831 * otherwise it will call {@link #onContainerDrop}.
20832 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20833 * @param {Event} e The event
20834 * @param {Object} data An object containing arbitrary data supplied by the drag source
20835 * @return {Boolean} True if the drop was valid, else false
20837 notifyDrop : function(dd, e, data){
20838 if(this.lastOverNode){
20839 this.onNodeOut(this.lastOverNode, dd, e, data);
20840 this.lastOverNode = null;
20842 var n = this.getTargetFromEvent(e);
20844 this.onNodeDrop(n, dd, e, data) :
20845 this.onContainerDrop(dd, e, data);
20849 triggerCacheRefresh : function(){
20850 Roo.dd.DDM.refreshCache(this.groups);
20854 * Ext JS Library 1.1.1
20855 * Copyright(c) 2006-2007, Ext JS, LLC.
20857 * Originally Released Under LGPL - original licence link has changed is not relivant.
20860 * <script type="text/javascript">
20865 * @class Roo.data.SortTypes
20867 * Defines the default sorting (casting?) comparison functions used when sorting data.
20869 Roo.data.SortTypes = {
20871 * Default sort that does nothing
20872 * @param {Mixed} s The value being converted
20873 * @return {Mixed} The comparison value
20875 none : function(s){
20880 * The regular expression used to strip tags
20884 stripTagsRE : /<\/?[^>]+>/gi,
20887 * Strips all HTML tags to sort on text only
20888 * @param {Mixed} s The value being converted
20889 * @return {String} The comparison value
20891 asText : function(s){
20892 return String(s).replace(this.stripTagsRE, "");
20896 * Strips all HTML tags to sort on text only - Case insensitive
20897 * @param {Mixed} s The value being converted
20898 * @return {String} The comparison value
20900 asUCText : function(s){
20901 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20905 * Case insensitive string
20906 * @param {Mixed} s The value being converted
20907 * @return {String} The comparison value
20909 asUCString : function(s) {
20910 return String(s).toUpperCase();
20915 * @param {Mixed} s The value being converted
20916 * @return {Number} The comparison value
20918 asDate : function(s) {
20922 if(s instanceof Date){
20923 return s.getTime();
20925 return Date.parse(String(s));
20930 * @param {Mixed} s The value being converted
20931 * @return {Float} The comparison value
20933 asFloat : function(s) {
20934 var val = parseFloat(String(s).replace(/,/g, ""));
20935 if(isNaN(val)) val = 0;
20941 * @param {Mixed} s The value being converted
20942 * @return {Number} The comparison value
20944 asInt : function(s) {
20945 var val = parseInt(String(s).replace(/,/g, ""));
20946 if(isNaN(val)) val = 0;
20951 * Ext JS Library 1.1.1
20952 * Copyright(c) 2006-2007, Ext JS, LLC.
20954 * Originally Released Under LGPL - original licence link has changed is not relivant.
20957 * <script type="text/javascript">
20961 * @class Roo.data.Record
20962 * Instances of this class encapsulate both record <em>definition</em> information, and record
20963 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20964 * to access Records cached in an {@link Roo.data.Store} object.<br>
20966 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20967 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20970 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20972 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20973 * {@link #create}. The parameters are the same.
20974 * @param {Array} data An associative Array of data values keyed by the field name.
20975 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20976 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20977 * not specified an integer id is generated.
20979 Roo.data.Record = function(data, id){
20980 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20985 * Generate a constructor for a specific record layout.
20986 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20987 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20988 * Each field definition object may contain the following properties: <ul>
20989 * <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,
20990 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20991 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20992 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20993 * is being used, then this is a string containing the javascript expression to reference the data relative to
20994 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20995 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20996 * this may be omitted.</p></li>
20997 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20998 * <ul><li>auto (Default, implies no conversion)</li>
21003 * <li>date</li></ul></p></li>
21004 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
21005 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
21006 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
21007 * by the Reader into an object that will be stored in the Record. It is passed the
21008 * following parameters:<ul>
21009 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
21011 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
21013 * <br>usage:<br><pre><code>
21014 var TopicRecord = Roo.data.Record.create(
21015 {name: 'title', mapping: 'topic_title'},
21016 {name: 'author', mapping: 'username'},
21017 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
21018 {name: 'lastPost', mapping: 'post_time', type: 'date'},
21019 {name: 'lastPoster', mapping: 'user2'},
21020 {name: 'excerpt', mapping: 'post_text'}
21023 var myNewRecord = new TopicRecord({
21024 title: 'Do my job please',
21027 lastPost: new Date(),
21028 lastPoster: 'Animal',
21029 excerpt: 'No way dude!'
21031 myStore.add(myNewRecord);
21036 Roo.data.Record.create = function(o){
21037 var f = function(){
21038 f.superclass.constructor.apply(this, arguments);
21040 Roo.extend(f, Roo.data.Record);
21041 var p = f.prototype;
21042 p.fields = new Roo.util.MixedCollection(false, function(field){
21045 for(var i = 0, len = o.length; i < len; i++){
21046 p.fields.add(new Roo.data.Field(o[i]));
21048 f.getField = function(name){
21049 return p.fields.get(name);
21054 Roo.data.Record.AUTO_ID = 1000;
21055 Roo.data.Record.EDIT = 'edit';
21056 Roo.data.Record.REJECT = 'reject';
21057 Roo.data.Record.COMMIT = 'commit';
21059 Roo.data.Record.prototype = {
21061 * Readonly flag - true if this record has been modified.
21070 join : function(store){
21071 this.store = store;
21075 * Set the named field to the specified value.
21076 * @param {String} name The name of the field to set.
21077 * @param {Object} value The value to set the field to.
21079 set : function(name, value){
21080 if(this.data[name] == value){
21084 if(!this.modified){
21085 this.modified = {};
21087 if(typeof this.modified[name] == 'undefined'){
21088 this.modified[name] = this.data[name];
21090 this.data[name] = value;
21091 if(!this.editing && this.store){
21092 this.store.afterEdit(this);
21097 * Get the value of the named field.
21098 * @param {String} name The name of the field to get the value of.
21099 * @return {Object} The value of the field.
21101 get : function(name){
21102 return this.data[name];
21106 beginEdit : function(){
21107 this.editing = true;
21108 this.modified = {};
21112 cancelEdit : function(){
21113 this.editing = false;
21114 delete this.modified;
21118 endEdit : function(){
21119 this.editing = false;
21120 if(this.dirty && this.store){
21121 this.store.afterEdit(this);
21126 * Usually called by the {@link Roo.data.Store} which owns the Record.
21127 * Rejects all changes made to the Record since either creation, or the last commit operation.
21128 * Modified fields are reverted to their original values.
21130 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21131 * of reject operations.
21133 reject : function(){
21134 var m = this.modified;
21136 if(typeof m[n] != "function"){
21137 this.data[n] = m[n];
21140 this.dirty = false;
21141 delete this.modified;
21142 this.editing = false;
21144 this.store.afterReject(this);
21149 * Usually called by the {@link Roo.data.Store} which owns the Record.
21150 * Commits all changes made to the Record since either creation, or the last commit operation.
21152 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21153 * of commit operations.
21155 commit : function(){
21156 this.dirty = false;
21157 delete this.modified;
21158 this.editing = false;
21160 this.store.afterCommit(this);
21165 hasError : function(){
21166 return this.error != null;
21170 clearError : function(){
21175 * Creates a copy of this record.
21176 * @param {String} id (optional) A new record id if you don't want to use this record's id
21179 copy : function(newId) {
21180 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21184 * Ext JS Library 1.1.1
21185 * Copyright(c) 2006-2007, Ext JS, LLC.
21187 * Originally Released Under LGPL - original licence link has changed is not relivant.
21190 * <script type="text/javascript">
21196 * @class Roo.data.Store
21197 * @extends Roo.util.Observable
21198 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21199 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21201 * 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
21202 * has no knowledge of the format of the data returned by the Proxy.<br>
21204 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21205 * instances from the data object. These records are cached and made available through accessor functions.
21207 * Creates a new Store.
21208 * @param {Object} config A config object containing the objects needed for the Store to access data,
21209 * and read the data into Records.
21211 Roo.data.Store = function(config){
21212 this.data = new Roo.util.MixedCollection(false);
21213 this.data.getKey = function(o){
21216 this.baseParams = {};
21218 this.paramNames = {
21223 "multisort" : "_multisort"
21226 if(config && config.data){
21227 this.inlineData = config.data;
21228 delete config.data;
21231 Roo.apply(this, config);
21233 if(this.reader){ // reader passed
21234 this.reader = Roo.factory(this.reader, Roo.data);
21235 this.reader.xmodule = this.xmodule || false;
21236 if(!this.recordType){
21237 this.recordType = this.reader.recordType;
21239 if(this.reader.onMetaChange){
21240 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21244 if(this.recordType){
21245 this.fields = this.recordType.prototype.fields;
21247 this.modified = [];
21251 * @event datachanged
21252 * Fires when the data cache has changed, and a widget which is using this Store
21253 * as a Record cache should refresh its view.
21254 * @param {Store} this
21256 datachanged : true,
21258 * @event metachange
21259 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21260 * @param {Store} this
21261 * @param {Object} meta The JSON metadata
21266 * Fires when Records have been added to the Store
21267 * @param {Store} this
21268 * @param {Roo.data.Record[]} records The array of Records added
21269 * @param {Number} index The index at which the record(s) were added
21274 * Fires when a Record has been removed from the Store
21275 * @param {Store} this
21276 * @param {Roo.data.Record} record The Record that was removed
21277 * @param {Number} index The index at which the record was removed
21282 * Fires when a Record has been updated
21283 * @param {Store} this
21284 * @param {Roo.data.Record} record The Record that was updated
21285 * @param {String} operation The update operation being performed. Value may be one of:
21287 Roo.data.Record.EDIT
21288 Roo.data.Record.REJECT
21289 Roo.data.Record.COMMIT
21295 * Fires when the data cache has been cleared.
21296 * @param {Store} this
21300 * @event beforeload
21301 * Fires before a request is made for a new data object. If the beforeload handler returns false
21302 * the load action will be canceled.
21303 * @param {Store} this
21304 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21308 * @event beforeloadadd
21309 * Fires after a new set of Records has been loaded.
21310 * @param {Store} this
21311 * @param {Roo.data.Record[]} records The Records that were loaded
21312 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21314 beforeloadadd : true,
21317 * Fires after a new set of Records has been loaded, before they are added to the store.
21318 * @param {Store} this
21319 * @param {Roo.data.Record[]} records The Records that were loaded
21320 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21321 * @params {Object} return from reader
21325 * @event loadexception
21326 * Fires if an exception occurs in the Proxy during loading.
21327 * Called with the signature of the Proxy's "loadexception" event.
21328 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21331 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21332 * @param {Object} load options
21333 * @param {Object} jsonData from your request (normally this contains the Exception)
21335 loadexception : true
21339 this.proxy = Roo.factory(this.proxy, Roo.data);
21340 this.proxy.xmodule = this.xmodule || false;
21341 this.relayEvents(this.proxy, ["loadexception"]);
21343 this.sortToggle = {};
21344 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21346 Roo.data.Store.superclass.constructor.call(this);
21348 if(this.inlineData){
21349 this.loadData(this.inlineData);
21350 delete this.inlineData;
21354 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21356 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21357 * without a remote query - used by combo/forms at present.
21361 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21364 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21367 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21368 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21371 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21372 * on any HTTP request
21375 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21378 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21382 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21383 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21385 remoteSort : false,
21388 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21389 * loaded or when a record is removed. (defaults to false).
21391 pruneModifiedRecords : false,
21394 lastOptions : null,
21397 * Add Records to the Store and fires the add event.
21398 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21400 add : function(records){
21401 records = [].concat(records);
21402 for(var i = 0, len = records.length; i < len; i++){
21403 records[i].join(this);
21405 var index = this.data.length;
21406 this.data.addAll(records);
21407 this.fireEvent("add", this, records, index);
21411 * Remove a Record from the Store and fires the remove event.
21412 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21414 remove : function(record){
21415 var index = this.data.indexOf(record);
21416 this.data.removeAt(index);
21417 if(this.pruneModifiedRecords){
21418 this.modified.remove(record);
21420 this.fireEvent("remove", this, record, index);
21424 * Remove all Records from the Store and fires the clear event.
21426 removeAll : function(){
21428 if(this.pruneModifiedRecords){
21429 this.modified = [];
21431 this.fireEvent("clear", this);
21435 * Inserts Records to the Store at the given index and fires the add event.
21436 * @param {Number} index The start index at which to insert the passed Records.
21437 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21439 insert : function(index, records){
21440 records = [].concat(records);
21441 for(var i = 0, len = records.length; i < len; i++){
21442 this.data.insert(index, records[i]);
21443 records[i].join(this);
21445 this.fireEvent("add", this, records, index);
21449 * Get the index within the cache of the passed Record.
21450 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21451 * @return {Number} The index of the passed Record. Returns -1 if not found.
21453 indexOf : function(record){
21454 return this.data.indexOf(record);
21458 * Get the index within the cache of the Record with the passed id.
21459 * @param {String} id The id of the Record to find.
21460 * @return {Number} The index of the Record. Returns -1 if not found.
21462 indexOfId : function(id){
21463 return this.data.indexOfKey(id);
21467 * Get the Record with the specified id.
21468 * @param {String} id The id of the Record to find.
21469 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21471 getById : function(id){
21472 return this.data.key(id);
21476 * Get the Record at the specified index.
21477 * @param {Number} index The index of the Record to find.
21478 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21480 getAt : function(index){
21481 return this.data.itemAt(index);
21485 * Returns a range of Records between specified indices.
21486 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21487 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21488 * @return {Roo.data.Record[]} An array of Records
21490 getRange : function(start, end){
21491 return this.data.getRange(start, end);
21495 storeOptions : function(o){
21496 o = Roo.apply({}, o);
21499 this.lastOptions = o;
21503 * Loads the Record cache from the configured Proxy using the configured Reader.
21505 * If using remote paging, then the first load call must specify the <em>start</em>
21506 * and <em>limit</em> properties in the options.params property to establish the initial
21507 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21509 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21510 * and this call will return before the new data has been loaded. Perform any post-processing
21511 * in a callback function, or in a "load" event handler.</strong>
21513 * @param {Object} options An object containing properties which control loading options:<ul>
21514 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21515 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21516 * passed the following arguments:<ul>
21517 * <li>r : Roo.data.Record[]</li>
21518 * <li>options: Options object from the load call</li>
21519 * <li>success: Boolean success indicator</li></ul></li>
21520 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21521 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21524 load : function(options){
21525 options = options || {};
21526 if(this.fireEvent("beforeload", this, options) !== false){
21527 this.storeOptions(options);
21528 var p = Roo.apply(options.params || {}, this.baseParams);
21529 // if meta was not loaded from remote source.. try requesting it.
21530 if (!this.reader.metaFromRemote) {
21531 p._requestMeta = 1;
21533 if(this.sortInfo && this.remoteSort){
21534 var pn = this.paramNames;
21535 p[pn["sort"]] = this.sortInfo.field;
21536 p[pn["dir"]] = this.sortInfo.direction;
21538 if (this.multiSort) {
21539 var pn = this.paramNames;
21540 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21543 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21548 * Reloads the Record cache from the configured Proxy using the configured Reader and
21549 * the options from the last load operation performed.
21550 * @param {Object} options (optional) An object containing properties which may override the options
21551 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21552 * the most recently used options are reused).
21554 reload : function(options){
21555 this.load(Roo.applyIf(options||{}, this.lastOptions));
21559 // Called as a callback by the Reader during a load operation.
21560 loadRecords : function(o, options, success){
21561 if(!o || success === false){
21562 if(success !== false){
21563 this.fireEvent("load", this, [], options, o);
21565 if(options.callback){
21566 options.callback.call(options.scope || this, [], options, false);
21570 // if data returned failure - throw an exception.
21571 if (o.success === false) {
21572 // show a message if no listener is registered.
21573 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21574 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21576 // loadmask wil be hooked into this..
21577 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21580 var r = o.records, t = o.totalRecords || r.length;
21582 this.fireEvent("beforeloadadd", this, r, options, o);
21584 if(!options || options.add !== true){
21585 if(this.pruneModifiedRecords){
21586 this.modified = [];
21588 for(var i = 0, len = r.length; i < len; i++){
21592 this.data = this.snapshot;
21593 delete this.snapshot;
21596 this.data.addAll(r);
21597 this.totalLength = t;
21599 this.fireEvent("datachanged", this);
21601 this.totalLength = Math.max(t, this.data.length+r.length);
21604 this.fireEvent("load", this, r, options, o);
21605 if(options.callback){
21606 options.callback.call(options.scope || this, r, options, true);
21612 * Loads data from a passed data block. A Reader which understands the format of the data
21613 * must have been configured in the constructor.
21614 * @param {Object} data The data block from which to read the Records. The format of the data expected
21615 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21616 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21618 loadData : function(o, append){
21619 var r = this.reader.readRecords(o);
21620 this.loadRecords(r, {add: append}, true);
21624 * Gets the number of cached records.
21626 * <em>If using paging, this may not be the total size of the dataset. If the data object
21627 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21628 * the data set size</em>
21630 getCount : function(){
21631 return this.data.length || 0;
21635 * Gets the total number of records in the dataset as returned by the server.
21637 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21638 * the dataset size</em>
21640 getTotalCount : function(){
21641 return this.totalLength || 0;
21645 * Returns the sort state of the Store as an object with two properties:
21647 field {String} The name of the field by which the Records are sorted
21648 direction {String} The sort order, "ASC" or "DESC"
21651 getSortState : function(){
21652 return this.sortInfo;
21656 applySort : function(){
21657 if(this.sortInfo && !this.remoteSort){
21658 var s = this.sortInfo, f = s.field;
21659 var st = this.fields.get(f).sortType;
21660 var fn = function(r1, r2){
21661 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21662 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21664 this.data.sort(s.direction, fn);
21665 if(this.snapshot && this.snapshot != this.data){
21666 this.snapshot.sort(s.direction, fn);
21672 * Sets the default sort column and order to be used by the next load operation.
21673 * @param {String} fieldName The name of the field to sort by.
21674 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21676 setDefaultSort : function(field, dir){
21677 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21681 * Sort the Records.
21682 * If remote sorting is used, the sort is performed on the server, and the cache is
21683 * reloaded. If local sorting is used, the cache is sorted internally.
21684 * @param {String} fieldName The name of the field to sort by.
21685 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21687 sort : function(fieldName, dir){
21688 var f = this.fields.get(fieldName);
21690 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21692 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21693 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21698 this.sortToggle[f.name] = dir;
21699 this.sortInfo = {field: f.name, direction: dir};
21700 if(!this.remoteSort){
21702 this.fireEvent("datachanged", this);
21704 this.load(this.lastOptions);
21709 * Calls the specified function for each of the Records in the cache.
21710 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21711 * Returning <em>false</em> aborts and exits the iteration.
21712 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21714 each : function(fn, scope){
21715 this.data.each(fn, scope);
21719 * Gets all records modified since the last commit. Modified records are persisted across load operations
21720 * (e.g., during paging).
21721 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21723 getModifiedRecords : function(){
21724 return this.modified;
21728 createFilterFn : function(property, value, anyMatch){
21729 if(!value.exec){ // not a regex
21730 value = String(value);
21731 if(value.length == 0){
21734 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21736 return function(r){
21737 return value.test(r.data[property]);
21742 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21743 * @param {String} property A field on your records
21744 * @param {Number} start The record index to start at (defaults to 0)
21745 * @param {Number} end The last record index to include (defaults to length - 1)
21746 * @return {Number} The sum
21748 sum : function(property, start, end){
21749 var rs = this.data.items, v = 0;
21750 start = start || 0;
21751 end = (end || end === 0) ? end : rs.length-1;
21753 for(var i = start; i <= end; i++){
21754 v += (rs[i].data[property] || 0);
21760 * Filter the records by a specified property.
21761 * @param {String} field A field on your records
21762 * @param {String/RegExp} value Either a string that the field
21763 * should start with or a RegExp to test against the field
21764 * @param {Boolean} anyMatch True to match any part not just the beginning
21766 filter : function(property, value, anyMatch){
21767 var fn = this.createFilterFn(property, value, anyMatch);
21768 return fn ? this.filterBy(fn) : this.clearFilter();
21772 * Filter by a function. The specified function will be called with each
21773 * record in this data source. If the function returns true the record is included,
21774 * otherwise it is filtered.
21775 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21776 * @param {Object} scope (optional) The scope of the function (defaults to this)
21778 filterBy : function(fn, scope){
21779 this.snapshot = this.snapshot || this.data;
21780 this.data = this.queryBy(fn, scope||this);
21781 this.fireEvent("datachanged", this);
21785 * Query the records by a specified property.
21786 * @param {String} field A field on your records
21787 * @param {String/RegExp} value Either a string that the field
21788 * should start with or a RegExp to test against the field
21789 * @param {Boolean} anyMatch True to match any part not just the beginning
21790 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21792 query : function(property, value, anyMatch){
21793 var fn = this.createFilterFn(property, value, anyMatch);
21794 return fn ? this.queryBy(fn) : this.data.clone();
21798 * Query by a function. The specified function will be called with each
21799 * record in this data source. If the function returns true the record is included
21801 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21802 * @param {Object} scope (optional) The scope of the function (defaults to this)
21803 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21805 queryBy : function(fn, scope){
21806 var data = this.snapshot || this.data;
21807 return data.filterBy(fn, scope||this);
21811 * Collects unique values for a particular dataIndex from this store.
21812 * @param {String} dataIndex The property to collect
21813 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21814 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21815 * @return {Array} An array of the unique values
21817 collect : function(dataIndex, allowNull, bypassFilter){
21818 var d = (bypassFilter === true && this.snapshot) ?
21819 this.snapshot.items : this.data.items;
21820 var v, sv, r = [], l = {};
21821 for(var i = 0, len = d.length; i < len; i++){
21822 v = d[i].data[dataIndex];
21824 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21833 * Revert to a view of the Record cache with no filtering applied.
21834 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21836 clearFilter : function(suppressEvent){
21837 if(this.snapshot && this.snapshot != this.data){
21838 this.data = this.snapshot;
21839 delete this.snapshot;
21840 if(suppressEvent !== true){
21841 this.fireEvent("datachanged", this);
21847 afterEdit : function(record){
21848 if(this.modified.indexOf(record) == -1){
21849 this.modified.push(record);
21851 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21855 afterReject : function(record){
21856 this.modified.remove(record);
21857 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21861 afterCommit : function(record){
21862 this.modified.remove(record);
21863 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21867 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21868 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21870 commitChanges : function(){
21871 var m = this.modified.slice(0);
21872 this.modified = [];
21873 for(var i = 0, len = m.length; i < len; i++){
21879 * Cancel outstanding changes on all changed records.
21881 rejectChanges : function(){
21882 var m = this.modified.slice(0);
21883 this.modified = [];
21884 for(var i = 0, len = m.length; i < len; i++){
21889 onMetaChange : function(meta, rtype, o){
21890 this.recordType = rtype;
21891 this.fields = rtype.prototype.fields;
21892 delete this.snapshot;
21893 this.sortInfo = meta.sortInfo || this.sortInfo;
21894 this.modified = [];
21895 this.fireEvent('metachange', this, this.reader.meta);
21898 moveIndex : function(data, type)
21900 var index = this.indexOf(data);
21902 var newIndex = index + type;
21906 this.insert(newIndex, data);
21911 * Ext JS Library 1.1.1
21912 * Copyright(c) 2006-2007, Ext JS, LLC.
21914 * Originally Released Under LGPL - original licence link has changed is not relivant.
21917 * <script type="text/javascript">
21921 * @class Roo.data.SimpleStore
21922 * @extends Roo.data.Store
21923 * Small helper class to make creating Stores from Array data easier.
21924 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21925 * @cfg {Array} fields An array of field definition objects, or field name strings.
21926 * @cfg {Array} data The multi-dimensional array of data
21928 * @param {Object} config
21930 Roo.data.SimpleStore = function(config){
21931 Roo.data.SimpleStore.superclass.constructor.call(this, {
21933 reader: new Roo.data.ArrayReader({
21936 Roo.data.Record.create(config.fields)
21938 proxy : new Roo.data.MemoryProxy(config.data)
21942 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21944 * Ext JS Library 1.1.1
21945 * Copyright(c) 2006-2007, Ext JS, LLC.
21947 * Originally Released Under LGPL - original licence link has changed is not relivant.
21950 * <script type="text/javascript">
21955 * @extends Roo.data.Store
21956 * @class Roo.data.JsonStore
21957 * Small helper class to make creating Stores for JSON data easier. <br/>
21959 var store = new Roo.data.JsonStore({
21960 url: 'get-images.php',
21962 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21965 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21966 * JsonReader and HttpProxy (unless inline data is provided).</b>
21967 * @cfg {Array} fields An array of field definition objects, or field name strings.
21969 * @param {Object} config
21971 Roo.data.JsonStore = function(c){
21972 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21973 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21974 reader: new Roo.data.JsonReader(c, c.fields)
21977 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21979 * Ext JS Library 1.1.1
21980 * Copyright(c) 2006-2007, Ext JS, LLC.
21982 * Originally Released Under LGPL - original licence link has changed is not relivant.
21985 * <script type="text/javascript">
21989 Roo.data.Field = function(config){
21990 if(typeof config == "string"){
21991 config = {name: config};
21993 Roo.apply(this, config);
21996 this.type = "auto";
21999 var st = Roo.data.SortTypes;
22000 // named sortTypes are supported, here we look them up
22001 if(typeof this.sortType == "string"){
22002 this.sortType = st[this.sortType];
22005 // set default sortType for strings and dates
22006 if(!this.sortType){
22009 this.sortType = st.asUCString;
22012 this.sortType = st.asDate;
22015 this.sortType = st.none;
22020 var stripRe = /[\$,%]/g;
22022 // prebuilt conversion function for this field, instead of
22023 // switching every time we're reading a value
22025 var cv, dateFormat = this.dateFormat;
22030 cv = function(v){ return v; };
22033 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
22037 return v !== undefined && v !== null && v !== '' ?
22038 parseInt(String(v).replace(stripRe, ""), 10) : '';
22043 return v !== undefined && v !== null && v !== '' ?
22044 parseFloat(String(v).replace(stripRe, ""), 10) : '';
22049 cv = function(v){ return v === true || v === "true" || v == 1; };
22056 if(v instanceof Date){
22060 if(dateFormat == "timestamp"){
22061 return new Date(v*1000);
22063 return Date.parseDate(v, dateFormat);
22065 var parsed = Date.parse(v);
22066 return parsed ? new Date(parsed) : null;
22075 Roo.data.Field.prototype = {
22083 * Ext JS Library 1.1.1
22084 * Copyright(c) 2006-2007, Ext JS, LLC.
22086 * Originally Released Under LGPL - original licence link has changed is not relivant.
22089 * <script type="text/javascript">
22092 // Base class for reading structured data from a data source. This class is intended to be
22093 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
22096 * @class Roo.data.DataReader
22097 * Base class for reading structured data from a data source. This class is intended to be
22098 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
22101 Roo.data.DataReader = function(meta, recordType){
22105 this.recordType = recordType instanceof Array ?
22106 Roo.data.Record.create(recordType) : recordType;
22109 Roo.data.DataReader.prototype = {
22111 * Create an empty record
22112 * @param {Object} data (optional) - overlay some values
22113 * @return {Roo.data.Record} record created.
22115 newRow : function(d) {
22117 this.recordType.prototype.fields.each(function(c) {
22119 case 'int' : da[c.name] = 0; break;
22120 case 'date' : da[c.name] = new Date(); break;
22121 case 'float' : da[c.name] = 0.0; break;
22122 case 'boolean' : da[c.name] = false; break;
22123 default : da[c.name] = ""; break;
22127 return new this.recordType(Roo.apply(da, d));
22132 * Ext JS Library 1.1.1
22133 * Copyright(c) 2006-2007, Ext JS, LLC.
22135 * Originally Released Under LGPL - original licence link has changed is not relivant.
22138 * <script type="text/javascript">
22142 * @class Roo.data.DataProxy
22143 * @extends Roo.data.Observable
22144 * This class is an abstract base class for implementations which provide retrieval of
22145 * unformatted data objects.<br>
22147 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
22148 * (of the appropriate type which knows how to parse the data object) to provide a block of
22149 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
22151 * Custom implementations must implement the load method as described in
22152 * {@link Roo.data.HttpProxy#load}.
22154 Roo.data.DataProxy = function(){
22157 * @event beforeload
22158 * Fires before a network request is made to retrieve a data object.
22159 * @param {Object} This DataProxy object.
22160 * @param {Object} params The params parameter to the load function.
22165 * Fires before the load method's callback is called.
22166 * @param {Object} This DataProxy object.
22167 * @param {Object} o The data object.
22168 * @param {Object} arg The callback argument object passed to the load function.
22172 * @event loadexception
22173 * Fires if an Exception occurs during data retrieval.
22174 * @param {Object} This DataProxy object.
22175 * @param {Object} o The data object.
22176 * @param {Object} arg The callback argument object passed to the load function.
22177 * @param {Object} e The Exception.
22179 loadexception : true
22181 Roo.data.DataProxy.superclass.constructor.call(this);
22184 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22187 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22191 * Ext JS Library 1.1.1
22192 * Copyright(c) 2006-2007, Ext JS, LLC.
22194 * Originally Released Under LGPL - original licence link has changed is not relivant.
22197 * <script type="text/javascript">
22200 * @class Roo.data.MemoryProxy
22201 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22202 * to the Reader when its load method is called.
22204 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22206 Roo.data.MemoryProxy = function(data){
22210 Roo.data.MemoryProxy.superclass.constructor.call(this);
22214 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22216 * Load data from the requested source (in this case an in-memory
22217 * data object passed to the constructor), read the data object into
22218 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22219 * process that block using the passed callback.
22220 * @param {Object} params This parameter is not used by the MemoryProxy class.
22221 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22222 * object into a block of Roo.data.Records.
22223 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22224 * The function must be passed <ul>
22225 * <li>The Record block object</li>
22226 * <li>The "arg" argument from the load function</li>
22227 * <li>A boolean success indicator</li>
22229 * @param {Object} scope The scope in which to call the callback
22230 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22232 load : function(params, reader, callback, scope, arg){
22233 params = params || {};
22236 result = reader.readRecords(this.data);
22238 this.fireEvent("loadexception", this, arg, null, e);
22239 callback.call(scope, null, arg, false);
22242 callback.call(scope, result, arg, true);
22246 update : function(params, records){
22251 * Ext JS Library 1.1.1
22252 * Copyright(c) 2006-2007, Ext JS, LLC.
22254 * Originally Released Under LGPL - original licence link has changed is not relivant.
22257 * <script type="text/javascript">
22260 * @class Roo.data.HttpProxy
22261 * @extends Roo.data.DataProxy
22262 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22263 * configured to reference a certain URL.<br><br>
22265 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22266 * from which the running page was served.<br><br>
22268 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22270 * Be aware that to enable the browser to parse an XML document, the server must set
22271 * the Content-Type header in the HTTP response to "text/xml".
22273 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22274 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22275 * will be used to make the request.
22277 Roo.data.HttpProxy = function(conn){
22278 Roo.data.HttpProxy.superclass.constructor.call(this);
22279 // is conn a conn config or a real conn?
22281 this.useAjax = !conn || !conn.events;
22285 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22286 // thse are take from connection...
22289 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22292 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22293 * extra parameters to each request made by this object. (defaults to undefined)
22296 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22297 * to each request made by this object. (defaults to undefined)
22300 * @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)
22303 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22306 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22312 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22316 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22317 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22318 * a finer-grained basis than the DataProxy events.
22320 getConnection : function(){
22321 return this.useAjax ? Roo.Ajax : this.conn;
22325 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22326 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22327 * process that block using the passed callback.
22328 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22329 * for the request to the remote server.
22330 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22331 * object into a block of Roo.data.Records.
22332 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22333 * The function must be passed <ul>
22334 * <li>The Record block object</li>
22335 * <li>The "arg" argument from the load function</li>
22336 * <li>A boolean success indicator</li>
22338 * @param {Object} scope The scope in which to call the callback
22339 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22341 load : function(params, reader, callback, scope, arg){
22342 if(this.fireEvent("beforeload", this, params) !== false){
22344 params : params || {},
22346 callback : callback,
22351 callback : this.loadResponse,
22355 Roo.applyIf(o, this.conn);
22356 if(this.activeRequest){
22357 Roo.Ajax.abort(this.activeRequest);
22359 this.activeRequest = Roo.Ajax.request(o);
22361 this.conn.request(o);
22364 callback.call(scope||this, null, arg, false);
22369 loadResponse : function(o, success, response){
22370 delete this.activeRequest;
22372 this.fireEvent("loadexception", this, o, response);
22373 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22378 result = o.reader.read(response);
22380 this.fireEvent("loadexception", this, o, response, e);
22381 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22385 this.fireEvent("load", this, o, o.request.arg);
22386 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22390 update : function(dataSet){
22395 updateResponse : function(dataSet){
22400 * Ext JS Library 1.1.1
22401 * Copyright(c) 2006-2007, Ext JS, LLC.
22403 * Originally Released Under LGPL - original licence link has changed is not relivant.
22406 * <script type="text/javascript">
22410 * @class Roo.data.ScriptTagProxy
22411 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22412 * other than the originating domain of the running page.<br><br>
22414 * <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
22415 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22417 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22418 * source code that is used as the source inside a <script> tag.<br><br>
22420 * In order for the browser to process the returned data, the server must wrap the data object
22421 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22422 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22423 * depending on whether the callback name was passed:
22426 boolean scriptTag = false;
22427 String cb = request.getParameter("callback");
22430 response.setContentType("text/javascript");
22432 response.setContentType("application/x-json");
22434 Writer out = response.getWriter();
22436 out.write(cb + "(");
22438 out.print(dataBlock.toJsonString());
22445 * @param {Object} config A configuration object.
22447 Roo.data.ScriptTagProxy = function(config){
22448 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22449 Roo.apply(this, config);
22450 this.head = document.getElementsByTagName("head")[0];
22453 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22455 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22457 * @cfg {String} url The URL from which to request the data object.
22460 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22464 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22465 * the server the name of the callback function set up by the load call to process the returned data object.
22466 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22467 * javascript output which calls this named function passing the data object as its only parameter.
22469 callbackParam : "callback",
22471 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22472 * name to the request.
22477 * Load data from the configured URL, read the data object into
22478 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22479 * process that block using the passed callback.
22480 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22481 * for the request to the remote server.
22482 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22483 * object into a block of Roo.data.Records.
22484 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22485 * The function must be passed <ul>
22486 * <li>The Record block object</li>
22487 * <li>The "arg" argument from the load function</li>
22488 * <li>A boolean success indicator</li>
22490 * @param {Object} scope The scope in which to call the callback
22491 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22493 load : function(params, reader, callback, scope, arg){
22494 if(this.fireEvent("beforeload", this, params) !== false){
22496 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22498 var url = this.url;
22499 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22501 url += "&_dc=" + (new Date().getTime());
22503 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22506 cb : "stcCallback"+transId,
22507 scriptId : "stcScript"+transId,
22511 callback : callback,
22517 window[trans.cb] = function(o){
22518 conn.handleResponse(o, trans);
22521 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22523 if(this.autoAbort !== false){
22527 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22529 var script = document.createElement("script");
22530 script.setAttribute("src", url);
22531 script.setAttribute("type", "text/javascript");
22532 script.setAttribute("id", trans.scriptId);
22533 this.head.appendChild(script);
22535 this.trans = trans;
22537 callback.call(scope||this, null, arg, false);
22542 isLoading : function(){
22543 return this.trans ? true : false;
22547 * Abort the current server request.
22549 abort : function(){
22550 if(this.isLoading()){
22551 this.destroyTrans(this.trans);
22556 destroyTrans : function(trans, isLoaded){
22557 this.head.removeChild(document.getElementById(trans.scriptId));
22558 clearTimeout(trans.timeoutId);
22560 window[trans.cb] = undefined;
22562 delete window[trans.cb];
22565 // if hasn't been loaded, wait for load to remove it to prevent script error
22566 window[trans.cb] = function(){
22567 window[trans.cb] = undefined;
22569 delete window[trans.cb];
22576 handleResponse : function(o, trans){
22577 this.trans = false;
22578 this.destroyTrans(trans, true);
22581 result = trans.reader.readRecords(o);
22583 this.fireEvent("loadexception", this, o, trans.arg, e);
22584 trans.callback.call(trans.scope||window, null, trans.arg, false);
22587 this.fireEvent("load", this, o, trans.arg);
22588 trans.callback.call(trans.scope||window, result, trans.arg, true);
22592 handleFailure : function(trans){
22593 this.trans = false;
22594 this.destroyTrans(trans, false);
22595 this.fireEvent("loadexception", this, null, trans.arg);
22596 trans.callback.call(trans.scope||window, null, trans.arg, false);
22600 * Ext JS Library 1.1.1
22601 * Copyright(c) 2006-2007, Ext JS, LLC.
22603 * Originally Released Under LGPL - original licence link has changed is not relivant.
22606 * <script type="text/javascript">
22610 * @class Roo.data.JsonReader
22611 * @extends Roo.data.DataReader
22612 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22613 * based on mappings in a provided Roo.data.Record constructor.
22615 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22616 * in the reply previously.
22621 var RecordDef = Roo.data.Record.create([
22622 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22623 {name: 'occupation'} // This field will use "occupation" as the mapping.
22625 var myReader = new Roo.data.JsonReader({
22626 totalProperty: "results", // The property which contains the total dataset size (optional)
22627 root: "rows", // The property which contains an Array of row objects
22628 id: "id" // The property within each row object that provides an ID for the record (optional)
22632 * This would consume a JSON file like this:
22634 { 'results': 2, 'rows': [
22635 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22636 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22639 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22640 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22641 * paged from the remote server.
22642 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22643 * @cfg {String} root name of the property which contains the Array of row objects.
22644 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22645 * @cfg {Array} fields Array of field definition objects
22647 * Create a new JsonReader
22648 * @param {Object} meta Metadata configuration options
22649 * @param {Object} recordType Either an Array of field definition objects,
22650 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22652 Roo.data.JsonReader = function(meta, recordType){
22655 // set some defaults:
22656 Roo.applyIf(meta, {
22657 totalProperty: 'total',
22658 successProperty : 'success',
22663 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22665 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22668 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22669 * Used by Store query builder to append _requestMeta to params.
22672 metaFromRemote : false,
22674 * This method is only used by a DataProxy which has retrieved data from a remote server.
22675 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22676 * @return {Object} data A data block which is used by an Roo.data.Store object as
22677 * a cache of Roo.data.Records.
22679 read : function(response){
22680 var json = response.responseText;
22682 var o = /* eval:var:o */ eval("("+json+")");
22684 throw {message: "JsonReader.read: Json object not found"};
22690 this.metaFromRemote = true;
22691 this.meta = o.metaData;
22692 this.recordType = Roo.data.Record.create(o.metaData.fields);
22693 this.onMetaChange(this.meta, this.recordType, o);
22695 return this.readRecords(o);
22698 // private function a store will implement
22699 onMetaChange : function(meta, recordType, o){
22706 simpleAccess: function(obj, subsc) {
22713 getJsonAccessor: function(){
22715 return function(expr) {
22717 return(re.test(expr))
22718 ? new Function("obj", "return obj." + expr)
22723 return Roo.emptyFn;
22728 * Create a data block containing Roo.data.Records from an XML document.
22729 * @param {Object} o An object which contains an Array of row objects in the property specified
22730 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22731 * which contains the total size of the dataset.
22732 * @return {Object} data A data block which is used by an Roo.data.Store object as
22733 * a cache of Roo.data.Records.
22735 readRecords : function(o){
22737 * After any data loads, the raw JSON data is available for further custom processing.
22741 var s = this.meta, Record = this.recordType,
22742 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
22744 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22746 if(s.totalProperty) {
22747 this.getTotal = this.getJsonAccessor(s.totalProperty);
22749 if(s.successProperty) {
22750 this.getSuccess = this.getJsonAccessor(s.successProperty);
22752 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22754 var g = this.getJsonAccessor(s.id);
22755 this.getId = function(rec) {
22757 return (r === undefined || r === "") ? null : r;
22760 this.getId = function(){return null;};
22763 for(var jj = 0; jj < fl; jj++){
22765 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22766 this.ef[jj] = this.getJsonAccessor(map);
22770 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22771 if(s.totalProperty){
22772 var vt = parseInt(this.getTotal(o), 10);
22777 if(s.successProperty){
22778 var vs = this.getSuccess(o);
22779 if(vs === false || vs === 'false'){
22784 for(var i = 0; i < c; i++){
22787 var id = this.getId(n);
22788 for(var j = 0; j < fl; j++){
22790 var v = this.ef[j](n);
22792 Roo.log('missing convert for ' + f.name);
22796 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22798 var record = new Record(values, id);
22800 records[i] = record;
22806 totalRecords : totalRecords
22811 * Ext JS Library 1.1.1
22812 * Copyright(c) 2006-2007, Ext JS, LLC.
22814 * Originally Released Under LGPL - original licence link has changed is not relivant.
22817 * <script type="text/javascript">
22821 * @class Roo.data.XmlReader
22822 * @extends Roo.data.DataReader
22823 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22824 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22826 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22827 * header in the HTTP response must be set to "text/xml".</em>
22831 var RecordDef = Roo.data.Record.create([
22832 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22833 {name: 'occupation'} // This field will use "occupation" as the mapping.
22835 var myReader = new Roo.data.XmlReader({
22836 totalRecords: "results", // The element which contains the total dataset size (optional)
22837 record: "row", // The repeated element which contains row information
22838 id: "id" // The element within the row that provides an ID for the record (optional)
22842 * This would consume an XML file like this:
22846 <results>2</results>
22849 <name>Bill</name>
22850 <occupation>Gardener</occupation>
22854 <name>Ben</name>
22855 <occupation>Horticulturalist</occupation>
22859 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22860 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22861 * paged from the remote server.
22862 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22863 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22864 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22865 * a record identifier value.
22867 * Create a new XmlReader
22868 * @param {Object} meta Metadata configuration options
22869 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22870 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22871 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22873 Roo.data.XmlReader = function(meta, recordType){
22875 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22877 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22879 * This method is only used by a DataProxy which has retrieved data from a remote server.
22880 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22881 * to contain a method called 'responseXML' that returns an XML document object.
22882 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22883 * a cache of Roo.data.Records.
22885 read : function(response){
22886 var doc = response.responseXML;
22888 throw {message: "XmlReader.read: XML Document not available"};
22890 return this.readRecords(doc);
22894 * Create a data block containing Roo.data.Records from an XML document.
22895 * @param {Object} doc A parsed XML document.
22896 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22897 * a cache of Roo.data.Records.
22899 readRecords : function(doc){
22901 * After any data loads/reads, the raw XML Document is available for further custom processing.
22902 * @type XMLDocument
22904 this.xmlData = doc;
22905 var root = doc.documentElement || doc;
22906 var q = Roo.DomQuery;
22907 var recordType = this.recordType, fields = recordType.prototype.fields;
22908 var sid = this.meta.id;
22909 var totalRecords = 0, success = true;
22910 if(this.meta.totalRecords){
22911 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22914 if(this.meta.success){
22915 var sv = q.selectValue(this.meta.success, root, true);
22916 success = sv !== false && sv !== 'false';
22919 var ns = q.select(this.meta.record, root);
22920 for(var i = 0, len = ns.length; i < len; i++) {
22923 var id = sid ? q.selectValue(sid, n) : undefined;
22924 for(var j = 0, jlen = fields.length; j < jlen; j++){
22925 var f = fields.items[j];
22926 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22928 values[f.name] = v;
22930 var record = new recordType(values, id);
22932 records[records.length] = record;
22938 totalRecords : totalRecords || records.length
22943 * Ext JS Library 1.1.1
22944 * Copyright(c) 2006-2007, Ext JS, LLC.
22946 * Originally Released Under LGPL - original licence link has changed is not relivant.
22949 * <script type="text/javascript">
22953 * @class Roo.data.ArrayReader
22954 * @extends Roo.data.DataReader
22955 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22956 * Each element of that Array represents a row of data fields. The
22957 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22958 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22962 var RecordDef = Roo.data.Record.create([
22963 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22964 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22966 var myReader = new Roo.data.ArrayReader({
22967 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22971 * This would consume an Array like this:
22973 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22975 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22977 * Create a new JsonReader
22978 * @param {Object} meta Metadata configuration options.
22979 * @param {Object} recordType Either an Array of field definition objects
22980 * as specified to {@link Roo.data.Record#create},
22981 * or an {@link Roo.data.Record} object
22982 * created using {@link Roo.data.Record#create}.
22984 Roo.data.ArrayReader = function(meta, recordType){
22985 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22988 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22990 * Create a data block containing Roo.data.Records from an XML document.
22991 * @param {Object} o An Array of row objects which represents the dataset.
22992 * @return {Object} data A data block which is used by an Roo.data.Store object as
22993 * a cache of Roo.data.Records.
22995 readRecords : function(o){
22996 var sid = this.meta ? this.meta.id : null;
22997 var recordType = this.recordType, fields = recordType.prototype.fields;
23000 for(var i = 0; i < root.length; i++){
23003 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
23004 for(var j = 0, jlen = fields.length; j < jlen; j++){
23005 var f = fields.items[j];
23006 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
23007 var v = n[k] !== undefined ? n[k] : f.defaultValue;
23009 values[f.name] = v;
23011 var record = new recordType(values, id);
23013 records[records.length] = record;
23017 totalRecords : records.length
23022 * Ext JS Library 1.1.1
23023 * Copyright(c) 2006-2007, Ext JS, LLC.
23025 * Originally Released Under LGPL - original licence link has changed is not relivant.
23028 * <script type="text/javascript">
23033 * @class Roo.data.Tree
23034 * @extends Roo.util.Observable
23035 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
23036 * in the tree have most standard DOM functionality.
23038 * @param {Node} root (optional) The root node
23040 Roo.data.Tree = function(root){
23041 this.nodeHash = {};
23043 * The root node for this tree
23048 this.setRootNode(root);
23053 * Fires when a new child node is appended to a node in this tree.
23054 * @param {Tree} tree The owner tree
23055 * @param {Node} parent The parent node
23056 * @param {Node} node The newly appended node
23057 * @param {Number} index The index of the newly appended node
23062 * Fires when a child node is removed from a node in this tree.
23063 * @param {Tree} tree The owner tree
23064 * @param {Node} parent The parent node
23065 * @param {Node} node The child node removed
23070 * Fires when a node is moved to a new location in the tree
23071 * @param {Tree} tree The owner tree
23072 * @param {Node} node The node moved
23073 * @param {Node} oldParent The old parent of this node
23074 * @param {Node} newParent The new parent of this node
23075 * @param {Number} index The index it was moved to
23080 * Fires when a new child node is inserted in a node in this tree.
23081 * @param {Tree} tree The owner tree
23082 * @param {Node} parent The parent node
23083 * @param {Node} node The child node inserted
23084 * @param {Node} refNode The child node the node was inserted before
23088 * @event beforeappend
23089 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
23090 * @param {Tree} tree The owner tree
23091 * @param {Node} parent The parent node
23092 * @param {Node} node The child node to be appended
23094 "beforeappend" : true,
23096 * @event beforeremove
23097 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
23098 * @param {Tree} tree The owner tree
23099 * @param {Node} parent The parent node
23100 * @param {Node} node The child node to be removed
23102 "beforeremove" : true,
23104 * @event beforemove
23105 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
23106 * @param {Tree} tree The owner tree
23107 * @param {Node} node The node being moved
23108 * @param {Node} oldParent The parent of the node
23109 * @param {Node} newParent The new parent the node is moving to
23110 * @param {Number} index The index it is being moved to
23112 "beforemove" : true,
23114 * @event beforeinsert
23115 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
23116 * @param {Tree} tree The owner tree
23117 * @param {Node} parent The parent node
23118 * @param {Node} node The child node to be inserted
23119 * @param {Node} refNode The child node the node is being inserted before
23121 "beforeinsert" : true
23124 Roo.data.Tree.superclass.constructor.call(this);
23127 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
23128 pathSeparator: "/",
23130 proxyNodeEvent : function(){
23131 return this.fireEvent.apply(this, arguments);
23135 * Returns the root node for this tree.
23138 getRootNode : function(){
23143 * Sets the root node for this tree.
23144 * @param {Node} node
23147 setRootNode : function(node){
23149 node.ownerTree = this;
23150 node.isRoot = true;
23151 this.registerNode(node);
23156 * Gets a node in this tree by its id.
23157 * @param {String} id
23160 getNodeById : function(id){
23161 return this.nodeHash[id];
23164 registerNode : function(node){
23165 this.nodeHash[node.id] = node;
23168 unregisterNode : function(node){
23169 delete this.nodeHash[node.id];
23172 toString : function(){
23173 return "[Tree"+(this.id?" "+this.id:"")+"]";
23178 * @class Roo.data.Node
23179 * @extends Roo.util.Observable
23180 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23181 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23183 * @param {Object} attributes The attributes/config for the node
23185 Roo.data.Node = function(attributes){
23187 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23190 this.attributes = attributes || {};
23191 this.leaf = this.attributes.leaf;
23193 * The node id. @type String
23195 this.id = this.attributes.id;
23197 this.id = Roo.id(null, "ynode-");
23198 this.attributes.id = this.id;
23203 * All child nodes of this node. @type Array
23205 this.childNodes = [];
23206 if(!this.childNodes.indexOf){ // indexOf is a must
23207 this.childNodes.indexOf = function(o){
23208 for(var i = 0, len = this.length; i < len; i++){
23217 * The parent node for this node. @type Node
23219 this.parentNode = null;
23221 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23223 this.firstChild = null;
23225 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23227 this.lastChild = null;
23229 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23231 this.previousSibling = null;
23233 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23235 this.nextSibling = null;
23240 * Fires when a new child node is appended
23241 * @param {Tree} tree The owner tree
23242 * @param {Node} this This node
23243 * @param {Node} node The newly appended node
23244 * @param {Number} index The index of the newly appended node
23249 * Fires when a child node is removed
23250 * @param {Tree} tree The owner tree
23251 * @param {Node} this This node
23252 * @param {Node} node The removed node
23257 * Fires when this node is moved to a new location in the tree
23258 * @param {Tree} tree The owner tree
23259 * @param {Node} this This node
23260 * @param {Node} oldParent The old parent of this node
23261 * @param {Node} newParent The new parent of this node
23262 * @param {Number} index The index it was moved to
23267 * Fires when a new child node is inserted.
23268 * @param {Tree} tree The owner tree
23269 * @param {Node} this This node
23270 * @param {Node} node The child node inserted
23271 * @param {Node} refNode The child node the node was inserted before
23275 * @event beforeappend
23276 * Fires before a new child is appended, return false to cancel the append.
23277 * @param {Tree} tree The owner tree
23278 * @param {Node} this This node
23279 * @param {Node} node The child node to be appended
23281 "beforeappend" : true,
23283 * @event beforeremove
23284 * Fires before a child is removed, return false to cancel the remove.
23285 * @param {Tree} tree The owner tree
23286 * @param {Node} this This node
23287 * @param {Node} node The child node to be removed
23289 "beforeremove" : true,
23291 * @event beforemove
23292 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23293 * @param {Tree} tree The owner tree
23294 * @param {Node} this This node
23295 * @param {Node} oldParent The parent of this node
23296 * @param {Node} newParent The new parent this node is moving to
23297 * @param {Number} index The index it is being moved to
23299 "beforemove" : true,
23301 * @event beforeinsert
23302 * Fires before a new child is inserted, return false to cancel the insert.
23303 * @param {Tree} tree The owner tree
23304 * @param {Node} this This node
23305 * @param {Node} node The child node to be inserted
23306 * @param {Node} refNode The child node the node is being inserted before
23308 "beforeinsert" : true
23310 this.listeners = this.attributes.listeners;
23311 Roo.data.Node.superclass.constructor.call(this);
23314 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23315 fireEvent : function(evtName){
23316 // first do standard event for this node
23317 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23320 // then bubble it up to the tree if the event wasn't cancelled
23321 var ot = this.getOwnerTree();
23323 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23331 * Returns true if this node is a leaf
23332 * @return {Boolean}
23334 isLeaf : function(){
23335 return this.leaf === true;
23339 setFirstChild : function(node){
23340 this.firstChild = node;
23344 setLastChild : function(node){
23345 this.lastChild = node;
23350 * Returns true if this node is the last child of its parent
23351 * @return {Boolean}
23353 isLast : function(){
23354 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23358 * Returns true if this node is the first child of its parent
23359 * @return {Boolean}
23361 isFirst : function(){
23362 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23365 hasChildNodes : function(){
23366 return !this.isLeaf() && this.childNodes.length > 0;
23370 * Insert node(s) as the last child node of this node.
23371 * @param {Node/Array} node The node or Array of nodes to append
23372 * @return {Node} The appended node if single append, or null if an array was passed
23374 appendChild : function(node){
23376 if(node instanceof Array){
23378 }else if(arguments.length > 1){
23381 // if passed an array or multiple args do them one by one
23383 for(var i = 0, len = multi.length; i < len; i++) {
23384 this.appendChild(multi[i]);
23387 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23390 var index = this.childNodes.length;
23391 var oldParent = node.parentNode;
23392 // it's a move, make sure we move it cleanly
23394 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23397 oldParent.removeChild(node);
23399 index = this.childNodes.length;
23401 this.setFirstChild(node);
23403 this.childNodes.push(node);
23404 node.parentNode = this;
23405 var ps = this.childNodes[index-1];
23407 node.previousSibling = ps;
23408 ps.nextSibling = node;
23410 node.previousSibling = null;
23412 node.nextSibling = null;
23413 this.setLastChild(node);
23414 node.setOwnerTree(this.getOwnerTree());
23415 this.fireEvent("append", this.ownerTree, this, node, index);
23417 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23424 * Removes a child node from this node.
23425 * @param {Node} node The node to remove
23426 * @return {Node} The removed node
23428 removeChild : function(node){
23429 var index = this.childNodes.indexOf(node);
23433 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23437 // remove it from childNodes collection
23438 this.childNodes.splice(index, 1);
23441 if(node.previousSibling){
23442 node.previousSibling.nextSibling = node.nextSibling;
23444 if(node.nextSibling){
23445 node.nextSibling.previousSibling = node.previousSibling;
23448 // update child refs
23449 if(this.firstChild == node){
23450 this.setFirstChild(node.nextSibling);
23452 if(this.lastChild == node){
23453 this.setLastChild(node.previousSibling);
23456 node.setOwnerTree(null);
23457 // clear any references from the node
23458 node.parentNode = null;
23459 node.previousSibling = null;
23460 node.nextSibling = null;
23461 this.fireEvent("remove", this.ownerTree, this, node);
23466 * Inserts the first node before the second node in this nodes childNodes collection.
23467 * @param {Node} node The node to insert
23468 * @param {Node} refNode The node to insert before (if null the node is appended)
23469 * @return {Node} The inserted node
23471 insertBefore : function(node, refNode){
23472 if(!refNode){ // like standard Dom, refNode can be null for append
23473 return this.appendChild(node);
23476 if(node == refNode){
23480 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23483 var index = this.childNodes.indexOf(refNode);
23484 var oldParent = node.parentNode;
23485 var refIndex = index;
23487 // when moving internally, indexes will change after remove
23488 if(oldParent == this && this.childNodes.indexOf(node) < index){
23492 // it's a move, make sure we move it cleanly
23494 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23497 oldParent.removeChild(node);
23500 this.setFirstChild(node);
23502 this.childNodes.splice(refIndex, 0, node);
23503 node.parentNode = this;
23504 var ps = this.childNodes[refIndex-1];
23506 node.previousSibling = ps;
23507 ps.nextSibling = node;
23509 node.previousSibling = null;
23511 node.nextSibling = refNode;
23512 refNode.previousSibling = node;
23513 node.setOwnerTree(this.getOwnerTree());
23514 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23516 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23522 * Returns the child node at the specified index.
23523 * @param {Number} index
23526 item : function(index){
23527 return this.childNodes[index];
23531 * Replaces one child node in this node with another.
23532 * @param {Node} newChild The replacement node
23533 * @param {Node} oldChild The node to replace
23534 * @return {Node} The replaced node
23536 replaceChild : function(newChild, oldChild){
23537 this.insertBefore(newChild, oldChild);
23538 this.removeChild(oldChild);
23543 * Returns the index of a child node
23544 * @param {Node} node
23545 * @return {Number} The index of the node or -1 if it was not found
23547 indexOf : function(child){
23548 return this.childNodes.indexOf(child);
23552 * Returns the tree this node is in.
23555 getOwnerTree : function(){
23556 // if it doesn't have one, look for one
23557 if(!this.ownerTree){
23561 this.ownerTree = p.ownerTree;
23567 return this.ownerTree;
23571 * Returns depth of this node (the root node has a depth of 0)
23574 getDepth : function(){
23577 while(p.parentNode){
23585 setOwnerTree : function(tree){
23586 // if it's move, we need to update everyone
23587 if(tree != this.ownerTree){
23588 if(this.ownerTree){
23589 this.ownerTree.unregisterNode(this);
23591 this.ownerTree = tree;
23592 var cs = this.childNodes;
23593 for(var i = 0, len = cs.length; i < len; i++) {
23594 cs[i].setOwnerTree(tree);
23597 tree.registerNode(this);
23603 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23604 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23605 * @return {String} The path
23607 getPath : function(attr){
23608 attr = attr || "id";
23609 var p = this.parentNode;
23610 var b = [this.attributes[attr]];
23612 b.unshift(p.attributes[attr]);
23615 var sep = this.getOwnerTree().pathSeparator;
23616 return sep + b.join(sep);
23620 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23621 * function call will be the scope provided or the current node. The arguments to the function
23622 * will be the args provided or the current node. If the function returns false at any point,
23623 * the bubble is stopped.
23624 * @param {Function} fn The function to call
23625 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23626 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23628 bubble : function(fn, scope, args){
23631 if(fn.call(scope || p, args || p) === false){
23639 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23640 * function call will be the scope provided or the current node. The arguments to the function
23641 * will be the args provided or the current node. If the function returns false at any point,
23642 * the cascade is stopped on that branch.
23643 * @param {Function} fn The function to call
23644 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23645 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23647 cascade : function(fn, scope, args){
23648 if(fn.call(scope || this, args || this) !== false){
23649 var cs = this.childNodes;
23650 for(var i = 0, len = cs.length; i < len; i++) {
23651 cs[i].cascade(fn, scope, args);
23657 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23658 * function call will be the scope provided or the current node. The arguments to the function
23659 * will be the args provided or the current node. If the function returns false at any point,
23660 * the iteration stops.
23661 * @param {Function} fn The function to call
23662 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23663 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23665 eachChild : function(fn, scope, args){
23666 var cs = this.childNodes;
23667 for(var i = 0, len = cs.length; i < len; i++) {
23668 if(fn.call(scope || this, args || cs[i]) === false){
23675 * Finds the first child that has the attribute with the specified value.
23676 * @param {String} attribute The attribute name
23677 * @param {Mixed} value The value to search for
23678 * @return {Node} The found child or null if none was found
23680 findChild : function(attribute, value){
23681 var cs = this.childNodes;
23682 for(var i = 0, len = cs.length; i < len; i++) {
23683 if(cs[i].attributes[attribute] == value){
23691 * Finds the first child by a custom function. The child matches if the function passed
23693 * @param {Function} fn
23694 * @param {Object} scope (optional)
23695 * @return {Node} The found child or null if none was found
23697 findChildBy : function(fn, scope){
23698 var cs = this.childNodes;
23699 for(var i = 0, len = cs.length; i < len; i++) {
23700 if(fn.call(scope||cs[i], cs[i]) === true){
23708 * Sorts this nodes children using the supplied sort function
23709 * @param {Function} fn
23710 * @param {Object} scope (optional)
23712 sort : function(fn, scope){
23713 var cs = this.childNodes;
23714 var len = cs.length;
23716 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23718 for(var i = 0; i < len; i++){
23720 n.previousSibling = cs[i-1];
23721 n.nextSibling = cs[i+1];
23723 this.setFirstChild(n);
23726 this.setLastChild(n);
23733 * Returns true if this node is an ancestor (at any point) of the passed node.
23734 * @param {Node} node
23735 * @return {Boolean}
23737 contains : function(node){
23738 return node.isAncestor(this);
23742 * Returns true if the passed node is an ancestor (at any point) of this node.
23743 * @param {Node} node
23744 * @return {Boolean}
23746 isAncestor : function(node){
23747 var p = this.parentNode;
23757 toString : function(){
23758 return "[Node"+(this.id?" "+this.id:"")+"]";
23762 * Ext JS Library 1.1.1
23763 * Copyright(c) 2006-2007, Ext JS, LLC.
23765 * Originally Released Under LGPL - original licence link has changed is not relivant.
23768 * <script type="text/javascript">
23773 * @extends Roo.Element
23774 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23775 * automatic maintaining of shadow/shim positions.
23776 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23777 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23778 * you can pass a string with a CSS class name. False turns off the shadow.
23779 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23780 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23781 * @cfg {String} cls CSS class to add to the element
23782 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23783 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23785 * @param {Object} config An object with config options.
23786 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23789 Roo.Layer = function(config, existingEl){
23790 config = config || {};
23791 var dh = Roo.DomHelper;
23792 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23794 this.dom = Roo.getDom(existingEl);
23797 var o = config.dh || {tag: "div", cls: "x-layer"};
23798 this.dom = dh.append(pel, o);
23801 this.addClass(config.cls);
23803 this.constrain = config.constrain !== false;
23804 this.visibilityMode = Roo.Element.VISIBILITY;
23806 this.id = this.dom.id = config.id;
23808 this.id = Roo.id(this.dom);
23810 this.zindex = config.zindex || this.getZIndex();
23811 this.position("absolute", this.zindex);
23813 this.shadowOffset = config.shadowOffset || 4;
23814 this.shadow = new Roo.Shadow({
23815 offset : this.shadowOffset,
23816 mode : config.shadow
23819 this.shadowOffset = 0;
23821 this.useShim = config.shim !== false && Roo.useShims;
23822 this.useDisplay = config.useDisplay;
23826 var supr = Roo.Element.prototype;
23828 // shims are shared among layer to keep from having 100 iframes
23831 Roo.extend(Roo.Layer, Roo.Element, {
23833 getZIndex : function(){
23834 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23837 getShim : function(){
23844 var shim = shims.shift();
23846 shim = this.createShim();
23847 shim.enableDisplayMode('block');
23848 shim.dom.style.display = 'none';
23849 shim.dom.style.visibility = 'visible';
23851 var pn = this.dom.parentNode;
23852 if(shim.dom.parentNode != pn){
23853 pn.insertBefore(shim.dom, this.dom);
23855 shim.setStyle('z-index', this.getZIndex()-2);
23860 hideShim : function(){
23862 this.shim.setDisplayed(false);
23863 shims.push(this.shim);
23868 disableShadow : function(){
23870 this.shadowDisabled = true;
23871 this.shadow.hide();
23872 this.lastShadowOffset = this.shadowOffset;
23873 this.shadowOffset = 0;
23877 enableShadow : function(show){
23879 this.shadowDisabled = false;
23880 this.shadowOffset = this.lastShadowOffset;
23881 delete this.lastShadowOffset;
23889 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23890 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23891 sync : function(doShow){
23892 var sw = this.shadow;
23893 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23894 var sh = this.getShim();
23896 var w = this.getWidth(),
23897 h = this.getHeight();
23899 var l = this.getLeft(true),
23900 t = this.getTop(true);
23902 if(sw && !this.shadowDisabled){
23903 if(doShow && !sw.isVisible()){
23906 sw.realign(l, t, w, h);
23912 // fit the shim behind the shadow, so it is shimmed too
23913 var a = sw.adjusts, s = sh.dom.style;
23914 s.left = (Math.min(l, l+a.l))+"px";
23915 s.top = (Math.min(t, t+a.t))+"px";
23916 s.width = (w+a.w)+"px";
23917 s.height = (h+a.h)+"px";
23924 sh.setLeftTop(l, t);
23931 destroy : function(){
23934 this.shadow.hide();
23936 this.removeAllListeners();
23937 var pn = this.dom.parentNode;
23939 pn.removeChild(this.dom);
23941 Roo.Element.uncache(this.id);
23944 remove : function(){
23949 beginUpdate : function(){
23950 this.updating = true;
23954 endUpdate : function(){
23955 this.updating = false;
23960 hideUnders : function(negOffset){
23962 this.shadow.hide();
23968 constrainXY : function(){
23969 if(this.constrain){
23970 var vw = Roo.lib.Dom.getViewWidth(),
23971 vh = Roo.lib.Dom.getViewHeight();
23972 var s = Roo.get(document).getScroll();
23974 var xy = this.getXY();
23975 var x = xy[0], y = xy[1];
23976 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23977 // only move it if it needs it
23979 // first validate right/bottom
23980 if((x + w) > vw+s.left){
23981 x = vw - w - this.shadowOffset;
23984 if((y + h) > vh+s.top){
23985 y = vh - h - this.shadowOffset;
23988 // then make sure top/left isn't negative
23999 var ay = this.avoidY;
24000 if(y <= ay && (y+h) >= ay){
24006 supr.setXY.call(this, xy);
24012 isVisible : function(){
24013 return this.visible;
24017 showAction : function(){
24018 this.visible = true; // track visibility to prevent getStyle calls
24019 if(this.useDisplay === true){
24020 this.setDisplayed("");
24021 }else if(this.lastXY){
24022 supr.setXY.call(this, this.lastXY);
24023 }else if(this.lastLT){
24024 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
24029 hideAction : function(){
24030 this.visible = false;
24031 if(this.useDisplay === true){
24032 this.setDisplayed(false);
24034 this.setLeftTop(-10000,-10000);
24038 // overridden Element method
24039 setVisible : function(v, a, d, c, e){
24044 var cb = function(){
24049 }.createDelegate(this);
24050 supr.setVisible.call(this, true, true, d, cb, e);
24053 this.hideUnders(true);
24062 }.createDelegate(this);
24064 supr.setVisible.call(this, v, a, d, cb, e);
24073 storeXY : function(xy){
24074 delete this.lastLT;
24078 storeLeftTop : function(left, top){
24079 delete this.lastXY;
24080 this.lastLT = [left, top];
24084 beforeFx : function(){
24085 this.beforeAction();
24086 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
24090 afterFx : function(){
24091 Roo.Layer.superclass.afterFx.apply(this, arguments);
24092 this.sync(this.isVisible());
24096 beforeAction : function(){
24097 if(!this.updating && this.shadow){
24098 this.shadow.hide();
24102 // overridden Element method
24103 setLeft : function(left){
24104 this.storeLeftTop(left, this.getTop(true));
24105 supr.setLeft.apply(this, arguments);
24109 setTop : function(top){
24110 this.storeLeftTop(this.getLeft(true), top);
24111 supr.setTop.apply(this, arguments);
24115 setLeftTop : function(left, top){
24116 this.storeLeftTop(left, top);
24117 supr.setLeftTop.apply(this, arguments);
24121 setXY : function(xy, a, d, c, e){
24123 this.beforeAction();
24125 var cb = this.createCB(c);
24126 supr.setXY.call(this, xy, a, d, cb, e);
24133 createCB : function(c){
24144 // overridden Element method
24145 setX : function(x, a, d, c, e){
24146 this.setXY([x, this.getY()], a, d, c, e);
24149 // overridden Element method
24150 setY : function(y, a, d, c, e){
24151 this.setXY([this.getX(), y], a, d, c, e);
24154 // overridden Element method
24155 setSize : function(w, h, a, d, c, e){
24156 this.beforeAction();
24157 var cb = this.createCB(c);
24158 supr.setSize.call(this, w, h, a, d, cb, e);
24164 // overridden Element method
24165 setWidth : function(w, a, d, c, e){
24166 this.beforeAction();
24167 var cb = this.createCB(c);
24168 supr.setWidth.call(this, w, a, d, cb, e);
24174 // overridden Element method
24175 setHeight : function(h, a, d, c, e){
24176 this.beforeAction();
24177 var cb = this.createCB(c);
24178 supr.setHeight.call(this, h, a, d, cb, e);
24184 // overridden Element method
24185 setBounds : function(x, y, w, h, a, d, c, e){
24186 this.beforeAction();
24187 var cb = this.createCB(c);
24189 this.storeXY([x, y]);
24190 supr.setXY.call(this, [x, y]);
24191 supr.setSize.call(this, w, h, a, d, cb, e);
24194 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24200 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24201 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24202 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24203 * @param {Number} zindex The new z-index to set
24204 * @return {this} The Layer
24206 setZIndex : function(zindex){
24207 this.zindex = zindex;
24208 this.setStyle("z-index", zindex + 2);
24210 this.shadow.setZIndex(zindex + 1);
24213 this.shim.setStyle("z-index", zindex);
24219 * Ext JS Library 1.1.1
24220 * Copyright(c) 2006-2007, Ext JS, LLC.
24222 * Originally Released Under LGPL - original licence link has changed is not relivant.
24225 * <script type="text/javascript">
24230 * @class Roo.Shadow
24231 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24232 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24233 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24235 * Create a new Shadow
24236 * @param {Object} config The config object
24238 Roo.Shadow = function(config){
24239 Roo.apply(this, config);
24240 if(typeof this.mode != "string"){
24241 this.mode = this.defaultMode;
24243 var o = this.offset, a = {h: 0};
24244 var rad = Math.floor(this.offset/2);
24245 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24251 a.l -= this.offset + rad;
24252 a.t -= this.offset + rad;
24263 a.l -= (this.offset - rad);
24264 a.t -= this.offset + rad;
24266 a.w -= (this.offset - rad)*2;
24277 a.l -= (this.offset - rad);
24278 a.t -= (this.offset - rad);
24280 a.w -= (this.offset + rad + 1);
24281 a.h -= (this.offset + rad);
24290 Roo.Shadow.prototype = {
24292 * @cfg {String} mode
24293 * The shadow display mode. Supports the following options:<br />
24294 * sides: Shadow displays on both sides and bottom only<br />
24295 * frame: Shadow displays equally on all four sides<br />
24296 * drop: Traditional bottom-right drop shadow (default)
24299 * @cfg {String} offset
24300 * The number of pixels to offset the shadow from the element (defaults to 4)
24305 defaultMode: "drop",
24308 * Displays the shadow under the target element
24309 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24311 show : function(target){
24312 target = Roo.get(target);
24314 this.el = Roo.Shadow.Pool.pull();
24315 if(this.el.dom.nextSibling != target.dom){
24316 this.el.insertBefore(target);
24319 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24321 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24324 target.getLeft(true),
24325 target.getTop(true),
24329 this.el.dom.style.display = "block";
24333 * Returns true if the shadow is visible, else false
24335 isVisible : function(){
24336 return this.el ? true : false;
24340 * Direct alignment when values are already available. Show must be called at least once before
24341 * calling this method to ensure it is initialized.
24342 * @param {Number} left The target element left position
24343 * @param {Number} top The target element top position
24344 * @param {Number} width The target element width
24345 * @param {Number} height The target element height
24347 realign : function(l, t, w, h){
24351 var a = this.adjusts, d = this.el.dom, s = d.style;
24353 s.left = (l+a.l)+"px";
24354 s.top = (t+a.t)+"px";
24355 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24357 if(s.width != sws || s.height != shs){
24361 var cn = d.childNodes;
24362 var sww = Math.max(0, (sw-12))+"px";
24363 cn[0].childNodes[1].style.width = sww;
24364 cn[1].childNodes[1].style.width = sww;
24365 cn[2].childNodes[1].style.width = sww;
24366 cn[1].style.height = Math.max(0, (sh-12))+"px";
24372 * Hides this shadow
24376 this.el.dom.style.display = "none";
24377 Roo.Shadow.Pool.push(this.el);
24383 * Adjust the z-index of this shadow
24384 * @param {Number} zindex The new z-index
24386 setZIndex : function(z){
24389 this.el.setStyle("z-index", z);
24394 // Private utility class that manages the internal Shadow cache
24395 Roo.Shadow.Pool = function(){
24397 var markup = Roo.isIE ?
24398 '<div class="x-ie-shadow"></div>' :
24399 '<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>';
24402 var sh = p.shift();
24404 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24405 sh.autoBoxAdjust = false;
24410 push : function(sh){
24416 * Ext JS Library 1.1.1
24417 * Copyright(c) 2006-2007, Ext JS, LLC.
24419 * Originally Released Under LGPL - original licence link has changed is not relivant.
24422 * <script type="text/javascript">
24427 * @class Roo.SplitBar
24428 * @extends Roo.util.Observable
24429 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24433 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24434 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24435 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24436 split.minSize = 100;
24437 split.maxSize = 600;
24438 split.animate = true;
24439 split.on('moved', splitterMoved);
24442 * Create a new SplitBar
24443 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24444 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24445 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24446 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24447 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24448 position of the SplitBar).
24450 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24453 this.el = Roo.get(dragElement, true);
24454 this.el.dom.unselectable = "on";
24456 this.resizingEl = Roo.get(resizingElement, true);
24460 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24461 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24464 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24467 * The minimum size of the resizing element. (Defaults to 0)
24473 * The maximum size of the resizing element. (Defaults to 2000)
24476 this.maxSize = 2000;
24479 * Whether to animate the transition to the new size
24482 this.animate = false;
24485 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24488 this.useShim = false;
24493 if(!existingProxy){
24495 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24497 this.proxy = Roo.get(existingProxy).dom;
24500 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24503 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24506 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24509 this.dragSpecs = {};
24512 * @private The adapter to use to positon and resize elements
24514 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24515 this.adapter.init(this);
24517 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24519 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24520 this.el.addClass("x-splitbar-h");
24523 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24524 this.el.addClass("x-splitbar-v");
24530 * Fires when the splitter is moved (alias for {@link #event-moved})
24531 * @param {Roo.SplitBar} this
24532 * @param {Number} newSize the new width or height
24537 * Fires when the splitter is moved
24538 * @param {Roo.SplitBar} this
24539 * @param {Number} newSize the new width or height
24543 * @event beforeresize
24544 * Fires before the splitter is dragged
24545 * @param {Roo.SplitBar} this
24547 "beforeresize" : true,
24549 "beforeapply" : true
24552 Roo.util.Observable.call(this);
24555 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24556 onStartProxyDrag : function(x, y){
24557 this.fireEvent("beforeresize", this);
24559 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24561 o.enableDisplayMode("block");
24562 // all splitbars share the same overlay
24563 Roo.SplitBar.prototype.overlay = o;
24565 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24566 this.overlay.show();
24567 Roo.get(this.proxy).setDisplayed("block");
24568 var size = this.adapter.getElementSize(this);
24569 this.activeMinSize = this.getMinimumSize();;
24570 this.activeMaxSize = this.getMaximumSize();;
24571 var c1 = size - this.activeMinSize;
24572 var c2 = Math.max(this.activeMaxSize - size, 0);
24573 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24574 this.dd.resetConstraints();
24575 this.dd.setXConstraint(
24576 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24577 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24579 this.dd.setYConstraint(0, 0);
24581 this.dd.resetConstraints();
24582 this.dd.setXConstraint(0, 0);
24583 this.dd.setYConstraint(
24584 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24585 this.placement == Roo.SplitBar.TOP ? c2 : c1
24588 this.dragSpecs.startSize = size;
24589 this.dragSpecs.startPoint = [x, y];
24590 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24594 * @private Called after the drag operation by the DDProxy
24596 onEndProxyDrag : function(e){
24597 Roo.get(this.proxy).setDisplayed(false);
24598 var endPoint = Roo.lib.Event.getXY(e);
24600 this.overlay.hide();
24603 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24604 newSize = this.dragSpecs.startSize +
24605 (this.placement == Roo.SplitBar.LEFT ?
24606 endPoint[0] - this.dragSpecs.startPoint[0] :
24607 this.dragSpecs.startPoint[0] - endPoint[0]
24610 newSize = this.dragSpecs.startSize +
24611 (this.placement == Roo.SplitBar.TOP ?
24612 endPoint[1] - this.dragSpecs.startPoint[1] :
24613 this.dragSpecs.startPoint[1] - endPoint[1]
24616 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24617 if(newSize != this.dragSpecs.startSize){
24618 if(this.fireEvent('beforeapply', this, newSize) !== false){
24619 this.adapter.setElementSize(this, newSize);
24620 this.fireEvent("moved", this, newSize);
24621 this.fireEvent("resize", this, newSize);
24627 * Get the adapter this SplitBar uses
24628 * @return The adapter object
24630 getAdapter : function(){
24631 return this.adapter;
24635 * Set the adapter this SplitBar uses
24636 * @param {Object} adapter A SplitBar adapter object
24638 setAdapter : function(adapter){
24639 this.adapter = adapter;
24640 this.adapter.init(this);
24644 * Gets the minimum size for the resizing element
24645 * @return {Number} The minimum size
24647 getMinimumSize : function(){
24648 return this.minSize;
24652 * Sets the minimum size for the resizing element
24653 * @param {Number} minSize The minimum size
24655 setMinimumSize : function(minSize){
24656 this.minSize = minSize;
24660 * Gets the maximum size for the resizing element
24661 * @return {Number} The maximum size
24663 getMaximumSize : function(){
24664 return this.maxSize;
24668 * Sets the maximum size for the resizing element
24669 * @param {Number} maxSize The maximum size
24671 setMaximumSize : function(maxSize){
24672 this.maxSize = maxSize;
24676 * Sets the initialize size for the resizing element
24677 * @param {Number} size The initial size
24679 setCurrentSize : function(size){
24680 var oldAnimate = this.animate;
24681 this.animate = false;
24682 this.adapter.setElementSize(this, size);
24683 this.animate = oldAnimate;
24687 * Destroy this splitbar.
24688 * @param {Boolean} removeEl True to remove the element
24690 destroy : function(removeEl){
24692 this.shim.remove();
24695 this.proxy.parentNode.removeChild(this.proxy);
24703 * @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.
24705 Roo.SplitBar.createProxy = function(dir){
24706 var proxy = new Roo.Element(document.createElement("div"));
24707 proxy.unselectable();
24708 var cls = 'x-splitbar-proxy';
24709 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24710 document.body.appendChild(proxy.dom);
24715 * @class Roo.SplitBar.BasicLayoutAdapter
24716 * Default Adapter. It assumes the splitter and resizing element are not positioned
24717 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24719 Roo.SplitBar.BasicLayoutAdapter = function(){
24722 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24723 // do nothing for now
24724 init : function(s){
24728 * Called before drag operations to get the current size of the resizing element.
24729 * @param {Roo.SplitBar} s The SplitBar using this adapter
24731 getElementSize : function(s){
24732 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24733 return s.resizingEl.getWidth();
24735 return s.resizingEl.getHeight();
24740 * Called after drag operations to set the size of the resizing element.
24741 * @param {Roo.SplitBar} s The SplitBar using this adapter
24742 * @param {Number} newSize The new size to set
24743 * @param {Function} onComplete A function to be invoked when resizing is complete
24745 setElementSize : function(s, newSize, onComplete){
24746 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24748 s.resizingEl.setWidth(newSize);
24750 onComplete(s, newSize);
24753 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24758 s.resizingEl.setHeight(newSize);
24760 onComplete(s, newSize);
24763 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24770 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24771 * @extends Roo.SplitBar.BasicLayoutAdapter
24772 * Adapter that moves the splitter element to align with the resized sizing element.
24773 * Used with an absolute positioned SplitBar.
24774 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24775 * document.body, make sure you assign an id to the body element.
24777 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24778 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24779 this.container = Roo.get(container);
24782 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24783 init : function(s){
24784 this.basic.init(s);
24787 getElementSize : function(s){
24788 return this.basic.getElementSize(s);
24791 setElementSize : function(s, newSize, onComplete){
24792 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24795 moveSplitter : function(s){
24796 var yes = Roo.SplitBar;
24797 switch(s.placement){
24799 s.el.setX(s.resizingEl.getRight());
24802 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24805 s.el.setY(s.resizingEl.getBottom());
24808 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24815 * Orientation constant - Create a vertical SplitBar
24819 Roo.SplitBar.VERTICAL = 1;
24822 * Orientation constant - Create a horizontal SplitBar
24826 Roo.SplitBar.HORIZONTAL = 2;
24829 * Placement constant - The resizing element is to the left of the splitter element
24833 Roo.SplitBar.LEFT = 1;
24836 * Placement constant - The resizing element is to the right of the splitter element
24840 Roo.SplitBar.RIGHT = 2;
24843 * Placement constant - The resizing element is positioned above the splitter element
24847 Roo.SplitBar.TOP = 3;
24850 * Placement constant - The resizing element is positioned under splitter element
24854 Roo.SplitBar.BOTTOM = 4;
24857 * Ext JS Library 1.1.1
24858 * Copyright(c) 2006-2007, Ext JS, LLC.
24860 * Originally Released Under LGPL - original licence link has changed is not relivant.
24863 * <script type="text/javascript">
24868 * @extends Roo.util.Observable
24869 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24870 * This class also supports single and multi selection modes. <br>
24871 * Create a data model bound view:
24873 var store = new Roo.data.Store(...);
24875 var view = new Roo.View({
24877 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24879 singleSelect: true,
24880 selectedClass: "ydataview-selected",
24884 // listen for node click?
24885 view.on("click", function(vw, index, node, e){
24886 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24890 dataModel.load("foobar.xml");
24892 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24894 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24895 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24897 * Note: old style constructor is still suported (container, template, config)
24900 * Create a new View
24901 * @param {Object} config The config object
24904 Roo.View = function(config, depreciated_tpl, depreciated_config){
24906 this.parent = false;
24908 if (typeof(depreciated_tpl) == 'undefined') {
24909 // new way.. - universal constructor.
24910 Roo.apply(this, config);
24911 this.el = Roo.get(this.el);
24914 this.el = Roo.get(config);
24915 this.tpl = depreciated_tpl;
24916 Roo.apply(this, depreciated_config);
24918 this.wrapEl = this.el.wrap().wrap();
24919 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24922 if(typeof(this.tpl) == "string"){
24923 this.tpl = new Roo.Template(this.tpl);
24925 // support xtype ctors..
24926 this.tpl = new Roo.factory(this.tpl, Roo);
24930 this.tpl.compile();
24935 * @event beforeclick
24936 * Fires before a click is processed. Returns false to cancel the default action.
24937 * @param {Roo.View} this
24938 * @param {Number} index The index of the target node
24939 * @param {HTMLElement} node The target node
24940 * @param {Roo.EventObject} e The raw event object
24942 "beforeclick" : true,
24945 * Fires when a template node is clicked.
24946 * @param {Roo.View} this
24947 * @param {Number} index The index of the target node
24948 * @param {HTMLElement} node The target node
24949 * @param {Roo.EventObject} e The raw event object
24954 * Fires when a template node is double clicked.
24955 * @param {Roo.View} this
24956 * @param {Number} index The index of the target node
24957 * @param {HTMLElement} node The target node
24958 * @param {Roo.EventObject} e The raw event object
24962 * @event contextmenu
24963 * Fires when a template node is right clicked.
24964 * @param {Roo.View} this
24965 * @param {Number} index The index of the target node
24966 * @param {HTMLElement} node The target node
24967 * @param {Roo.EventObject} e The raw event object
24969 "contextmenu" : true,
24971 * @event selectionchange
24972 * Fires when the selected nodes change.
24973 * @param {Roo.View} this
24974 * @param {Array} selections Array of the selected nodes
24976 "selectionchange" : true,
24979 * @event beforeselect
24980 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24981 * @param {Roo.View} this
24982 * @param {HTMLElement} node The node to be selected
24983 * @param {Array} selections Array of currently selected nodes
24985 "beforeselect" : true,
24987 * @event preparedata
24988 * Fires on every row to render, to allow you to change the data.
24989 * @param {Roo.View} this
24990 * @param {Object} data to be rendered (change this)
24992 "preparedata" : true
25000 "click": this.onClick,
25001 "dblclick": this.onDblClick,
25002 "contextmenu": this.onContextMenu,
25006 this.selections = [];
25008 this.cmp = new Roo.CompositeElementLite([]);
25010 this.store = Roo.factory(this.store, Roo.data);
25011 this.setStore(this.store, true);
25014 if ( this.footer && this.footer.xtype) {
25016 var fctr = this.wrapEl.appendChild(document.createElement("div"));
25018 this.footer.dataSource = this.store
25019 this.footer.container = fctr;
25020 this.footer = Roo.factory(this.footer, Roo);
25021 fctr.insertFirst(this.el);
25023 // this is a bit insane - as the paging toolbar seems to detach the el..
25024 // dom.parentNode.parentNode.parentNode
25025 // they get detached?
25029 Roo.View.superclass.constructor.call(this);
25034 Roo.extend(Roo.View, Roo.util.Observable, {
25037 * @cfg {Roo.data.Store} store Data store to load data from.
25042 * @cfg {String|Roo.Element} el The container element.
25047 * @cfg {String|Roo.Template} tpl The template used by this View
25051 * @cfg {String} dataName the named area of the template to use as the data area
25052 * Works with domtemplates roo-name="name"
25056 * @cfg {String} selectedClass The css class to add to selected nodes
25058 selectedClass : "x-view-selected",
25060 * @cfg {String} emptyText The empty text to show when nothing is loaded.
25065 * @cfg {String} text to display on mask (default Loading)
25069 * @cfg {Boolean} multiSelect Allow multiple selection
25071 multiSelect : false,
25073 * @cfg {Boolean} singleSelect Allow single selection
25075 singleSelect: false,
25078 * @cfg {Boolean} toggleSelect - selecting
25080 toggleSelect : false,
25083 * @cfg {Boolean} tickable - selecting
25088 * Returns the element this view is bound to.
25089 * @return {Roo.Element}
25091 getEl : function(){
25092 return this.wrapEl;
25098 * Refreshes the view. - called by datachanged on the store. - do not call directly.
25100 refresh : function(){
25101 //Roo.log('refresh');
25104 // if we are using something like 'domtemplate', then
25105 // the what gets used is:
25106 // t.applySubtemplate(NAME, data, wrapping data..)
25107 // the outer template then get' applied with
25108 // the store 'extra data'
25109 // and the body get's added to the
25110 // roo-name="data" node?
25111 // <span class='roo-tpl-{name}'></span> ?????
25115 this.clearSelections();
25116 this.el.update("");
25118 var records = this.store.getRange();
25119 if(records.length < 1) {
25121 // is this valid?? = should it render a template??
25123 this.el.update(this.emptyText);
25127 if (this.dataName) {
25128 this.el.update(t.apply(this.store.meta)); //????
25129 el = this.el.child('.roo-tpl-' + this.dataName);
25132 for(var i = 0, len = records.length; i < len; i++){
25133 var data = this.prepareData(records[i].data, i, records[i]);
25134 this.fireEvent("preparedata", this, data, i, records[i]);
25136 var d = Roo.apply({}, data);
25139 Roo.apply(d, {'roo-id' : Roo.id()});
25143 Roo.each(this.parent.item, function(item){
25144 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
25147 Roo.apply(d, {'roo-data-checked' : 'checked'});
25151 html[html.length] = Roo.util.Format.trim(
25153 t.applySubtemplate(this.dataName, d, this.store.meta) :
25160 el.update(html.join(""));
25161 this.nodes = el.dom.childNodes;
25162 this.updateIndexes(0);
25167 * Function to override to reformat the data that is sent to
25168 * the template for each node.
25169 * DEPRICATED - use the preparedata event handler.
25170 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25171 * a JSON object for an UpdateManager bound view).
25173 prepareData : function(data, index, record)
25175 this.fireEvent("preparedata", this, data, index, record);
25179 onUpdate : function(ds, record){
25180 // Roo.log('on update');
25181 this.clearSelections();
25182 var index = this.store.indexOf(record);
25183 var n = this.nodes[index];
25184 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25185 n.parentNode.removeChild(n);
25186 this.updateIndexes(index, index);
25192 onAdd : function(ds, records, index)
25194 //Roo.log(['on Add', ds, records, index] );
25195 this.clearSelections();
25196 if(this.nodes.length == 0){
25200 var n = this.nodes[index];
25201 for(var i = 0, len = records.length; i < len; i++){
25202 var d = this.prepareData(records[i].data, i, records[i]);
25204 this.tpl.insertBefore(n, d);
25207 this.tpl.append(this.el, d);
25210 this.updateIndexes(index);
25213 onRemove : function(ds, record, index){
25214 // Roo.log('onRemove');
25215 this.clearSelections();
25216 var el = this.dataName ?
25217 this.el.child('.roo-tpl-' + this.dataName) :
25220 el.dom.removeChild(this.nodes[index]);
25221 this.updateIndexes(index);
25225 * Refresh an individual node.
25226 * @param {Number} index
25228 refreshNode : function(index){
25229 this.onUpdate(this.store, this.store.getAt(index));
25232 updateIndexes : function(startIndex, endIndex){
25233 var ns = this.nodes;
25234 startIndex = startIndex || 0;
25235 endIndex = endIndex || ns.length - 1;
25236 for(var i = startIndex; i <= endIndex; i++){
25237 ns[i].nodeIndex = i;
25242 * Changes the data store this view uses and refresh the view.
25243 * @param {Store} store
25245 setStore : function(store, initial){
25246 if(!initial && this.store){
25247 this.store.un("datachanged", this.refresh);
25248 this.store.un("add", this.onAdd);
25249 this.store.un("remove", this.onRemove);
25250 this.store.un("update", this.onUpdate);
25251 this.store.un("clear", this.refresh);
25252 this.store.un("beforeload", this.onBeforeLoad);
25253 this.store.un("load", this.onLoad);
25254 this.store.un("loadexception", this.onLoad);
25258 store.on("datachanged", this.refresh, this);
25259 store.on("add", this.onAdd, this);
25260 store.on("remove", this.onRemove, this);
25261 store.on("update", this.onUpdate, this);
25262 store.on("clear", this.refresh, this);
25263 store.on("beforeload", this.onBeforeLoad, this);
25264 store.on("load", this.onLoad, this);
25265 store.on("loadexception", this.onLoad, this);
25273 * onbeforeLoad - masks the loading area.
25276 onBeforeLoad : function(store,opts)
25278 //Roo.log('onBeforeLoad');
25280 this.el.update("");
25282 this.el.mask(this.mask ? this.mask : "Loading" );
25284 onLoad : function ()
25291 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25292 * @param {HTMLElement} node
25293 * @return {HTMLElement} The template node
25295 findItemFromChild : function(node){
25296 var el = this.dataName ?
25297 this.el.child('.roo-tpl-' + this.dataName,true) :
25300 if(!node || node.parentNode == el){
25303 var p = node.parentNode;
25304 while(p && p != el){
25305 if(p.parentNode == el){
25314 onClick : function(e){
25315 var item = this.findItemFromChild(e.getTarget());
25317 var index = this.indexOf(item);
25318 if(this.onItemClick(item, index, e) !== false){
25319 this.fireEvent("click", this, index, item, e);
25322 this.clearSelections();
25327 onContextMenu : function(e){
25328 var item = this.findItemFromChild(e.getTarget());
25330 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25335 onDblClick : function(e){
25336 var item = this.findItemFromChild(e.getTarget());
25338 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25342 onItemClick : function(item, index, e)
25344 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25347 if (this.toggleSelect) {
25348 var m = this.isSelected(item) ? 'unselect' : 'select';
25351 _t[m](item, true, false);
25354 if(this.multiSelect || this.singleSelect){
25355 if(this.multiSelect && e.shiftKey && this.lastSelection){
25356 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25358 this.select(item, this.multiSelect && e.ctrlKey);
25359 this.lastSelection = item;
25362 if(!this.tickable){
25363 e.preventDefault();
25371 * Get the number of selected nodes.
25374 getSelectionCount : function(){
25375 return this.selections.length;
25379 * Get the currently selected nodes.
25380 * @return {Array} An array of HTMLElements
25382 getSelectedNodes : function(){
25383 return this.selections;
25387 * Get the indexes of the selected nodes.
25390 getSelectedIndexes : function(){
25391 var indexes = [], s = this.selections;
25392 for(var i = 0, len = s.length; i < len; i++){
25393 indexes.push(s[i].nodeIndex);
25399 * Clear all selections
25400 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25402 clearSelections : function(suppressEvent){
25403 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25404 this.cmp.elements = this.selections;
25405 this.cmp.removeClass(this.selectedClass);
25406 this.selections = [];
25407 if(!suppressEvent){
25408 this.fireEvent("selectionchange", this, this.selections);
25414 * Returns true if the passed node is selected
25415 * @param {HTMLElement/Number} node The node or node index
25416 * @return {Boolean}
25418 isSelected : function(node){
25419 var s = this.selections;
25423 node = this.getNode(node);
25424 return s.indexOf(node) !== -1;
25429 * @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
25430 * @param {Boolean} keepExisting (optional) true to keep existing selections
25431 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25433 select : function(nodeInfo, keepExisting, suppressEvent){
25434 if(nodeInfo instanceof Array){
25436 this.clearSelections(true);
25438 for(var i = 0, len = nodeInfo.length; i < len; i++){
25439 this.select(nodeInfo[i], true, true);
25443 var node = this.getNode(nodeInfo);
25444 if(!node || this.isSelected(node)){
25445 return; // already selected.
25448 this.clearSelections(true);
25451 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25452 Roo.fly(node).addClass(this.selectedClass);
25453 this.selections.push(node);
25454 if(!suppressEvent){
25455 this.fireEvent("selectionchange", this, this.selections);
25463 * @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
25464 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25465 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25467 unselect : function(nodeInfo, keepExisting, suppressEvent)
25469 if(nodeInfo instanceof Array){
25470 Roo.each(this.selections, function(s) {
25471 this.unselect(s, nodeInfo);
25475 var node = this.getNode(nodeInfo);
25476 if(!node || !this.isSelected(node)){
25477 //Roo.log("not selected");
25478 return; // not selected.
25482 Roo.each(this.selections, function(s) {
25484 Roo.fly(node).removeClass(this.selectedClass);
25491 this.selections= ns;
25492 this.fireEvent("selectionchange", this, this.selections);
25496 * Gets a template node.
25497 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25498 * @return {HTMLElement} The node or null if it wasn't found
25500 getNode : function(nodeInfo){
25501 if(typeof nodeInfo == "string"){
25502 return document.getElementById(nodeInfo);
25503 }else if(typeof nodeInfo == "number"){
25504 return this.nodes[nodeInfo];
25510 * Gets a range template nodes.
25511 * @param {Number} startIndex
25512 * @param {Number} endIndex
25513 * @return {Array} An array of nodes
25515 getNodes : function(start, end){
25516 var ns = this.nodes;
25517 start = start || 0;
25518 end = typeof end == "undefined" ? ns.length - 1 : end;
25521 for(var i = start; i <= end; i++){
25525 for(var i = start; i >= end; i--){
25533 * Finds the index of the passed node
25534 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25535 * @return {Number} The index of the node or -1
25537 indexOf : function(node){
25538 node = this.getNode(node);
25539 if(typeof node.nodeIndex == "number"){
25540 return node.nodeIndex;
25542 var ns = this.nodes;
25543 for(var i = 0, len = ns.length; i < len; i++){
25553 * Ext JS Library 1.1.1
25554 * Copyright(c) 2006-2007, Ext JS, LLC.
25556 * Originally Released Under LGPL - original licence link has changed is not relivant.
25559 * <script type="text/javascript">
25563 * @class Roo.JsonView
25564 * @extends Roo.View
25565 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25567 var view = new Roo.JsonView({
25568 container: "my-element",
25569 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25574 // listen for node click?
25575 view.on("click", function(vw, index, node, e){
25576 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25579 // direct load of JSON data
25580 view.load("foobar.php");
25582 // Example from my blog list
25583 var tpl = new Roo.Template(
25584 '<div class="entry">' +
25585 '<a class="entry-title" href="{link}">{title}</a>' +
25586 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25587 "</div><hr />"
25590 var moreView = new Roo.JsonView({
25591 container : "entry-list",
25595 moreView.on("beforerender", this.sortEntries, this);
25597 url: "/blog/get-posts.php",
25598 params: "allposts=true",
25599 text: "Loading Blog Entries..."
25603 * Note: old code is supported with arguments : (container, template, config)
25607 * Create a new JsonView
25609 * @param {Object} config The config object
25612 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25615 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25617 var um = this.el.getUpdateManager();
25618 um.setRenderer(this);
25619 um.on("update", this.onLoad, this);
25620 um.on("failure", this.onLoadException, this);
25623 * @event beforerender
25624 * Fires before rendering of the downloaded JSON data.
25625 * @param {Roo.JsonView} this
25626 * @param {Object} data The JSON data loaded
25630 * Fires when data is loaded.
25631 * @param {Roo.JsonView} this
25632 * @param {Object} data The JSON data loaded
25633 * @param {Object} response The raw Connect response object
25636 * @event loadexception
25637 * Fires when loading fails.
25638 * @param {Roo.JsonView} this
25639 * @param {Object} response The raw Connect response object
25642 'beforerender' : true,
25644 'loadexception' : true
25647 Roo.extend(Roo.JsonView, Roo.View, {
25649 * @type {String} The root property in the loaded JSON object that contains the data
25654 * Refreshes the view.
25656 refresh : function(){
25657 this.clearSelections();
25658 this.el.update("");
25660 var o = this.jsonData;
25661 if(o && o.length > 0){
25662 for(var i = 0, len = o.length; i < len; i++){
25663 var data = this.prepareData(o[i], i, o);
25664 html[html.length] = this.tpl.apply(data);
25667 html.push(this.emptyText);
25669 this.el.update(html.join(""));
25670 this.nodes = this.el.dom.childNodes;
25671 this.updateIndexes(0);
25675 * 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.
25676 * @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:
25679 url: "your-url.php",
25680 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25681 callback: yourFunction,
25682 scope: yourObject, //(optional scope)
25685 text: "Loading...",
25690 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25691 * 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.
25692 * @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}
25693 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25694 * @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.
25697 var um = this.el.getUpdateManager();
25698 um.update.apply(um, arguments);
25701 render : function(el, response){
25702 this.clearSelections();
25703 this.el.update("");
25706 o = Roo.util.JSON.decode(response.responseText);
25709 o = o[this.jsonRoot];
25714 * The current JSON data or null
25717 this.beforeRender();
25722 * Get the number of records in the current JSON dataset
25725 getCount : function(){
25726 return this.jsonData ? this.jsonData.length : 0;
25730 * Returns the JSON object for the specified node(s)
25731 * @param {HTMLElement/Array} node The node or an array of nodes
25732 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25733 * you get the JSON object for the node
25735 getNodeData : function(node){
25736 if(node instanceof Array){
25738 for(var i = 0, len = node.length; i < len; i++){
25739 data.push(this.getNodeData(node[i]));
25743 return this.jsonData[this.indexOf(node)] || null;
25746 beforeRender : function(){
25747 this.snapshot = this.jsonData;
25749 this.sort.apply(this, this.sortInfo);
25751 this.fireEvent("beforerender", this, this.jsonData);
25754 onLoad : function(el, o){
25755 this.fireEvent("load", this, this.jsonData, o);
25758 onLoadException : function(el, o){
25759 this.fireEvent("loadexception", this, o);
25763 * Filter the data by a specific property.
25764 * @param {String} property A property on your JSON objects
25765 * @param {String/RegExp} value Either string that the property values
25766 * should start with, or a RegExp to test against the property
25768 filter : function(property, value){
25771 var ss = this.snapshot;
25772 if(typeof value == "string"){
25773 var vlen = value.length;
25775 this.clearFilter();
25778 value = value.toLowerCase();
25779 for(var i = 0, len = ss.length; i < len; i++){
25781 if(o[property].substr(0, vlen).toLowerCase() == value){
25785 } else if(value.exec){ // regex?
25786 for(var i = 0, len = ss.length; i < len; i++){
25788 if(value.test(o[property])){
25795 this.jsonData = data;
25801 * Filter by a function. The passed function will be called with each
25802 * object in the current dataset. If the function returns true the value is kept,
25803 * otherwise it is filtered.
25804 * @param {Function} fn
25805 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25807 filterBy : function(fn, scope){
25810 var ss = this.snapshot;
25811 for(var i = 0, len = ss.length; i < len; i++){
25813 if(fn.call(scope || this, o)){
25817 this.jsonData = data;
25823 * Clears the current filter.
25825 clearFilter : function(){
25826 if(this.snapshot && this.jsonData != this.snapshot){
25827 this.jsonData = this.snapshot;
25834 * Sorts the data for this view and refreshes it.
25835 * @param {String} property A property on your JSON objects to sort on
25836 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25837 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25839 sort : function(property, dir, sortType){
25840 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25843 var dsc = dir && dir.toLowerCase() == "desc";
25844 var f = function(o1, o2){
25845 var v1 = sortType ? sortType(o1[p]) : o1[p];
25846 var v2 = sortType ? sortType(o2[p]) : o2[p];
25849 return dsc ? +1 : -1;
25850 } else if(v1 > v2){
25851 return dsc ? -1 : +1;
25856 this.jsonData.sort(f);
25858 if(this.jsonData != this.snapshot){
25859 this.snapshot.sort(f);
25865 * Ext JS Library 1.1.1
25866 * Copyright(c) 2006-2007, Ext JS, LLC.
25868 * Originally Released Under LGPL - original licence link has changed is not relivant.
25871 * <script type="text/javascript">
25876 * @class Roo.ColorPalette
25877 * @extends Roo.Component
25878 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25879 * Here's an example of typical usage:
25881 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25882 cp.render('my-div');
25884 cp.on('select', function(palette, selColor){
25885 // do something with selColor
25889 * Create a new ColorPalette
25890 * @param {Object} config The config object
25892 Roo.ColorPalette = function(config){
25893 Roo.ColorPalette.superclass.constructor.call(this, config);
25897 * Fires when a color is selected
25898 * @param {ColorPalette} this
25899 * @param {String} color The 6-digit color hex code (without the # symbol)
25905 this.on("select", this.handler, this.scope, true);
25908 Roo.extend(Roo.ColorPalette, Roo.Component, {
25910 * @cfg {String} itemCls
25911 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25913 itemCls : "x-color-palette",
25915 * @cfg {String} value
25916 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25917 * the hex codes are case-sensitive.
25920 clickEvent:'click',
25922 ctype: "Roo.ColorPalette",
25925 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25927 allowReselect : false,
25930 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25931 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25932 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25933 * of colors with the width setting until the box is symmetrical.</p>
25934 * <p>You can override individual colors if needed:</p>
25936 var cp = new Roo.ColorPalette();
25937 cp.colors[0] = "FF0000"; // change the first box to red
25940 Or you can provide a custom array of your own for complete control:
25942 var cp = new Roo.ColorPalette();
25943 cp.colors = ["000000", "993300", "333300"];
25948 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25949 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25950 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25951 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25952 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25956 onRender : function(container, position){
25957 var t = new Roo.MasterTemplate(
25958 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25960 var c = this.colors;
25961 for(var i = 0, len = c.length; i < len; i++){
25964 var el = document.createElement("div");
25965 el.className = this.itemCls;
25967 container.dom.insertBefore(el, position);
25968 this.el = Roo.get(el);
25969 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25970 if(this.clickEvent != 'click'){
25971 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25976 afterRender : function(){
25977 Roo.ColorPalette.superclass.afterRender.call(this);
25979 var s = this.value;
25986 handleClick : function(e, t){
25987 e.preventDefault();
25988 if(!this.disabled){
25989 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25990 this.select(c.toUpperCase());
25995 * Selects the specified color in the palette (fires the select event)
25996 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25998 select : function(color){
25999 color = color.replace("#", "");
26000 if(color != this.value || this.allowReselect){
26003 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
26005 el.child("a.color-"+color).addClass("x-color-palette-sel");
26006 this.value = color;
26007 this.fireEvent("select", this, color);
26012 * Ext JS Library 1.1.1
26013 * Copyright(c) 2006-2007, Ext JS, LLC.
26015 * Originally Released Under LGPL - original licence link has changed is not relivant.
26018 * <script type="text/javascript">
26022 * @class Roo.DatePicker
26023 * @extends Roo.Component
26024 * Simple date picker class.
26026 * Create a new DatePicker
26027 * @param {Object} config The config object
26029 Roo.DatePicker = function(config){
26030 Roo.DatePicker.superclass.constructor.call(this, config);
26032 this.value = config && config.value ?
26033 config.value.clearTime() : new Date().clearTime();
26038 * Fires when a date is selected
26039 * @param {DatePicker} this
26040 * @param {Date} date The selected date
26044 * @event monthchange
26045 * Fires when the displayed month changes
26046 * @param {DatePicker} this
26047 * @param {Date} date The selected month
26049 'monthchange': true
26053 this.on("select", this.handler, this.scope || this);
26055 // build the disabledDatesRE
26056 if(!this.disabledDatesRE && this.disabledDates){
26057 var dd = this.disabledDates;
26059 for(var i = 0; i < dd.length; i++){
26061 if(i != dd.length-1) re += "|";
26063 this.disabledDatesRE = new RegExp(re + ")");
26067 Roo.extend(Roo.DatePicker, Roo.Component, {
26069 * @cfg {String} todayText
26070 * The text to display on the button that selects the current date (defaults to "Today")
26072 todayText : "Today",
26074 * @cfg {String} okText
26075 * The text to display on the ok button
26077 okText : " OK ", //   to give the user extra clicking room
26079 * @cfg {String} cancelText
26080 * The text to display on the cancel button
26082 cancelText : "Cancel",
26084 * @cfg {String} todayTip
26085 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
26087 todayTip : "{0} (Spacebar)",
26089 * @cfg {Date} minDate
26090 * Minimum allowable date (JavaScript date object, defaults to null)
26094 * @cfg {Date} maxDate
26095 * Maximum allowable date (JavaScript date object, defaults to null)
26099 * @cfg {String} minText
26100 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
26102 minText : "This date is before the minimum date",
26104 * @cfg {String} maxText
26105 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
26107 maxText : "This date is after the maximum date",
26109 * @cfg {String} format
26110 * The default date format string which can be overriden for localization support. The format must be
26111 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
26115 * @cfg {Array} disabledDays
26116 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
26118 disabledDays : null,
26120 * @cfg {String} disabledDaysText
26121 * The tooltip to display when the date falls on a disabled day (defaults to "")
26123 disabledDaysText : "",
26125 * @cfg {RegExp} disabledDatesRE
26126 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
26128 disabledDatesRE : null,
26130 * @cfg {String} disabledDatesText
26131 * The tooltip text to display when the date falls on a disabled date (defaults to "")
26133 disabledDatesText : "",
26135 * @cfg {Boolean} constrainToViewport
26136 * True to constrain the date picker to the viewport (defaults to true)
26138 constrainToViewport : true,
26140 * @cfg {Array} monthNames
26141 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
26143 monthNames : Date.monthNames,
26145 * @cfg {Array} dayNames
26146 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
26148 dayNames : Date.dayNames,
26150 * @cfg {String} nextText
26151 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
26153 nextText: 'Next Month (Control+Right)',
26155 * @cfg {String} prevText
26156 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
26158 prevText: 'Previous Month (Control+Left)',
26160 * @cfg {String} monthYearText
26161 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
26163 monthYearText: 'Choose a month (Control+Up/Down to move years)',
26165 * @cfg {Number} startDay
26166 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
26170 * @cfg {Bool} showClear
26171 * Show a clear button (usefull for date form elements that can be blank.)
26177 * Sets the value of the date field
26178 * @param {Date} value The date to set
26180 setValue : function(value){
26181 var old = this.value;
26183 if (typeof(value) == 'string') {
26185 value = Date.parseDate(value, this.format);
26188 value = new Date();
26191 this.value = value.clearTime(true);
26193 this.update(this.value);
26198 * Gets the current selected value of the date field
26199 * @return {Date} The selected date
26201 getValue : function(){
26206 focus : function(){
26208 this.update(this.activeDate);
26213 onRender : function(container, position){
26216 '<table cellspacing="0">',
26217 '<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>',
26218 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26219 var dn = this.dayNames;
26220 for(var i = 0; i < 7; i++){
26221 var d = this.startDay+i;
26225 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26227 m[m.length] = "</tr></thead><tbody><tr>";
26228 for(var i = 0; i < 42; i++) {
26229 if(i % 7 == 0 && i != 0){
26230 m[m.length] = "</tr><tr>";
26232 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26234 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26235 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26237 var el = document.createElement("div");
26238 el.className = "x-date-picker";
26239 el.innerHTML = m.join("");
26241 container.dom.insertBefore(el, position);
26243 this.el = Roo.get(el);
26244 this.eventEl = Roo.get(el.firstChild);
26246 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26247 handler: this.showPrevMonth,
26249 preventDefault:true,
26253 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26254 handler: this.showNextMonth,
26256 preventDefault:true,
26260 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26262 this.monthPicker = this.el.down('div.x-date-mp');
26263 this.monthPicker.enableDisplayMode('block');
26265 var kn = new Roo.KeyNav(this.eventEl, {
26266 "left" : function(e){
26268 this.showPrevMonth() :
26269 this.update(this.activeDate.add("d", -1));
26272 "right" : function(e){
26274 this.showNextMonth() :
26275 this.update(this.activeDate.add("d", 1));
26278 "up" : function(e){
26280 this.showNextYear() :
26281 this.update(this.activeDate.add("d", -7));
26284 "down" : function(e){
26286 this.showPrevYear() :
26287 this.update(this.activeDate.add("d", 7));
26290 "pageUp" : function(e){
26291 this.showNextMonth();
26294 "pageDown" : function(e){
26295 this.showPrevMonth();
26298 "enter" : function(e){
26299 e.stopPropagation();
26306 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26308 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26310 this.el.unselectable();
26312 this.cells = this.el.select("table.x-date-inner tbody td");
26313 this.textNodes = this.el.query("table.x-date-inner tbody span");
26315 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26317 tooltip: this.monthYearText
26320 this.mbtn.on('click', this.showMonthPicker, this);
26321 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26324 var today = (new Date()).dateFormat(this.format);
26326 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26327 if (this.showClear) {
26328 baseTb.add( new Roo.Toolbar.Fill());
26331 text: String.format(this.todayText, today),
26332 tooltip: String.format(this.todayTip, today),
26333 handler: this.selectToday,
26337 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26340 if (this.showClear) {
26342 baseTb.add( new Roo.Toolbar.Fill());
26345 cls: 'x-btn-icon x-btn-clear',
26346 handler: function() {
26348 this.fireEvent("select", this, '');
26358 this.update(this.value);
26361 createMonthPicker : function(){
26362 if(!this.monthPicker.dom.firstChild){
26363 var buf = ['<table border="0" cellspacing="0">'];
26364 for(var i = 0; i < 6; i++){
26366 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26367 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26369 '<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>' :
26370 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26374 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26376 '</button><button type="button" class="x-date-mp-cancel">',
26378 '</button></td></tr>',
26381 this.monthPicker.update(buf.join(''));
26382 this.monthPicker.on('click', this.onMonthClick, this);
26383 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26385 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26386 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26388 this.mpMonths.each(function(m, a, i){
26391 m.dom.xmonth = 5 + Math.round(i * .5);
26393 m.dom.xmonth = Math.round((i-1) * .5);
26399 showMonthPicker : function(){
26400 this.createMonthPicker();
26401 var size = this.el.getSize();
26402 this.monthPicker.setSize(size);
26403 this.monthPicker.child('table').setSize(size);
26405 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26406 this.updateMPMonth(this.mpSelMonth);
26407 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26408 this.updateMPYear(this.mpSelYear);
26410 this.monthPicker.slideIn('t', {duration:.2});
26413 updateMPYear : function(y){
26415 var ys = this.mpYears.elements;
26416 for(var i = 1; i <= 10; i++){
26417 var td = ys[i-1], y2;
26419 y2 = y + Math.round(i * .5);
26420 td.firstChild.innerHTML = y2;
26423 y2 = y - (5-Math.round(i * .5));
26424 td.firstChild.innerHTML = y2;
26427 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26431 updateMPMonth : function(sm){
26432 this.mpMonths.each(function(m, a, i){
26433 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26437 selectMPMonth: function(m){
26441 onMonthClick : function(e, t){
26443 var el = new Roo.Element(t), pn;
26444 if(el.is('button.x-date-mp-cancel')){
26445 this.hideMonthPicker();
26447 else if(el.is('button.x-date-mp-ok')){
26448 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26449 this.hideMonthPicker();
26451 else if(pn = el.up('td.x-date-mp-month', 2)){
26452 this.mpMonths.removeClass('x-date-mp-sel');
26453 pn.addClass('x-date-mp-sel');
26454 this.mpSelMonth = pn.dom.xmonth;
26456 else if(pn = el.up('td.x-date-mp-year', 2)){
26457 this.mpYears.removeClass('x-date-mp-sel');
26458 pn.addClass('x-date-mp-sel');
26459 this.mpSelYear = pn.dom.xyear;
26461 else if(el.is('a.x-date-mp-prev')){
26462 this.updateMPYear(this.mpyear-10);
26464 else if(el.is('a.x-date-mp-next')){
26465 this.updateMPYear(this.mpyear+10);
26469 onMonthDblClick : function(e, t){
26471 var el = new Roo.Element(t), pn;
26472 if(pn = el.up('td.x-date-mp-month', 2)){
26473 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26474 this.hideMonthPicker();
26476 else if(pn = el.up('td.x-date-mp-year', 2)){
26477 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26478 this.hideMonthPicker();
26482 hideMonthPicker : function(disableAnim){
26483 if(this.monthPicker){
26484 if(disableAnim === true){
26485 this.monthPicker.hide();
26487 this.monthPicker.slideOut('t', {duration:.2});
26493 showPrevMonth : function(e){
26494 this.update(this.activeDate.add("mo", -1));
26498 showNextMonth : function(e){
26499 this.update(this.activeDate.add("mo", 1));
26503 showPrevYear : function(){
26504 this.update(this.activeDate.add("y", -1));
26508 showNextYear : function(){
26509 this.update(this.activeDate.add("y", 1));
26513 handleMouseWheel : function(e){
26514 var delta = e.getWheelDelta();
26516 this.showPrevMonth();
26518 } else if(delta < 0){
26519 this.showNextMonth();
26525 handleDateClick : function(e, t){
26527 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26528 this.setValue(new Date(t.dateValue));
26529 this.fireEvent("select", this, this.value);
26534 selectToday : function(){
26535 this.setValue(new Date().clearTime());
26536 this.fireEvent("select", this, this.value);
26540 update : function(date)
26542 var vd = this.activeDate;
26543 this.activeDate = date;
26545 var t = date.getTime();
26546 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26547 this.cells.removeClass("x-date-selected");
26548 this.cells.each(function(c){
26549 if(c.dom.firstChild.dateValue == t){
26550 c.addClass("x-date-selected");
26551 setTimeout(function(){
26552 try{c.dom.firstChild.focus();}catch(e){}
26561 var days = date.getDaysInMonth();
26562 var firstOfMonth = date.getFirstDateOfMonth();
26563 var startingPos = firstOfMonth.getDay()-this.startDay;
26565 if(startingPos <= this.startDay){
26569 var pm = date.add("mo", -1);
26570 var prevStart = pm.getDaysInMonth()-startingPos;
26572 var cells = this.cells.elements;
26573 var textEls = this.textNodes;
26574 days += startingPos;
26576 // convert everything to numbers so it's fast
26577 var day = 86400000;
26578 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26579 var today = new Date().clearTime().getTime();
26580 var sel = date.clearTime().getTime();
26581 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26582 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26583 var ddMatch = this.disabledDatesRE;
26584 var ddText = this.disabledDatesText;
26585 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26586 var ddaysText = this.disabledDaysText;
26587 var format = this.format;
26589 var setCellClass = function(cal, cell){
26591 var t = d.getTime();
26592 cell.firstChild.dateValue = t;
26594 cell.className += " x-date-today";
26595 cell.title = cal.todayText;
26598 cell.className += " x-date-selected";
26599 setTimeout(function(){
26600 try{cell.firstChild.focus();}catch(e){}
26605 cell.className = " x-date-disabled";
26606 cell.title = cal.minText;
26610 cell.className = " x-date-disabled";
26611 cell.title = cal.maxText;
26615 if(ddays.indexOf(d.getDay()) != -1){
26616 cell.title = ddaysText;
26617 cell.className = " x-date-disabled";
26620 if(ddMatch && format){
26621 var fvalue = d.dateFormat(format);
26622 if(ddMatch.test(fvalue)){
26623 cell.title = ddText.replace("%0", fvalue);
26624 cell.className = " x-date-disabled";
26630 for(; i < startingPos; i++) {
26631 textEls[i].innerHTML = (++prevStart);
26632 d.setDate(d.getDate()+1);
26633 cells[i].className = "x-date-prevday";
26634 setCellClass(this, cells[i]);
26636 for(; i < days; i++){
26637 intDay = i - startingPos + 1;
26638 textEls[i].innerHTML = (intDay);
26639 d.setDate(d.getDate()+1);
26640 cells[i].className = "x-date-active";
26641 setCellClass(this, cells[i]);
26644 for(; i < 42; i++) {
26645 textEls[i].innerHTML = (++extraDays);
26646 d.setDate(d.getDate()+1);
26647 cells[i].className = "x-date-nextday";
26648 setCellClass(this, cells[i]);
26651 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26652 this.fireEvent('monthchange', this, date);
26654 if(!this.internalRender){
26655 var main = this.el.dom.firstChild;
26656 var w = main.offsetWidth;
26657 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26658 Roo.fly(main).setWidth(w);
26659 this.internalRender = true;
26660 // opera does not respect the auto grow header center column
26661 // then, after it gets a width opera refuses to recalculate
26662 // without a second pass
26663 if(Roo.isOpera && !this.secondPass){
26664 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26665 this.secondPass = true;
26666 this.update.defer(10, this, [date]);
26674 * Ext JS Library 1.1.1
26675 * Copyright(c) 2006-2007, Ext JS, LLC.
26677 * Originally Released Under LGPL - original licence link has changed is not relivant.
26680 * <script type="text/javascript">
26683 * @class Roo.TabPanel
26684 * @extends Roo.util.Observable
26685 * A lightweight tab container.
26689 // basic tabs 1, built from existing content
26690 var tabs = new Roo.TabPanel("tabs1");
26691 tabs.addTab("script", "View Script");
26692 tabs.addTab("markup", "View Markup");
26693 tabs.activate("script");
26695 // more advanced tabs, built from javascript
26696 var jtabs = new Roo.TabPanel("jtabs");
26697 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26699 // set up the UpdateManager
26700 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26701 var updater = tab2.getUpdateManager();
26702 updater.setDefaultUrl("ajax1.htm");
26703 tab2.on('activate', updater.refresh, updater, true);
26705 // Use setUrl for Ajax loading
26706 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26707 tab3.setUrl("ajax2.htm", null, true);
26710 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26713 jtabs.activate("jtabs-1");
26716 * Create a new TabPanel.
26717 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26718 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26720 Roo.TabPanel = function(container, config){
26722 * The container element for this TabPanel.
26723 * @type Roo.Element
26725 this.el = Roo.get(container, true);
26727 if(typeof config == "boolean"){
26728 this.tabPosition = config ? "bottom" : "top";
26730 Roo.apply(this, config);
26733 if(this.tabPosition == "bottom"){
26734 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26735 this.el.addClass("x-tabs-bottom");
26737 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26738 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26739 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26741 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26743 if(this.tabPosition != "bottom"){
26744 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26745 * @type Roo.Element
26747 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26748 this.el.addClass("x-tabs-top");
26752 this.bodyEl.setStyle("position", "relative");
26754 this.active = null;
26755 this.activateDelegate = this.activate.createDelegate(this);
26760 * Fires when the active tab changes
26761 * @param {Roo.TabPanel} this
26762 * @param {Roo.TabPanelItem} activePanel The new active tab
26766 * @event beforetabchange
26767 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26768 * @param {Roo.TabPanel} this
26769 * @param {Object} e Set cancel to true on this object to cancel the tab change
26770 * @param {Roo.TabPanelItem} tab The tab being changed to
26772 "beforetabchange" : true
26775 Roo.EventManager.onWindowResize(this.onResize, this);
26776 this.cpad = this.el.getPadding("lr");
26777 this.hiddenCount = 0;
26780 // toolbar on the tabbar support...
26781 if (this.toolbar) {
26782 var tcfg = this.toolbar;
26783 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26784 this.toolbar = new Roo.Toolbar(tcfg);
26785 if (Roo.isSafari) {
26786 var tbl = tcfg.container.child('table', true);
26787 tbl.setAttribute('width', '100%');
26794 Roo.TabPanel.superclass.constructor.call(this);
26797 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26799 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26801 tabPosition : "top",
26803 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26805 currentTabWidth : 0,
26807 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26811 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26815 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26817 preferredTabWidth : 175,
26819 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26821 resizeTabs : false,
26823 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26825 monitorResize : true,
26827 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26832 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26833 * @param {String} id The id of the div to use <b>or create</b>
26834 * @param {String} text The text for the tab
26835 * @param {String} content (optional) Content to put in the TabPanelItem body
26836 * @param {Boolean} closable (optional) True to create a close icon on the tab
26837 * @return {Roo.TabPanelItem} The created TabPanelItem
26839 addTab : function(id, text, content, closable){
26840 var item = new Roo.TabPanelItem(this, id, text, closable);
26841 this.addTabItem(item);
26843 item.setContent(content);
26849 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26850 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26851 * @return {Roo.TabPanelItem}
26853 getTab : function(id){
26854 return this.items[id];
26858 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26859 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26861 hideTab : function(id){
26862 var t = this.items[id];
26865 this.hiddenCount++;
26866 this.autoSizeTabs();
26871 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26872 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26874 unhideTab : function(id){
26875 var t = this.items[id];
26877 t.setHidden(false);
26878 this.hiddenCount--;
26879 this.autoSizeTabs();
26884 * Adds an existing {@link Roo.TabPanelItem}.
26885 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26887 addTabItem : function(item){
26888 this.items[item.id] = item;
26889 this.items.push(item);
26890 if(this.resizeTabs){
26891 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26892 this.autoSizeTabs();
26899 * Removes a {@link Roo.TabPanelItem}.
26900 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26902 removeTab : function(id){
26903 var items = this.items;
26904 var tab = items[id];
26905 if(!tab) { return; }
26906 var index = items.indexOf(tab);
26907 if(this.active == tab && items.length > 1){
26908 var newTab = this.getNextAvailable(index);
26913 this.stripEl.dom.removeChild(tab.pnode.dom);
26914 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26915 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26917 items.splice(index, 1);
26918 delete this.items[tab.id];
26919 tab.fireEvent("close", tab);
26920 tab.purgeListeners();
26921 this.autoSizeTabs();
26924 getNextAvailable : function(start){
26925 var items = this.items;
26927 // look for a next tab that will slide over to
26928 // replace the one being removed
26929 while(index < items.length){
26930 var item = items[++index];
26931 if(item && !item.isHidden()){
26935 // if one isn't found select the previous tab (on the left)
26938 var item = items[--index];
26939 if(item && !item.isHidden()){
26947 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26948 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26950 disableTab : function(id){
26951 var tab = this.items[id];
26952 if(tab && this.active != tab){
26958 * Enables a {@link Roo.TabPanelItem} that is disabled.
26959 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26961 enableTab : function(id){
26962 var tab = this.items[id];
26967 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26968 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26969 * @return {Roo.TabPanelItem} The TabPanelItem.
26971 activate : function(id){
26972 var tab = this.items[id];
26976 if(tab == this.active || tab.disabled){
26980 this.fireEvent("beforetabchange", this, e, tab);
26981 if(e.cancel !== true && !tab.disabled){
26983 this.active.hide();
26985 this.active = this.items[id];
26986 this.active.show();
26987 this.fireEvent("tabchange", this, this.active);
26993 * Gets the active {@link Roo.TabPanelItem}.
26994 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26996 getActiveTab : function(){
26997 return this.active;
27001 * Updates the tab body element to fit the height of the container element
27002 * for overflow scrolling
27003 * @param {Number} targetHeight (optional) Override the starting height from the elements height
27005 syncHeight : function(targetHeight){
27006 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
27007 var bm = this.bodyEl.getMargins();
27008 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
27009 this.bodyEl.setHeight(newHeight);
27013 onResize : function(){
27014 if(this.monitorResize){
27015 this.autoSizeTabs();
27020 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
27022 beginUpdate : function(){
27023 this.updating = true;
27027 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
27029 endUpdate : function(){
27030 this.updating = false;
27031 this.autoSizeTabs();
27035 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
27037 autoSizeTabs : function(){
27038 var count = this.items.length;
27039 var vcount = count - this.hiddenCount;
27040 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
27041 var w = Math.max(this.el.getWidth() - this.cpad, 10);
27042 var availWidth = Math.floor(w / vcount);
27043 var b = this.stripBody;
27044 if(b.getWidth() > w){
27045 var tabs = this.items;
27046 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
27047 if(availWidth < this.minTabWidth){
27048 /*if(!this.sleft){ // incomplete scrolling code
27049 this.createScrollButtons();
27052 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
27055 if(this.currentTabWidth < this.preferredTabWidth){
27056 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
27062 * Returns the number of tabs in this TabPanel.
27065 getCount : function(){
27066 return this.items.length;
27070 * Resizes all the tabs to the passed width
27071 * @param {Number} The new width
27073 setTabWidth : function(width){
27074 this.currentTabWidth = width;
27075 for(var i = 0, len = this.items.length; i < len; i++) {
27076 if(!this.items[i].isHidden())this.items[i].setWidth(width);
27081 * Destroys this TabPanel
27082 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
27084 destroy : function(removeEl){
27085 Roo.EventManager.removeResizeListener(this.onResize, this);
27086 for(var i = 0, len = this.items.length; i < len; i++){
27087 this.items[i].purgeListeners();
27089 if(removeEl === true){
27090 this.el.update("");
27097 * @class Roo.TabPanelItem
27098 * @extends Roo.util.Observable
27099 * Represents an individual item (tab plus body) in a TabPanel.
27100 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
27101 * @param {String} id The id of this TabPanelItem
27102 * @param {String} text The text for the tab of this TabPanelItem
27103 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
27105 Roo.TabPanelItem = function(tabPanel, id, text, closable){
27107 * The {@link Roo.TabPanel} this TabPanelItem belongs to
27108 * @type Roo.TabPanel
27110 this.tabPanel = tabPanel;
27112 * The id for this TabPanelItem
27117 this.disabled = false;
27121 this.loaded = false;
27122 this.closable = closable;
27125 * The body element for this TabPanelItem.
27126 * @type Roo.Element
27128 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
27129 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
27130 this.bodyEl.setStyle("display", "block");
27131 this.bodyEl.setStyle("zoom", "1");
27134 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
27136 this.el = Roo.get(els.el, true);
27137 this.inner = Roo.get(els.inner, true);
27138 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
27139 this.pnode = Roo.get(els.el.parentNode, true);
27140 this.el.on("mousedown", this.onTabMouseDown, this);
27141 this.el.on("click", this.onTabClick, this);
27144 var c = Roo.get(els.close, true);
27145 c.dom.title = this.closeText;
27146 c.addClassOnOver("close-over");
27147 c.on("click", this.closeClick, this);
27153 * Fires when this tab becomes the active tab.
27154 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27155 * @param {Roo.TabPanelItem} this
27159 * @event beforeclose
27160 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
27161 * @param {Roo.TabPanelItem} this
27162 * @param {Object} e Set cancel to true on this object to cancel the close.
27164 "beforeclose": true,
27167 * Fires when this tab is closed.
27168 * @param {Roo.TabPanelItem} this
27172 * @event deactivate
27173 * Fires when this tab is no longer the active tab.
27174 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27175 * @param {Roo.TabPanelItem} this
27177 "deactivate" : true
27179 this.hidden = false;
27181 Roo.TabPanelItem.superclass.constructor.call(this);
27184 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27185 purgeListeners : function(){
27186 Roo.util.Observable.prototype.purgeListeners.call(this);
27187 this.el.removeAllListeners();
27190 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27193 this.pnode.addClass("on");
27196 this.tabPanel.stripWrap.repaint();
27198 this.fireEvent("activate", this.tabPanel, this);
27202 * Returns true if this tab is the active tab.
27203 * @return {Boolean}
27205 isActive : function(){
27206 return this.tabPanel.getActiveTab() == this;
27210 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27213 this.pnode.removeClass("on");
27215 this.fireEvent("deactivate", this.tabPanel, this);
27218 hideAction : function(){
27219 this.bodyEl.hide();
27220 this.bodyEl.setStyle("position", "absolute");
27221 this.bodyEl.setLeft("-20000px");
27222 this.bodyEl.setTop("-20000px");
27225 showAction : function(){
27226 this.bodyEl.setStyle("position", "relative");
27227 this.bodyEl.setTop("");
27228 this.bodyEl.setLeft("");
27229 this.bodyEl.show();
27233 * Set the tooltip for the tab.
27234 * @param {String} tooltip The tab's tooltip
27236 setTooltip : function(text){
27237 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27238 this.textEl.dom.qtip = text;
27239 this.textEl.dom.removeAttribute('title');
27241 this.textEl.dom.title = text;
27245 onTabClick : function(e){
27246 e.preventDefault();
27247 this.tabPanel.activate(this.id);
27250 onTabMouseDown : function(e){
27251 e.preventDefault();
27252 this.tabPanel.activate(this.id);
27255 getWidth : function(){
27256 return this.inner.getWidth();
27259 setWidth : function(width){
27260 var iwidth = width - this.pnode.getPadding("lr");
27261 this.inner.setWidth(iwidth);
27262 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27263 this.pnode.setWidth(width);
27267 * Show or hide the tab
27268 * @param {Boolean} hidden True to hide or false to show.
27270 setHidden : function(hidden){
27271 this.hidden = hidden;
27272 this.pnode.setStyle("display", hidden ? "none" : "");
27276 * Returns true if this tab is "hidden"
27277 * @return {Boolean}
27279 isHidden : function(){
27280 return this.hidden;
27284 * Returns the text for this tab
27287 getText : function(){
27291 autoSize : function(){
27292 //this.el.beginMeasure();
27293 this.textEl.setWidth(1);
27295 * #2804 [new] Tabs in Roojs
27296 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
27298 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
27299 //this.el.endMeasure();
27303 * Sets the text for the tab (Note: this also sets the tooltip text)
27304 * @param {String} text The tab's text and tooltip
27306 setText : function(text){
27308 this.textEl.update(text);
27309 this.setTooltip(text);
27310 if(!this.tabPanel.resizeTabs){
27315 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27317 activate : function(){
27318 this.tabPanel.activate(this.id);
27322 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27324 disable : function(){
27325 if(this.tabPanel.active != this){
27326 this.disabled = true;
27327 this.pnode.addClass("disabled");
27332 * Enables this TabPanelItem if it was previously disabled.
27334 enable : function(){
27335 this.disabled = false;
27336 this.pnode.removeClass("disabled");
27340 * Sets the content for this TabPanelItem.
27341 * @param {String} content The content
27342 * @param {Boolean} loadScripts true to look for and load scripts
27344 setContent : function(content, loadScripts){
27345 this.bodyEl.update(content, loadScripts);
27349 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27350 * @return {Roo.UpdateManager} The UpdateManager
27352 getUpdateManager : function(){
27353 return this.bodyEl.getUpdateManager();
27357 * Set a URL to be used to load the content for this TabPanelItem.
27358 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27359 * @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)
27360 * @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)
27361 * @return {Roo.UpdateManager} The UpdateManager
27363 setUrl : function(url, params, loadOnce){
27364 if(this.refreshDelegate){
27365 this.un('activate', this.refreshDelegate);
27367 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27368 this.on("activate", this.refreshDelegate);
27369 return this.bodyEl.getUpdateManager();
27373 _handleRefresh : function(url, params, loadOnce){
27374 if(!loadOnce || !this.loaded){
27375 var updater = this.bodyEl.getUpdateManager();
27376 updater.update(url, params, this._setLoaded.createDelegate(this));
27381 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27382 * Will fail silently if the setUrl method has not been called.
27383 * This does not activate the panel, just updates its content.
27385 refresh : function(){
27386 if(this.refreshDelegate){
27387 this.loaded = false;
27388 this.refreshDelegate();
27393 _setLoaded : function(){
27394 this.loaded = true;
27398 closeClick : function(e){
27401 this.fireEvent("beforeclose", this, o);
27402 if(o.cancel !== true){
27403 this.tabPanel.removeTab(this.id);
27407 * The text displayed in the tooltip for the close icon.
27410 closeText : "Close this tab"
27414 Roo.TabPanel.prototype.createStrip = function(container){
27415 var strip = document.createElement("div");
27416 strip.className = "x-tabs-wrap";
27417 container.appendChild(strip);
27421 Roo.TabPanel.prototype.createStripList = function(strip){
27422 // div wrapper for retard IE
27423 // returns the "tr" element.
27424 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27425 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27426 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27427 return strip.firstChild.firstChild.firstChild.firstChild;
27430 Roo.TabPanel.prototype.createBody = function(container){
27431 var body = document.createElement("div");
27432 Roo.id(body, "tab-body");
27433 Roo.fly(body).addClass("x-tabs-body");
27434 container.appendChild(body);
27438 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27439 var body = Roo.getDom(id);
27441 body = document.createElement("div");
27444 Roo.fly(body).addClass("x-tabs-item-body");
27445 bodyEl.insertBefore(body, bodyEl.firstChild);
27449 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27450 var td = document.createElement("td");
27451 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27452 //stripEl.appendChild(td);
27454 td.className = "x-tabs-closable";
27455 if(!this.closeTpl){
27456 this.closeTpl = new Roo.Template(
27457 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27458 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27459 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27462 var el = this.closeTpl.overwrite(td, {"text": text});
27463 var close = el.getElementsByTagName("div")[0];
27464 var inner = el.getElementsByTagName("em")[0];
27465 return {"el": el, "close": close, "inner": inner};
27468 this.tabTpl = new Roo.Template(
27469 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27470 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27473 var el = this.tabTpl.overwrite(td, {"text": text});
27474 var inner = el.getElementsByTagName("em")[0];
27475 return {"el": el, "inner": inner};
27479 * Ext JS Library 1.1.1
27480 * Copyright(c) 2006-2007, Ext JS, LLC.
27482 * Originally Released Under LGPL - original licence link has changed is not relivant.
27485 * <script type="text/javascript">
27489 * @class Roo.Button
27490 * @extends Roo.util.Observable
27491 * Simple Button class
27492 * @cfg {String} text The button text
27493 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27494 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27495 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27496 * @cfg {Object} scope The scope of the handler
27497 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27498 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27499 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27500 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27501 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27502 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27503 applies if enableToggle = true)
27504 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27505 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27506 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27508 * Create a new button
27509 * @param {Object} config The config object
27511 Roo.Button = function(renderTo, config)
27515 renderTo = config.renderTo || false;
27518 Roo.apply(this, config);
27522 * Fires when this button is clicked
27523 * @param {Button} this
27524 * @param {EventObject} e The click event
27529 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27530 * @param {Button} this
27531 * @param {Boolean} pressed
27536 * Fires when the mouse hovers over the button
27537 * @param {Button} this
27538 * @param {Event} e The event object
27540 'mouseover' : true,
27543 * Fires when the mouse exits the button
27544 * @param {Button} this
27545 * @param {Event} e The event object
27550 * Fires when the button is rendered
27551 * @param {Button} this
27556 this.menu = Roo.menu.MenuMgr.get(this.menu);
27558 // register listeners first!! - so render can be captured..
27559 Roo.util.Observable.call(this);
27561 this.render(renderTo);
27567 Roo.extend(Roo.Button, Roo.util.Observable, {
27573 * Read-only. True if this button is hidden
27578 * Read-only. True if this button is disabled
27583 * Read-only. True if this button is pressed (only if enableToggle = true)
27589 * @cfg {Number} tabIndex
27590 * The DOM tabIndex for this button (defaults to undefined)
27592 tabIndex : undefined,
27595 * @cfg {Boolean} enableToggle
27596 * True to enable pressed/not pressed toggling (defaults to false)
27598 enableToggle: false,
27600 * @cfg {Mixed} menu
27601 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27605 * @cfg {String} menuAlign
27606 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27608 menuAlign : "tl-bl?",
27611 * @cfg {String} iconCls
27612 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27614 iconCls : undefined,
27616 * @cfg {String} type
27617 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27622 menuClassTarget: 'tr',
27625 * @cfg {String} clickEvent
27626 * The type of event to map to the button's event handler (defaults to 'click')
27628 clickEvent : 'click',
27631 * @cfg {Boolean} handleMouseEvents
27632 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27634 handleMouseEvents : true,
27637 * @cfg {String} tooltipType
27638 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27640 tooltipType : 'qtip',
27643 * @cfg {String} cls
27644 * A CSS class to apply to the button's main element.
27648 * @cfg {Roo.Template} template (Optional)
27649 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27650 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27651 * require code modifications if required elements (e.g. a button) aren't present.
27655 render : function(renderTo){
27657 if(this.hideParent){
27658 this.parentEl = Roo.get(renderTo);
27660 if(!this.dhconfig){
27661 if(!this.template){
27662 if(!Roo.Button.buttonTemplate){
27663 // hideous table template
27664 Roo.Button.buttonTemplate = new Roo.Template(
27665 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27666 '<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>',
27667 "</tr></tbody></table>");
27669 this.template = Roo.Button.buttonTemplate;
27671 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27672 var btnEl = btn.child("button:first");
27673 btnEl.on('focus', this.onFocus, this);
27674 btnEl.on('blur', this.onBlur, this);
27676 btn.addClass(this.cls);
27679 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27682 btnEl.addClass(this.iconCls);
27684 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27687 if(this.tabIndex !== undefined){
27688 btnEl.dom.tabIndex = this.tabIndex;
27691 if(typeof this.tooltip == 'object'){
27692 Roo.QuickTips.tips(Roo.apply({
27696 btnEl.dom[this.tooltipType] = this.tooltip;
27700 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27704 this.el.dom.id = this.el.id = this.id;
27707 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27708 this.menu.on("show", this.onMenuShow, this);
27709 this.menu.on("hide", this.onMenuHide, this);
27711 btn.addClass("x-btn");
27712 if(Roo.isIE && !Roo.isIE7){
27713 this.autoWidth.defer(1, this);
27717 if(this.handleMouseEvents){
27718 btn.on("mouseover", this.onMouseOver, this);
27719 btn.on("mouseout", this.onMouseOut, this);
27720 btn.on("mousedown", this.onMouseDown, this);
27722 btn.on(this.clickEvent, this.onClick, this);
27723 //btn.on("mouseup", this.onMouseUp, this);
27730 Roo.ButtonToggleMgr.register(this);
27732 this.el.addClass("x-btn-pressed");
27735 var repeater = new Roo.util.ClickRepeater(btn,
27736 typeof this.repeat == "object" ? this.repeat : {}
27738 repeater.on("click", this.onClick, this);
27741 this.fireEvent('render', this);
27745 * Returns the button's underlying element
27746 * @return {Roo.Element} The element
27748 getEl : function(){
27753 * Destroys this Button and removes any listeners.
27755 destroy : function(){
27756 Roo.ButtonToggleMgr.unregister(this);
27757 this.el.removeAllListeners();
27758 this.purgeListeners();
27763 autoWidth : function(){
27765 this.el.setWidth("auto");
27766 if(Roo.isIE7 && Roo.isStrict){
27767 var ib = this.el.child('button');
27768 if(ib && ib.getWidth() > 20){
27770 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27775 this.el.beginMeasure();
27777 if(this.el.getWidth() < this.minWidth){
27778 this.el.setWidth(this.minWidth);
27781 this.el.endMeasure();
27788 * Assigns this button's click handler
27789 * @param {Function} handler The function to call when the button is clicked
27790 * @param {Object} scope (optional) Scope for the function passed in
27792 setHandler : function(handler, scope){
27793 this.handler = handler;
27794 this.scope = scope;
27798 * Sets this button's text
27799 * @param {String} text The button text
27801 setText : function(text){
27804 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27810 * Gets the text for this button
27811 * @return {String} The button text
27813 getText : function(){
27821 this.hidden = false;
27823 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27831 this.hidden = true;
27833 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27838 * Convenience function for boolean show/hide
27839 * @param {Boolean} visible True to show, false to hide
27841 setVisible: function(visible){
27850 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27851 * @param {Boolean} state (optional) Force a particular state
27853 toggle : function(state){
27854 state = state === undefined ? !this.pressed : state;
27855 if(state != this.pressed){
27857 this.el.addClass("x-btn-pressed");
27858 this.pressed = true;
27859 this.fireEvent("toggle", this, true);
27861 this.el.removeClass("x-btn-pressed");
27862 this.pressed = false;
27863 this.fireEvent("toggle", this, false);
27865 if(this.toggleHandler){
27866 this.toggleHandler.call(this.scope || this, this, state);
27874 focus : function(){
27875 this.el.child('button:first').focus();
27879 * Disable this button
27881 disable : function(){
27883 this.el.addClass("x-btn-disabled");
27885 this.disabled = true;
27889 * Enable this button
27891 enable : function(){
27893 this.el.removeClass("x-btn-disabled");
27895 this.disabled = false;
27899 * Convenience function for boolean enable/disable
27900 * @param {Boolean} enabled True to enable, false to disable
27902 setDisabled : function(v){
27903 this[v !== true ? "enable" : "disable"]();
27907 onClick : function(e)
27910 e.preventDefault();
27915 if(!this.disabled){
27916 if(this.enableToggle){
27919 if(this.menu && !this.menu.isVisible()){
27920 this.menu.show(this.el, this.menuAlign);
27922 this.fireEvent("click", this, e);
27924 this.el.removeClass("x-btn-over");
27925 this.handler.call(this.scope || this, this, e);
27930 onMouseOver : function(e){
27931 if(!this.disabled){
27932 this.el.addClass("x-btn-over");
27933 this.fireEvent('mouseover', this, e);
27937 onMouseOut : function(e){
27938 if(!e.within(this.el, true)){
27939 this.el.removeClass("x-btn-over");
27940 this.fireEvent('mouseout', this, e);
27944 onFocus : function(e){
27945 if(!this.disabled){
27946 this.el.addClass("x-btn-focus");
27950 onBlur : function(e){
27951 this.el.removeClass("x-btn-focus");
27954 onMouseDown : function(e){
27955 if(!this.disabled && e.button == 0){
27956 this.el.addClass("x-btn-click");
27957 Roo.get(document).on('mouseup', this.onMouseUp, this);
27961 onMouseUp : function(e){
27963 this.el.removeClass("x-btn-click");
27964 Roo.get(document).un('mouseup', this.onMouseUp, this);
27968 onMenuShow : function(e){
27969 this.el.addClass("x-btn-menu-active");
27972 onMenuHide : function(e){
27973 this.el.removeClass("x-btn-menu-active");
27977 // Private utility class used by Button
27978 Roo.ButtonToggleMgr = function(){
27981 function toggleGroup(btn, state){
27983 var g = groups[btn.toggleGroup];
27984 for(var i = 0, l = g.length; i < l; i++){
27986 g[i].toggle(false);
27993 register : function(btn){
27994 if(!btn.toggleGroup){
27997 var g = groups[btn.toggleGroup];
27999 g = groups[btn.toggleGroup] = [];
28002 btn.on("toggle", toggleGroup);
28005 unregister : function(btn){
28006 if(!btn.toggleGroup){
28009 var g = groups[btn.toggleGroup];
28012 btn.un("toggle", toggleGroup);
28018 * Ext JS Library 1.1.1
28019 * Copyright(c) 2006-2007, Ext JS, LLC.
28021 * Originally Released Under LGPL - original licence link has changed is not relivant.
28024 * <script type="text/javascript">
28028 * @class Roo.SplitButton
28029 * @extends Roo.Button
28030 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
28031 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
28032 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
28033 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
28034 * @cfg {String} arrowTooltip The title attribute of the arrow
28036 * Create a new menu button
28037 * @param {String/HTMLElement/Element} renderTo The element to append the button to
28038 * @param {Object} config The config object
28040 Roo.SplitButton = function(renderTo, config){
28041 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
28043 * @event arrowclick
28044 * Fires when this button's arrow is clicked
28045 * @param {SplitButton} this
28046 * @param {EventObject} e The click event
28048 this.addEvents({"arrowclick":true});
28051 Roo.extend(Roo.SplitButton, Roo.Button, {
28052 render : function(renderTo){
28053 // this is one sweet looking template!
28054 var tpl = new Roo.Template(
28055 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
28056 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
28057 '<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>',
28058 "</tbody></table></td><td>",
28059 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
28060 '<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>',
28061 "</tbody></table></td></tr></table>"
28063 var btn = tpl.append(renderTo, [this.text, this.type], true);
28064 var btnEl = btn.child("button");
28066 btn.addClass(this.cls);
28069 btnEl.setStyle('background-image', 'url(' +this.icon +')');
28072 btnEl.addClass(this.iconCls);
28074 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
28078 if(this.handleMouseEvents){
28079 btn.on("mouseover", this.onMouseOver, this);
28080 btn.on("mouseout", this.onMouseOut, this);
28081 btn.on("mousedown", this.onMouseDown, this);
28082 btn.on("mouseup", this.onMouseUp, this);
28084 btn.on(this.clickEvent, this.onClick, this);
28086 if(typeof this.tooltip == 'object'){
28087 Roo.QuickTips.tips(Roo.apply({
28091 btnEl.dom[this.tooltipType] = this.tooltip;
28094 if(this.arrowTooltip){
28095 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
28104 this.el.addClass("x-btn-pressed");
28106 if(Roo.isIE && !Roo.isIE7){
28107 this.autoWidth.defer(1, this);
28112 this.menu.on("show", this.onMenuShow, this);
28113 this.menu.on("hide", this.onMenuHide, this);
28115 this.fireEvent('render', this);
28119 autoWidth : function(){
28121 var tbl = this.el.child("table:first");
28122 var tbl2 = this.el.child("table:last");
28123 this.el.setWidth("auto");
28124 tbl.setWidth("auto");
28125 if(Roo.isIE7 && Roo.isStrict){
28126 var ib = this.el.child('button:first');
28127 if(ib && ib.getWidth() > 20){
28129 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
28134 this.el.beginMeasure();
28136 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
28137 tbl.setWidth(this.minWidth-tbl2.getWidth());
28140 this.el.endMeasure();
28143 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
28147 * Sets this button's click handler
28148 * @param {Function} handler The function to call when the button is clicked
28149 * @param {Object} scope (optional) Scope for the function passed above
28151 setHandler : function(handler, scope){
28152 this.handler = handler;
28153 this.scope = scope;
28157 * Sets this button's arrow click handler
28158 * @param {Function} handler The function to call when the arrow is clicked
28159 * @param {Object} scope (optional) Scope for the function passed above
28161 setArrowHandler : function(handler, scope){
28162 this.arrowHandler = handler;
28163 this.scope = scope;
28169 focus : function(){
28171 this.el.child("button:first").focus();
28176 onClick : function(e){
28177 e.preventDefault();
28178 if(!this.disabled){
28179 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28180 if(this.menu && !this.menu.isVisible()){
28181 this.menu.show(this.el, this.menuAlign);
28183 this.fireEvent("arrowclick", this, e);
28184 if(this.arrowHandler){
28185 this.arrowHandler.call(this.scope || this, this, e);
28188 this.fireEvent("click", this, e);
28190 this.handler.call(this.scope || this, this, e);
28196 onMouseDown : function(e){
28197 if(!this.disabled){
28198 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28202 onMouseUp : function(e){
28203 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28208 // backwards compat
28209 Roo.MenuButton = Roo.SplitButton;/*
28211 * Ext JS Library 1.1.1
28212 * Copyright(c) 2006-2007, Ext JS, LLC.
28214 * Originally Released Under LGPL - original licence link has changed is not relivant.
28217 * <script type="text/javascript">
28221 * @class Roo.Toolbar
28222 * Basic Toolbar class.
28224 * Creates a new Toolbar
28225 * @param {Object} container The config object
28227 Roo.Toolbar = function(container, buttons, config)
28229 /// old consturctor format still supported..
28230 if(container instanceof Array){ // omit the container for later rendering
28231 buttons = container;
28235 if (typeof(container) == 'object' && container.xtype) {
28236 config = container;
28237 container = config.container;
28238 buttons = config.buttons || []; // not really - use items!!
28241 if (config && config.items) {
28242 xitems = config.items;
28243 delete config.items;
28245 Roo.apply(this, config);
28246 this.buttons = buttons;
28249 this.render(container);
28251 this.xitems = xitems;
28252 Roo.each(xitems, function(b) {
28258 Roo.Toolbar.prototype = {
28260 * @cfg {Array} items
28261 * array of button configs or elements to add (will be converted to a MixedCollection)
28265 * @cfg {String/HTMLElement/Element} container
28266 * The id or element that will contain the toolbar
28269 render : function(ct){
28270 this.el = Roo.get(ct);
28272 this.el.addClass(this.cls);
28274 // using a table allows for vertical alignment
28275 // 100% width is needed by Safari...
28276 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28277 this.tr = this.el.child("tr", true);
28279 this.items = new Roo.util.MixedCollection(false, function(o){
28280 return o.id || ("item" + (++autoId));
28283 this.add.apply(this, this.buttons);
28284 delete this.buttons;
28289 * Adds element(s) to the toolbar -- this function takes a variable number of
28290 * arguments of mixed type and adds them to the toolbar.
28291 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28293 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28294 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28295 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28296 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28297 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28298 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28299 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28300 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28301 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28303 * @param {Mixed} arg2
28304 * @param {Mixed} etc.
28307 var a = arguments, l = a.length;
28308 for(var i = 0; i < l; i++){
28313 _add : function(el) {
28316 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28319 if (el.applyTo){ // some kind of form field
28320 return this.addField(el);
28322 if (el.render){ // some kind of Toolbar.Item
28323 return this.addItem(el);
28325 if (typeof el == "string"){ // string
28326 if(el == "separator" || el == "-"){
28327 return this.addSeparator();
28330 return this.addSpacer();
28333 return this.addFill();
28335 return this.addText(el);
28338 if(el.tagName){ // element
28339 return this.addElement(el);
28341 if(typeof el == "object"){ // must be button config?
28342 return this.addButton(el);
28344 // and now what?!?!
28350 * Add an Xtype element
28351 * @param {Object} xtype Xtype Object
28352 * @return {Object} created Object
28354 addxtype : function(e){
28355 return this.add(e);
28359 * Returns the Element for this toolbar.
28360 * @return {Roo.Element}
28362 getEl : function(){
28368 * @return {Roo.Toolbar.Item} The separator item
28370 addSeparator : function(){
28371 return this.addItem(new Roo.Toolbar.Separator());
28375 * Adds a spacer element
28376 * @return {Roo.Toolbar.Spacer} The spacer item
28378 addSpacer : function(){
28379 return this.addItem(new Roo.Toolbar.Spacer());
28383 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28384 * @return {Roo.Toolbar.Fill} The fill item
28386 addFill : function(){
28387 return this.addItem(new Roo.Toolbar.Fill());
28391 * Adds any standard HTML element to the toolbar
28392 * @param {String/HTMLElement/Element} el The element or id of the element to add
28393 * @return {Roo.Toolbar.Item} The element's item
28395 addElement : function(el){
28396 return this.addItem(new Roo.Toolbar.Item(el));
28399 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28400 * @type Roo.util.MixedCollection
28405 * Adds any Toolbar.Item or subclass
28406 * @param {Roo.Toolbar.Item} item
28407 * @return {Roo.Toolbar.Item} The item
28409 addItem : function(item){
28410 var td = this.nextBlock();
28412 this.items.add(item);
28417 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28418 * @param {Object/Array} config A button config or array of configs
28419 * @return {Roo.Toolbar.Button/Array}
28421 addButton : function(config){
28422 if(config instanceof Array){
28424 for(var i = 0, len = config.length; i < len; i++) {
28425 buttons.push(this.addButton(config[i]));
28430 if(!(config instanceof Roo.Toolbar.Button)){
28432 new Roo.Toolbar.SplitButton(config) :
28433 new Roo.Toolbar.Button(config);
28435 var td = this.nextBlock();
28442 * Adds text to the toolbar
28443 * @param {String} text The text to add
28444 * @return {Roo.Toolbar.Item} The element's item
28446 addText : function(text){
28447 return this.addItem(new Roo.Toolbar.TextItem(text));
28451 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28452 * @param {Number} index The index where the item is to be inserted
28453 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28454 * @return {Roo.Toolbar.Button/Item}
28456 insertButton : function(index, item){
28457 if(item instanceof Array){
28459 for(var i = 0, len = item.length; i < len; i++) {
28460 buttons.push(this.insertButton(index + i, item[i]));
28464 if (!(item instanceof Roo.Toolbar.Button)){
28465 item = new Roo.Toolbar.Button(item);
28467 var td = document.createElement("td");
28468 this.tr.insertBefore(td, this.tr.childNodes[index]);
28470 this.items.insert(index, item);
28475 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28476 * @param {Object} config
28477 * @return {Roo.Toolbar.Item} The element's item
28479 addDom : function(config, returnEl){
28480 var td = this.nextBlock();
28481 Roo.DomHelper.overwrite(td, config);
28482 var ti = new Roo.Toolbar.Item(td.firstChild);
28484 this.items.add(ti);
28489 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28490 * @type Roo.util.MixedCollection
28495 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28496 * Note: the field should not have been rendered yet. For a field that has already been
28497 * rendered, use {@link #addElement}.
28498 * @param {Roo.form.Field} field
28499 * @return {Roo.ToolbarItem}
28503 addField : function(field) {
28504 if (!this.fields) {
28506 this.fields = new Roo.util.MixedCollection(false, function(o){
28507 return o.id || ("item" + (++autoId));
28512 var td = this.nextBlock();
28514 var ti = new Roo.Toolbar.Item(td.firstChild);
28516 this.items.add(ti);
28517 this.fields.add(field);
28528 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28529 this.el.child('div').hide();
28537 this.el.child('div').show();
28541 nextBlock : function(){
28542 var td = document.createElement("td");
28543 this.tr.appendChild(td);
28548 destroy : function(){
28549 if(this.items){ // rendered?
28550 Roo.destroy.apply(Roo, this.items.items);
28552 if(this.fields){ // rendered?
28553 Roo.destroy.apply(Roo, this.fields.items);
28555 Roo.Element.uncache(this.el, this.tr);
28560 * @class Roo.Toolbar.Item
28561 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28563 * Creates a new Item
28564 * @param {HTMLElement} el
28566 Roo.Toolbar.Item = function(el){
28568 if (typeof (el.xtype) != 'undefined') {
28573 this.el = Roo.getDom(el);
28574 this.id = Roo.id(this.el);
28575 this.hidden = false;
28580 * Fires when the button is rendered
28581 * @param {Button} this
28585 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
28587 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
28588 //Roo.Toolbar.Item.prototype = {
28591 * Get this item's HTML Element
28592 * @return {HTMLElement}
28594 getEl : function(){
28599 render : function(td){
28602 td.appendChild(this.el);
28604 this.fireEvent('render', this);
28608 * Removes and destroys this item.
28610 destroy : function(){
28611 this.td.parentNode.removeChild(this.td);
28618 this.hidden = false;
28619 this.td.style.display = "";
28626 this.hidden = true;
28627 this.td.style.display = "none";
28631 * Convenience function for boolean show/hide.
28632 * @param {Boolean} visible true to show/false to hide
28634 setVisible: function(visible){
28643 * Try to focus this item.
28645 focus : function(){
28646 Roo.fly(this.el).focus();
28650 * Disables this item.
28652 disable : function(){
28653 Roo.fly(this.td).addClass("x-item-disabled");
28654 this.disabled = true;
28655 this.el.disabled = true;
28659 * Enables this item.
28661 enable : function(){
28662 Roo.fly(this.td).removeClass("x-item-disabled");
28663 this.disabled = false;
28664 this.el.disabled = false;
28670 * @class Roo.Toolbar.Separator
28671 * @extends Roo.Toolbar.Item
28672 * A simple toolbar separator class
28674 * Creates a new Separator
28676 Roo.Toolbar.Separator = function(cfg){
28678 var s = document.createElement("span");
28679 s.className = "ytb-sep";
28684 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
28686 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28687 enable:Roo.emptyFn,
28688 disable:Roo.emptyFn,
28693 * @class Roo.Toolbar.Spacer
28694 * @extends Roo.Toolbar.Item
28695 * A simple element that adds extra horizontal space to a toolbar.
28697 * Creates a new Spacer
28699 Roo.Toolbar.Spacer = function(cfg){
28700 var s = document.createElement("div");
28701 s.className = "ytb-spacer";
28705 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
28707 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28708 enable:Roo.emptyFn,
28709 disable:Roo.emptyFn,
28714 * @class Roo.Toolbar.Fill
28715 * @extends Roo.Toolbar.Spacer
28716 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28718 * Creates a new Spacer
28720 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28722 render : function(td){
28723 td.style.width = '100%';
28724 Roo.Toolbar.Fill.superclass.render.call(this, td);
28729 * @class Roo.Toolbar.TextItem
28730 * @extends Roo.Toolbar.Item
28731 * A simple class that renders text directly into a toolbar.
28733 * Creates a new TextItem
28734 * @param {String} text
28736 Roo.Toolbar.TextItem = function(cfg){
28737 var text = cfg || "";
28738 if (typeof(cfg) == 'object') {
28739 text = cfg.text || "";
28743 var s = document.createElement("span");
28744 s.className = "ytb-text";
28745 s.innerHTML = text;
28750 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
28752 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28755 enable:Roo.emptyFn,
28756 disable:Roo.emptyFn,
28761 * @class Roo.Toolbar.Button
28762 * @extends Roo.Button
28763 * A button that renders into a toolbar.
28765 * Creates a new Button
28766 * @param {Object} config A standard {@link Roo.Button} config object
28768 Roo.Toolbar.Button = function(config){
28769 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28771 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28772 render : function(td){
28774 Roo.Toolbar.Button.superclass.render.call(this, td);
28778 * Removes and destroys this button
28780 destroy : function(){
28781 Roo.Toolbar.Button.superclass.destroy.call(this);
28782 this.td.parentNode.removeChild(this.td);
28786 * Shows this button
28789 this.hidden = false;
28790 this.td.style.display = "";
28794 * Hides this button
28797 this.hidden = true;
28798 this.td.style.display = "none";
28802 * Disables this item
28804 disable : function(){
28805 Roo.fly(this.td).addClass("x-item-disabled");
28806 this.disabled = true;
28810 * Enables this item
28812 enable : function(){
28813 Roo.fly(this.td).removeClass("x-item-disabled");
28814 this.disabled = false;
28817 // backwards compat
28818 Roo.ToolbarButton = Roo.Toolbar.Button;
28821 * @class Roo.Toolbar.SplitButton
28822 * @extends Roo.SplitButton
28823 * A menu button that renders into a toolbar.
28825 * Creates a new SplitButton
28826 * @param {Object} config A standard {@link Roo.SplitButton} config object
28828 Roo.Toolbar.SplitButton = function(config){
28829 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28831 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28832 render : function(td){
28834 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28838 * Removes and destroys this button
28840 destroy : function(){
28841 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28842 this.td.parentNode.removeChild(this.td);
28846 * Shows this button
28849 this.hidden = false;
28850 this.td.style.display = "";
28854 * Hides this button
28857 this.hidden = true;
28858 this.td.style.display = "none";
28862 // backwards compat
28863 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28865 * Ext JS Library 1.1.1
28866 * Copyright(c) 2006-2007, Ext JS, LLC.
28868 * Originally Released Under LGPL - original licence link has changed is not relivant.
28871 * <script type="text/javascript">
28875 * @class Roo.PagingToolbar
28876 * @extends Roo.Toolbar
28877 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28879 * Create a new PagingToolbar
28880 * @param {Object} config The config object
28882 Roo.PagingToolbar = function(el, ds, config)
28884 // old args format still supported... - xtype is prefered..
28885 if (typeof(el) == 'object' && el.xtype) {
28886 // created from xtype...
28888 ds = el.dataSource;
28889 el = config.container;
28892 if (config.items) {
28893 items = config.items;
28897 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28900 this.renderButtons(this.el);
28903 // supprot items array.
28905 Roo.each(items, function(e) {
28906 this.add(Roo.factory(e));
28911 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28913 * @cfg {Roo.data.Store} dataSource
28914 * The underlying data store providing the paged data
28917 * @cfg {String/HTMLElement/Element} container
28918 * container The id or element that will contain the toolbar
28921 * @cfg {Boolean} displayInfo
28922 * True to display the displayMsg (defaults to false)
28925 * @cfg {Number} pageSize
28926 * The number of records to display per page (defaults to 20)
28930 * @cfg {String} displayMsg
28931 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28933 displayMsg : 'Displaying {0} - {1} of {2}',
28935 * @cfg {String} emptyMsg
28936 * The message to display when no records are found (defaults to "No data to display")
28938 emptyMsg : 'No data to display',
28940 * Customizable piece of the default paging text (defaults to "Page")
28943 beforePageText : "Page",
28945 * Customizable piece of the default paging text (defaults to "of %0")
28948 afterPageText : "of {0}",
28950 * Customizable piece of the default paging text (defaults to "First Page")
28953 firstText : "First Page",
28955 * Customizable piece of the default paging text (defaults to "Previous Page")
28958 prevText : "Previous Page",
28960 * Customizable piece of the default paging text (defaults to "Next Page")
28963 nextText : "Next Page",
28965 * Customizable piece of the default paging text (defaults to "Last Page")
28968 lastText : "Last Page",
28970 * Customizable piece of the default paging text (defaults to "Refresh")
28973 refreshText : "Refresh",
28976 renderButtons : function(el){
28977 Roo.PagingToolbar.superclass.render.call(this, el);
28978 this.first = this.addButton({
28979 tooltip: this.firstText,
28980 cls: "x-btn-icon x-grid-page-first",
28982 handler: this.onClick.createDelegate(this, ["first"])
28984 this.prev = this.addButton({
28985 tooltip: this.prevText,
28986 cls: "x-btn-icon x-grid-page-prev",
28988 handler: this.onClick.createDelegate(this, ["prev"])
28990 //this.addSeparator();
28991 this.add(this.beforePageText);
28992 this.field = Roo.get(this.addDom({
28997 cls: "x-grid-page-number"
28999 this.field.on("keydown", this.onPagingKeydown, this);
29000 this.field.on("focus", function(){this.dom.select();});
29001 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
29002 this.field.setHeight(18);
29003 //this.addSeparator();
29004 this.next = this.addButton({
29005 tooltip: this.nextText,
29006 cls: "x-btn-icon x-grid-page-next",
29008 handler: this.onClick.createDelegate(this, ["next"])
29010 this.last = this.addButton({
29011 tooltip: this.lastText,
29012 cls: "x-btn-icon x-grid-page-last",
29014 handler: this.onClick.createDelegate(this, ["last"])
29016 //this.addSeparator();
29017 this.loading = this.addButton({
29018 tooltip: this.refreshText,
29019 cls: "x-btn-icon x-grid-loading",
29020 handler: this.onClick.createDelegate(this, ["refresh"])
29023 if(this.displayInfo){
29024 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
29029 updateInfo : function(){
29030 if(this.displayEl){
29031 var count = this.ds.getCount();
29032 var msg = count == 0 ?
29036 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
29038 this.displayEl.update(msg);
29043 onLoad : function(ds, r, o){
29044 this.cursor = o.params ? o.params.start : 0;
29045 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
29047 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
29048 this.field.dom.value = ap;
29049 this.first.setDisabled(ap == 1);
29050 this.prev.setDisabled(ap == 1);
29051 this.next.setDisabled(ap == ps);
29052 this.last.setDisabled(ap == ps);
29053 this.loading.enable();
29058 getPageData : function(){
29059 var total = this.ds.getTotalCount();
29062 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
29063 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
29068 onLoadError : function(){
29069 this.loading.enable();
29073 onPagingKeydown : function(e){
29074 var k = e.getKey();
29075 var d = this.getPageData();
29077 var v = this.field.dom.value, pageNum;
29078 if(!v || isNaN(pageNum = parseInt(v, 10))){
29079 this.field.dom.value = d.activePage;
29082 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
29083 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29086 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))
29088 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
29089 this.field.dom.value = pageNum;
29090 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
29093 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29095 var v = this.field.dom.value, pageNum;
29096 var increment = (e.shiftKey) ? 10 : 1;
29097 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29099 if(!v || isNaN(pageNum = parseInt(v, 10))) {
29100 this.field.dom.value = d.activePage;
29103 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
29105 this.field.dom.value = parseInt(v, 10) + increment;
29106 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
29107 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29114 beforeLoad : function(){
29116 this.loading.disable();
29121 onClick : function(which){
29125 ds.load({params:{start: 0, limit: this.pageSize}});
29128 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
29131 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
29134 var total = ds.getTotalCount();
29135 var extra = total % this.pageSize;
29136 var lastStart = extra ? (total - extra) : total-this.pageSize;
29137 ds.load({params:{start: lastStart, limit: this.pageSize}});
29140 ds.load({params:{start: this.cursor, limit: this.pageSize}});
29146 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
29147 * @param {Roo.data.Store} store The data store to unbind
29149 unbind : function(ds){
29150 ds.un("beforeload", this.beforeLoad, this);
29151 ds.un("load", this.onLoad, this);
29152 ds.un("loadexception", this.onLoadError, this);
29153 ds.un("remove", this.updateInfo, this);
29154 ds.un("add", this.updateInfo, this);
29155 this.ds = undefined;
29159 * Binds the paging toolbar to the specified {@link Roo.data.Store}
29160 * @param {Roo.data.Store} store The data store to bind
29162 bind : function(ds){
29163 ds.on("beforeload", this.beforeLoad, this);
29164 ds.on("load", this.onLoad, this);
29165 ds.on("loadexception", this.onLoadError, this);
29166 ds.on("remove", this.updateInfo, this);
29167 ds.on("add", this.updateInfo, this);
29172 * Ext JS Library 1.1.1
29173 * Copyright(c) 2006-2007, Ext JS, LLC.
29175 * Originally Released Under LGPL - original licence link has changed is not relivant.
29178 * <script type="text/javascript">
29182 * @class Roo.Resizable
29183 * @extends Roo.util.Observable
29184 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
29185 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
29186 * 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
29187 * the element will be wrapped for you automatically.</p>
29188 * <p>Here is the list of valid resize handles:</p>
29191 ------ -------------------
29200 'hd' horizontal drag
29203 * <p>Here's an example showing the creation of a typical Resizable:</p>
29205 var resizer = new Roo.Resizable("element-id", {
29213 resizer.on("resize", myHandler);
29215 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29216 * resizer.east.setDisplayed(false);</p>
29217 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29218 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29219 * resize operation's new size (defaults to [0, 0])
29220 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29221 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29222 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29223 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29224 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29225 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29226 * @cfg {Number} width The width of the element in pixels (defaults to null)
29227 * @cfg {Number} height The height of the element in pixels (defaults to null)
29228 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29229 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29230 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29231 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29232 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29233 * in favor of the handles config option (defaults to false)
29234 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29235 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29236 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29237 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29238 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29239 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29240 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29241 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29242 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29243 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29244 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29246 * Create a new resizable component
29247 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29248 * @param {Object} config configuration options
29250 Roo.Resizable = function(el, config)
29252 this.el = Roo.get(el);
29254 if(config && config.wrap){
29255 config.resizeChild = this.el;
29256 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29257 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29258 this.el.setStyle("overflow", "hidden");
29259 this.el.setPositioning(config.resizeChild.getPositioning());
29260 config.resizeChild.clearPositioning();
29261 if(!config.width || !config.height){
29262 var csize = config.resizeChild.getSize();
29263 this.el.setSize(csize.width, csize.height);
29265 if(config.pinned && !config.adjustments){
29266 config.adjustments = "auto";
29270 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29271 this.proxy.unselectable();
29272 this.proxy.enableDisplayMode('block');
29274 Roo.apply(this, config);
29277 this.disableTrackOver = true;
29278 this.el.addClass("x-resizable-pinned");
29280 // if the element isn't positioned, make it relative
29281 var position = this.el.getStyle("position");
29282 if(position != "absolute" && position != "fixed"){
29283 this.el.setStyle("position", "relative");
29285 if(!this.handles){ // no handles passed, must be legacy style
29286 this.handles = 's,e,se';
29287 if(this.multiDirectional){
29288 this.handles += ',n,w';
29291 if(this.handles == "all"){
29292 this.handles = "n s e w ne nw se sw";
29294 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29295 var ps = Roo.Resizable.positions;
29296 for(var i = 0, len = hs.length; i < len; i++){
29297 if(hs[i] && ps[hs[i]]){
29298 var pos = ps[hs[i]];
29299 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29303 this.corner = this.southeast;
29305 // updateBox = the box can move..
29306 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29307 this.updateBox = true;
29310 this.activeHandle = null;
29312 if(this.resizeChild){
29313 if(typeof this.resizeChild == "boolean"){
29314 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29316 this.resizeChild = Roo.get(this.resizeChild, true);
29320 if(this.adjustments == "auto"){
29321 var rc = this.resizeChild;
29322 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29323 if(rc && (hw || hn)){
29324 rc.position("relative");
29325 rc.setLeft(hw ? hw.el.getWidth() : 0);
29326 rc.setTop(hn ? hn.el.getHeight() : 0);
29328 this.adjustments = [
29329 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29330 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29334 if(this.draggable){
29335 this.dd = this.dynamic ?
29336 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29337 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29343 * @event beforeresize
29344 * Fired before resize is allowed. Set enabled to false to cancel resize.
29345 * @param {Roo.Resizable} this
29346 * @param {Roo.EventObject} e The mousedown event
29348 "beforeresize" : true,
29351 * Fired a resizing.
29352 * @param {Roo.Resizable} this
29353 * @param {Number} x The new x position
29354 * @param {Number} y The new y position
29355 * @param {Number} w The new w width
29356 * @param {Number} h The new h hight
29357 * @param {Roo.EventObject} e The mouseup event
29362 * Fired after a resize.
29363 * @param {Roo.Resizable} this
29364 * @param {Number} width The new width
29365 * @param {Number} height The new height
29366 * @param {Roo.EventObject} e The mouseup event
29371 if(this.width !== null && this.height !== null){
29372 this.resizeTo(this.width, this.height);
29374 this.updateChildSize();
29377 this.el.dom.style.zoom = 1;
29379 Roo.Resizable.superclass.constructor.call(this);
29382 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29383 resizeChild : false,
29384 adjustments : [0, 0],
29394 multiDirectional : false,
29395 disableTrackOver : false,
29396 easing : 'easeOutStrong',
29397 widthIncrement : 0,
29398 heightIncrement : 0,
29402 preserveRatio : false,
29403 transparent: false,
29409 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29411 constrainTo: undefined,
29413 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29415 resizeRegion: undefined,
29419 * Perform a manual resize
29420 * @param {Number} width
29421 * @param {Number} height
29423 resizeTo : function(width, height){
29424 this.el.setSize(width, height);
29425 this.updateChildSize();
29426 this.fireEvent("resize", this, width, height, null);
29430 startSizing : function(e, handle){
29431 this.fireEvent("beforeresize", this, e);
29432 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29435 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29436 this.overlay.unselectable();
29437 this.overlay.enableDisplayMode("block");
29438 this.overlay.on("mousemove", this.onMouseMove, this);
29439 this.overlay.on("mouseup", this.onMouseUp, this);
29441 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29443 this.resizing = true;
29444 this.startBox = this.el.getBox();
29445 this.startPoint = e.getXY();
29446 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29447 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29449 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29450 this.overlay.show();
29452 if(this.constrainTo) {
29453 var ct = Roo.get(this.constrainTo);
29454 this.resizeRegion = ct.getRegion().adjust(
29455 ct.getFrameWidth('t'),
29456 ct.getFrameWidth('l'),
29457 -ct.getFrameWidth('b'),
29458 -ct.getFrameWidth('r')
29462 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29464 this.proxy.setBox(this.startBox);
29466 this.proxy.setStyle('visibility', 'visible');
29472 onMouseDown : function(handle, e){
29475 this.activeHandle = handle;
29476 this.startSizing(e, handle);
29481 onMouseUp : function(e){
29482 var size = this.resizeElement();
29483 this.resizing = false;
29485 this.overlay.hide();
29487 this.fireEvent("resize", this, size.width, size.height, e);
29491 updateChildSize : function(){
29493 if(this.resizeChild){
29495 var child = this.resizeChild;
29496 var adj = this.adjustments;
29497 if(el.dom.offsetWidth){
29498 var b = el.getSize(true);
29499 child.setSize(b.width+adj[0], b.height+adj[1]);
29501 // Second call here for IE
29502 // The first call enables instant resizing and
29503 // the second call corrects scroll bars if they
29506 setTimeout(function(){
29507 if(el.dom.offsetWidth){
29508 var b = el.getSize(true);
29509 child.setSize(b.width+adj[0], b.height+adj[1]);
29517 snap : function(value, inc, min){
29518 if(!inc || !value) return value;
29519 var newValue = value;
29520 var m = value % inc;
29523 newValue = value + (inc-m);
29525 newValue = value - m;
29528 return Math.max(min, newValue);
29532 resizeElement : function(){
29533 var box = this.proxy.getBox();
29534 if(this.updateBox){
29535 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29537 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29539 this.updateChildSize();
29547 constrain : function(v, diff, m, mx){
29550 }else if(v - diff > mx){
29557 onMouseMove : function(e){
29560 try{// try catch so if something goes wrong the user doesn't get hung
29562 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29566 //var curXY = this.startPoint;
29567 var curSize = this.curSize || this.startBox;
29568 var x = this.startBox.x, y = this.startBox.y;
29569 var ox = x, oy = y;
29570 var w = curSize.width, h = curSize.height;
29571 var ow = w, oh = h;
29572 var mw = this.minWidth, mh = this.minHeight;
29573 var mxw = this.maxWidth, mxh = this.maxHeight;
29574 var wi = this.widthIncrement;
29575 var hi = this.heightIncrement;
29577 var eventXY = e.getXY();
29578 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29579 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29581 var pos = this.activeHandle.position;
29586 w = Math.min(Math.max(mw, w), mxw);
29591 h = Math.min(Math.max(mh, h), mxh);
29596 w = Math.min(Math.max(mw, w), mxw);
29597 h = Math.min(Math.max(mh, h), mxh);
29600 diffY = this.constrain(h, diffY, mh, mxh);
29607 var adiffX = Math.abs(diffX);
29608 var sub = (adiffX % wi); // how much
29609 if (sub > (wi/2)) { // far enough to snap
29610 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29612 // remove difference..
29613 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29617 x = Math.max(this.minX, x);
29620 diffX = this.constrain(w, diffX, mw, mxw);
29626 w = Math.min(Math.max(mw, w), mxw);
29627 diffY = this.constrain(h, diffY, mh, mxh);
29632 diffX = this.constrain(w, diffX, mw, mxw);
29633 diffY = this.constrain(h, diffY, mh, mxh);
29640 diffX = this.constrain(w, diffX, mw, mxw);
29642 h = Math.min(Math.max(mh, h), mxh);
29648 var sw = this.snap(w, wi, mw);
29649 var sh = this.snap(h, hi, mh);
29650 if(sw != w || sh != h){
29673 if(this.preserveRatio){
29678 h = Math.min(Math.max(mh, h), mxh);
29683 w = Math.min(Math.max(mw, w), mxw);
29688 w = Math.min(Math.max(mw, w), mxw);
29694 w = Math.min(Math.max(mw, w), mxw);
29700 h = Math.min(Math.max(mh, h), mxh);
29708 h = Math.min(Math.max(mh, h), mxh);
29718 h = Math.min(Math.max(mh, h), mxh);
29726 if (pos == 'hdrag') {
29729 this.proxy.setBounds(x, y, w, h);
29731 this.resizeElement();
29735 this.fireEvent("resizing", this, x, y, w, h, e);
29739 handleOver : function(){
29741 this.el.addClass("x-resizable-over");
29746 handleOut : function(){
29747 if(!this.resizing){
29748 this.el.removeClass("x-resizable-over");
29753 * Returns the element this component is bound to.
29754 * @return {Roo.Element}
29756 getEl : function(){
29761 * Returns the resizeChild element (or null).
29762 * @return {Roo.Element}
29764 getResizeChild : function(){
29765 return this.resizeChild;
29767 groupHandler : function()
29772 * Destroys this resizable. If the element was wrapped and
29773 * removeEl is not true then the element remains.
29774 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29776 destroy : function(removeEl){
29777 this.proxy.remove();
29779 this.overlay.removeAllListeners();
29780 this.overlay.remove();
29782 var ps = Roo.Resizable.positions;
29784 if(typeof ps[k] != "function" && this[ps[k]]){
29785 var h = this[ps[k]];
29786 h.el.removeAllListeners();
29791 this.el.update("");
29798 // hash to map config positions to true positions
29799 Roo.Resizable.positions = {
29800 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29805 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29807 // only initialize the template if resizable is used
29808 var tpl = Roo.DomHelper.createTemplate(
29809 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29812 Roo.Resizable.Handle.prototype.tpl = tpl;
29814 this.position = pos;
29816 // show north drag fro topdra
29817 var handlepos = pos == 'hdrag' ? 'north' : pos;
29819 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29820 if (pos == 'hdrag') {
29821 this.el.setStyle('cursor', 'pointer');
29823 this.el.unselectable();
29825 this.el.setOpacity(0);
29827 this.el.on("mousedown", this.onMouseDown, this);
29828 if(!disableTrackOver){
29829 this.el.on("mouseover", this.onMouseOver, this);
29830 this.el.on("mouseout", this.onMouseOut, this);
29835 Roo.Resizable.Handle.prototype = {
29836 afterResize : function(rz){
29841 onMouseDown : function(e){
29842 this.rz.onMouseDown(this, e);
29845 onMouseOver : function(e){
29846 this.rz.handleOver(this, e);
29849 onMouseOut : function(e){
29850 this.rz.handleOut(this, e);
29854 * Ext JS Library 1.1.1
29855 * Copyright(c) 2006-2007, Ext JS, LLC.
29857 * Originally Released Under LGPL - original licence link has changed is not relivant.
29860 * <script type="text/javascript">
29864 * @class Roo.Editor
29865 * @extends Roo.Component
29866 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29868 * Create a new Editor
29869 * @param {Roo.form.Field} field The Field object (or descendant)
29870 * @param {Object} config The config object
29872 Roo.Editor = function(field, config){
29873 Roo.Editor.superclass.constructor.call(this, config);
29874 this.field = field;
29877 * @event beforestartedit
29878 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29879 * false from the handler of this event.
29880 * @param {Editor} this
29881 * @param {Roo.Element} boundEl The underlying element bound to this editor
29882 * @param {Mixed} value The field value being set
29884 "beforestartedit" : true,
29887 * Fires when this editor is displayed
29888 * @param {Roo.Element} boundEl The underlying element bound to this editor
29889 * @param {Mixed} value The starting field value
29891 "startedit" : true,
29893 * @event beforecomplete
29894 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29895 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29896 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29897 * event will not fire since no edit actually occurred.
29898 * @param {Editor} this
29899 * @param {Mixed} value The current field value
29900 * @param {Mixed} startValue The original field value
29902 "beforecomplete" : true,
29905 * Fires after editing is complete and any changed value has been written to the underlying field.
29906 * @param {Editor} this
29907 * @param {Mixed} value The current field value
29908 * @param {Mixed} startValue The original field value
29912 * @event specialkey
29913 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29914 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29915 * @param {Roo.form.Field} this
29916 * @param {Roo.EventObject} e The event object
29918 "specialkey" : true
29922 Roo.extend(Roo.Editor, Roo.Component, {
29924 * @cfg {Boolean/String} autosize
29925 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29926 * or "height" to adopt the height only (defaults to false)
29929 * @cfg {Boolean} revertInvalid
29930 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29931 * validation fails (defaults to true)
29934 * @cfg {Boolean} ignoreNoChange
29935 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29936 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29937 * will never be ignored.
29940 * @cfg {Boolean} hideEl
29941 * False to keep the bound element visible while the editor is displayed (defaults to true)
29944 * @cfg {Mixed} value
29945 * The data value of the underlying field (defaults to "")
29949 * @cfg {String} alignment
29950 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29954 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29955 * for bottom-right shadow (defaults to "frame")
29959 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29963 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29965 completeOnEnter : false,
29967 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29969 cancelOnEsc : false,
29971 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29976 onRender : function(ct, position){
29977 this.el = new Roo.Layer({
29978 shadow: this.shadow,
29984 constrain: this.constrain
29986 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29987 if(this.field.msgTarget != 'title'){
29988 this.field.msgTarget = 'qtip';
29990 this.field.render(this.el);
29992 this.field.el.dom.setAttribute('autocomplete', 'off');
29994 this.field.on("specialkey", this.onSpecialKey, this);
29995 if(this.swallowKeys){
29996 this.field.el.swallowEvent(['keydown','keypress']);
29999 this.field.on("blur", this.onBlur, this);
30000 if(this.field.grow){
30001 this.field.on("autosize", this.el.sync, this.el, {delay:1});
30005 onSpecialKey : function(field, e)
30007 //Roo.log('editor onSpecialKey');
30008 if(this.completeOnEnter && e.getKey() == e.ENTER){
30010 this.completeEdit();
30013 // do not fire special key otherwise it might hide close the editor...
30014 if(e.getKey() == e.ENTER){
30017 if(this.cancelOnEsc && e.getKey() == e.ESC){
30021 this.fireEvent('specialkey', field, e);
30026 * Starts the editing process and shows the editor.
30027 * @param {String/HTMLElement/Element} el The element to edit
30028 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
30029 * to the innerHTML of el.
30031 startEdit : function(el, value){
30033 this.completeEdit();
30035 this.boundEl = Roo.get(el);
30036 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
30037 if(!this.rendered){
30038 this.render(this.parentEl || document.body);
30040 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
30043 this.startValue = v;
30044 this.field.setValue(v);
30046 var sz = this.boundEl.getSize();
30047 switch(this.autoSize){
30049 this.setSize(sz.width, "");
30052 this.setSize("", sz.height);
30055 this.setSize(sz.width, sz.height);
30058 this.el.alignTo(this.boundEl, this.alignment);
30059 this.editing = true;
30061 Roo.QuickTips.disable();
30067 * Sets the height and width of this editor.
30068 * @param {Number} width The new width
30069 * @param {Number} height The new height
30071 setSize : function(w, h){
30072 this.field.setSize(w, h);
30079 * Realigns the editor to the bound field based on the current alignment config value.
30081 realign : function(){
30082 this.el.alignTo(this.boundEl, this.alignment);
30086 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
30087 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
30089 completeEdit : function(remainVisible){
30093 var v = this.getValue();
30094 if(this.revertInvalid !== false && !this.field.isValid()){
30095 v = this.startValue;
30096 this.cancelEdit(true);
30098 if(String(v) === String(this.startValue) && this.ignoreNoChange){
30099 this.editing = false;
30103 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
30104 this.editing = false;
30105 if(this.updateEl && this.boundEl){
30106 this.boundEl.update(v);
30108 if(remainVisible !== true){
30111 this.fireEvent("complete", this, v, this.startValue);
30116 onShow : function(){
30118 if(this.hideEl !== false){
30119 this.boundEl.hide();
30122 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
30123 this.fixIEFocus = true;
30124 this.deferredFocus.defer(50, this);
30126 this.field.focus();
30128 this.fireEvent("startedit", this.boundEl, this.startValue);
30131 deferredFocus : function(){
30133 this.field.focus();
30138 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
30139 * reverted to the original starting value.
30140 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
30141 * cancel (defaults to false)
30143 cancelEdit : function(remainVisible){
30145 this.setValue(this.startValue);
30146 if(remainVisible !== true){
30153 onBlur : function(){
30154 if(this.allowBlur !== true && this.editing){
30155 this.completeEdit();
30160 onHide : function(){
30162 this.completeEdit();
30166 if(this.field.collapse){
30167 this.field.collapse();
30170 if(this.hideEl !== false){
30171 this.boundEl.show();
30174 Roo.QuickTips.enable();
30179 * Sets the data value of the editor
30180 * @param {Mixed} value Any valid value supported by the underlying field
30182 setValue : function(v){
30183 this.field.setValue(v);
30187 * Gets the data value of the editor
30188 * @return {Mixed} The data value
30190 getValue : function(){
30191 return this.field.getValue();
30195 * Ext JS Library 1.1.1
30196 * Copyright(c) 2006-2007, Ext JS, LLC.
30198 * Originally Released Under LGPL - original licence link has changed is not relivant.
30201 * <script type="text/javascript">
30205 * @class Roo.BasicDialog
30206 * @extends Roo.util.Observable
30207 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
30209 var dlg = new Roo.BasicDialog("my-dlg", {
30218 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30219 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30220 dlg.addButton('Cancel', dlg.hide, dlg);
30223 <b>A Dialog should always be a direct child of the body element.</b>
30224 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30225 * @cfg {String} title Default text to display in the title bar (defaults to null)
30226 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30227 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30228 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30229 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30230 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30231 * (defaults to null with no animation)
30232 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30233 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30234 * property for valid values (defaults to 'all')
30235 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30236 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30237 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30238 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30239 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30240 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30241 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30242 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30243 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30244 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30245 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30246 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30247 * draggable = true (defaults to false)
30248 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30249 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30250 * shadow (defaults to false)
30251 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30252 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30253 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30254 * @cfg {Array} buttons Array of buttons
30255 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30257 * Create a new BasicDialog.
30258 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30259 * @param {Object} config Configuration options
30261 Roo.BasicDialog = function(el, config){
30262 this.el = Roo.get(el);
30263 var dh = Roo.DomHelper;
30264 if(!this.el && config && config.autoCreate){
30265 if(typeof config.autoCreate == "object"){
30266 if(!config.autoCreate.id){
30267 config.autoCreate.id = el;
30269 this.el = dh.append(document.body,
30270 config.autoCreate, true);
30272 this.el = dh.append(document.body,
30273 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30277 el.setDisplayed(true);
30278 el.hide = this.hideAction;
30280 el.addClass("x-dlg");
30282 Roo.apply(this, config);
30284 this.proxy = el.createProxy("x-dlg-proxy");
30285 this.proxy.hide = this.hideAction;
30286 this.proxy.setOpacity(.5);
30290 el.setWidth(config.width);
30293 el.setHeight(config.height);
30295 this.size = el.getSize();
30296 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30297 this.xy = [config.x,config.y];
30299 this.xy = el.getCenterXY(true);
30301 /** The header element @type Roo.Element */
30302 this.header = el.child("> .x-dlg-hd");
30303 /** The body element @type Roo.Element */
30304 this.body = el.child("> .x-dlg-bd");
30305 /** The footer element @type Roo.Element */
30306 this.footer = el.child("> .x-dlg-ft");
30309 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30312 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30315 this.header.unselectable();
30317 this.header.update(this.title);
30319 // this element allows the dialog to be focused for keyboard event
30320 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30321 this.focusEl.swallowEvent("click", true);
30323 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30325 // wrap the body and footer for special rendering
30326 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30328 this.bwrap.dom.appendChild(this.footer.dom);
30331 this.bg = this.el.createChild({
30332 tag: "div", cls:"x-dlg-bg",
30333 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30335 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30338 if(this.autoScroll !== false && !this.autoTabs){
30339 this.body.setStyle("overflow", "auto");
30342 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30344 if(this.closable !== false){
30345 this.el.addClass("x-dlg-closable");
30346 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30347 this.close.on("click", this.closeClick, this);
30348 this.close.addClassOnOver("x-dlg-close-over");
30350 if(this.collapsible !== false){
30351 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30352 this.collapseBtn.on("click", this.collapseClick, this);
30353 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30354 this.header.on("dblclick", this.collapseClick, this);
30356 if(this.resizable !== false){
30357 this.el.addClass("x-dlg-resizable");
30358 this.resizer = new Roo.Resizable(el, {
30359 minWidth: this.minWidth || 80,
30360 minHeight:this.minHeight || 80,
30361 handles: this.resizeHandles || "all",
30364 this.resizer.on("beforeresize", this.beforeResize, this);
30365 this.resizer.on("resize", this.onResize, this);
30367 if(this.draggable !== false){
30368 el.addClass("x-dlg-draggable");
30369 if (!this.proxyDrag) {
30370 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30373 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30375 dd.setHandleElId(this.header.id);
30376 dd.endDrag = this.endMove.createDelegate(this);
30377 dd.startDrag = this.startMove.createDelegate(this);
30378 dd.onDrag = this.onDrag.createDelegate(this);
30383 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30384 this.mask.enableDisplayMode("block");
30386 this.el.addClass("x-dlg-modal");
30389 this.shadow = new Roo.Shadow({
30390 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30391 offset : this.shadowOffset
30394 this.shadowOffset = 0;
30396 if(Roo.useShims && this.shim !== false){
30397 this.shim = this.el.createShim();
30398 this.shim.hide = this.hideAction;
30406 if (this.buttons) {
30407 var bts= this.buttons;
30409 Roo.each(bts, function(b) {
30418 * Fires when a key is pressed
30419 * @param {Roo.BasicDialog} this
30420 * @param {Roo.EventObject} e
30425 * Fires when this dialog is moved by the user.
30426 * @param {Roo.BasicDialog} this
30427 * @param {Number} x The new page X
30428 * @param {Number} y The new page Y
30433 * Fires when this dialog is resized by the user.
30434 * @param {Roo.BasicDialog} this
30435 * @param {Number} width The new width
30436 * @param {Number} height The new height
30440 * @event beforehide
30441 * Fires before this dialog is hidden.
30442 * @param {Roo.BasicDialog} this
30444 "beforehide" : true,
30447 * Fires when this dialog is hidden.
30448 * @param {Roo.BasicDialog} this
30452 * @event beforeshow
30453 * Fires before this dialog is shown.
30454 * @param {Roo.BasicDialog} this
30456 "beforeshow" : true,
30459 * Fires when this dialog is shown.
30460 * @param {Roo.BasicDialog} this
30464 el.on("keydown", this.onKeyDown, this);
30465 el.on("mousedown", this.toFront, this);
30466 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30468 Roo.DialogManager.register(this);
30469 Roo.BasicDialog.superclass.constructor.call(this);
30472 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30473 shadowOffset: Roo.isIE ? 6 : 5,
30476 minButtonWidth: 75,
30477 defaultButton: null,
30478 buttonAlign: "right",
30483 * Sets the dialog title text
30484 * @param {String} text The title text to display
30485 * @return {Roo.BasicDialog} this
30487 setTitle : function(text){
30488 this.header.update(text);
30493 closeClick : function(){
30498 collapseClick : function(){
30499 this[this.collapsed ? "expand" : "collapse"]();
30503 * Collapses the dialog to its minimized state (only the title bar is visible).
30504 * Equivalent to the user clicking the collapse dialog button.
30506 collapse : function(){
30507 if(!this.collapsed){
30508 this.collapsed = true;
30509 this.el.addClass("x-dlg-collapsed");
30510 this.restoreHeight = this.el.getHeight();
30511 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30516 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30517 * clicking the expand dialog button.
30519 expand : function(){
30520 if(this.collapsed){
30521 this.collapsed = false;
30522 this.el.removeClass("x-dlg-collapsed");
30523 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30528 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30529 * @return {Roo.TabPanel} The tabs component
30531 initTabs : function(){
30532 var tabs = this.getTabs();
30533 while(tabs.getTab(0)){
30536 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30538 tabs.addTab(Roo.id(dom), dom.title);
30546 beforeResize : function(){
30547 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30551 onResize : function(){
30552 this.refreshSize();
30553 this.syncBodyHeight();
30554 this.adjustAssets();
30556 this.fireEvent("resize", this, this.size.width, this.size.height);
30560 onKeyDown : function(e){
30561 if(this.isVisible()){
30562 this.fireEvent("keydown", this, e);
30567 * Resizes the dialog.
30568 * @param {Number} width
30569 * @param {Number} height
30570 * @return {Roo.BasicDialog} this
30572 resizeTo : function(width, height){
30573 this.el.setSize(width, height);
30574 this.size = {width: width, height: height};
30575 this.syncBodyHeight();
30576 if(this.fixedcenter){
30579 if(this.isVisible()){
30580 this.constrainXY();
30581 this.adjustAssets();
30583 this.fireEvent("resize", this, width, height);
30589 * Resizes the dialog to fit the specified content size.
30590 * @param {Number} width
30591 * @param {Number} height
30592 * @return {Roo.BasicDialog} this
30594 setContentSize : function(w, h){
30595 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30596 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30597 //if(!this.el.isBorderBox()){
30598 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30599 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30602 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30603 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30605 this.resizeTo(w, h);
30610 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30611 * executed in response to a particular key being pressed while the dialog is active.
30612 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30613 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30614 * @param {Function} fn The function to call
30615 * @param {Object} scope (optional) The scope of the function
30616 * @return {Roo.BasicDialog} this
30618 addKeyListener : function(key, fn, scope){
30619 var keyCode, shift, ctrl, alt;
30620 if(typeof key == "object" && !(key instanceof Array)){
30621 keyCode = key["key"];
30622 shift = key["shift"];
30623 ctrl = key["ctrl"];
30628 var handler = function(dlg, e){
30629 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30630 var k = e.getKey();
30631 if(keyCode instanceof Array){
30632 for(var i = 0, len = keyCode.length; i < len; i++){
30633 if(keyCode[i] == k){
30634 fn.call(scope || window, dlg, k, e);
30640 fn.call(scope || window, dlg, k, e);
30645 this.on("keydown", handler);
30650 * Returns the TabPanel component (creates it if it doesn't exist).
30651 * Note: If you wish to simply check for the existence of tabs without creating them,
30652 * check for a null 'tabs' property.
30653 * @return {Roo.TabPanel} The tabs component
30655 getTabs : function(){
30657 this.el.addClass("x-dlg-auto-tabs");
30658 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30659 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30665 * Adds a button to the footer section of the dialog.
30666 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30667 * object or a valid Roo.DomHelper element config
30668 * @param {Function} handler The function called when the button is clicked
30669 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30670 * @return {Roo.Button} The new button
30672 addButton : function(config, handler, scope){
30673 var dh = Roo.DomHelper;
30675 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30677 if(!this.btnContainer){
30678 var tb = this.footer.createChild({
30680 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30681 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30683 this.btnContainer = tb.firstChild.firstChild.firstChild;
30688 minWidth: this.minButtonWidth,
30691 if(typeof config == "string"){
30692 bconfig.text = config;
30695 bconfig.dhconfig = config;
30697 Roo.apply(bconfig, config);
30701 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30702 bconfig.position = Math.max(0, bconfig.position);
30703 fc = this.btnContainer.childNodes[bconfig.position];
30706 var btn = new Roo.Button(
30708 this.btnContainer.insertBefore(document.createElement("td"),fc)
30709 : this.btnContainer.appendChild(document.createElement("td")),
30710 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30713 this.syncBodyHeight();
30716 * Array of all the buttons that have been added to this dialog via addButton
30721 this.buttons.push(btn);
30726 * Sets the default button to be focused when the dialog is displayed.
30727 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30728 * @return {Roo.BasicDialog} this
30730 setDefaultButton : function(btn){
30731 this.defaultButton = btn;
30736 getHeaderFooterHeight : function(safe){
30739 height += this.header.getHeight();
30742 var fm = this.footer.getMargins();
30743 height += (this.footer.getHeight()+fm.top+fm.bottom);
30745 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30746 height += this.centerBg.getPadding("tb");
30751 syncBodyHeight : function()
30753 var bd = this.body, // the text
30754 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30756 var height = this.size.height - this.getHeaderFooterHeight(false);
30757 bd.setHeight(height-bd.getMargins("tb"));
30758 var hh = this.header.getHeight();
30759 var h = this.size.height-hh;
30762 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30763 bw.setHeight(h-cb.getPadding("tb"));
30765 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30766 bd.setWidth(bw.getWidth(true));
30768 this.tabs.syncHeight();
30770 this.tabs.el.repaint();
30776 * Restores the previous state of the dialog if Roo.state is configured.
30777 * @return {Roo.BasicDialog} this
30779 restoreState : function(){
30780 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30781 if(box && box.width){
30782 this.xy = [box.x, box.y];
30783 this.resizeTo(box.width, box.height);
30789 beforeShow : function(){
30791 if(this.fixedcenter){
30792 this.xy = this.el.getCenterXY(true);
30795 Roo.get(document.body).addClass("x-body-masked");
30796 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30799 this.constrainXY();
30803 animShow : function(){
30804 var b = Roo.get(this.animateTarget).getBox();
30805 this.proxy.setSize(b.width, b.height);
30806 this.proxy.setLocation(b.x, b.y);
30808 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30809 true, .35, this.showEl.createDelegate(this));
30813 * Shows the dialog.
30814 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30815 * @return {Roo.BasicDialog} this
30817 show : function(animateTarget){
30818 if (this.fireEvent("beforeshow", this) === false){
30821 if(this.syncHeightBeforeShow){
30822 this.syncBodyHeight();
30823 }else if(this.firstShow){
30824 this.firstShow = false;
30825 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30827 this.animateTarget = animateTarget || this.animateTarget;
30828 if(!this.el.isVisible()){
30830 if(this.animateTarget && Roo.get(this.animateTarget)){
30840 showEl : function(){
30842 this.el.setXY(this.xy);
30844 this.adjustAssets(true);
30847 // IE peekaboo bug - fix found by Dave Fenwick
30851 this.fireEvent("show", this);
30855 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30856 * dialog itself will receive focus.
30858 focus : function(){
30859 if(this.defaultButton){
30860 this.defaultButton.focus();
30862 this.focusEl.focus();
30867 constrainXY : function(){
30868 if(this.constraintoviewport !== false){
30869 if(!this.viewSize){
30870 if(this.container){
30871 var s = this.container.getSize();
30872 this.viewSize = [s.width, s.height];
30874 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30877 var s = Roo.get(this.container||document).getScroll();
30879 var x = this.xy[0], y = this.xy[1];
30880 var w = this.size.width, h = this.size.height;
30881 var vw = this.viewSize[0], vh = this.viewSize[1];
30882 // only move it if it needs it
30884 // first validate right/bottom
30885 if(x + w > vw+s.left){
30889 if(y + h > vh+s.top){
30893 // then make sure top/left isn't negative
30905 if(this.isVisible()){
30906 this.el.setLocation(x, y);
30907 this.adjustAssets();
30914 onDrag : function(){
30915 if(!this.proxyDrag){
30916 this.xy = this.el.getXY();
30917 this.adjustAssets();
30922 adjustAssets : function(doShow){
30923 var x = this.xy[0], y = this.xy[1];
30924 var w = this.size.width, h = this.size.height;
30925 if(doShow === true){
30927 this.shadow.show(this.el);
30933 if(this.shadow && this.shadow.isVisible()){
30934 this.shadow.show(this.el);
30936 if(this.shim && this.shim.isVisible()){
30937 this.shim.setBounds(x, y, w, h);
30942 adjustViewport : function(w, h){
30944 w = Roo.lib.Dom.getViewWidth();
30945 h = Roo.lib.Dom.getViewHeight();
30948 this.viewSize = [w, h];
30949 if(this.modal && this.mask.isVisible()){
30950 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30951 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30953 if(this.isVisible()){
30954 this.constrainXY();
30959 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30960 * shadow, proxy, mask, etc.) Also removes all event listeners.
30961 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30963 destroy : function(removeEl){
30964 if(this.isVisible()){
30965 this.animateTarget = null;
30968 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30970 this.tabs.destroy(removeEl);
30983 for(var i = 0, len = this.buttons.length; i < len; i++){
30984 this.buttons[i].destroy();
30987 this.el.removeAllListeners();
30988 if(removeEl === true){
30989 this.el.update("");
30992 Roo.DialogManager.unregister(this);
30996 startMove : function(){
30997 if(this.proxyDrag){
31000 if(this.constraintoviewport !== false){
31001 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
31006 endMove : function(){
31007 if(!this.proxyDrag){
31008 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
31010 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
31013 this.refreshSize();
31014 this.adjustAssets();
31016 this.fireEvent("move", this, this.xy[0], this.xy[1]);
31020 * Brings this dialog to the front of any other visible dialogs
31021 * @return {Roo.BasicDialog} this
31023 toFront : function(){
31024 Roo.DialogManager.bringToFront(this);
31029 * Sends this dialog to the back (under) of any other visible dialogs
31030 * @return {Roo.BasicDialog} this
31032 toBack : function(){
31033 Roo.DialogManager.sendToBack(this);
31038 * Centers this dialog in the viewport
31039 * @return {Roo.BasicDialog} this
31041 center : function(){
31042 var xy = this.el.getCenterXY(true);
31043 this.moveTo(xy[0], xy[1]);
31048 * Moves the dialog's top-left corner to the specified point
31049 * @param {Number} x
31050 * @param {Number} y
31051 * @return {Roo.BasicDialog} this
31053 moveTo : function(x, y){
31055 if(this.isVisible()){
31056 this.el.setXY(this.xy);
31057 this.adjustAssets();
31063 * Aligns the dialog to the specified element
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 * @return {Roo.BasicDialog} this
31069 alignTo : function(element, position, offsets){
31070 this.xy = this.el.getAlignToXY(element, position, offsets);
31071 if(this.isVisible()){
31072 this.el.setXY(this.xy);
31073 this.adjustAssets();
31079 * Anchors an element to another element and realigns it when the window is resized.
31080 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31081 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
31082 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31083 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
31084 * is a number, it is used as the buffer delay (defaults to 50ms).
31085 * @return {Roo.BasicDialog} this
31087 anchorTo : function(el, alignment, offsets, monitorScroll){
31088 var action = function(){
31089 this.alignTo(el, alignment, offsets);
31091 Roo.EventManager.onWindowResize(action, this);
31092 var tm = typeof monitorScroll;
31093 if(tm != 'undefined'){
31094 Roo.EventManager.on(window, 'scroll', action, this,
31095 {buffer: tm == 'number' ? monitorScroll : 50});
31102 * Returns true if the dialog is visible
31103 * @return {Boolean}
31105 isVisible : function(){
31106 return this.el.isVisible();
31110 animHide : function(callback){
31111 var b = Roo.get(this.animateTarget).getBox();
31113 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
31115 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
31116 this.hideEl.createDelegate(this, [callback]));
31120 * Hides the dialog.
31121 * @param {Function} callback (optional) Function to call when the dialog is hidden
31122 * @return {Roo.BasicDialog} this
31124 hide : function(callback){
31125 if (this.fireEvent("beforehide", this) === false){
31129 this.shadow.hide();
31134 // sometimes animateTarget seems to get set.. causing problems...
31135 // this just double checks..
31136 if(this.animateTarget && Roo.get(this.animateTarget)) {
31137 this.animHide(callback);
31140 this.hideEl(callback);
31146 hideEl : function(callback){
31150 Roo.get(document.body).removeClass("x-body-masked");
31152 this.fireEvent("hide", this);
31153 if(typeof callback == "function"){
31159 hideAction : function(){
31160 this.setLeft("-10000px");
31161 this.setTop("-10000px");
31162 this.setStyle("visibility", "hidden");
31166 refreshSize : function(){
31167 this.size = this.el.getSize();
31168 this.xy = this.el.getXY();
31169 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
31173 // z-index is managed by the DialogManager and may be overwritten at any time
31174 setZIndex : function(index){
31176 this.mask.setStyle("z-index", index);
31179 this.shim.setStyle("z-index", ++index);
31182 this.shadow.setZIndex(++index);
31184 this.el.setStyle("z-index", ++index);
31186 this.proxy.setStyle("z-index", ++index);
31189 this.resizer.proxy.setStyle("z-index", ++index);
31192 this.lastZIndex = index;
31196 * Returns the element for this dialog
31197 * @return {Roo.Element} The underlying dialog Element
31199 getEl : function(){
31205 * @class Roo.DialogManager
31206 * Provides global access to BasicDialogs that have been created and
31207 * support for z-indexing (layering) multiple open dialogs.
31209 Roo.DialogManager = function(){
31211 var accessList = [];
31215 var sortDialogs = function(d1, d2){
31216 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31220 var orderDialogs = function(){
31221 accessList.sort(sortDialogs);
31222 var seed = Roo.DialogManager.zseed;
31223 for(var i = 0, len = accessList.length; i < len; i++){
31224 var dlg = accessList[i];
31226 dlg.setZIndex(seed + (i*10));
31233 * The starting z-index for BasicDialogs (defaults to 9000)
31234 * @type Number The z-index value
31239 register : function(dlg){
31240 list[dlg.id] = dlg;
31241 accessList.push(dlg);
31245 unregister : function(dlg){
31246 delete list[dlg.id];
31249 if(!accessList.indexOf){
31250 for( i = 0, len = accessList.length; i < len; i++){
31251 if(accessList[i] == dlg){
31252 accessList.splice(i, 1);
31257 i = accessList.indexOf(dlg);
31259 accessList.splice(i, 1);
31265 * Gets a registered dialog by id
31266 * @param {String/Object} id The id of the dialog or a dialog
31267 * @return {Roo.BasicDialog} this
31269 get : function(id){
31270 return typeof id == "object" ? id : list[id];
31274 * Brings the specified dialog to the front
31275 * @param {String/Object} dlg The id of the dialog or a dialog
31276 * @return {Roo.BasicDialog} this
31278 bringToFront : function(dlg){
31279 dlg = this.get(dlg);
31282 dlg._lastAccess = new Date().getTime();
31289 * Sends the specified dialog to the back
31290 * @param {String/Object} dlg The id of the dialog or a dialog
31291 * @return {Roo.BasicDialog} this
31293 sendToBack : function(dlg){
31294 dlg = this.get(dlg);
31295 dlg._lastAccess = -(new Date().getTime());
31301 * Hides all dialogs
31303 hideAll : function(){
31304 for(var id in list){
31305 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31314 * @class Roo.LayoutDialog
31315 * @extends Roo.BasicDialog
31316 * Dialog which provides adjustments for working with a layout in a Dialog.
31317 * Add your necessary layout config options to the dialog's config.<br>
31318 * Example usage (including a nested layout):
31321 dialog = new Roo.LayoutDialog("download-dlg", {
31330 // layout config merges with the dialog config
31332 tabPosition: "top",
31333 alwaysShowTabs: true
31336 dialog.addKeyListener(27, dialog.hide, dialog);
31337 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31338 dialog.addButton("Build It!", this.getDownload, this);
31340 // we can even add nested layouts
31341 var innerLayout = new Roo.BorderLayout("dl-inner", {
31351 innerLayout.beginUpdate();
31352 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31353 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31354 innerLayout.endUpdate(true);
31356 var layout = dialog.getLayout();
31357 layout.beginUpdate();
31358 layout.add("center", new Roo.ContentPanel("standard-panel",
31359 {title: "Download the Source", fitToFrame:true}));
31360 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31361 {title: "Build your own roo.js"}));
31362 layout.getRegion("center").showPanel(sp);
31363 layout.endUpdate();
31367 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31368 * @param {Object} config configuration options
31370 Roo.LayoutDialog = function(el, cfg){
31373 if (typeof(cfg) == 'undefined') {
31374 config = Roo.apply({}, el);
31375 // not sure why we use documentElement here.. - it should always be body.
31376 // IE7 borks horribly if we use documentElement.
31377 // webkit also does not like documentElement - it creates a body element...
31378 el = Roo.get( document.body || document.documentElement ).createChild();
31379 //config.autoCreate = true;
31383 config.autoTabs = false;
31384 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31385 this.body.setStyle({overflow:"hidden", position:"relative"});
31386 this.layout = new Roo.BorderLayout(this.body.dom, config);
31387 this.layout.monitorWindowResize = false;
31388 this.el.addClass("x-dlg-auto-layout");
31389 // fix case when center region overwrites center function
31390 this.center = Roo.BasicDialog.prototype.center;
31391 this.on("show", this.layout.layout, this.layout, true);
31392 if (config.items) {
31393 var xitems = config.items;
31394 delete config.items;
31395 Roo.each(xitems, this.addxtype, this);
31400 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31402 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31405 endUpdate : function(){
31406 this.layout.endUpdate();
31410 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31413 beginUpdate : function(){
31414 this.layout.beginUpdate();
31418 * Get the BorderLayout for this dialog
31419 * @return {Roo.BorderLayout}
31421 getLayout : function(){
31422 return this.layout;
31425 showEl : function(){
31426 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31428 this.layout.layout();
31433 // Use the syncHeightBeforeShow config option to control this automatically
31434 syncBodyHeight : function(){
31435 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31436 if(this.layout){this.layout.layout();}
31440 * Add an xtype element (actually adds to the layout.)
31441 * @return {Object} xdata xtype object data.
31444 addxtype : function(c) {
31445 return this.layout.addxtype(c);
31449 * Ext JS Library 1.1.1
31450 * Copyright(c) 2006-2007, Ext JS, LLC.
31452 * Originally Released Under LGPL - original licence link has changed is not relivant.
31455 * <script type="text/javascript">
31459 * @class Roo.MessageBox
31460 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31464 Roo.Msg.alert('Status', 'Changes saved successfully.');
31466 // Prompt for user data:
31467 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31469 // process text value...
31473 // Show a dialog using config options:
31475 title:'Save Changes?',
31476 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31477 buttons: Roo.Msg.YESNOCANCEL,
31484 Roo.MessageBox = function(){
31485 var dlg, opt, mask, waitTimer;
31486 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31487 var buttons, activeTextEl, bwidth;
31490 var handleButton = function(button){
31492 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31496 var handleHide = function(){
31497 if(opt && opt.cls){
31498 dlg.el.removeClass(opt.cls);
31501 Roo.TaskMgr.stop(waitTimer);
31507 var updateButtons = function(b){
31510 buttons["ok"].hide();
31511 buttons["cancel"].hide();
31512 buttons["yes"].hide();
31513 buttons["no"].hide();
31514 dlg.footer.dom.style.display = 'none';
31517 dlg.footer.dom.style.display = '';
31518 for(var k in buttons){
31519 if(typeof buttons[k] != "function"){
31522 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31523 width += buttons[k].el.getWidth()+15;
31533 var handleEsc = function(d, k, e){
31534 if(opt && opt.closable !== false){
31544 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31545 * @return {Roo.BasicDialog} The BasicDialog element
31547 getDialog : function(){
31549 dlg = new Roo.BasicDialog("x-msg-box", {
31554 constraintoviewport:false,
31556 collapsible : false,
31559 width:400, height:100,
31560 buttonAlign:"center",
31561 closeClick : function(){
31562 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31563 handleButton("no");
31565 handleButton("cancel");
31569 dlg.on("hide", handleHide);
31571 dlg.addKeyListener(27, handleEsc);
31573 var bt = this.buttonText;
31574 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31575 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31576 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31577 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31578 bodyEl = dlg.body.createChild({
31580 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>'
31582 msgEl = bodyEl.dom.firstChild;
31583 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31584 textboxEl.enableDisplayMode();
31585 textboxEl.addKeyListener([10,13], function(){
31586 if(dlg.isVisible() && opt && opt.buttons){
31587 if(opt.buttons.ok){
31588 handleButton("ok");
31589 }else if(opt.buttons.yes){
31590 handleButton("yes");
31594 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31595 textareaEl.enableDisplayMode();
31596 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31597 progressEl.enableDisplayMode();
31598 var pf = progressEl.dom.firstChild;
31600 pp = Roo.get(pf.firstChild);
31601 pp.setHeight(pf.offsetHeight);
31609 * Updates the message box body text
31610 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31611 * the XHTML-compliant non-breaking space character '&#160;')
31612 * @return {Roo.MessageBox} This message box
31614 updateText : function(text){
31615 if(!dlg.isVisible() && !opt.width){
31616 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31618 msgEl.innerHTML = text || ' ';
31620 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31621 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31623 Math.min(opt.width || cw , this.maxWidth),
31624 Math.max(opt.minWidth || this.minWidth, bwidth)
31627 activeTextEl.setWidth(w);
31629 if(dlg.isVisible()){
31630 dlg.fixedcenter = false;
31632 // to big, make it scroll. = But as usual stupid IE does not support
31635 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31636 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31637 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31639 bodyEl.dom.style.height = '';
31640 bodyEl.dom.style.overflowY = '';
31643 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31645 bodyEl.dom.style.overflowX = '';
31648 dlg.setContentSize(w, bodyEl.getHeight());
31649 if(dlg.isVisible()){
31650 dlg.fixedcenter = true;
31656 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31657 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31658 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31659 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31660 * @return {Roo.MessageBox} This message box
31662 updateProgress : function(value, text){
31664 this.updateText(text);
31666 if (pp) { // weird bug on my firefox - for some reason this is not defined
31667 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31673 * Returns true if the message box is currently displayed
31674 * @return {Boolean} True if the message box is visible, else false
31676 isVisible : function(){
31677 return dlg && dlg.isVisible();
31681 * Hides the message box if it is displayed
31684 if(this.isVisible()){
31690 * Displays a new message box, or reinitializes an existing message box, based on the config options
31691 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31692 * The following config object properties are supported:
31694 Property Type Description
31695 ---------- --------------- ------------------------------------------------------------------------------------
31696 animEl String/Element An id or Element from which the message box should animate as it opens and
31697 closes (defaults to undefined)
31698 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31699 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31700 closable Boolean False to hide the top-right close button (defaults to true). Note that
31701 progress and wait dialogs will ignore this property and always hide the
31702 close button as they can only be closed programmatically.
31703 cls String A custom CSS class to apply to the message box element
31704 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31705 displayed (defaults to 75)
31706 fn Function A callback function to execute after closing the dialog. The arguments to the
31707 function will be btn (the name of the button that was clicked, if applicable,
31708 e.g. "ok"), and text (the value of the active text field, if applicable).
31709 Progress and wait dialogs will ignore this option since they do not respond to
31710 user actions and can only be closed programmatically, so any required function
31711 should be called by the same code after it closes the dialog.
31712 icon String A CSS class that provides a background image to be used as an icon for
31713 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31714 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31715 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31716 modal Boolean False to allow user interaction with the page while the message box is
31717 displayed (defaults to true)
31718 msg String A string that will replace the existing message box body text (defaults
31719 to the XHTML-compliant non-breaking space character ' ')
31720 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31721 progress Boolean True to display a progress bar (defaults to false)
31722 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31723 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31724 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31725 title String The title text
31726 value String The string value to set into the active textbox element if displayed
31727 wait Boolean True to display a progress bar (defaults to false)
31728 width Number The width of the dialog in pixels
31735 msg: 'Please enter your address:',
31737 buttons: Roo.MessageBox.OKCANCEL,
31740 animEl: 'addAddressBtn'
31743 * @param {Object} config Configuration options
31744 * @return {Roo.MessageBox} This message box
31746 show : function(options)
31749 // this causes nightmares if you show one dialog after another
31750 // especially on callbacks..
31752 if(this.isVisible()){
31755 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31756 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31757 Roo.log("New Dialog Message:" + options.msg )
31758 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31759 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31762 var d = this.getDialog();
31764 d.setTitle(opt.title || " ");
31765 d.close.setDisplayed(opt.closable !== false);
31766 activeTextEl = textboxEl;
31767 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31772 textareaEl.setHeight(typeof opt.multiline == "number" ?
31773 opt.multiline : this.defaultTextHeight);
31774 activeTextEl = textareaEl;
31783 progressEl.setDisplayed(opt.progress === true);
31784 this.updateProgress(0);
31785 activeTextEl.dom.value = opt.value || "";
31787 dlg.setDefaultButton(activeTextEl);
31789 var bs = opt.buttons;
31792 db = buttons["ok"];
31793 }else if(bs && bs.yes){
31794 db = buttons["yes"];
31796 dlg.setDefaultButton(db);
31798 bwidth = updateButtons(opt.buttons);
31799 this.updateText(opt.msg);
31801 d.el.addClass(opt.cls);
31803 d.proxyDrag = opt.proxyDrag === true;
31804 d.modal = opt.modal !== false;
31805 d.mask = opt.modal !== false ? mask : false;
31806 if(!d.isVisible()){
31807 // force it to the end of the z-index stack so it gets a cursor in FF
31808 document.body.appendChild(dlg.el.dom);
31809 d.animateTarget = null;
31810 d.show(options.animEl);
31816 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31817 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31818 * and closing the message box when the process is complete.
31819 * @param {String} title The title bar text
31820 * @param {String} msg The message box body text
31821 * @return {Roo.MessageBox} This message box
31823 progress : function(title, msg){
31830 minWidth: this.minProgressWidth,
31837 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31838 * If a callback function is passed it will be called after the user clicks the button, and the
31839 * id of the button that was clicked will be passed as the only parameter to the callback
31840 * (could also be the top-right close button).
31841 * @param {String} title The title bar text
31842 * @param {String} msg The message box body text
31843 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31844 * @param {Object} scope (optional) The scope of the callback function
31845 * @return {Roo.MessageBox} This message box
31847 alert : function(title, msg, fn, scope){
31860 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31861 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31862 * You are responsible for closing the message box when the process is complete.
31863 * @param {String} msg The message box body text
31864 * @param {String} title (optional) The title bar text
31865 * @return {Roo.MessageBox} This message box
31867 wait : function(msg, title){
31878 waitTimer = Roo.TaskMgr.start({
31880 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31888 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31889 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31890 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31891 * @param {String} title The title bar text
31892 * @param {String} msg The message box body text
31893 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31894 * @param {Object} scope (optional) The scope of the callback function
31895 * @return {Roo.MessageBox} This message box
31897 confirm : function(title, msg, fn, scope){
31901 buttons: this.YESNO,
31910 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31911 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31912 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31913 * (could also be the top-right close button) and the text that was entered will be passed as the two
31914 * parameters to the callback.
31915 * @param {String} title The title bar text
31916 * @param {String} msg The message box body text
31917 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31918 * @param {Object} scope (optional) The scope of the callback function
31919 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31920 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31921 * @return {Roo.MessageBox} This message box
31923 prompt : function(title, msg, fn, scope, multiline){
31927 buttons: this.OKCANCEL,
31932 multiline: multiline,
31939 * Button config that displays a single OK button
31944 * Button config that displays Yes and No buttons
31947 YESNO : {yes:true, no:true},
31949 * Button config that displays OK and Cancel buttons
31952 OKCANCEL : {ok:true, cancel:true},
31954 * Button config that displays Yes, No and Cancel buttons
31957 YESNOCANCEL : {yes:true, no:true, cancel:true},
31960 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31963 defaultTextHeight : 75,
31965 * The maximum width in pixels of the message box (defaults to 600)
31970 * The minimum width in pixels of the message box (defaults to 100)
31975 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31976 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31979 minProgressWidth : 250,
31981 * An object containing the default button text strings that can be overriden for localized language support.
31982 * Supported properties are: ok, cancel, yes and no.
31983 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31996 * Shorthand for {@link Roo.MessageBox}
31998 Roo.Msg = Roo.MessageBox;/*
32000 * Ext JS Library 1.1.1
32001 * Copyright(c) 2006-2007, Ext JS, LLC.
32003 * Originally Released Under LGPL - original licence link has changed is not relivant.
32006 * <script type="text/javascript">
32009 * @class Roo.QuickTips
32010 * Provides attractive and customizable tooltips for any element.
32013 Roo.QuickTips = function(){
32014 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
32015 var ce, bd, xy, dd;
32016 var visible = false, disabled = true, inited = false;
32017 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
32019 var onOver = function(e){
32023 var t = e.getTarget();
32024 if(!t || t.nodeType !== 1 || t == document || t == document.body){
32027 if(ce && t == ce.el){
32028 clearTimeout(hideProc);
32031 if(t && tagEls[t.id]){
32032 tagEls[t.id].el = t;
32033 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
32036 var ttp, et = Roo.fly(t);
32037 var ns = cfg.namespace;
32038 if(tm.interceptTitles && t.title){
32041 t.removeAttribute("title");
32042 e.preventDefault();
32044 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
32047 showProc = show.defer(tm.showDelay, tm, [{
32050 width: et.getAttributeNS(ns, cfg.width),
32051 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
32052 title: et.getAttributeNS(ns, cfg.title),
32053 cls: et.getAttributeNS(ns, cfg.cls)
32058 var onOut = function(e){
32059 clearTimeout(showProc);
32060 var t = e.getTarget();
32061 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
32062 hideProc = setTimeout(hide, tm.hideDelay);
32066 var onMove = function(e){
32072 if(tm.trackMouse && ce){
32077 var onDown = function(e){
32078 clearTimeout(showProc);
32079 clearTimeout(hideProc);
32081 if(tm.hideOnClick){
32084 tm.enable.defer(100, tm);
32089 var getPad = function(){
32090 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
32093 var show = function(o){
32097 clearTimeout(dismissProc);
32099 if(removeCls){ // in case manually hidden
32100 el.removeClass(removeCls);
32104 el.addClass(ce.cls);
32105 removeCls = ce.cls;
32108 tipTitle.update(ce.title);
32111 tipTitle.update('');
32114 el.dom.style.width = tm.maxWidth+'px';
32115 //tipBody.dom.style.width = '';
32116 tipBodyText.update(o.text);
32117 var p = getPad(), w = ce.width;
32119 var td = tipBodyText.dom;
32120 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
32121 if(aw > tm.maxWidth){
32123 }else if(aw < tm.minWidth){
32129 //tipBody.setWidth(w);
32130 el.setWidth(parseInt(w, 10) + p);
32131 if(ce.autoHide === false){
32132 close.setDisplayed(true);
32137 close.setDisplayed(false);
32143 el.avoidY = xy[1]-18;
32148 el.setStyle("visibility", "visible");
32149 el.fadeIn({callback: afterShow});
32155 var afterShow = function(){
32159 if(tm.autoDismiss && ce.autoHide !== false){
32160 dismissProc = setTimeout(hide, tm.autoDismissDelay);
32165 var hide = function(noanim){
32166 clearTimeout(dismissProc);
32167 clearTimeout(hideProc);
32169 if(el.isVisible()){
32171 if(noanim !== true && tm.animate){
32172 el.fadeOut({callback: afterHide});
32179 var afterHide = function(){
32182 el.removeClass(removeCls);
32189 * @cfg {Number} minWidth
32190 * The minimum width of the quick tip (defaults to 40)
32194 * @cfg {Number} maxWidth
32195 * The maximum width of the quick tip (defaults to 300)
32199 * @cfg {Boolean} interceptTitles
32200 * True to automatically use the element's DOM title value if available (defaults to false)
32202 interceptTitles : false,
32204 * @cfg {Boolean} trackMouse
32205 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
32207 trackMouse : false,
32209 * @cfg {Boolean} hideOnClick
32210 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32212 hideOnClick : true,
32214 * @cfg {Number} showDelay
32215 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32219 * @cfg {Number} hideDelay
32220 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32224 * @cfg {Boolean} autoHide
32225 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32226 * Used in conjunction with hideDelay.
32231 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32232 * (defaults to true). Used in conjunction with autoDismissDelay.
32234 autoDismiss : true,
32237 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32239 autoDismissDelay : 5000,
32241 * @cfg {Boolean} animate
32242 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32247 * @cfg {String} title
32248 * Title text to display (defaults to ''). This can be any valid HTML markup.
32252 * @cfg {String} text
32253 * Body text to display (defaults to ''). This can be any valid HTML markup.
32257 * @cfg {String} cls
32258 * A CSS class to apply to the base quick tip element (defaults to '').
32262 * @cfg {Number} width
32263 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32264 * minWidth or maxWidth.
32269 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32270 * or display QuickTips in a page.
32273 tm = Roo.QuickTips;
32274 cfg = tm.tagConfig;
32276 if(!Roo.isReady){ // allow calling of init() before onReady
32277 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32280 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32281 el.fxDefaults = {stopFx: true};
32282 // maximum custom styling
32283 //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>');
32284 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>');
32285 tipTitle = el.child('h3');
32286 tipTitle.enableDisplayMode("block");
32287 tipBody = el.child('div.x-tip-bd');
32288 tipBodyText = el.child('div.x-tip-bd-inner');
32289 //bdLeft = el.child('div.x-tip-bd-left');
32290 //bdRight = el.child('div.x-tip-bd-right');
32291 close = el.child('div.x-tip-close');
32292 close.enableDisplayMode("block");
32293 close.on("click", hide);
32294 var d = Roo.get(document);
32295 d.on("mousedown", onDown);
32296 d.on("mouseover", onOver);
32297 d.on("mouseout", onOut);
32298 d.on("mousemove", onMove);
32299 esc = d.addKeyListener(27, hide);
32302 dd = el.initDD("default", null, {
32303 onDrag : function(){
32307 dd.setHandleElId(tipTitle.id);
32316 * Configures a new quick tip instance and assigns it to a target element. The following config options
32319 Property Type Description
32320 ---------- --------------------- ------------------------------------------------------------------------
32321 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32323 * @param {Object} config The config object
32325 register : function(config){
32326 var cs = config instanceof Array ? config : arguments;
32327 for(var i = 0, len = cs.length; i < len; i++) {
32329 var target = c.target;
32331 if(target instanceof Array){
32332 for(var j = 0, jlen = target.length; j < jlen; j++){
32333 tagEls[target[j]] = c;
32336 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32343 * Removes this quick tip from its element and destroys it.
32344 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32346 unregister : function(el){
32347 delete tagEls[Roo.id(el)];
32351 * Enable this quick tip.
32353 enable : function(){
32354 if(inited && disabled){
32356 if(locks.length < 1){
32363 * Disable this quick tip.
32365 disable : function(){
32367 clearTimeout(showProc);
32368 clearTimeout(hideProc);
32369 clearTimeout(dismissProc);
32377 * Returns true if the quick tip is enabled, else false.
32379 isEnabled : function(){
32386 attribute : "qtip",
32396 // backwards compat
32397 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32399 * Ext JS Library 1.1.1
32400 * Copyright(c) 2006-2007, Ext JS, LLC.
32402 * Originally Released Under LGPL - original licence link has changed is not relivant.
32405 * <script type="text/javascript">
32410 * @class Roo.tree.TreePanel
32411 * @extends Roo.data.Tree
32413 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32414 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32415 * @cfg {Boolean} enableDD true to enable drag and drop
32416 * @cfg {Boolean} enableDrag true to enable just drag
32417 * @cfg {Boolean} enableDrop true to enable just drop
32418 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32419 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32420 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32421 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32422 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32423 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32424 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32425 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32426 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32427 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32428 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32429 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32430 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32431 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32432 * @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>
32433 * @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>
32436 * @param {String/HTMLElement/Element} el The container element
32437 * @param {Object} config
32439 Roo.tree.TreePanel = function(el, config){
32441 var loader = false;
32443 root = config.root;
32444 delete config.root;
32446 if (config.loader) {
32447 loader = config.loader;
32448 delete config.loader;
32451 Roo.apply(this, config);
32452 Roo.tree.TreePanel.superclass.constructor.call(this);
32453 this.el = Roo.get(el);
32454 this.el.addClass('x-tree');
32455 //console.log(root);
32457 this.setRootNode( Roo.factory(root, Roo.tree));
32460 this.loader = Roo.factory(loader, Roo.tree);
32463 * Read-only. The id of the container element becomes this TreePanel's id.
32465 this.id = this.el.id;
32468 * @event beforeload
32469 * Fires before a node is loaded, return false to cancel
32470 * @param {Node} node The node being loaded
32472 "beforeload" : true,
32475 * Fires when a node is loaded
32476 * @param {Node} node The node that was loaded
32480 * @event textchange
32481 * Fires when the text for a node is changed
32482 * @param {Node} node The node
32483 * @param {String} text The new text
32484 * @param {String} oldText The old text
32486 "textchange" : true,
32488 * @event beforeexpand
32489 * Fires before a node is expanded, return false to cancel.
32490 * @param {Node} node The node
32491 * @param {Boolean} deep
32492 * @param {Boolean} anim
32494 "beforeexpand" : true,
32496 * @event beforecollapse
32497 * Fires before a node is collapsed, return false to cancel.
32498 * @param {Node} node The node
32499 * @param {Boolean} deep
32500 * @param {Boolean} anim
32502 "beforecollapse" : true,
32505 * Fires when a node is expanded
32506 * @param {Node} node The node
32510 * @event disabledchange
32511 * Fires when the disabled status of a node changes
32512 * @param {Node} node The node
32513 * @param {Boolean} disabled
32515 "disabledchange" : true,
32518 * Fires when a node is collapsed
32519 * @param {Node} node The node
32523 * @event beforeclick
32524 * Fires before click processing on a node. Return false to cancel the default action.
32525 * @param {Node} node The node
32526 * @param {Roo.EventObject} e The event object
32528 "beforeclick":true,
32530 * @event checkchange
32531 * Fires when a node with a checkbox's checked property changes
32532 * @param {Node} this This node
32533 * @param {Boolean} checked
32535 "checkchange":true,
32538 * Fires when a node is clicked
32539 * @param {Node} node The node
32540 * @param {Roo.EventObject} e The event object
32545 * Fires when a node is double clicked
32546 * @param {Node} node The node
32547 * @param {Roo.EventObject} e The event object
32551 * @event contextmenu
32552 * Fires when a node is right clicked
32553 * @param {Node} node The node
32554 * @param {Roo.EventObject} e The event object
32556 "contextmenu":true,
32558 * @event beforechildrenrendered
32559 * Fires right before the child nodes for a node are rendered
32560 * @param {Node} node The node
32562 "beforechildrenrendered":true,
32565 * Fires when a node starts being dragged
32566 * @param {Roo.tree.TreePanel} this
32567 * @param {Roo.tree.TreeNode} node
32568 * @param {event} e The raw browser event
32570 "startdrag" : true,
32573 * Fires when a drag operation is complete
32574 * @param {Roo.tree.TreePanel} this
32575 * @param {Roo.tree.TreeNode} node
32576 * @param {event} e The raw browser event
32581 * Fires when a dragged node is dropped on a valid DD target
32582 * @param {Roo.tree.TreePanel} this
32583 * @param {Roo.tree.TreeNode} node
32584 * @param {DD} dd The dd it was dropped on
32585 * @param {event} e The raw browser event
32589 * @event beforenodedrop
32590 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32591 * passed to handlers has the following properties:<br />
32592 * <ul style="padding:5px;padding-left:16px;">
32593 * <li>tree - The TreePanel</li>
32594 * <li>target - The node being targeted for the drop</li>
32595 * <li>data - The drag data from the drag source</li>
32596 * <li>point - The point of the drop - append, above or below</li>
32597 * <li>source - The drag source</li>
32598 * <li>rawEvent - Raw mouse event</li>
32599 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32600 * to be inserted by setting them on this object.</li>
32601 * <li>cancel - Set this to true to cancel the drop.</li>
32603 * @param {Object} dropEvent
32605 "beforenodedrop" : true,
32608 * Fires after a DD object is dropped on a node in this tree. The dropEvent
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 - Dropped node(s).</li>
32619 * @param {Object} dropEvent
32623 * @event nodedragover
32624 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32625 * passed to handlers has the following properties:<br />
32626 * <ul style="padding:5px;padding-left:16px;">
32627 * <li>tree - The TreePanel</li>
32628 * <li>target - The node being targeted for the drop</li>
32629 * <li>data - The drag data from the drag source</li>
32630 * <li>point - The point of the drop - append, above or below</li>
32631 * <li>source - The drag source</li>
32632 * <li>rawEvent - Raw mouse event</li>
32633 * <li>dropNode - Drop node(s) provided by the source.</li>
32634 * <li>cancel - Set this to true to signal drop not allowed.</li>
32636 * @param {Object} dragOverEvent
32638 "nodedragover" : true
32641 if(this.singleExpand){
32642 this.on("beforeexpand", this.restrictExpand, this);
32645 this.editor.tree = this;
32646 this.editor = Roo.factory(this.editor, Roo.tree);
32649 if (this.selModel) {
32650 this.selModel = Roo.factory(this.selModel, Roo.tree);
32654 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32655 rootVisible : true,
32656 animate: Roo.enableFx,
32659 hlDrop : Roo.enableFx,
32663 rendererTip: false,
32665 restrictExpand : function(node){
32666 var p = node.parentNode;
32668 if(p.expandedChild && p.expandedChild.parentNode == p){
32669 p.expandedChild.collapse();
32671 p.expandedChild = node;
32675 // private override
32676 setRootNode : function(node){
32677 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32678 if(!this.rootVisible){
32679 node.ui = new Roo.tree.RootTreeNodeUI(node);
32685 * Returns the container element for this TreePanel
32687 getEl : function(){
32692 * Returns the default TreeLoader for this TreePanel
32694 getLoader : function(){
32695 return this.loader;
32701 expandAll : function(){
32702 this.root.expand(true);
32706 * Collapse all nodes
32708 collapseAll : function(){
32709 this.root.collapse(true);
32713 * Returns the selection model used by this TreePanel
32715 getSelectionModel : function(){
32716 if(!this.selModel){
32717 this.selModel = new Roo.tree.DefaultSelectionModel();
32719 return this.selModel;
32723 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32724 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32725 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32728 getChecked : function(a, startNode){
32729 startNode = startNode || this.root;
32731 var f = function(){
32732 if(this.attributes.checked){
32733 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32736 startNode.cascade(f);
32741 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32742 * @param {String} path
32743 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32744 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32745 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32747 expandPath : function(path, attr, callback){
32748 attr = attr || "id";
32749 var keys = path.split(this.pathSeparator);
32750 var curNode = this.root;
32751 if(curNode.attributes[attr] != keys[1]){ // invalid root
32753 callback(false, null);
32758 var f = function(){
32759 if(++index == keys.length){
32761 callback(true, curNode);
32765 var c = curNode.findChild(attr, keys[index]);
32768 callback(false, curNode);
32773 c.expand(false, false, f);
32775 curNode.expand(false, false, f);
32779 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32780 * @param {String} path
32781 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32782 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32783 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32785 selectPath : function(path, attr, callback){
32786 attr = attr || "id";
32787 var keys = path.split(this.pathSeparator);
32788 var v = keys.pop();
32789 if(keys.length > 0){
32790 var f = function(success, node){
32791 if(success && node){
32792 var n = node.findChild(attr, v);
32798 }else if(callback){
32799 callback(false, n);
32803 callback(false, n);
32807 this.expandPath(keys.join(this.pathSeparator), attr, f);
32809 this.root.select();
32811 callback(true, this.root);
32816 getTreeEl : function(){
32821 * Trigger rendering of this TreePanel
32823 render : function(){
32824 if (this.innerCt) {
32825 return this; // stop it rendering more than once!!
32828 this.innerCt = this.el.createChild({tag:"ul",
32829 cls:"x-tree-root-ct " +
32830 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32832 if(this.containerScroll){
32833 Roo.dd.ScrollManager.register(this.el);
32835 if((this.enableDD || this.enableDrop) && !this.dropZone){
32837 * The dropZone used by this tree if drop is enabled
32838 * @type Roo.tree.TreeDropZone
32840 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32841 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32844 if((this.enableDD || this.enableDrag) && !this.dragZone){
32846 * The dragZone used by this tree if drag is enabled
32847 * @type Roo.tree.TreeDragZone
32849 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32850 ddGroup: this.ddGroup || "TreeDD",
32851 scroll: this.ddScroll
32854 this.getSelectionModel().init(this);
32856 Roo.log("ROOT not set in tree");
32859 this.root.render();
32860 if(!this.rootVisible){
32861 this.root.renderChildren();
32867 * Ext JS Library 1.1.1
32868 * Copyright(c) 2006-2007, Ext JS, LLC.
32870 * Originally Released Under LGPL - original licence link has changed is not relivant.
32873 * <script type="text/javascript">
32878 * @class Roo.tree.DefaultSelectionModel
32879 * @extends Roo.util.Observable
32880 * The default single selection for a TreePanel.
32881 * @param {Object} cfg Configuration
32883 Roo.tree.DefaultSelectionModel = function(cfg){
32884 this.selNode = null;
32890 * @event selectionchange
32891 * Fires when the selected node changes
32892 * @param {DefaultSelectionModel} this
32893 * @param {TreeNode} node the new selection
32895 "selectionchange" : true,
32898 * @event beforeselect
32899 * Fires before the selected node changes, return false to cancel the change
32900 * @param {DefaultSelectionModel} this
32901 * @param {TreeNode} node the new selection
32902 * @param {TreeNode} node the old selection
32904 "beforeselect" : true
32907 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32910 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32911 init : function(tree){
32913 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32914 tree.on("click", this.onNodeClick, this);
32917 onNodeClick : function(node, e){
32918 if (e.ctrlKey && this.selNode == node) {
32919 this.unselect(node);
32927 * @param {TreeNode} node The node to select
32928 * @return {TreeNode} The selected node
32930 select : function(node){
32931 var last = this.selNode;
32932 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32934 last.ui.onSelectedChange(false);
32936 this.selNode = node;
32937 node.ui.onSelectedChange(true);
32938 this.fireEvent("selectionchange", this, node, last);
32945 * @param {TreeNode} node The node to unselect
32947 unselect : function(node){
32948 if(this.selNode == node){
32949 this.clearSelections();
32954 * Clear all selections
32956 clearSelections : function(){
32957 var n = this.selNode;
32959 n.ui.onSelectedChange(false);
32960 this.selNode = null;
32961 this.fireEvent("selectionchange", this, null);
32967 * Get the selected node
32968 * @return {TreeNode} The selected node
32970 getSelectedNode : function(){
32971 return this.selNode;
32975 * Returns true if the node is selected
32976 * @param {TreeNode} node The node to check
32977 * @return {Boolean}
32979 isSelected : function(node){
32980 return this.selNode == node;
32984 * Selects the node above the selected node in the tree, intelligently walking the nodes
32985 * @return TreeNode The new selection
32987 selectPrevious : function(){
32988 var s = this.selNode || this.lastSelNode;
32992 var ps = s.previousSibling;
32994 if(!ps.isExpanded() || ps.childNodes.length < 1){
32995 return this.select(ps);
32997 var lc = ps.lastChild;
32998 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
33001 return this.select(lc);
33003 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
33004 return this.select(s.parentNode);
33010 * Selects the node above the selected node in the tree, intelligently walking the nodes
33011 * @return TreeNode The new selection
33013 selectNext : function(){
33014 var s = this.selNode || this.lastSelNode;
33018 if(s.firstChild && s.isExpanded()){
33019 return this.select(s.firstChild);
33020 }else if(s.nextSibling){
33021 return this.select(s.nextSibling);
33022 }else if(s.parentNode){
33024 s.parentNode.bubble(function(){
33025 if(this.nextSibling){
33026 newS = this.getOwnerTree().selModel.select(this.nextSibling);
33035 onKeyDown : function(e){
33036 var s = this.selNode || this.lastSelNode;
33037 // undesirable, but required
33042 var k = e.getKey();
33050 this.selectPrevious();
33053 e.preventDefault();
33054 if(s.hasChildNodes()){
33055 if(!s.isExpanded()){
33057 }else if(s.firstChild){
33058 this.select(s.firstChild, e);
33063 e.preventDefault();
33064 if(s.hasChildNodes() && s.isExpanded()){
33066 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
33067 this.select(s.parentNode, e);
33075 * @class Roo.tree.MultiSelectionModel
33076 * @extends Roo.util.Observable
33077 * Multi selection for a TreePanel.
33078 * @param {Object} cfg Configuration
33080 Roo.tree.MultiSelectionModel = function(){
33081 this.selNodes = [];
33085 * @event selectionchange
33086 * Fires when the selected nodes change
33087 * @param {MultiSelectionModel} this
33088 * @param {Array} nodes Array of the selected nodes
33090 "selectionchange" : true
33092 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
33096 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
33097 init : function(tree){
33099 tree.getTreeEl().on("keydown", this.onKeyDown, this);
33100 tree.on("click", this.onNodeClick, this);
33103 onNodeClick : function(node, e){
33104 this.select(node, e, e.ctrlKey);
33109 * @param {TreeNode} node The node to select
33110 * @param {EventObject} e (optional) An event associated with the selection
33111 * @param {Boolean} keepExisting True to retain existing selections
33112 * @return {TreeNode} The selected node
33114 select : function(node, e, keepExisting){
33115 if(keepExisting !== true){
33116 this.clearSelections(true);
33118 if(this.isSelected(node)){
33119 this.lastSelNode = node;
33122 this.selNodes.push(node);
33123 this.selMap[node.id] = node;
33124 this.lastSelNode = node;
33125 node.ui.onSelectedChange(true);
33126 this.fireEvent("selectionchange", this, this.selNodes);
33132 * @param {TreeNode} node The node to unselect
33134 unselect : function(node){
33135 if(this.selMap[node.id]){
33136 node.ui.onSelectedChange(false);
33137 var sn = this.selNodes;
33140 index = sn.indexOf(node);
33142 for(var i = 0, len = sn.length; i < len; i++){
33150 this.selNodes.splice(index, 1);
33152 delete this.selMap[node.id];
33153 this.fireEvent("selectionchange", this, this.selNodes);
33158 * Clear all selections
33160 clearSelections : function(suppressEvent){
33161 var sn = this.selNodes;
33163 for(var i = 0, len = sn.length; i < len; i++){
33164 sn[i].ui.onSelectedChange(false);
33166 this.selNodes = [];
33168 if(suppressEvent !== true){
33169 this.fireEvent("selectionchange", this, this.selNodes);
33175 * Returns true if the node is selected
33176 * @param {TreeNode} node The node to check
33177 * @return {Boolean}
33179 isSelected : function(node){
33180 return this.selMap[node.id] ? true : false;
33184 * Returns an array of the selected nodes
33187 getSelectedNodes : function(){
33188 return this.selNodes;
33191 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
33193 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
33195 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
33198 * Ext JS Library 1.1.1
33199 * Copyright(c) 2006-2007, Ext JS, LLC.
33201 * Originally Released Under LGPL - original licence link has changed is not relivant.
33204 * <script type="text/javascript">
33208 * @class Roo.tree.TreeNode
33209 * @extends Roo.data.Node
33210 * @cfg {String} text The text for this node
33211 * @cfg {Boolean} expanded true to start the node expanded
33212 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33213 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33214 * @cfg {Boolean} disabled true to start the node disabled
33215 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33216 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33217 * @cfg {String} cls A css class to be added to the node
33218 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33219 * @cfg {String} href URL of the link used for the node (defaults to #)
33220 * @cfg {String} hrefTarget target frame for the link
33221 * @cfg {String} qtip An Ext QuickTip for the node
33222 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33223 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33224 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33225 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33226 * (defaults to undefined with no checkbox rendered)
33228 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33230 Roo.tree.TreeNode = function(attributes){
33231 attributes = attributes || {};
33232 if(typeof attributes == "string"){
33233 attributes = {text: attributes};
33235 this.childrenRendered = false;
33236 this.rendered = false;
33237 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33238 this.expanded = attributes.expanded === true;
33239 this.isTarget = attributes.isTarget !== false;
33240 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33241 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33244 * Read-only. The text for this node. To change it use setText().
33247 this.text = attributes.text;
33249 * True if this node is disabled.
33252 this.disabled = attributes.disabled === true;
33256 * @event textchange
33257 * Fires when the text for this node is changed
33258 * @param {Node} this This node
33259 * @param {String} text The new text
33260 * @param {String} oldText The old text
33262 "textchange" : true,
33264 * @event beforeexpand
33265 * Fires before this node is expanded, return false to cancel.
33266 * @param {Node} this This node
33267 * @param {Boolean} deep
33268 * @param {Boolean} anim
33270 "beforeexpand" : true,
33272 * @event beforecollapse
33273 * Fires before this node is collapsed, return false to cancel.
33274 * @param {Node} this This node
33275 * @param {Boolean} deep
33276 * @param {Boolean} anim
33278 "beforecollapse" : true,
33281 * Fires when this node is expanded
33282 * @param {Node} this This node
33286 * @event disabledchange
33287 * Fires when the disabled status of this node changes
33288 * @param {Node} this This node
33289 * @param {Boolean} disabled
33291 "disabledchange" : true,
33294 * Fires when this node is collapsed
33295 * @param {Node} this This node
33299 * @event beforeclick
33300 * Fires before click processing. Return false to cancel the default action.
33301 * @param {Node} this This node
33302 * @param {Roo.EventObject} e The event object
33304 "beforeclick":true,
33306 * @event checkchange
33307 * Fires when a node with a checkbox's checked property changes
33308 * @param {Node} this This node
33309 * @param {Boolean} checked
33311 "checkchange":true,
33314 * Fires when this node is clicked
33315 * @param {Node} this This node
33316 * @param {Roo.EventObject} e The event object
33321 * Fires when this node is double clicked
33322 * @param {Node} this This node
33323 * @param {Roo.EventObject} e The event object
33327 * @event contextmenu
33328 * Fires when this node is right clicked
33329 * @param {Node} this This node
33330 * @param {Roo.EventObject} e The event object
33332 "contextmenu":true,
33334 * @event beforechildrenrendered
33335 * Fires right before the child nodes for this node are rendered
33336 * @param {Node} this This node
33338 "beforechildrenrendered":true
33341 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33344 * Read-only. The UI for this node
33347 this.ui = new uiClass(this);
33349 // finally support items[]
33350 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33355 Roo.each(this.attributes.items, function(c) {
33356 this.appendChild(Roo.factory(c,Roo.Tree));
33358 delete this.attributes.items;
33363 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33364 preventHScroll: true,
33366 * Returns true if this node is expanded
33367 * @return {Boolean}
33369 isExpanded : function(){
33370 return this.expanded;
33374 * Returns the UI object for this node
33375 * @return {TreeNodeUI}
33377 getUI : function(){
33381 // private override
33382 setFirstChild : function(node){
33383 var of = this.firstChild;
33384 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33385 if(this.childrenRendered && of && node != of){
33386 of.renderIndent(true, true);
33389 this.renderIndent(true, true);
33393 // private override
33394 setLastChild : function(node){
33395 var ol = this.lastChild;
33396 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33397 if(this.childrenRendered && ol && node != ol){
33398 ol.renderIndent(true, true);
33401 this.renderIndent(true, true);
33405 // these methods are overridden to provide lazy rendering support
33406 // private override
33407 appendChild : function()
33409 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33410 if(node && this.childrenRendered){
33413 this.ui.updateExpandIcon();
33417 // private override
33418 removeChild : function(node){
33419 this.ownerTree.getSelectionModel().unselect(node);
33420 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33421 // if it's been rendered remove dom node
33422 if(this.childrenRendered){
33425 if(this.childNodes.length < 1){
33426 this.collapse(false, false);
33428 this.ui.updateExpandIcon();
33430 if(!this.firstChild) {
33431 this.childrenRendered = false;
33436 // private override
33437 insertBefore : function(node, refNode){
33438 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33439 if(newNode && refNode && this.childrenRendered){
33442 this.ui.updateExpandIcon();
33447 * Sets the text for this node
33448 * @param {String} text
33450 setText : function(text){
33451 var oldText = this.text;
33453 this.attributes.text = text;
33454 if(this.rendered){ // event without subscribing
33455 this.ui.onTextChange(this, text, oldText);
33457 this.fireEvent("textchange", this, text, oldText);
33461 * Triggers selection of this node
33463 select : function(){
33464 this.getOwnerTree().getSelectionModel().select(this);
33468 * Triggers deselection of this node
33470 unselect : function(){
33471 this.getOwnerTree().getSelectionModel().unselect(this);
33475 * Returns true if this node is selected
33476 * @return {Boolean}
33478 isSelected : function(){
33479 return this.getOwnerTree().getSelectionModel().isSelected(this);
33483 * Expand this node.
33484 * @param {Boolean} deep (optional) True to expand all children as well
33485 * @param {Boolean} anim (optional) false to cancel the default animation
33486 * @param {Function} callback (optional) A callback to be called when
33487 * expanding this node completes (does not wait for deep expand to complete).
33488 * Called with 1 parameter, this node.
33490 expand : function(deep, anim, callback){
33491 if(!this.expanded){
33492 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33495 if(!this.childrenRendered){
33496 this.renderChildren();
33498 this.expanded = true;
33499 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33500 this.ui.animExpand(function(){
33501 this.fireEvent("expand", this);
33502 if(typeof callback == "function"){
33506 this.expandChildNodes(true);
33508 }.createDelegate(this));
33512 this.fireEvent("expand", this);
33513 if(typeof callback == "function"){
33518 if(typeof callback == "function"){
33523 this.expandChildNodes(true);
33527 isHiddenRoot : function(){
33528 return this.isRoot && !this.getOwnerTree().rootVisible;
33532 * Collapse this node.
33533 * @param {Boolean} deep (optional) True to collapse all children as well
33534 * @param {Boolean} anim (optional) false to cancel the default animation
33536 collapse : function(deep, anim){
33537 if(this.expanded && !this.isHiddenRoot()){
33538 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33541 this.expanded = false;
33542 if((this.getOwnerTree().animate && anim !== false) || anim){
33543 this.ui.animCollapse(function(){
33544 this.fireEvent("collapse", this);
33546 this.collapseChildNodes(true);
33548 }.createDelegate(this));
33551 this.ui.collapse();
33552 this.fireEvent("collapse", this);
33556 var cs = this.childNodes;
33557 for(var i = 0, len = cs.length; i < len; i++) {
33558 cs[i].collapse(true, false);
33564 delayedExpand : function(delay){
33565 if(!this.expandProcId){
33566 this.expandProcId = this.expand.defer(delay, this);
33571 cancelExpand : function(){
33572 if(this.expandProcId){
33573 clearTimeout(this.expandProcId);
33575 this.expandProcId = false;
33579 * Toggles expanded/collapsed state of the node
33581 toggle : function(){
33590 * Ensures all parent nodes are expanded
33592 ensureVisible : function(callback){
33593 var tree = this.getOwnerTree();
33594 tree.expandPath(this.parentNode.getPath(), false, function(){
33595 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33596 Roo.callback(callback);
33597 }.createDelegate(this));
33601 * Expand all child nodes
33602 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33604 expandChildNodes : function(deep){
33605 var cs = this.childNodes;
33606 for(var i = 0, len = cs.length; i < len; i++) {
33607 cs[i].expand(deep);
33612 * Collapse all child nodes
33613 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33615 collapseChildNodes : function(deep){
33616 var cs = this.childNodes;
33617 for(var i = 0, len = cs.length; i < len; i++) {
33618 cs[i].collapse(deep);
33623 * Disables this node
33625 disable : function(){
33626 this.disabled = true;
33628 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33629 this.ui.onDisableChange(this, true);
33631 this.fireEvent("disabledchange", this, true);
33635 * Enables this node
33637 enable : function(){
33638 this.disabled = false;
33639 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33640 this.ui.onDisableChange(this, false);
33642 this.fireEvent("disabledchange", this, false);
33646 renderChildren : function(suppressEvent){
33647 if(suppressEvent !== false){
33648 this.fireEvent("beforechildrenrendered", this);
33650 var cs = this.childNodes;
33651 for(var i = 0, len = cs.length; i < len; i++){
33652 cs[i].render(true);
33654 this.childrenRendered = true;
33658 sort : function(fn, scope){
33659 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33660 if(this.childrenRendered){
33661 var cs = this.childNodes;
33662 for(var i = 0, len = cs.length; i < len; i++){
33663 cs[i].render(true);
33669 render : function(bulkRender){
33670 this.ui.render(bulkRender);
33671 if(!this.rendered){
33672 this.rendered = true;
33674 this.expanded = false;
33675 this.expand(false, false);
33681 renderIndent : function(deep, refresh){
33683 this.ui.childIndent = null;
33685 this.ui.renderIndent();
33686 if(deep === true && this.childrenRendered){
33687 var cs = this.childNodes;
33688 for(var i = 0, len = cs.length; i < len; i++){
33689 cs[i].renderIndent(true, refresh);
33695 * Ext JS Library 1.1.1
33696 * Copyright(c) 2006-2007, Ext JS, LLC.
33698 * Originally Released Under LGPL - original licence link has changed is not relivant.
33701 * <script type="text/javascript">
33705 * @class Roo.tree.AsyncTreeNode
33706 * @extends Roo.tree.TreeNode
33707 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33709 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33711 Roo.tree.AsyncTreeNode = function(config){
33712 this.loaded = false;
33713 this.loading = false;
33714 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33716 * @event beforeload
33717 * Fires before this node is loaded, return false to cancel
33718 * @param {Node} this This node
33720 this.addEvents({'beforeload':true, 'load': true});
33723 * Fires when this node is loaded
33724 * @param {Node} this This node
33727 * The loader used by this node (defaults to using the tree's defined loader)
33732 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33733 expand : function(deep, anim, callback){
33734 if(this.loading){ // if an async load is already running, waiting til it's done
33736 var f = function(){
33737 if(!this.loading){ // done loading
33738 clearInterval(timer);
33739 this.expand(deep, anim, callback);
33741 }.createDelegate(this);
33742 timer = setInterval(f, 200);
33746 if(this.fireEvent("beforeload", this) === false){
33749 this.loading = true;
33750 this.ui.beforeLoad(this);
33751 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33753 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33757 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33761 * Returns true if this node is currently loading
33762 * @return {Boolean}
33764 isLoading : function(){
33765 return this.loading;
33768 loadComplete : function(deep, anim, callback){
33769 this.loading = false;
33770 this.loaded = true;
33771 this.ui.afterLoad(this);
33772 this.fireEvent("load", this);
33773 this.expand(deep, anim, callback);
33777 * Returns true if this node has been loaded
33778 * @return {Boolean}
33780 isLoaded : function(){
33781 return this.loaded;
33784 hasChildNodes : function(){
33785 if(!this.isLeaf() && !this.loaded){
33788 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33793 * Trigger a reload for this node
33794 * @param {Function} callback
33796 reload : function(callback){
33797 this.collapse(false, false);
33798 while(this.firstChild){
33799 this.removeChild(this.firstChild);
33801 this.childrenRendered = false;
33802 this.loaded = false;
33803 if(this.isHiddenRoot()){
33804 this.expanded = false;
33806 this.expand(false, false, callback);
33810 * Ext JS Library 1.1.1
33811 * Copyright(c) 2006-2007, Ext JS, LLC.
33813 * Originally Released Under LGPL - original licence link has changed is not relivant.
33816 * <script type="text/javascript">
33820 * @class Roo.tree.TreeNodeUI
33822 * @param {Object} node The node to render
33823 * The TreeNode UI implementation is separate from the
33824 * tree implementation. Unless you are customizing the tree UI,
33825 * you should never have to use this directly.
33827 Roo.tree.TreeNodeUI = function(node){
33829 this.rendered = false;
33830 this.animating = false;
33831 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33834 Roo.tree.TreeNodeUI.prototype = {
33835 removeChild : function(node){
33837 this.ctNode.removeChild(node.ui.getEl());
33841 beforeLoad : function(){
33842 this.addClass("x-tree-node-loading");
33845 afterLoad : function(){
33846 this.removeClass("x-tree-node-loading");
33849 onTextChange : function(node, text, oldText){
33851 this.textNode.innerHTML = text;
33855 onDisableChange : function(node, state){
33856 this.disabled = state;
33858 this.addClass("x-tree-node-disabled");
33860 this.removeClass("x-tree-node-disabled");
33864 onSelectedChange : function(state){
33867 this.addClass("x-tree-selected");
33870 this.removeClass("x-tree-selected");
33874 onMove : function(tree, node, oldParent, newParent, index, refNode){
33875 this.childIndent = null;
33877 var targetNode = newParent.ui.getContainer();
33878 if(!targetNode){//target not rendered
33879 this.holder = document.createElement("div");
33880 this.holder.appendChild(this.wrap);
33883 var insertBefore = refNode ? refNode.ui.getEl() : null;
33885 targetNode.insertBefore(this.wrap, insertBefore);
33887 targetNode.appendChild(this.wrap);
33889 this.node.renderIndent(true);
33893 addClass : function(cls){
33895 Roo.fly(this.elNode).addClass(cls);
33899 removeClass : function(cls){
33901 Roo.fly(this.elNode).removeClass(cls);
33905 remove : function(){
33907 this.holder = document.createElement("div");
33908 this.holder.appendChild(this.wrap);
33912 fireEvent : function(){
33913 return this.node.fireEvent.apply(this.node, arguments);
33916 initEvents : function(){
33917 this.node.on("move", this.onMove, this);
33918 var E = Roo.EventManager;
33919 var a = this.anchor;
33921 var el = Roo.fly(a, '_treeui');
33923 if(Roo.isOpera){ // opera render bug ignores the CSS
33924 el.setStyle("text-decoration", "none");
33927 el.on("click", this.onClick, this);
33928 el.on("dblclick", this.onDblClick, this);
33931 Roo.EventManager.on(this.checkbox,
33932 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33935 el.on("contextmenu", this.onContextMenu, this);
33937 var icon = Roo.fly(this.iconNode);
33938 icon.on("click", this.onClick, this);
33939 icon.on("dblclick", this.onDblClick, this);
33940 icon.on("contextmenu", this.onContextMenu, this);
33941 E.on(this.ecNode, "click", this.ecClick, this, true);
33943 if(this.node.disabled){
33944 this.addClass("x-tree-node-disabled");
33946 if(this.node.hidden){
33947 this.addClass("x-tree-node-disabled");
33949 var ot = this.node.getOwnerTree();
33950 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33951 if(dd && (!this.node.isRoot || ot.rootVisible)){
33952 Roo.dd.Registry.register(this.elNode, {
33954 handles: this.getDDHandles(),
33960 getDDHandles : function(){
33961 return [this.iconNode, this.textNode];
33966 this.wrap.style.display = "none";
33972 this.wrap.style.display = "";
33976 onContextMenu : function(e){
33977 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33978 e.preventDefault();
33980 this.fireEvent("contextmenu", this.node, e);
33984 onClick : function(e){
33989 if(this.fireEvent("beforeclick", this.node, e) !== false){
33990 if(!this.disabled && this.node.attributes.href){
33991 this.fireEvent("click", this.node, e);
33994 e.preventDefault();
33999 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
34000 this.node.toggle();
34003 this.fireEvent("click", this.node, e);
34009 onDblClick : function(e){
34010 e.preventDefault();
34015 this.toggleCheck();
34017 if(!this.animating && this.node.hasChildNodes()){
34018 this.node.toggle();
34020 this.fireEvent("dblclick", this.node, e);
34023 onCheckChange : function(){
34024 var checked = this.checkbox.checked;
34025 this.node.attributes.checked = checked;
34026 this.fireEvent('checkchange', this.node, checked);
34029 ecClick : function(e){
34030 if(!this.animating && this.node.hasChildNodes()){
34031 this.node.toggle();
34035 startDrop : function(){
34036 this.dropping = true;
34039 // delayed drop so the click event doesn't get fired on a drop
34040 endDrop : function(){
34041 setTimeout(function(){
34042 this.dropping = false;
34043 }.createDelegate(this), 50);
34046 expand : function(){
34047 this.updateExpandIcon();
34048 this.ctNode.style.display = "";
34051 focus : function(){
34052 if(!this.node.preventHScroll){
34053 try{this.anchor.focus();
34055 }else if(!Roo.isIE){
34057 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
34058 var l = noscroll.scrollLeft;
34059 this.anchor.focus();
34060 noscroll.scrollLeft = l;
34065 toggleCheck : function(value){
34066 var cb = this.checkbox;
34068 cb.checked = (value === undefined ? !cb.checked : value);
34074 this.anchor.blur();
34078 animExpand : function(callback){
34079 var ct = Roo.get(this.ctNode);
34081 if(!this.node.hasChildNodes()){
34082 this.updateExpandIcon();
34083 this.ctNode.style.display = "";
34084 Roo.callback(callback);
34087 this.animating = true;
34088 this.updateExpandIcon();
34091 callback : function(){
34092 this.animating = false;
34093 Roo.callback(callback);
34096 duration: this.node.ownerTree.duration || .25
34100 highlight : function(){
34101 var tree = this.node.getOwnerTree();
34102 Roo.fly(this.wrap).highlight(
34103 tree.hlColor || "C3DAF9",
34104 {endColor: tree.hlBaseColor}
34108 collapse : function(){
34109 this.updateExpandIcon();
34110 this.ctNode.style.display = "none";
34113 animCollapse : function(callback){
34114 var ct = Roo.get(this.ctNode);
34115 ct.enableDisplayMode('block');
34118 this.animating = true;
34119 this.updateExpandIcon();
34122 callback : function(){
34123 this.animating = false;
34124 Roo.callback(callback);
34127 duration: this.node.ownerTree.duration || .25
34131 getContainer : function(){
34132 return this.ctNode;
34135 getEl : function(){
34139 appendDDGhost : function(ghostNode){
34140 ghostNode.appendChild(this.elNode.cloneNode(true));
34143 getDDRepairXY : function(){
34144 return Roo.lib.Dom.getXY(this.iconNode);
34147 onRender : function(){
34151 render : function(bulkRender){
34152 var n = this.node, a = n.attributes;
34153 var targetNode = n.parentNode ?
34154 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
34156 if(!this.rendered){
34157 this.rendered = true;
34159 this.renderElements(n, a, targetNode, bulkRender);
34162 if(this.textNode.setAttributeNS){
34163 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
34165 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
34168 this.textNode.setAttribute("ext:qtip", a.qtip);
34170 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
34173 }else if(a.qtipCfg){
34174 a.qtipCfg.target = Roo.id(this.textNode);
34175 Roo.QuickTips.register(a.qtipCfg);
34178 if(!this.node.expanded){
34179 this.updateExpandIcon();
34182 if(bulkRender === true) {
34183 targetNode.appendChild(this.wrap);
34188 renderElements : function(n, a, targetNode, bulkRender)
34190 // add some indent caching, this helps performance when rendering a large tree
34191 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34192 var t = n.getOwnerTree();
34193 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
34194 if (typeof(n.attributes.html) != 'undefined') {
34195 txt = n.attributes.html;
34197 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
34198 var cb = typeof a.checked == 'boolean';
34199 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34200 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
34201 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
34202 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
34203 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
34204 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
34205 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
34206 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
34207 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
34208 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34211 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34212 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34213 n.nextSibling.ui.getEl(), buf.join(""));
34215 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34218 this.elNode = this.wrap.childNodes[0];
34219 this.ctNode = this.wrap.childNodes[1];
34220 var cs = this.elNode.childNodes;
34221 this.indentNode = cs[0];
34222 this.ecNode = cs[1];
34223 this.iconNode = cs[2];
34226 this.checkbox = cs[3];
34229 this.anchor = cs[index];
34230 this.textNode = cs[index].firstChild;
34233 getAnchor : function(){
34234 return this.anchor;
34237 getTextEl : function(){
34238 return this.textNode;
34241 getIconEl : function(){
34242 return this.iconNode;
34245 isChecked : function(){
34246 return this.checkbox ? this.checkbox.checked : false;
34249 updateExpandIcon : function(){
34251 var n = this.node, c1, c2;
34252 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34253 var hasChild = n.hasChildNodes();
34257 c1 = "x-tree-node-collapsed";
34258 c2 = "x-tree-node-expanded";
34261 c1 = "x-tree-node-expanded";
34262 c2 = "x-tree-node-collapsed";
34265 this.removeClass("x-tree-node-leaf");
34266 this.wasLeaf = false;
34268 if(this.c1 != c1 || this.c2 != c2){
34269 Roo.fly(this.elNode).replaceClass(c1, c2);
34270 this.c1 = c1; this.c2 = c2;
34273 // this changes non-leafs into leafs if they have no children.
34274 // it's not very rational behaviour..
34276 if(!this.wasLeaf && this.node.leaf){
34277 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34280 this.wasLeaf = true;
34283 var ecc = "x-tree-ec-icon "+cls;
34284 if(this.ecc != ecc){
34285 this.ecNode.className = ecc;
34291 getChildIndent : function(){
34292 if(!this.childIndent){
34296 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34298 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34300 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34305 this.childIndent = buf.join("");
34307 return this.childIndent;
34310 renderIndent : function(){
34313 var p = this.node.parentNode;
34315 indent = p.ui.getChildIndent();
34317 if(this.indentMarkup != indent){ // don't rerender if not required
34318 this.indentNode.innerHTML = indent;
34319 this.indentMarkup = indent;
34321 this.updateExpandIcon();
34326 Roo.tree.RootTreeNodeUI = function(){
34327 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34329 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34330 render : function(){
34331 if(!this.rendered){
34332 var targetNode = this.node.ownerTree.innerCt.dom;
34333 this.node.expanded = true;
34334 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34335 this.wrap = this.ctNode = targetNode.firstChild;
34338 collapse : function(){
34340 expand : function(){
34344 * Ext JS Library 1.1.1
34345 * Copyright(c) 2006-2007, Ext JS, LLC.
34347 * Originally Released Under LGPL - original licence link has changed is not relivant.
34350 * <script type="text/javascript">
34353 * @class Roo.tree.TreeLoader
34354 * @extends Roo.util.Observable
34355 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34356 * nodes from a specified URL. The response must be a javascript Array definition
34357 * who's elements are node definition objects. eg:
34362 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34363 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34370 * The old style respose with just an array is still supported, but not recommended.
34373 * A server request is sent, and child nodes are loaded only when a node is expanded.
34374 * The loading node's id is passed to the server under the parameter name "node" to
34375 * enable the server to produce the correct child nodes.
34377 * To pass extra parameters, an event handler may be attached to the "beforeload"
34378 * event, and the parameters specified in the TreeLoader's baseParams property:
34380 myTreeLoader.on("beforeload", function(treeLoader, node) {
34381 this.baseParams.category = node.attributes.category;
34384 * This would pass an HTTP parameter called "category" to the server containing
34385 * the value of the Node's "category" attribute.
34387 * Creates a new Treeloader.
34388 * @param {Object} config A config object containing config properties.
34390 Roo.tree.TreeLoader = function(config){
34391 this.baseParams = {};
34392 this.requestMethod = "POST";
34393 Roo.apply(this, config);
34398 * @event beforeload
34399 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34400 * @param {Object} This TreeLoader object.
34401 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34402 * @param {Object} callback The callback function specified in the {@link #load} call.
34407 * Fires when the node has been successfuly loaded.
34408 * @param {Object} This TreeLoader object.
34409 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34410 * @param {Object} response The response object containing the data from the server.
34414 * @event loadexception
34415 * Fires if the network request failed.
34416 * @param {Object} This TreeLoader object.
34417 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34418 * @param {Object} response The response object containing the data from the server.
34420 loadexception : true,
34423 * Fires before a node is created, enabling you to return custom Node types
34424 * @param {Object} This TreeLoader object.
34425 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34430 Roo.tree.TreeLoader.superclass.constructor.call(this);
34433 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34435 * @cfg {String} dataUrl The URL from which to request a Json string which
34436 * specifies an array of node definition object representing the child nodes
34440 * @cfg {String} requestMethod either GET or POST
34441 * defaults to POST (due to BC)
34445 * @cfg {Object} baseParams (optional) An object containing properties which
34446 * specify HTTP parameters to be passed to each request for child nodes.
34449 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34450 * created by this loader. If the attributes sent by the server have an attribute in this object,
34451 * they take priority.
34454 * @cfg {Object} uiProviders (optional) An object containing properties which
34456 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34457 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34458 * <i>uiProvider</i> attribute of a returned child node is a string rather
34459 * than a reference to a TreeNodeUI implementation, this that string value
34460 * is used as a property name in the uiProviders object. You can define the provider named
34461 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34466 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34467 * child nodes before loading.
34469 clearOnLoad : true,
34472 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34473 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34474 * Grid query { data : [ .....] }
34479 * @cfg {String} queryParam (optional)
34480 * Name of the query as it will be passed on the querystring (defaults to 'node')
34481 * eg. the request will be ?node=[id]
34488 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34489 * This is called automatically when a node is expanded, but may be used to reload
34490 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34491 * @param {Roo.tree.TreeNode} node
34492 * @param {Function} callback
34494 load : function(node, callback){
34495 if(this.clearOnLoad){
34496 while(node.firstChild){
34497 node.removeChild(node.firstChild);
34500 if(node.attributes.children){ // preloaded json children
34501 var cs = node.attributes.children;
34502 for(var i = 0, len = cs.length; i < len; i++){
34503 node.appendChild(this.createNode(cs[i]));
34505 if(typeof callback == "function"){
34508 }else if(this.dataUrl){
34509 this.requestData(node, callback);
34513 getParams: function(node){
34514 var buf = [], bp = this.baseParams;
34515 for(var key in bp){
34516 if(typeof bp[key] != "function"){
34517 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34520 var n = this.queryParam === false ? 'node' : this.queryParam;
34521 buf.push(n + "=", encodeURIComponent(node.id));
34522 return buf.join("");
34525 requestData : function(node, callback){
34526 if(this.fireEvent("beforeload", this, node, callback) !== false){
34527 this.transId = Roo.Ajax.request({
34528 method:this.requestMethod,
34529 url: this.dataUrl||this.url,
34530 success: this.handleResponse,
34531 failure: this.handleFailure,
34533 argument: {callback: callback, node: node},
34534 params: this.getParams(node)
34537 // if the load is cancelled, make sure we notify
34538 // the node that we are done
34539 if(typeof callback == "function"){
34545 isLoading : function(){
34546 return this.transId ? true : false;
34549 abort : function(){
34550 if(this.isLoading()){
34551 Roo.Ajax.abort(this.transId);
34556 createNode : function(attr)
34558 // apply baseAttrs, nice idea Corey!
34559 if(this.baseAttrs){
34560 Roo.applyIf(attr, this.baseAttrs);
34562 if(this.applyLoader !== false){
34563 attr.loader = this;
34565 // uiProvider = depreciated..
34567 if(typeof(attr.uiProvider) == 'string'){
34568 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34569 /** eval:var:attr */ eval(attr.uiProvider);
34571 if(typeof(this.uiProviders['default']) != 'undefined') {
34572 attr.uiProvider = this.uiProviders['default'];
34575 this.fireEvent('create', this, attr);
34577 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34579 new Roo.tree.TreeNode(attr) :
34580 new Roo.tree.AsyncTreeNode(attr));
34583 processResponse : function(response, node, callback)
34585 var json = response.responseText;
34588 var o = Roo.decode(json);
34590 if (this.root === false && typeof(o.success) != undefined) {
34591 this.root = 'data'; // the default behaviour for list like data..
34594 if (this.root !== false && !o.success) {
34595 // it's a failure condition.
34596 var a = response.argument;
34597 this.fireEvent("loadexception", this, a.node, response);
34598 Roo.log("Load failed - should have a handler really");
34604 if (this.root !== false) {
34608 for(var i = 0, len = o.length; i < len; i++){
34609 var n = this.createNode(o[i]);
34611 node.appendChild(n);
34614 if(typeof callback == "function"){
34615 callback(this, node);
34618 this.handleFailure(response);
34622 handleResponse : function(response){
34623 this.transId = false;
34624 var a = response.argument;
34625 this.processResponse(response, a.node, a.callback);
34626 this.fireEvent("load", this, a.node, response);
34629 handleFailure : function(response)
34631 // should handle failure better..
34632 this.transId = false;
34633 var a = response.argument;
34634 this.fireEvent("loadexception", this, a.node, response);
34635 if(typeof a.callback == "function"){
34636 a.callback(this, a.node);
34641 * Ext JS Library 1.1.1
34642 * Copyright(c) 2006-2007, Ext JS, LLC.
34644 * Originally Released Under LGPL - original licence link has changed is not relivant.
34647 * <script type="text/javascript">
34651 * @class Roo.tree.TreeFilter
34652 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34653 * @param {TreePanel} tree
34654 * @param {Object} config (optional)
34656 Roo.tree.TreeFilter = function(tree, config){
34658 this.filtered = {};
34659 Roo.apply(this, config);
34662 Roo.tree.TreeFilter.prototype = {
34669 * Filter the data by a specific attribute.
34670 * @param {String/RegExp} value Either string that the attribute value
34671 * should start with or a RegExp to test against the attribute
34672 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34673 * @param {TreeNode} startNode (optional) The node to start the filter at.
34675 filter : function(value, attr, startNode){
34676 attr = attr || "text";
34678 if(typeof value == "string"){
34679 var vlen = value.length;
34680 // auto clear empty filter
34681 if(vlen == 0 && this.clearBlank){
34685 value = value.toLowerCase();
34687 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34689 }else if(value.exec){ // regex?
34691 return value.test(n.attributes[attr]);
34694 throw 'Illegal filter type, must be string or regex';
34696 this.filterBy(f, null, startNode);
34700 * Filter by a function. The passed function will be called with each
34701 * node in the tree (or from the startNode). If the function returns true, the node is kept
34702 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34703 * @param {Function} fn The filter function
34704 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34706 filterBy : function(fn, scope, startNode){
34707 startNode = startNode || this.tree.root;
34708 if(this.autoClear){
34711 var af = this.filtered, rv = this.reverse;
34712 var f = function(n){
34713 if(n == startNode){
34719 var m = fn.call(scope || n, n);
34727 startNode.cascade(f);
34730 if(typeof id != "function"){
34732 if(n && n.parentNode){
34733 n.parentNode.removeChild(n);
34741 * Clears the current filter. Note: with the "remove" option
34742 * set a filter cannot be cleared.
34744 clear : function(){
34746 var af = this.filtered;
34748 if(typeof id != "function"){
34755 this.filtered = {};
34760 * Ext JS Library 1.1.1
34761 * Copyright(c) 2006-2007, Ext JS, LLC.
34763 * Originally Released Under LGPL - original licence link has changed is not relivant.
34766 * <script type="text/javascript">
34771 * @class Roo.tree.TreeSorter
34772 * Provides sorting of nodes in a TreePanel
34774 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34775 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34776 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34777 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34778 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34779 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34781 * @param {TreePanel} tree
34782 * @param {Object} config
34784 Roo.tree.TreeSorter = function(tree, config){
34785 Roo.apply(this, config);
34786 tree.on("beforechildrenrendered", this.doSort, this);
34787 tree.on("append", this.updateSort, this);
34788 tree.on("insert", this.updateSort, this);
34790 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34791 var p = this.property || "text";
34792 var sortType = this.sortType;
34793 var fs = this.folderSort;
34794 var cs = this.caseSensitive === true;
34795 var leafAttr = this.leafAttr || 'leaf';
34797 this.sortFn = function(n1, n2){
34799 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34802 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34806 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34807 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34809 return dsc ? +1 : -1;
34811 return dsc ? -1 : +1;
34818 Roo.tree.TreeSorter.prototype = {
34819 doSort : function(node){
34820 node.sort(this.sortFn);
34823 compareNodes : function(n1, n2){
34824 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34827 updateSort : function(tree, node){
34828 if(node.childrenRendered){
34829 this.doSort.defer(1, this, [node]);
34834 * Ext JS Library 1.1.1
34835 * Copyright(c) 2006-2007, Ext JS, LLC.
34837 * Originally Released Under LGPL - original licence link has changed is not relivant.
34840 * <script type="text/javascript">
34843 if(Roo.dd.DropZone){
34845 Roo.tree.TreeDropZone = function(tree, config){
34846 this.allowParentInsert = false;
34847 this.allowContainerDrop = false;
34848 this.appendOnly = false;
34849 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34851 this.lastInsertClass = "x-tree-no-status";
34852 this.dragOverData = {};
34855 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34856 ddGroup : "TreeDD",
34859 expandDelay : 1000,
34861 expandNode : function(node){
34862 if(node.hasChildNodes() && !node.isExpanded()){
34863 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34867 queueExpand : function(node){
34868 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34871 cancelExpand : function(){
34872 if(this.expandProcId){
34873 clearTimeout(this.expandProcId);
34874 this.expandProcId = false;
34878 isValidDropPoint : function(n, pt, dd, e, data){
34879 if(!n || !data){ return false; }
34880 var targetNode = n.node;
34881 var dropNode = data.node;
34882 // default drop rules
34883 if(!(targetNode && targetNode.isTarget && pt)){
34886 if(pt == "append" && targetNode.allowChildren === false){
34889 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34892 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34895 // reuse the object
34896 var overEvent = this.dragOverData;
34897 overEvent.tree = this.tree;
34898 overEvent.target = targetNode;
34899 overEvent.data = data;
34900 overEvent.point = pt;
34901 overEvent.source = dd;
34902 overEvent.rawEvent = e;
34903 overEvent.dropNode = dropNode;
34904 overEvent.cancel = false;
34905 var result = this.tree.fireEvent("nodedragover", overEvent);
34906 return overEvent.cancel === false && result !== false;
34909 getDropPoint : function(e, n, dd)
34913 return tn.allowChildren !== false ? "append" : false; // always append for root
34915 var dragEl = n.ddel;
34916 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34917 var y = Roo.lib.Event.getPageY(e);
34918 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34920 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34921 var noAppend = tn.allowChildren === false;
34922 if(this.appendOnly || tn.parentNode.allowChildren === false){
34923 return noAppend ? false : "append";
34925 var noBelow = false;
34926 if(!this.allowParentInsert){
34927 noBelow = tn.hasChildNodes() && tn.isExpanded();
34929 var q = (b - t) / (noAppend ? 2 : 3);
34930 if(y >= t && y < (t + q)){
34932 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34939 onNodeEnter : function(n, dd, e, data)
34941 this.cancelExpand();
34944 onNodeOver : function(n, dd, e, data)
34947 var pt = this.getDropPoint(e, n, dd);
34950 // auto node expand check
34951 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34952 this.queueExpand(node);
34953 }else if(pt != "append"){
34954 this.cancelExpand();
34957 // set the insert point style on the target node
34958 var returnCls = this.dropNotAllowed;
34959 if(this.isValidDropPoint(n, pt, dd, e, data)){
34964 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34965 cls = "x-tree-drag-insert-above";
34966 }else if(pt == "below"){
34967 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34968 cls = "x-tree-drag-insert-below";
34970 returnCls = "x-tree-drop-ok-append";
34971 cls = "x-tree-drag-append";
34973 if(this.lastInsertClass != cls){
34974 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34975 this.lastInsertClass = cls;
34982 onNodeOut : function(n, dd, e, data){
34984 this.cancelExpand();
34985 this.removeDropIndicators(n);
34988 onNodeDrop : function(n, dd, e, data){
34989 var point = this.getDropPoint(e, n, dd);
34990 var targetNode = n.node;
34991 targetNode.ui.startDrop();
34992 if(!this.isValidDropPoint(n, point, dd, e, data)){
34993 targetNode.ui.endDrop();
34996 // first try to find the drop node
34997 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
35000 target: targetNode,
35005 dropNode: dropNode,
35008 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
35009 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
35010 targetNode.ui.endDrop();
35013 // allow target changing
35014 targetNode = dropEvent.target;
35015 if(point == "append" && !targetNode.isExpanded()){
35016 targetNode.expand(false, null, function(){
35017 this.completeDrop(dropEvent);
35018 }.createDelegate(this));
35020 this.completeDrop(dropEvent);
35025 completeDrop : function(de){
35026 var ns = de.dropNode, p = de.point, t = de.target;
35027 if(!(ns instanceof Array)){
35031 for(var i = 0, len = ns.length; i < len; i++){
35034 t.parentNode.insertBefore(n, t);
35035 }else if(p == "below"){
35036 t.parentNode.insertBefore(n, t.nextSibling);
35042 if(this.tree.hlDrop){
35046 this.tree.fireEvent("nodedrop", de);
35049 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
35050 if(this.tree.hlDrop){
35051 dropNode.ui.focus();
35052 dropNode.ui.highlight();
35054 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
35057 getTree : function(){
35061 removeDropIndicators : function(n){
35064 Roo.fly(el).removeClass([
35065 "x-tree-drag-insert-above",
35066 "x-tree-drag-insert-below",
35067 "x-tree-drag-append"]);
35068 this.lastInsertClass = "_noclass";
35072 beforeDragDrop : function(target, e, id){
35073 this.cancelExpand();
35077 afterRepair : function(data){
35078 if(data && Roo.enableFx){
35079 data.node.ui.highlight();
35089 * Ext JS Library 1.1.1
35090 * Copyright(c) 2006-2007, Ext JS, LLC.
35092 * Originally Released Under LGPL - original licence link has changed is not relivant.
35095 * <script type="text/javascript">
35099 if(Roo.dd.DragZone){
35100 Roo.tree.TreeDragZone = function(tree, config){
35101 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
35105 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
35106 ddGroup : "TreeDD",
35108 onBeforeDrag : function(data, e){
35110 return n && n.draggable && !n.disabled;
35114 onInitDrag : function(e){
35115 var data = this.dragData;
35116 this.tree.getSelectionModel().select(data.node);
35117 this.proxy.update("");
35118 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
35119 this.tree.fireEvent("startdrag", this.tree, data.node, e);
35122 getRepairXY : function(e, data){
35123 return data.node.ui.getDDRepairXY();
35126 onEndDrag : function(data, e){
35127 this.tree.fireEvent("enddrag", this.tree, data.node, e);
35132 onValidDrop : function(dd, e, id){
35133 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
35137 beforeInvalidDrop : function(e, id){
35138 // this scrolls the original position back into view
35139 var sm = this.tree.getSelectionModel();
35140 sm.clearSelections();
35141 sm.select(this.dragData.node);
35146 * Ext JS Library 1.1.1
35147 * Copyright(c) 2006-2007, Ext JS, LLC.
35149 * Originally Released Under LGPL - original licence link has changed is not relivant.
35152 * <script type="text/javascript">
35155 * @class Roo.tree.TreeEditor
35156 * @extends Roo.Editor
35157 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
35158 * as the editor field.
35160 * @param {Object} config (used to be the tree panel.)
35161 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
35163 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
35164 * @cfg {Roo.form.TextField|Object} field The field configuration
35168 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
35171 if (oldconfig) { // old style..
35172 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
35175 tree = config.tree;
35176 config.field = config.field || {};
35177 config.field.xtype = 'TextField';
35178 field = Roo.factory(config.field, Roo.form);
35180 config = config || {};
35185 * @event beforenodeedit
35186 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
35187 * false from the handler of this event.
35188 * @param {Editor} this
35189 * @param {Roo.tree.Node} node
35191 "beforenodeedit" : true
35195 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
35199 tree.on('beforeclick', this.beforeNodeClick, this);
35200 tree.getTreeEl().on('mousedown', this.hide, this);
35201 this.on('complete', this.updateNode, this);
35202 this.on('beforestartedit', this.fitToTree, this);
35203 this.on('startedit', this.bindScroll, this, {delay:10});
35204 this.on('specialkey', this.onSpecialKey, this);
35207 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
35209 * @cfg {String} alignment
35210 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35216 * @cfg {Boolean} hideEl
35217 * True to hide the bound element while the editor is displayed (defaults to false)
35221 * @cfg {String} cls
35222 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35224 cls: "x-small-editor x-tree-editor",
35226 * @cfg {Boolean} shim
35227 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35233 * @cfg {Number} maxWidth
35234 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35235 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35236 * scroll and client offsets into account prior to each edit.
35243 fitToTree : function(ed, el){
35244 var td = this.tree.getTreeEl().dom, nd = el.dom;
35245 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35246 td.scrollLeft = nd.offsetLeft;
35250 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35251 this.setSize(w, '');
35253 return this.fireEvent('beforenodeedit', this, this.editNode);
35258 triggerEdit : function(node){
35259 this.completeEdit();
35260 this.editNode = node;
35261 this.startEdit(node.ui.textNode, node.text);
35265 bindScroll : function(){
35266 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35270 beforeNodeClick : function(node, e){
35271 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35272 this.lastClick = new Date();
35273 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35275 this.triggerEdit(node);
35282 updateNode : function(ed, value){
35283 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35284 this.editNode.setText(value);
35288 onHide : function(){
35289 Roo.tree.TreeEditor.superclass.onHide.call(this);
35291 this.editNode.ui.focus();
35296 onSpecialKey : function(field, e){
35297 var k = e.getKey();
35301 }else if(k == e.ENTER && !e.hasModifier()){
35303 this.completeEdit();
35306 });//<Script type="text/javascript">
35309 * Ext JS Library 1.1.1
35310 * Copyright(c) 2006-2007, Ext JS, LLC.
35312 * Originally Released Under LGPL - original licence link has changed is not relivant.
35315 * <script type="text/javascript">
35319 * Not documented??? - probably should be...
35322 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35323 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35325 renderElements : function(n, a, targetNode, bulkRender){
35326 //consel.log("renderElements?");
35327 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35329 var t = n.getOwnerTree();
35330 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35332 var cols = t.columns;
35333 var bw = t.borderWidth;
35335 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35336 var cb = typeof a.checked == "boolean";
35337 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35338 var colcls = 'x-t-' + tid + '-c0';
35340 '<li class="x-tree-node">',
35343 '<div class="x-tree-node-el ', a.cls,'">',
35345 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35348 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35349 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35350 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35351 (a.icon ? ' x-tree-node-inline-icon' : ''),
35352 (a.iconCls ? ' '+a.iconCls : ''),
35353 '" unselectable="on" />',
35354 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35355 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35357 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35358 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35359 '<span unselectable="on" qtip="' + tx + '">',
35363 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35364 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35366 for(var i = 1, len = cols.length; i < len; i++){
35368 colcls = 'x-t-' + tid + '-c' +i;
35369 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35370 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35371 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35377 '<div class="x-clear"></div></div>',
35378 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35381 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35382 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35383 n.nextSibling.ui.getEl(), buf.join(""));
35385 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35387 var el = this.wrap.firstChild;
35389 this.elNode = el.firstChild;
35390 this.ranchor = el.childNodes[1];
35391 this.ctNode = this.wrap.childNodes[1];
35392 var cs = el.firstChild.childNodes;
35393 this.indentNode = cs[0];
35394 this.ecNode = cs[1];
35395 this.iconNode = cs[2];
35398 this.checkbox = cs[3];
35401 this.anchor = cs[index];
35403 this.textNode = cs[index].firstChild;
35405 //el.on("click", this.onClick, this);
35406 //el.on("dblclick", this.onDblClick, this);
35409 // console.log(this);
35411 initEvents : function(){
35412 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35415 var a = this.ranchor;
35417 var el = Roo.get(a);
35419 if(Roo.isOpera){ // opera render bug ignores the CSS
35420 el.setStyle("text-decoration", "none");
35423 el.on("click", this.onClick, this);
35424 el.on("dblclick", this.onDblClick, this);
35425 el.on("contextmenu", this.onContextMenu, this);
35429 /*onSelectedChange : function(state){
35432 this.addClass("x-tree-selected");
35435 this.removeClass("x-tree-selected");
35438 addClass : function(cls){
35440 Roo.fly(this.elRow).addClass(cls);
35446 removeClass : function(cls){
35448 Roo.fly(this.elRow).removeClass(cls);
35454 });//<Script type="text/javascript">
35458 * Ext JS Library 1.1.1
35459 * Copyright(c) 2006-2007, Ext JS, LLC.
35461 * Originally Released Under LGPL - original licence link has changed is not relivant.
35464 * <script type="text/javascript">
35469 * @class Roo.tree.ColumnTree
35470 * @extends Roo.data.TreePanel
35471 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35472 * @cfg {int} borderWidth compined right/left border allowance
35474 * @param {String/HTMLElement/Element} el The container element
35475 * @param {Object} config
35477 Roo.tree.ColumnTree = function(el, config)
35479 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35483 * Fire this event on a container when it resizes
35484 * @param {int} w Width
35485 * @param {int} h Height
35489 this.on('resize', this.onResize, this);
35492 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35496 borderWidth: Roo.isBorderBox ? 0 : 2,
35499 render : function(){
35500 // add the header.....
35502 Roo.tree.ColumnTree.superclass.render.apply(this);
35504 this.el.addClass('x-column-tree');
35506 this.headers = this.el.createChild(
35507 {cls:'x-tree-headers'},this.innerCt.dom);
35509 var cols = this.columns, c;
35510 var totalWidth = 0;
35512 var len = cols.length;
35513 for(var i = 0; i < len; i++){
35515 totalWidth += c.width;
35516 this.headEls.push(this.headers.createChild({
35517 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35519 cls:'x-tree-hd-text',
35522 style:'width:'+(c.width-this.borderWidth)+'px;'
35525 this.headers.createChild({cls:'x-clear'});
35526 // prevent floats from wrapping when clipped
35527 this.headers.setWidth(totalWidth);
35528 //this.innerCt.setWidth(totalWidth);
35529 this.innerCt.setStyle({ overflow: 'auto' });
35530 this.onResize(this.width, this.height);
35534 onResize : function(w,h)
35539 this.innerCt.setWidth(this.width);
35540 this.innerCt.setHeight(this.height-20);
35543 var cols = this.columns, c;
35544 var totalWidth = 0;
35546 var len = cols.length;
35547 for(var i = 0; i < len; i++){
35549 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35550 // it's the expander..
35551 expEl = this.headEls[i];
35554 totalWidth += c.width;
35558 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35560 this.headers.setWidth(w-20);
35569 * Ext JS Library 1.1.1
35570 * Copyright(c) 2006-2007, Ext JS, LLC.
35572 * Originally Released Under LGPL - original licence link has changed is not relivant.
35575 * <script type="text/javascript">
35579 * @class Roo.menu.Menu
35580 * @extends Roo.util.Observable
35581 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35582 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35584 * Creates a new Menu
35585 * @param {Object} config Configuration options
35587 Roo.menu.Menu = function(config){
35588 Roo.apply(this, config);
35589 this.id = this.id || Roo.id();
35592 * @event beforeshow
35593 * Fires before this menu is displayed
35594 * @param {Roo.menu.Menu} this
35598 * @event beforehide
35599 * Fires before this menu is hidden
35600 * @param {Roo.menu.Menu} this
35605 * Fires after this menu is displayed
35606 * @param {Roo.menu.Menu} this
35611 * Fires after this menu is hidden
35612 * @param {Roo.menu.Menu} this
35617 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35618 * @param {Roo.menu.Menu} this
35619 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35620 * @param {Roo.EventObject} e
35625 * Fires when the mouse is hovering over this menu
35626 * @param {Roo.menu.Menu} this
35627 * @param {Roo.EventObject} e
35628 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35633 * Fires when the mouse exits this menu
35634 * @param {Roo.menu.Menu} this
35635 * @param {Roo.EventObject} e
35636 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35641 * Fires when a menu item contained in this menu is clicked
35642 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35643 * @param {Roo.EventObject} e
35647 if (this.registerMenu) {
35648 Roo.menu.MenuMgr.register(this);
35651 var mis = this.items;
35652 this.items = new Roo.util.MixedCollection();
35654 this.add.apply(this, mis);
35658 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35660 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35664 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35665 * for bottom-right shadow (defaults to "sides")
35669 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35670 * this menu (defaults to "tl-tr?")
35672 subMenuAlign : "tl-tr?",
35674 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35675 * relative to its element of origin (defaults to "tl-bl?")
35677 defaultAlign : "tl-bl?",
35679 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35681 allowOtherMenus : false,
35683 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35685 registerMenu : true,
35690 render : function(){
35694 var el = this.el = new Roo.Layer({
35696 shadow:this.shadow,
35698 parentEl: this.parentEl || document.body,
35702 this.keyNav = new Roo.menu.MenuNav(this);
35705 el.addClass("x-menu-plain");
35708 el.addClass(this.cls);
35710 // generic focus element
35711 this.focusEl = el.createChild({
35712 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35714 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35715 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35717 ul.on("mouseover", this.onMouseOver, this);
35718 ul.on("mouseout", this.onMouseOut, this);
35719 this.items.each(function(item){
35724 var li = document.createElement("li");
35725 li.className = "x-menu-list-item";
35726 ul.dom.appendChild(li);
35727 item.render(li, this);
35734 autoWidth : function(){
35735 var el = this.el, ul = this.ul;
35739 var w = this.width;
35742 }else if(Roo.isIE){
35743 el.setWidth(this.minWidth);
35744 var t = el.dom.offsetWidth; // force recalc
35745 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35750 delayAutoWidth : function(){
35753 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35755 this.awTask.delay(20);
35760 findTargetItem : function(e){
35761 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35762 if(t && t.menuItemId){
35763 return this.items.get(t.menuItemId);
35768 onClick : function(e){
35769 Roo.log("menu.onClick");
35770 var t = this.findTargetItem(e);
35775 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35776 if(t == this.activeItem && t.shouldDeactivate(e)){
35777 this.activeItem.deactivate();
35778 delete this.activeItem;
35782 this.setActiveItem(t, true);
35790 this.fireEvent("click", this, t, e);
35794 setActiveItem : function(item, autoExpand){
35795 if(item != this.activeItem){
35796 if(this.activeItem){
35797 this.activeItem.deactivate();
35799 this.activeItem = item;
35800 item.activate(autoExpand);
35801 }else if(autoExpand){
35807 tryActivate : function(start, step){
35808 var items = this.items;
35809 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35810 var item = items.get(i);
35811 if(!item.disabled && item.canActivate){
35812 this.setActiveItem(item, false);
35820 onMouseOver : function(e){
35822 if(t = this.findTargetItem(e)){
35823 if(t.canActivate && !t.disabled){
35824 this.setActiveItem(t, true);
35827 this.fireEvent("mouseover", this, e, t);
35831 onMouseOut : function(e){
35833 if(t = this.findTargetItem(e)){
35834 if(t == this.activeItem && t.shouldDeactivate(e)){
35835 this.activeItem.deactivate();
35836 delete this.activeItem;
35839 this.fireEvent("mouseout", this, e, t);
35843 * Read-only. Returns true if the menu is currently displayed, else false.
35846 isVisible : function(){
35847 return this.el && !this.hidden;
35851 * Displays this menu relative to another element
35852 * @param {String/HTMLElement/Roo.Element} element The element to align to
35853 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35854 * the element (defaults to this.defaultAlign)
35855 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35857 show : function(el, pos, parentMenu){
35858 this.parentMenu = parentMenu;
35862 this.fireEvent("beforeshow", this);
35863 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35867 * Displays this menu at a specific xy position
35868 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35869 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35871 showAt : function(xy, parentMenu, /* private: */_e){
35872 this.parentMenu = parentMenu;
35877 this.fireEvent("beforeshow", this);
35878 xy = this.el.adjustForConstraints(xy);
35882 this.hidden = false;
35884 this.fireEvent("show", this);
35887 focus : function(){
35889 this.doFocus.defer(50, this);
35893 doFocus : function(){
35895 this.focusEl.focus();
35900 * Hides this menu and optionally all parent menus
35901 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35903 hide : function(deep){
35904 if(this.el && this.isVisible()){
35905 this.fireEvent("beforehide", this);
35906 if(this.activeItem){
35907 this.activeItem.deactivate();
35908 this.activeItem = null;
35911 this.hidden = true;
35912 this.fireEvent("hide", this);
35914 if(deep === true && this.parentMenu){
35915 this.parentMenu.hide(true);
35920 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35921 * Any of the following are valid:
35923 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35924 * <li>An HTMLElement object which will be converted to a menu item</li>
35925 * <li>A menu item config object that will be created as a new menu item</li>
35926 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35927 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35932 var menu = new Roo.menu.Menu();
35934 // Create a menu item to add by reference
35935 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35937 // Add a bunch of items at once using different methods.
35938 // Only the last item added will be returned.
35939 var item = menu.add(
35940 menuItem, // add existing item by ref
35941 'Dynamic Item', // new TextItem
35942 '-', // new separator
35943 { text: 'Config Item' } // new item by config
35946 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35947 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35950 var a = arguments, l = a.length, item;
35951 for(var i = 0; i < l; i++){
35953 if ((typeof(el) == "object") && el.xtype && el.xns) {
35954 el = Roo.factory(el, Roo.menu);
35957 if(el.render){ // some kind of Item
35958 item = this.addItem(el);
35959 }else if(typeof el == "string"){ // string
35960 if(el == "separator" || el == "-"){
35961 item = this.addSeparator();
35963 item = this.addText(el);
35965 }else if(el.tagName || el.el){ // element
35966 item = this.addElement(el);
35967 }else if(typeof el == "object"){ // must be menu item config?
35968 item = this.addMenuItem(el);
35975 * Returns this menu's underlying {@link Roo.Element} object
35976 * @return {Roo.Element} The element
35978 getEl : function(){
35986 * Adds a separator bar to the menu
35987 * @return {Roo.menu.Item} The menu item that was added
35989 addSeparator : function(){
35990 return this.addItem(new Roo.menu.Separator());
35994 * Adds an {@link Roo.Element} object to the menu
35995 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35996 * @return {Roo.menu.Item} The menu item that was added
35998 addElement : function(el){
35999 return this.addItem(new Roo.menu.BaseItem(el));
36003 * Adds an existing object based on {@link Roo.menu.Item} to the menu
36004 * @param {Roo.menu.Item} item The menu item to add
36005 * @return {Roo.menu.Item} The menu item that was added
36007 addItem : function(item){
36008 this.items.add(item);
36010 var li = document.createElement("li");
36011 li.className = "x-menu-list-item";
36012 this.ul.dom.appendChild(li);
36013 item.render(li, this);
36014 this.delayAutoWidth();
36020 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
36021 * @param {Object} config A MenuItem config object
36022 * @return {Roo.menu.Item} The menu item that was added
36024 addMenuItem : function(config){
36025 if(!(config instanceof Roo.menu.Item)){
36026 if(typeof config.checked == "boolean"){ // must be check menu item config?
36027 config = new Roo.menu.CheckItem(config);
36029 config = new Roo.menu.Item(config);
36032 return this.addItem(config);
36036 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
36037 * @param {String} text The text to display in the menu item
36038 * @return {Roo.menu.Item} The menu item that was added
36040 addText : function(text){
36041 return this.addItem(new Roo.menu.TextItem({ text : text }));
36045 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
36046 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
36047 * @param {Roo.menu.Item} item The menu item to add
36048 * @return {Roo.menu.Item} The menu item that was added
36050 insert : function(index, item){
36051 this.items.insert(index, item);
36053 var li = document.createElement("li");
36054 li.className = "x-menu-list-item";
36055 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
36056 item.render(li, this);
36057 this.delayAutoWidth();
36063 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
36064 * @param {Roo.menu.Item} item The menu item to remove
36066 remove : function(item){
36067 this.items.removeKey(item.id);
36072 * Removes and destroys all items in the menu
36074 removeAll : function(){
36076 while(f = this.items.first()){
36082 // MenuNav is a private utility class used internally by the Menu
36083 Roo.menu.MenuNav = function(menu){
36084 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
36085 this.scope = this.menu = menu;
36088 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
36089 doRelay : function(e, h){
36090 var k = e.getKey();
36091 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
36092 this.menu.tryActivate(0, 1);
36095 return h.call(this.scope || this, e, this.menu);
36098 up : function(e, m){
36099 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
36100 m.tryActivate(m.items.length-1, -1);
36104 down : function(e, m){
36105 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
36106 m.tryActivate(0, 1);
36110 right : function(e, m){
36112 m.activeItem.expandMenu(true);
36116 left : function(e, m){
36118 if(m.parentMenu && m.parentMenu.activeItem){
36119 m.parentMenu.activeItem.activate();
36123 enter : function(e, m){
36125 e.stopPropagation();
36126 m.activeItem.onClick(e);
36127 m.fireEvent("click", this, m.activeItem);
36133 * Ext JS Library 1.1.1
36134 * Copyright(c) 2006-2007, Ext JS, LLC.
36136 * Originally Released Under LGPL - original licence link has changed is not relivant.
36139 * <script type="text/javascript">
36143 * @class Roo.menu.MenuMgr
36144 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
36147 Roo.menu.MenuMgr = function(){
36148 var menus, active, groups = {}, attached = false, lastShow = new Date();
36150 // private - called when first menu is created
36153 active = new Roo.util.MixedCollection();
36154 Roo.get(document).addKeyListener(27, function(){
36155 if(active.length > 0){
36162 function hideAll(){
36163 if(active && active.length > 0){
36164 var c = active.clone();
36165 c.each(function(m){
36172 function onHide(m){
36174 if(active.length < 1){
36175 Roo.get(document).un("mousedown", onMouseDown);
36181 function onShow(m){
36182 var last = active.last();
36183 lastShow = new Date();
36186 Roo.get(document).on("mousedown", onMouseDown);
36190 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
36191 m.parentMenu.activeChild = m;
36192 }else if(last && last.isVisible()){
36193 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
36198 function onBeforeHide(m){
36200 m.activeChild.hide();
36202 if(m.autoHideTimer){
36203 clearTimeout(m.autoHideTimer);
36204 delete m.autoHideTimer;
36209 function onBeforeShow(m){
36210 var pm = m.parentMenu;
36211 if(!pm && !m.allowOtherMenus){
36213 }else if(pm && pm.activeChild && active != m){
36214 pm.activeChild.hide();
36219 function onMouseDown(e){
36220 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36226 function onBeforeCheck(mi, state){
36228 var g = groups[mi.group];
36229 for(var i = 0, l = g.length; i < l; i++){
36231 g[i].setChecked(false);
36240 * Hides all menus that are currently visible
36242 hideAll : function(){
36247 register : function(menu){
36251 menus[menu.id] = menu;
36252 menu.on("beforehide", onBeforeHide);
36253 menu.on("hide", onHide);
36254 menu.on("beforeshow", onBeforeShow);
36255 menu.on("show", onShow);
36256 var g = menu.group;
36257 if(g && menu.events["checkchange"]){
36261 groups[g].push(menu);
36262 menu.on("checkchange", onCheck);
36267 * Returns a {@link Roo.menu.Menu} object
36268 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36269 * be used to generate and return a new Menu instance.
36271 get : function(menu){
36272 if(typeof menu == "string"){ // menu id
36273 return menus[menu];
36274 }else if(menu.events){ // menu instance
36276 }else if(typeof menu.length == 'number'){ // array of menu items?
36277 return new Roo.menu.Menu({items:menu});
36278 }else{ // otherwise, must be a config
36279 return new Roo.menu.Menu(menu);
36284 unregister : function(menu){
36285 delete menus[menu.id];
36286 menu.un("beforehide", onBeforeHide);
36287 menu.un("hide", onHide);
36288 menu.un("beforeshow", onBeforeShow);
36289 menu.un("show", onShow);
36290 var g = menu.group;
36291 if(g && menu.events["checkchange"]){
36292 groups[g].remove(menu);
36293 menu.un("checkchange", onCheck);
36298 registerCheckable : function(menuItem){
36299 var g = menuItem.group;
36304 groups[g].push(menuItem);
36305 menuItem.on("beforecheckchange", onBeforeCheck);
36310 unregisterCheckable : function(menuItem){
36311 var g = menuItem.group;
36313 groups[g].remove(menuItem);
36314 menuItem.un("beforecheckchange", onBeforeCheck);
36320 * Ext JS Library 1.1.1
36321 * Copyright(c) 2006-2007, Ext JS, LLC.
36323 * Originally Released Under LGPL - original licence link has changed is not relivant.
36326 * <script type="text/javascript">
36331 * @class Roo.menu.BaseItem
36332 * @extends Roo.Component
36333 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36334 * management and base configuration options shared by all menu components.
36336 * Creates a new BaseItem
36337 * @param {Object} config Configuration options
36339 Roo.menu.BaseItem = function(config){
36340 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36345 * Fires when this item is clicked
36346 * @param {Roo.menu.BaseItem} this
36347 * @param {Roo.EventObject} e
36352 * Fires when this item is activated
36353 * @param {Roo.menu.BaseItem} this
36357 * @event deactivate
36358 * Fires when this item is deactivated
36359 * @param {Roo.menu.BaseItem} this
36365 this.on("click", this.handler, this.scope, true);
36369 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36371 * @cfg {Function} handler
36372 * A function that will handle the click event of this menu item (defaults to undefined)
36375 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36377 canActivate : false,
36380 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36385 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36387 activeClass : "x-menu-item-active",
36389 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36391 hideOnClick : true,
36393 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36398 ctype: "Roo.menu.BaseItem",
36401 actionMode : "container",
36404 render : function(container, parentMenu){
36405 this.parentMenu = parentMenu;
36406 Roo.menu.BaseItem.superclass.render.call(this, container);
36407 this.container.menuItemId = this.id;
36411 onRender : function(container, position){
36412 this.el = Roo.get(this.el);
36413 container.dom.appendChild(this.el.dom);
36417 onClick : function(e){
36418 if(!this.disabled && this.fireEvent("click", this, e) !== false
36419 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36420 this.handleClick(e);
36427 activate : function(){
36431 var li = this.container;
36432 li.addClass(this.activeClass);
36433 this.region = li.getRegion().adjust(2, 2, -2, -2);
36434 this.fireEvent("activate", this);
36439 deactivate : function(){
36440 this.container.removeClass(this.activeClass);
36441 this.fireEvent("deactivate", this);
36445 shouldDeactivate : function(e){
36446 return !this.region || !this.region.contains(e.getPoint());
36450 handleClick : function(e){
36451 if(this.hideOnClick){
36452 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36457 expandMenu : function(autoActivate){
36462 hideMenu : function(){
36467 * Ext JS Library 1.1.1
36468 * Copyright(c) 2006-2007, Ext JS, LLC.
36470 * Originally Released Under LGPL - original licence link has changed is not relivant.
36473 * <script type="text/javascript">
36477 * @class Roo.menu.Adapter
36478 * @extends Roo.menu.BaseItem
36479 * 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.
36480 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36482 * Creates a new Adapter
36483 * @param {Object} config Configuration options
36485 Roo.menu.Adapter = function(component, config){
36486 Roo.menu.Adapter.superclass.constructor.call(this, config);
36487 this.component = component;
36489 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36491 canActivate : true,
36494 onRender : function(container, position){
36495 this.component.render(container);
36496 this.el = this.component.getEl();
36500 activate : function(){
36504 this.component.focus();
36505 this.fireEvent("activate", this);
36510 deactivate : function(){
36511 this.fireEvent("deactivate", this);
36515 disable : function(){
36516 this.component.disable();
36517 Roo.menu.Adapter.superclass.disable.call(this);
36521 enable : function(){
36522 this.component.enable();
36523 Roo.menu.Adapter.superclass.enable.call(this);
36527 * Ext JS Library 1.1.1
36528 * Copyright(c) 2006-2007, Ext JS, LLC.
36530 * Originally Released Under LGPL - original licence link has changed is not relivant.
36533 * <script type="text/javascript">
36537 * @class Roo.menu.TextItem
36538 * @extends Roo.menu.BaseItem
36539 * Adds a static text string to a menu, usually used as either a heading or group separator.
36540 * Note: old style constructor with text is still supported.
36543 * Creates a new TextItem
36544 * @param {Object} cfg Configuration
36546 Roo.menu.TextItem = function(cfg){
36547 if (typeof(cfg) == 'string') {
36550 Roo.apply(this,cfg);
36553 Roo.menu.TextItem.superclass.constructor.call(this);
36556 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36558 * @cfg {Boolean} text Text to show on item.
36563 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36565 hideOnClick : false,
36567 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36569 itemCls : "x-menu-text",
36572 onRender : function(){
36573 var s = document.createElement("span");
36574 s.className = this.itemCls;
36575 s.innerHTML = this.text;
36577 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36581 * Ext JS Library 1.1.1
36582 * Copyright(c) 2006-2007, Ext JS, LLC.
36584 * Originally Released Under LGPL - original licence link has changed is not relivant.
36587 * <script type="text/javascript">
36591 * @class Roo.menu.Separator
36592 * @extends Roo.menu.BaseItem
36593 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36594 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36596 * @param {Object} config Configuration options
36598 Roo.menu.Separator = function(config){
36599 Roo.menu.Separator.superclass.constructor.call(this, config);
36602 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36604 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36606 itemCls : "x-menu-sep",
36608 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36610 hideOnClick : false,
36613 onRender : function(li){
36614 var s = document.createElement("span");
36615 s.className = this.itemCls;
36616 s.innerHTML = " ";
36618 li.addClass("x-menu-sep-li");
36619 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36623 * Ext JS Library 1.1.1
36624 * Copyright(c) 2006-2007, Ext JS, LLC.
36626 * Originally Released Under LGPL - original licence link has changed is not relivant.
36629 * <script type="text/javascript">
36632 * @class Roo.menu.Item
36633 * @extends Roo.menu.BaseItem
36634 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36635 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36636 * activation and click handling.
36638 * Creates a new Item
36639 * @param {Object} config Configuration options
36641 Roo.menu.Item = function(config){
36642 Roo.menu.Item.superclass.constructor.call(this, config);
36644 this.menu = Roo.menu.MenuMgr.get(this.menu);
36647 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36650 * @cfg {String} text
36651 * The text to show on the menu item.
36655 * @cfg {String} HTML to render in menu
36656 * The text to show on the menu item (HTML version).
36660 * @cfg {String} icon
36661 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36665 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36667 itemCls : "x-menu-item",
36669 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36671 canActivate : true,
36673 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36676 // doc'd in BaseItem
36680 ctype: "Roo.menu.Item",
36683 onRender : function(container, position){
36684 var el = document.createElement("a");
36685 el.hideFocus = true;
36686 el.unselectable = "on";
36687 el.href = this.href || "#";
36688 if(this.hrefTarget){
36689 el.target = this.hrefTarget;
36691 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36693 var html = this.html.length ? this.html : String.format('{0}',this.text);
36695 el.innerHTML = String.format(
36696 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36697 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36699 Roo.menu.Item.superclass.onRender.call(this, container, position);
36703 * Sets the text to display in this menu item
36704 * @param {String} text The text to display
36705 * @param {Boolean} isHTML true to indicate text is pure html.
36707 setText : function(text, isHTML){
36715 var html = this.html.length ? this.html : String.format('{0}',this.text);
36717 this.el.update(String.format(
36718 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36719 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36720 this.parentMenu.autoWidth();
36725 handleClick : function(e){
36726 if(!this.href){ // if no link defined, stop the event automatically
36729 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36733 activate : function(autoExpand){
36734 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36744 shouldDeactivate : function(e){
36745 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36746 if(this.menu && this.menu.isVisible()){
36747 return !this.menu.getEl().getRegion().contains(e.getPoint());
36755 deactivate : function(){
36756 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36761 expandMenu : function(autoActivate){
36762 if(!this.disabled && this.menu){
36763 clearTimeout(this.hideTimer);
36764 delete this.hideTimer;
36765 if(!this.menu.isVisible() && !this.showTimer){
36766 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36767 }else if (this.menu.isVisible() && autoActivate){
36768 this.menu.tryActivate(0, 1);
36774 deferExpand : function(autoActivate){
36775 delete this.showTimer;
36776 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36778 this.menu.tryActivate(0, 1);
36783 hideMenu : function(){
36784 clearTimeout(this.showTimer);
36785 delete this.showTimer;
36786 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36787 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36792 deferHide : function(){
36793 delete this.hideTimer;
36798 * Ext JS Library 1.1.1
36799 * Copyright(c) 2006-2007, Ext JS, LLC.
36801 * Originally Released Under LGPL - original licence link has changed is not relivant.
36804 * <script type="text/javascript">
36808 * @class Roo.menu.CheckItem
36809 * @extends Roo.menu.Item
36810 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36812 * Creates a new CheckItem
36813 * @param {Object} config Configuration options
36815 Roo.menu.CheckItem = function(config){
36816 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36819 * @event beforecheckchange
36820 * Fires before the checked value is set, providing an opportunity to cancel if needed
36821 * @param {Roo.menu.CheckItem} this
36822 * @param {Boolean} checked The new checked value that will be set
36824 "beforecheckchange" : true,
36826 * @event checkchange
36827 * Fires after the checked value has been set
36828 * @param {Roo.menu.CheckItem} this
36829 * @param {Boolean} checked The checked value that was set
36831 "checkchange" : true
36833 if(this.checkHandler){
36834 this.on('checkchange', this.checkHandler, this.scope);
36837 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36839 * @cfg {String} group
36840 * All check items with the same group name will automatically be grouped into a single-select
36841 * radio button group (defaults to '')
36844 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36846 itemCls : "x-menu-item x-menu-check-item",
36848 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36850 groupClass : "x-menu-group-item",
36853 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36854 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36855 * initialized with checked = true will be rendered as checked.
36860 ctype: "Roo.menu.CheckItem",
36863 onRender : function(c){
36864 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36866 this.el.addClass(this.groupClass);
36868 Roo.menu.MenuMgr.registerCheckable(this);
36870 this.checked = false;
36871 this.setChecked(true, true);
36876 destroy : function(){
36878 Roo.menu.MenuMgr.unregisterCheckable(this);
36880 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36884 * Set the checked state of this item
36885 * @param {Boolean} checked The new checked value
36886 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36888 setChecked : function(state, suppressEvent){
36889 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36890 if(this.container){
36891 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36893 this.checked = state;
36894 if(suppressEvent !== true){
36895 this.fireEvent("checkchange", this, state);
36901 handleClick : function(e){
36902 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36903 this.setChecked(!this.checked);
36905 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36909 * Ext JS Library 1.1.1
36910 * Copyright(c) 2006-2007, Ext JS, LLC.
36912 * Originally Released Under LGPL - original licence link has changed is not relivant.
36915 * <script type="text/javascript">
36919 * @class Roo.menu.DateItem
36920 * @extends Roo.menu.Adapter
36921 * A menu item that wraps the {@link Roo.DatPicker} component.
36923 * Creates a new DateItem
36924 * @param {Object} config Configuration options
36926 Roo.menu.DateItem = function(config){
36927 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36928 /** The Roo.DatePicker object @type Roo.DatePicker */
36929 this.picker = this.component;
36930 this.addEvents({select: true});
36932 this.picker.on("render", function(picker){
36933 picker.getEl().swallowEvent("click");
36934 picker.container.addClass("x-menu-date-item");
36937 this.picker.on("select", this.onSelect, this);
36940 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36942 onSelect : function(picker, date){
36943 this.fireEvent("select", this, date, picker);
36944 Roo.menu.DateItem.superclass.handleClick.call(this);
36948 * Ext JS Library 1.1.1
36949 * Copyright(c) 2006-2007, Ext JS, LLC.
36951 * Originally Released Under LGPL - original licence link has changed is not relivant.
36954 * <script type="text/javascript">
36958 * @class Roo.menu.ColorItem
36959 * @extends Roo.menu.Adapter
36960 * A menu item that wraps the {@link Roo.ColorPalette} component.
36962 * Creates a new ColorItem
36963 * @param {Object} config Configuration options
36965 Roo.menu.ColorItem = function(config){
36966 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36967 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36968 this.palette = this.component;
36969 this.relayEvents(this.palette, ["select"]);
36970 if(this.selectHandler){
36971 this.on('select', this.selectHandler, this.scope);
36974 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36976 * Ext JS Library 1.1.1
36977 * Copyright(c) 2006-2007, Ext JS, LLC.
36979 * Originally Released Under LGPL - original licence link has changed is not relivant.
36982 * <script type="text/javascript">
36987 * @class Roo.menu.DateMenu
36988 * @extends Roo.menu.Menu
36989 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36991 * Creates a new DateMenu
36992 * @param {Object} config Configuration options
36994 Roo.menu.DateMenu = function(config){
36995 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36997 var di = new Roo.menu.DateItem(config);
37000 * The {@link Roo.DatePicker} instance for this DateMenu
37003 this.picker = di.picker;
37006 * @param {DatePicker} picker
37007 * @param {Date} date
37009 this.relayEvents(di, ["select"]);
37010 this.on('beforeshow', function(){
37012 this.picker.hideMonthPicker(false);
37016 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
37020 * Ext JS Library 1.1.1
37021 * Copyright(c) 2006-2007, Ext JS, LLC.
37023 * Originally Released Under LGPL - original licence link has changed is not relivant.
37026 * <script type="text/javascript">
37031 * @class Roo.menu.ColorMenu
37032 * @extends Roo.menu.Menu
37033 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
37035 * Creates a new ColorMenu
37036 * @param {Object} config Configuration options
37038 Roo.menu.ColorMenu = function(config){
37039 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
37041 var ci = new Roo.menu.ColorItem(config);
37044 * The {@link Roo.ColorPalette} instance for this ColorMenu
37045 * @type ColorPalette
37047 this.palette = ci.palette;
37050 * @param {ColorPalette} palette
37051 * @param {String} color
37053 this.relayEvents(ci, ["select"]);
37055 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
37057 * Ext JS Library 1.1.1
37058 * Copyright(c) 2006-2007, Ext JS, LLC.
37060 * Originally Released Under LGPL - original licence link has changed is not relivant.
37063 * <script type="text/javascript">
37067 * @class Roo.form.Field
37068 * @extends Roo.BoxComponent
37069 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
37071 * Creates a new Field
37072 * @param {Object} config Configuration options
37074 Roo.form.Field = function(config){
37075 Roo.form.Field.superclass.constructor.call(this, config);
37078 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
37080 * @cfg {String} fieldLabel Label to use when rendering a form.
37083 * @cfg {String} qtip Mouse over tip
37087 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
37089 invalidClass : "x-form-invalid",
37091 * @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")
37093 invalidText : "The value in this field is invalid",
37095 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
37097 focusClass : "x-form-focus",
37099 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
37100 automatic validation (defaults to "keyup").
37102 validationEvent : "keyup",
37104 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
37106 validateOnBlur : true,
37108 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
37110 validationDelay : 250,
37112 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37113 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
37115 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
37117 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
37119 fieldClass : "x-form-field",
37121 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
37124 ----------- ----------------------------------------------------------------------
37125 qtip Display a quick tip when the user hovers over the field
37126 title Display a default browser title attribute popup
37127 under Add a block div beneath the field containing the error text
37128 side Add an error icon to the right of the field with a popup on hover
37129 [element id] Add the error text directly to the innerHTML of the specified element
37132 msgTarget : 'qtip',
37134 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
37139 * @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.
37144 * @cfg {Boolean} disabled True to disable the field (defaults to false).
37149 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
37151 inputType : undefined,
37154 * @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).
37156 tabIndex : undefined,
37159 isFormField : true,
37164 * @property {Roo.Element} fieldEl
37165 * Element Containing the rendered Field (with label etc.)
37168 * @cfg {Mixed} value A value to initialize this field with.
37173 * @cfg {String} name The field's HTML name attribute.
37176 * @cfg {String} cls A CSS class to apply to the field's underlying element.
37180 initComponent : function(){
37181 Roo.form.Field.superclass.initComponent.call(this);
37185 * Fires when this field receives input focus.
37186 * @param {Roo.form.Field} this
37191 * Fires when this field loses input focus.
37192 * @param {Roo.form.Field} this
37196 * @event specialkey
37197 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
37198 * {@link Roo.EventObject#getKey} to determine which key was pressed.
37199 * @param {Roo.form.Field} this
37200 * @param {Roo.EventObject} e The event object
37205 * Fires just before the field blurs if the field value has changed.
37206 * @param {Roo.form.Field} this
37207 * @param {Mixed} newValue The new value
37208 * @param {Mixed} oldValue The original value
37213 * Fires after the field has been marked as invalid.
37214 * @param {Roo.form.Field} this
37215 * @param {String} msg The validation message
37220 * Fires after the field has been validated with no errors.
37221 * @param {Roo.form.Field} this
37226 * Fires after the key up
37227 * @param {Roo.form.Field} this
37228 * @param {Roo.EventObject} e The event Object
37235 * Returns the name attribute of the field if available
37236 * @return {String} name The field name
37238 getName: function(){
37239 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37243 onRender : function(ct, position){
37244 Roo.form.Field.superclass.onRender.call(this, ct, position);
37246 var cfg = this.getAutoCreate();
37248 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37250 if (!cfg.name.length) {
37253 if(this.inputType){
37254 cfg.type = this.inputType;
37256 this.el = ct.createChild(cfg, position);
37258 var type = this.el.dom.type;
37260 if(type == 'password'){
37263 this.el.addClass('x-form-'+type);
37266 this.el.dom.readOnly = true;
37268 if(this.tabIndex !== undefined){
37269 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37272 this.el.addClass([this.fieldClass, this.cls]);
37277 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37278 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37279 * @return {Roo.form.Field} this
37281 applyTo : function(target){
37282 this.allowDomMove = false;
37283 this.el = Roo.get(target);
37284 this.render(this.el.dom.parentNode);
37289 initValue : function(){
37290 if(this.value !== undefined){
37291 this.setValue(this.value);
37292 }else if(this.el.dom.value.length > 0){
37293 this.setValue(this.el.dom.value);
37298 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37300 isDirty : function() {
37301 if(this.disabled) {
37304 return String(this.getValue()) !== String(this.originalValue);
37308 afterRender : function(){
37309 Roo.form.Field.superclass.afterRender.call(this);
37314 fireKey : function(e){
37315 //Roo.log('field ' + e.getKey());
37316 if(e.isNavKeyPress()){
37317 this.fireEvent("specialkey", this, e);
37322 * Resets the current field value to the originally loaded value and clears any validation messages
37324 reset : function(){
37325 this.setValue(this.resetValue);
37326 this.clearInvalid();
37330 initEvents : function(){
37331 // safari killled keypress - so keydown is now used..
37332 this.el.on("keydown" , this.fireKey, this);
37333 this.el.on("focus", this.onFocus, this);
37334 this.el.on("blur", this.onBlur, this);
37335 this.el.relayEvent('keyup', this);
37337 // reference to original value for reset
37338 this.originalValue = this.getValue();
37339 this.resetValue = this.getValue();
37343 onFocus : function(){
37344 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37345 this.el.addClass(this.focusClass);
37347 if(!this.hasFocus){
37348 this.hasFocus = true;
37349 this.startValue = this.getValue();
37350 this.fireEvent("focus", this);
37354 beforeBlur : Roo.emptyFn,
37357 onBlur : function(){
37359 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37360 this.el.removeClass(this.focusClass);
37362 this.hasFocus = false;
37363 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37366 var v = this.getValue();
37367 if(String(v) !== String(this.startValue)){
37368 this.fireEvent('change', this, v, this.startValue);
37370 this.fireEvent("blur", this);
37374 * Returns whether or not the field value is currently valid
37375 * @param {Boolean} preventMark True to disable marking the field invalid
37376 * @return {Boolean} True if the value is valid, else false
37378 isValid : function(preventMark){
37382 var restore = this.preventMark;
37383 this.preventMark = preventMark === true;
37384 var v = this.validateValue(this.processValue(this.getRawValue()));
37385 this.preventMark = restore;
37390 * Validates the field value
37391 * @return {Boolean} True if the value is valid, else false
37393 validate : function(){
37394 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37395 this.clearInvalid();
37401 processValue : function(value){
37406 // Subclasses should provide the validation implementation by overriding this
37407 validateValue : function(value){
37412 * Mark this field as invalid
37413 * @param {String} msg The validation message
37415 markInvalid : function(msg){
37416 if(!this.rendered || this.preventMark){ // not rendered
37420 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37422 obj.el.addClass(this.invalidClass);
37423 msg = msg || this.invalidText;
37424 switch(this.msgTarget){
37426 obj.el.dom.qtip = msg;
37427 obj.el.dom.qclass = 'x-form-invalid-tip';
37428 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37429 Roo.QuickTips.enable();
37433 this.el.dom.title = msg;
37437 var elp = this.el.findParent('.x-form-element', 5, true);
37438 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37439 this.errorEl.setWidth(elp.getWidth(true)-20);
37441 this.errorEl.update(msg);
37442 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37445 if(!this.errorIcon){
37446 var elp = this.el.findParent('.x-form-element', 5, true);
37447 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37449 this.alignErrorIcon();
37450 this.errorIcon.dom.qtip = msg;
37451 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37452 this.errorIcon.show();
37453 this.on('resize', this.alignErrorIcon, this);
37456 var t = Roo.getDom(this.msgTarget);
37458 t.style.display = this.msgDisplay;
37461 this.fireEvent('invalid', this, msg);
37465 alignErrorIcon : function(){
37466 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37470 * Clear any invalid styles/messages for this field
37472 clearInvalid : function(){
37473 if(!this.rendered || this.preventMark){ // not rendered
37476 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37478 obj.el.removeClass(this.invalidClass);
37479 switch(this.msgTarget){
37481 obj.el.dom.qtip = '';
37484 this.el.dom.title = '';
37488 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37492 if(this.errorIcon){
37493 this.errorIcon.dom.qtip = '';
37494 this.errorIcon.hide();
37495 this.un('resize', this.alignErrorIcon, this);
37499 var t = Roo.getDom(this.msgTarget);
37501 t.style.display = 'none';
37504 this.fireEvent('valid', this);
37508 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37509 * @return {Mixed} value The field value
37511 getRawValue : function(){
37512 var v = this.el.getValue();
37518 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37519 * @return {Mixed} value The field value
37521 getValue : function(){
37522 var v = this.el.getValue();
37528 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37529 * @param {Mixed} value The value to set
37531 setRawValue : function(v){
37532 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37536 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37537 * @param {Mixed} value The value to set
37539 setValue : function(v){
37542 this.el.dom.value = (v === null || v === undefined ? '' : v);
37547 adjustSize : function(w, h){
37548 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37549 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37553 adjustWidth : function(tag, w){
37554 tag = tag.toLowerCase();
37555 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37556 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37557 if(tag == 'input'){
37560 if(tag == 'textarea'){
37563 }else if(Roo.isOpera){
37564 if(tag == 'input'){
37567 if(tag == 'textarea'){
37577 // anything other than normal should be considered experimental
37578 Roo.form.Field.msgFx = {
37580 show: function(msgEl, f){
37581 msgEl.setDisplayed('block');
37584 hide : function(msgEl, f){
37585 msgEl.setDisplayed(false).update('');
37590 show: function(msgEl, f){
37591 msgEl.slideIn('t', {stopFx:true});
37594 hide : function(msgEl, f){
37595 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37600 show: function(msgEl, f){
37601 msgEl.fixDisplay();
37602 msgEl.alignTo(f.el, 'tl-tr');
37603 msgEl.slideIn('l', {stopFx:true});
37606 hide : function(msgEl, f){
37607 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37612 * Ext JS Library 1.1.1
37613 * Copyright(c) 2006-2007, Ext JS, LLC.
37615 * Originally Released Under LGPL - original licence link has changed is not relivant.
37618 * <script type="text/javascript">
37623 * @class Roo.form.TextField
37624 * @extends Roo.form.Field
37625 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37626 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37628 * Creates a new TextField
37629 * @param {Object} config Configuration options
37631 Roo.form.TextField = function(config){
37632 Roo.form.TextField.superclass.constructor.call(this, config);
37636 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37637 * according to the default logic, but this event provides a hook for the developer to apply additional
37638 * logic at runtime to resize the field if needed.
37639 * @param {Roo.form.Field} this This text field
37640 * @param {Number} width The new field width
37646 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37648 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37652 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37656 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37660 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37664 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37668 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37670 disableKeyFilter : false,
37672 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37676 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37680 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37682 maxLength : Number.MAX_VALUE,
37684 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37686 minLengthText : "The minimum length for this field is {0}",
37688 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37690 maxLengthText : "The maximum length for this field is {0}",
37692 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37694 selectOnFocus : false,
37696 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37698 blankText : "This field is required",
37700 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37701 * If available, this function will be called only after the basic validators all return true, and will be passed the
37702 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37706 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37707 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37708 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37712 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37716 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37722 initEvents : function()
37724 if (this.emptyText) {
37725 this.el.attr('placeholder', this.emptyText);
37728 Roo.form.TextField.superclass.initEvents.call(this);
37729 if(this.validationEvent == 'keyup'){
37730 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37731 this.el.on('keyup', this.filterValidation, this);
37733 else if(this.validationEvent !== false){
37734 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37737 if(this.selectOnFocus){
37738 this.on("focus", this.preFocus, this);
37741 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37742 this.el.on("keypress", this.filterKeys, this);
37745 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37746 this.el.on("click", this.autoSize, this);
37748 if(this.el.is('input[type=password]') && Roo.isSafari){
37749 this.el.on('keydown', this.SafariOnKeyDown, this);
37753 processValue : function(value){
37754 if(this.stripCharsRe){
37755 var newValue = value.replace(this.stripCharsRe, '');
37756 if(newValue !== value){
37757 this.setRawValue(newValue);
37764 filterValidation : function(e){
37765 if(!e.isNavKeyPress()){
37766 this.validationTask.delay(this.validationDelay);
37771 onKeyUp : function(e){
37772 if(!e.isNavKeyPress()){
37778 * Resets the current field value to the originally-loaded value and clears any validation messages.
37781 reset : function(){
37782 Roo.form.TextField.superclass.reset.call(this);
37788 preFocus : function(){
37790 if(this.selectOnFocus){
37791 this.el.dom.select();
37797 filterKeys : function(e){
37798 var k = e.getKey();
37799 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37802 var c = e.getCharCode(), cc = String.fromCharCode(c);
37803 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37806 if(!this.maskRe.test(cc)){
37811 setValue : function(v){
37813 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37819 * Validates a value according to the field's validation rules and marks the field as invalid
37820 * if the validation fails
37821 * @param {Mixed} value The value to validate
37822 * @return {Boolean} True if the value is valid, else false
37824 validateValue : function(value){
37825 if(value.length < 1) { // if it's blank
37826 if(this.allowBlank){
37827 this.clearInvalid();
37830 this.markInvalid(this.blankText);
37834 if(value.length < this.minLength){
37835 this.markInvalid(String.format(this.minLengthText, this.minLength));
37838 if(value.length > this.maxLength){
37839 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37843 var vt = Roo.form.VTypes;
37844 if(!vt[this.vtype](value, this)){
37845 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37849 if(typeof this.validator == "function"){
37850 var msg = this.validator(value);
37852 this.markInvalid(msg);
37856 if(this.regex && !this.regex.test(value)){
37857 this.markInvalid(this.regexText);
37864 * Selects text in this field
37865 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37866 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37868 selectText : function(start, end){
37869 var v = this.getRawValue();
37871 start = start === undefined ? 0 : start;
37872 end = end === undefined ? v.length : end;
37873 var d = this.el.dom;
37874 if(d.setSelectionRange){
37875 d.setSelectionRange(start, end);
37876 }else if(d.createTextRange){
37877 var range = d.createTextRange();
37878 range.moveStart("character", start);
37879 range.moveEnd("character", v.length-end);
37886 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37887 * This only takes effect if grow = true, and fires the autosize event.
37889 autoSize : function(){
37890 if(!this.grow || !this.rendered){
37894 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37897 var v = el.dom.value;
37898 var d = document.createElement('div');
37899 d.appendChild(document.createTextNode(v));
37903 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37904 this.el.setWidth(w);
37905 this.fireEvent("autosize", this, w);
37909 SafariOnKeyDown : function(event)
37911 // this is a workaround for a password hang bug on chrome/ webkit.
37913 var isSelectAll = false;
37915 if(this.el.dom.selectionEnd > 0){
37916 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37918 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37919 event.preventDefault();
37924 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
37926 event.preventDefault();
37927 // this is very hacky as keydown always get's upper case.
37929 var cc = String.fromCharCode(event.getCharCode());
37932 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37940 * Ext JS Library 1.1.1
37941 * Copyright(c) 2006-2007, Ext JS, LLC.
37943 * Originally Released Under LGPL - original licence link has changed is not relivant.
37946 * <script type="text/javascript">
37950 * @class Roo.form.Hidden
37951 * @extends Roo.form.TextField
37952 * Simple Hidden element used on forms
37954 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37957 * Creates a new Hidden form element.
37958 * @param {Object} config Configuration options
37963 // easy hidden field...
37964 Roo.form.Hidden = function(config){
37965 Roo.form.Hidden.superclass.constructor.call(this, config);
37968 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37970 inputType: 'hidden',
37973 labelSeparator: '',
37975 itemCls : 'x-form-item-display-none'
37983 * Ext JS Library 1.1.1
37984 * Copyright(c) 2006-2007, Ext JS, LLC.
37986 * Originally Released Under LGPL - original licence link has changed is not relivant.
37989 * <script type="text/javascript">
37993 * @class Roo.form.TriggerField
37994 * @extends Roo.form.TextField
37995 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37996 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37997 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37998 * for which you can provide a custom implementation. For example:
38000 var trigger = new Roo.form.TriggerField();
38001 trigger.onTriggerClick = myTriggerFn;
38002 trigger.applyTo('my-field');
38005 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
38006 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
38007 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
38008 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
38010 * Create a new TriggerField.
38011 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
38012 * to the base TextField)
38014 Roo.form.TriggerField = function(config){
38015 this.mimicing = false;
38016 Roo.form.TriggerField.superclass.constructor.call(this, config);
38019 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
38021 * @cfg {String} triggerClass A CSS class to apply to the trigger
38024 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38025 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
38027 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
38029 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
38033 /** @cfg {Boolean} grow @hide */
38034 /** @cfg {Number} growMin @hide */
38035 /** @cfg {Number} growMax @hide */
38041 autoSize: Roo.emptyFn,
38045 deferHeight : true,
38048 actionMode : 'wrap',
38050 onResize : function(w, h){
38051 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
38052 if(typeof w == 'number'){
38053 var x = w - this.trigger.getWidth();
38054 this.el.setWidth(this.adjustWidth('input', x));
38055 this.trigger.setStyle('left', x+'px');
38060 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38063 getResizeEl : function(){
38068 getPositionEl : function(){
38073 alignErrorIcon : function(){
38074 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
38078 onRender : function(ct, position){
38079 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
38080 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
38081 this.trigger = this.wrap.createChild(this.triggerConfig ||
38082 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
38083 if(this.hideTrigger){
38084 this.trigger.setDisplayed(false);
38086 this.initTrigger();
38088 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
38093 initTrigger : function(){
38094 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
38095 this.trigger.addClassOnOver('x-form-trigger-over');
38096 this.trigger.addClassOnClick('x-form-trigger-click');
38100 onDestroy : function(){
38102 this.trigger.removeAllListeners();
38103 this.trigger.remove();
38106 this.wrap.remove();
38108 Roo.form.TriggerField.superclass.onDestroy.call(this);
38112 onFocus : function(){
38113 Roo.form.TriggerField.superclass.onFocus.call(this);
38114 if(!this.mimicing){
38115 this.wrap.addClass('x-trigger-wrap-focus');
38116 this.mimicing = true;
38117 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
38118 if(this.monitorTab){
38119 this.el.on("keydown", this.checkTab, this);
38125 checkTab : function(e){
38126 if(e.getKey() == e.TAB){
38127 this.triggerBlur();
38132 onBlur : function(){
38137 mimicBlur : function(e, t){
38138 if(!this.wrap.contains(t) && this.validateBlur()){
38139 this.triggerBlur();
38144 triggerBlur : function(){
38145 this.mimicing = false;
38146 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
38147 if(this.monitorTab){
38148 this.el.un("keydown", this.checkTab, this);
38150 this.wrap.removeClass('x-trigger-wrap-focus');
38151 Roo.form.TriggerField.superclass.onBlur.call(this);
38155 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
38156 validateBlur : function(e, t){
38161 onDisable : function(){
38162 Roo.form.TriggerField.superclass.onDisable.call(this);
38164 this.wrap.addClass('x-item-disabled');
38169 onEnable : function(){
38170 Roo.form.TriggerField.superclass.onEnable.call(this);
38172 this.wrap.removeClass('x-item-disabled');
38177 onShow : function(){
38178 var ae = this.getActionEl();
38181 ae.dom.style.display = '';
38182 ae.dom.style.visibility = 'visible';
38188 onHide : function(){
38189 var ae = this.getActionEl();
38190 ae.dom.style.display = 'none';
38194 * The function that should handle the trigger's click event. This method does nothing by default until overridden
38195 * by an implementing function.
38197 * @param {EventObject} e
38199 onTriggerClick : Roo.emptyFn
38202 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
38203 // to be extended by an implementing class. For an example of implementing this class, see the custom
38204 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
38205 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
38206 initComponent : function(){
38207 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
38209 this.triggerConfig = {
38210 tag:'span', cls:'x-form-twin-triggers', cn:[
38211 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38212 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38216 getTrigger : function(index){
38217 return this.triggers[index];
38220 initTrigger : function(){
38221 var ts = this.trigger.select('.x-form-trigger', true);
38222 this.wrap.setStyle('overflow', 'hidden');
38223 var triggerField = this;
38224 ts.each(function(t, all, index){
38225 t.hide = function(){
38226 var w = triggerField.wrap.getWidth();
38227 this.dom.style.display = 'none';
38228 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38230 t.show = function(){
38231 var w = triggerField.wrap.getWidth();
38232 this.dom.style.display = '';
38233 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38235 var triggerIndex = 'Trigger'+(index+1);
38237 if(this['hide'+triggerIndex]){
38238 t.dom.style.display = 'none';
38240 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38241 t.addClassOnOver('x-form-trigger-over');
38242 t.addClassOnClick('x-form-trigger-click');
38244 this.triggers = ts.elements;
38247 onTrigger1Click : Roo.emptyFn,
38248 onTrigger2Click : Roo.emptyFn
38251 * Ext JS Library 1.1.1
38252 * Copyright(c) 2006-2007, Ext JS, LLC.
38254 * Originally Released Under LGPL - original licence link has changed is not relivant.
38257 * <script type="text/javascript">
38261 * @class Roo.form.TextArea
38262 * @extends Roo.form.TextField
38263 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38264 * support for auto-sizing.
38266 * Creates a new TextArea
38267 * @param {Object} config Configuration options
38269 Roo.form.TextArea = function(config){
38270 Roo.form.TextArea.superclass.constructor.call(this, config);
38271 // these are provided exchanges for backwards compat
38272 // minHeight/maxHeight were replaced by growMin/growMax to be
38273 // compatible with TextField growing config values
38274 if(this.minHeight !== undefined){
38275 this.growMin = this.minHeight;
38277 if(this.maxHeight !== undefined){
38278 this.growMax = this.maxHeight;
38282 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38284 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38288 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38292 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38293 * in the field (equivalent to setting overflow: hidden, defaults to false)
38295 preventScrollbars: false,
38297 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38298 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38302 onRender : function(ct, position){
38304 this.defaultAutoCreate = {
38306 style:"width:300px;height:60px;",
38307 autocomplete: "new-password"
38310 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38312 this.textSizeEl = Roo.DomHelper.append(document.body, {
38313 tag: "pre", cls: "x-form-grow-sizer"
38315 if(this.preventScrollbars){
38316 this.el.setStyle("overflow", "hidden");
38318 this.el.setHeight(this.growMin);
38322 onDestroy : function(){
38323 if(this.textSizeEl){
38324 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38326 Roo.form.TextArea.superclass.onDestroy.call(this);
38330 onKeyUp : function(e){
38331 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38337 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38338 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38340 autoSize : function(){
38341 if(!this.grow || !this.textSizeEl){
38345 var v = el.dom.value;
38346 var ts = this.textSizeEl;
38349 ts.appendChild(document.createTextNode(v));
38352 Roo.fly(ts).setWidth(this.el.getWidth());
38354 v = "  ";
38357 v = v.replace(/\n/g, '<p> </p>');
38359 v += " \n ";
38362 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38363 if(h != this.lastHeight){
38364 this.lastHeight = h;
38365 this.el.setHeight(h);
38366 this.fireEvent("autosize", this, h);
38371 * Ext JS Library 1.1.1
38372 * Copyright(c) 2006-2007, Ext JS, LLC.
38374 * Originally Released Under LGPL - original licence link has changed is not relivant.
38377 * <script type="text/javascript">
38382 * @class Roo.form.NumberField
38383 * @extends Roo.form.TextField
38384 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38386 * Creates a new NumberField
38387 * @param {Object} config Configuration options
38389 Roo.form.NumberField = function(config){
38390 Roo.form.NumberField.superclass.constructor.call(this, config);
38393 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38395 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38397 fieldClass: "x-form-field x-form-num-field",
38399 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38401 allowDecimals : true,
38403 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38405 decimalSeparator : ".",
38407 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38409 decimalPrecision : 2,
38411 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38413 allowNegative : true,
38415 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38417 minValue : Number.NEGATIVE_INFINITY,
38419 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38421 maxValue : Number.MAX_VALUE,
38423 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38425 minText : "The minimum value for this field is {0}",
38427 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38429 maxText : "The maximum value for this field is {0}",
38431 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38432 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38434 nanText : "{0} is not a valid number",
38437 initEvents : function(){
38438 Roo.form.NumberField.superclass.initEvents.call(this);
38439 var allowed = "0123456789";
38440 if(this.allowDecimals){
38441 allowed += this.decimalSeparator;
38443 if(this.allowNegative){
38446 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38447 var keyPress = function(e){
38448 var k = e.getKey();
38449 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38452 var c = e.getCharCode();
38453 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38457 this.el.on("keypress", keyPress, this);
38461 validateValue : function(value){
38462 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38465 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38468 var num = this.parseValue(value);
38470 this.markInvalid(String.format(this.nanText, value));
38473 if(num < this.minValue){
38474 this.markInvalid(String.format(this.minText, this.minValue));
38477 if(num > this.maxValue){
38478 this.markInvalid(String.format(this.maxText, this.maxValue));
38484 getValue : function(){
38485 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38489 parseValue : function(value){
38490 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38491 return isNaN(value) ? '' : value;
38495 fixPrecision : function(value){
38496 var nan = isNaN(value);
38497 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38498 return nan ? '' : value;
38500 return parseFloat(value).toFixed(this.decimalPrecision);
38503 setValue : function(v){
38504 v = this.fixPrecision(v);
38505 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38509 decimalPrecisionFcn : function(v){
38510 return Math.floor(v);
38513 beforeBlur : function(){
38514 var v = this.parseValue(this.getRawValue());
38521 * Ext JS Library 1.1.1
38522 * Copyright(c) 2006-2007, Ext JS, LLC.
38524 * Originally Released Under LGPL - original licence link has changed is not relivant.
38527 * <script type="text/javascript">
38531 * @class Roo.form.DateField
38532 * @extends Roo.form.TriggerField
38533 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38535 * Create a new DateField
38536 * @param {Object} config
38538 Roo.form.DateField = function(config){
38539 Roo.form.DateField.superclass.constructor.call(this, config);
38545 * Fires when a date is selected
38546 * @param {Roo.form.DateField} combo This combo box
38547 * @param {Date} date The date selected
38554 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38555 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38556 this.ddMatch = null;
38557 if(this.disabledDates){
38558 var dd = this.disabledDates;
38560 for(var i = 0; i < dd.length; i++){
38562 if(i != dd.length-1) re += "|";
38564 this.ddMatch = new RegExp(re + ")");
38568 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38570 * @cfg {String} format
38571 * The default date format string which can be overriden for localization support. The format must be
38572 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38576 * @cfg {String} altFormats
38577 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38578 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38580 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38582 * @cfg {Array} disabledDays
38583 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38585 disabledDays : null,
38587 * @cfg {String} disabledDaysText
38588 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38590 disabledDaysText : "Disabled",
38592 * @cfg {Array} disabledDates
38593 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38594 * expression so they are very powerful. Some examples:
38596 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38597 * <li>["03/08", "09/16"] would disable those days for every year</li>
38598 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38599 * <li>["03/../2006"] would disable every day in March 2006</li>
38600 * <li>["^03"] would disable every day in every March</li>
38602 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38603 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38605 disabledDates : null,
38607 * @cfg {String} disabledDatesText
38608 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38610 disabledDatesText : "Disabled",
38612 * @cfg {Date/String} minValue
38613 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38614 * valid format (defaults to null).
38618 * @cfg {Date/String} maxValue
38619 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38620 * valid format (defaults to null).
38624 * @cfg {String} minText
38625 * The error text to display when the date in the cell is before minValue (defaults to
38626 * 'The date in this field must be after {minValue}').
38628 minText : "The date in this field must be equal to or after {0}",
38630 * @cfg {String} maxText
38631 * The error text to display when the date in the cell is after maxValue (defaults to
38632 * 'The date in this field must be before {maxValue}').
38634 maxText : "The date in this field must be equal to or before {0}",
38636 * @cfg {String} invalidText
38637 * The error text to display when the date in the field is invalid (defaults to
38638 * '{value} is not a valid date - it must be in the format {format}').
38640 invalidText : "{0} is not a valid date - it must be in the format {1}",
38642 * @cfg {String} triggerClass
38643 * An additional CSS class used to style the trigger button. The trigger will always get the
38644 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38645 * which displays a calendar icon).
38647 triggerClass : 'x-form-date-trigger',
38651 * @cfg {Boolean} useIso
38652 * if enabled, then the date field will use a hidden field to store the
38653 * real value as iso formated date. default (false)
38657 * @cfg {String/Object} autoCreate
38658 * A DomHelper element spec, or true for a default element spec (defaults to
38659 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38662 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38665 hiddenField: false,
38667 onRender : function(ct, position)
38669 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38671 //this.el.dom.removeAttribute('name');
38672 Roo.log("Changing name?");
38673 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38674 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38676 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38677 // prevent input submission
38678 this.hiddenName = this.name;
38685 validateValue : function(value)
38687 value = this.formatDate(value);
38688 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38689 Roo.log('super failed');
38692 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38695 var svalue = value;
38696 value = this.parseDate(value);
38698 Roo.log('parse date failed' + svalue);
38699 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38702 var time = value.getTime();
38703 if(this.minValue && time < this.minValue.getTime()){
38704 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38707 if(this.maxValue && time > this.maxValue.getTime()){
38708 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38711 if(this.disabledDays){
38712 var day = value.getDay();
38713 for(var i = 0; i < this.disabledDays.length; i++) {
38714 if(day === this.disabledDays[i]){
38715 this.markInvalid(this.disabledDaysText);
38720 var fvalue = this.formatDate(value);
38721 if(this.ddMatch && this.ddMatch.test(fvalue)){
38722 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38729 // Provides logic to override the default TriggerField.validateBlur which just returns true
38730 validateBlur : function(){
38731 return !this.menu || !this.menu.isVisible();
38734 getName: function()
38736 // returns hidden if it's set..
38737 if (!this.rendered) {return ''};
38738 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38743 * Returns the current date value of the date field.
38744 * @return {Date} The date value
38746 getValue : function(){
38748 return this.hiddenField ?
38749 this.hiddenField.value :
38750 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38754 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38755 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38756 * (the default format used is "m/d/y").
38759 //All of these calls set the same date value (May 4, 2006)
38761 //Pass a date object:
38762 var dt = new Date('5/4/06');
38763 dateField.setValue(dt);
38765 //Pass a date string (default format):
38766 dateField.setValue('5/4/06');
38768 //Pass a date string (custom format):
38769 dateField.format = 'Y-m-d';
38770 dateField.setValue('2006-5-4');
38772 * @param {String/Date} date The date or valid date string
38774 setValue : function(date){
38775 if (this.hiddenField) {
38776 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38778 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38779 // make sure the value field is always stored as a date..
38780 this.value = this.parseDate(date);
38786 parseDate : function(value){
38787 if(!value || value instanceof Date){
38790 var v = Date.parseDate(value, this.format);
38791 if (!v && this.useIso) {
38792 v = Date.parseDate(value, 'Y-m-d');
38794 if(!v && this.altFormats){
38795 if(!this.altFormatsArray){
38796 this.altFormatsArray = this.altFormats.split("|");
38798 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38799 v = Date.parseDate(value, this.altFormatsArray[i]);
38806 formatDate : function(date, fmt){
38807 return (!date || !(date instanceof Date)) ?
38808 date : date.dateFormat(fmt || this.format);
38813 select: function(m, d){
38816 this.fireEvent('select', this, d);
38818 show : function(){ // retain focus styling
38822 this.focus.defer(10, this);
38823 var ml = this.menuListeners;
38824 this.menu.un("select", ml.select, this);
38825 this.menu.un("show", ml.show, this);
38826 this.menu.un("hide", ml.hide, this);
38831 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38832 onTriggerClick : function(){
38836 if(this.menu == null){
38837 this.menu = new Roo.menu.DateMenu();
38839 Roo.apply(this.menu.picker, {
38840 showClear: this.allowBlank,
38841 minDate : this.minValue,
38842 maxDate : this.maxValue,
38843 disabledDatesRE : this.ddMatch,
38844 disabledDatesText : this.disabledDatesText,
38845 disabledDays : this.disabledDays,
38846 disabledDaysText : this.disabledDaysText,
38847 format : this.useIso ? 'Y-m-d' : this.format,
38848 minText : String.format(this.minText, this.formatDate(this.minValue)),
38849 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38851 this.menu.on(Roo.apply({}, this.menuListeners, {
38854 this.menu.picker.setValue(this.getValue() || new Date());
38855 this.menu.show(this.el, "tl-bl?");
38858 beforeBlur : function(){
38859 var v = this.parseDate(this.getRawValue());
38869 isDirty : function() {
38870 if(this.disabled) {
38874 if(typeof(this.startValue) === 'undefined'){
38878 return String(this.getValue()) !== String(this.startValue);
38883 * Ext JS Library 1.1.1
38884 * Copyright(c) 2006-2007, Ext JS, LLC.
38886 * Originally Released Under LGPL - original licence link has changed is not relivant.
38889 * <script type="text/javascript">
38893 * @class Roo.form.MonthField
38894 * @extends Roo.form.TriggerField
38895 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38897 * Create a new MonthField
38898 * @param {Object} config
38900 Roo.form.MonthField = function(config){
38902 Roo.form.MonthField.superclass.constructor.call(this, config);
38908 * Fires when a date is selected
38909 * @param {Roo.form.MonthFieeld} combo This combo box
38910 * @param {Date} date The date selected
38917 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38918 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38919 this.ddMatch = null;
38920 if(this.disabledDates){
38921 var dd = this.disabledDates;
38923 for(var i = 0; i < dd.length; i++){
38925 if(i != dd.length-1) re += "|";
38927 this.ddMatch = new RegExp(re + ")");
38931 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38933 * @cfg {String} format
38934 * The default date format string which can be overriden for localization support. The format must be
38935 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38939 * @cfg {String} altFormats
38940 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38941 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38943 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38945 * @cfg {Array} disabledDays
38946 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38948 disabledDays : [0,1,2,3,4,5,6],
38950 * @cfg {String} disabledDaysText
38951 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38953 disabledDaysText : "Disabled",
38955 * @cfg {Array} disabledDates
38956 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38957 * expression so they are very powerful. Some examples:
38959 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38960 * <li>["03/08", "09/16"] would disable those days for every year</li>
38961 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38962 * <li>["03/../2006"] would disable every day in March 2006</li>
38963 * <li>["^03"] would disable every day in every March</li>
38965 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38966 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38968 disabledDates : null,
38970 * @cfg {String} disabledDatesText
38971 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38973 disabledDatesText : "Disabled",
38975 * @cfg {Date/String} minValue
38976 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38977 * valid format (defaults to null).
38981 * @cfg {Date/String} maxValue
38982 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38983 * valid format (defaults to null).
38987 * @cfg {String} minText
38988 * The error text to display when the date in the cell is before minValue (defaults to
38989 * 'The date in this field must be after {minValue}').
38991 minText : "The date in this field must be equal to or after {0}",
38993 * @cfg {String} maxTextf
38994 * The error text to display when the date in the cell is after maxValue (defaults to
38995 * 'The date in this field must be before {maxValue}').
38997 maxText : "The date in this field must be equal to or before {0}",
38999 * @cfg {String} invalidText
39000 * The error text to display when the date in the field is invalid (defaults to
39001 * '{value} is not a valid date - it must be in the format {format}').
39003 invalidText : "{0} is not a valid date - it must be in the format {1}",
39005 * @cfg {String} triggerClass
39006 * An additional CSS class used to style the trigger button. The trigger will always get the
39007 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
39008 * which displays a calendar icon).
39010 triggerClass : 'x-form-date-trigger',
39014 * @cfg {Boolean} useIso
39015 * if enabled, then the date field will use a hidden field to store the
39016 * real value as iso formated date. default (true)
39020 * @cfg {String/Object} autoCreate
39021 * A DomHelper element spec, or true for a default element spec (defaults to
39022 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
39025 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
39028 hiddenField: false,
39030 hideMonthPicker : false,
39032 onRender : function(ct, position)
39034 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
39036 this.el.dom.removeAttribute('name');
39037 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
39039 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
39040 // prevent input submission
39041 this.hiddenName = this.name;
39048 validateValue : function(value)
39050 value = this.formatDate(value);
39051 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
39054 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39057 var svalue = value;
39058 value = this.parseDate(value);
39060 this.markInvalid(String.format(this.invalidText, svalue, this.format));
39063 var time = value.getTime();
39064 if(this.minValue && time < this.minValue.getTime()){
39065 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
39068 if(this.maxValue && time > this.maxValue.getTime()){
39069 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
39072 /*if(this.disabledDays){
39073 var day = value.getDay();
39074 for(var i = 0; i < this.disabledDays.length; i++) {
39075 if(day === this.disabledDays[i]){
39076 this.markInvalid(this.disabledDaysText);
39082 var fvalue = this.formatDate(value);
39083 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
39084 this.markInvalid(String.format(this.disabledDatesText, fvalue));
39092 // Provides logic to override the default TriggerField.validateBlur which just returns true
39093 validateBlur : function(){
39094 return !this.menu || !this.menu.isVisible();
39098 * Returns the current date value of the date field.
39099 * @return {Date} The date value
39101 getValue : function(){
39105 return this.hiddenField ?
39106 this.hiddenField.value :
39107 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
39111 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
39112 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
39113 * (the default format used is "m/d/y").
39116 //All of these calls set the same date value (May 4, 2006)
39118 //Pass a date object:
39119 var dt = new Date('5/4/06');
39120 monthField.setValue(dt);
39122 //Pass a date string (default format):
39123 monthField.setValue('5/4/06');
39125 //Pass a date string (custom format):
39126 monthField.format = 'Y-m-d';
39127 monthField.setValue('2006-5-4');
39129 * @param {String/Date} date The date or valid date string
39131 setValue : function(date){
39132 Roo.log('month setValue' + date);
39133 // can only be first of month..
39135 var val = this.parseDate(date);
39137 if (this.hiddenField) {
39138 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
39140 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
39141 this.value = this.parseDate(date);
39145 parseDate : function(value){
39146 if(!value || value instanceof Date){
39147 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
39150 var v = Date.parseDate(value, this.format);
39151 if (!v && this.useIso) {
39152 v = Date.parseDate(value, 'Y-m-d');
39156 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
39160 if(!v && this.altFormats){
39161 if(!this.altFormatsArray){
39162 this.altFormatsArray = this.altFormats.split("|");
39164 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
39165 v = Date.parseDate(value, this.altFormatsArray[i]);
39172 formatDate : function(date, fmt){
39173 return (!date || !(date instanceof Date)) ?
39174 date : date.dateFormat(fmt || this.format);
39179 select: function(m, d){
39181 this.fireEvent('select', this, d);
39183 show : function(){ // retain focus styling
39187 this.focus.defer(10, this);
39188 var ml = this.menuListeners;
39189 this.menu.un("select", ml.select, this);
39190 this.menu.un("show", ml.show, this);
39191 this.menu.un("hide", ml.hide, this);
39195 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
39196 onTriggerClick : function(){
39200 if(this.menu == null){
39201 this.menu = new Roo.menu.DateMenu();
39205 Roo.apply(this.menu.picker, {
39207 showClear: this.allowBlank,
39208 minDate : this.minValue,
39209 maxDate : this.maxValue,
39210 disabledDatesRE : this.ddMatch,
39211 disabledDatesText : this.disabledDatesText,
39213 format : this.useIso ? 'Y-m-d' : this.format,
39214 minText : String.format(this.minText, this.formatDate(this.minValue)),
39215 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39218 this.menu.on(Roo.apply({}, this.menuListeners, {
39226 // hide month picker get's called when we called by 'before hide';
39228 var ignorehide = true;
39229 p.hideMonthPicker = function(disableAnim){
39233 if(this.monthPicker){
39234 Roo.log("hideMonthPicker called");
39235 if(disableAnim === true){
39236 this.monthPicker.hide();
39238 this.monthPicker.slideOut('t', {duration:.2});
39239 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39240 p.fireEvent("select", this, this.value);
39246 Roo.log('picker set value');
39247 Roo.log(this.getValue());
39248 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39249 m.show(this.el, 'tl-bl?');
39250 ignorehide = false;
39251 // this will trigger hideMonthPicker..
39254 // hidden the day picker
39255 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39261 p.showMonthPicker.defer(100, p);
39267 beforeBlur : function(){
39268 var v = this.parseDate(this.getRawValue());
39274 /** @cfg {Boolean} grow @hide */
39275 /** @cfg {Number} growMin @hide */
39276 /** @cfg {Number} growMax @hide */
39283 * Ext JS Library 1.1.1
39284 * Copyright(c) 2006-2007, Ext JS, LLC.
39286 * Originally Released Under LGPL - original licence link has changed is not relivant.
39289 * <script type="text/javascript">
39294 * @class Roo.form.ComboBox
39295 * @extends Roo.form.TriggerField
39296 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39298 * Create a new ComboBox.
39299 * @param {Object} config Configuration options
39301 Roo.form.ComboBox = function(config){
39302 Roo.form.ComboBox.superclass.constructor.call(this, config);
39306 * Fires when the dropdown list is expanded
39307 * @param {Roo.form.ComboBox} combo This combo box
39312 * Fires when the dropdown list is collapsed
39313 * @param {Roo.form.ComboBox} combo This combo box
39317 * @event beforeselect
39318 * Fires before a list item is selected. Return false to cancel the selection.
39319 * @param {Roo.form.ComboBox} combo This combo box
39320 * @param {Roo.data.Record} record The data record returned from the underlying store
39321 * @param {Number} index The index of the selected item in the dropdown list
39323 'beforeselect' : true,
39326 * Fires when a list item is selected
39327 * @param {Roo.form.ComboBox} combo This combo box
39328 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39329 * @param {Number} index The index of the selected item in the dropdown list
39333 * @event beforequery
39334 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39335 * The event object passed has these properties:
39336 * @param {Roo.form.ComboBox} combo This combo box
39337 * @param {String} query The query
39338 * @param {Boolean} forceAll true to force "all" query
39339 * @param {Boolean} cancel true to cancel the query
39340 * @param {Object} e The query event object
39342 'beforequery': true,
39345 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39346 * @param {Roo.form.ComboBox} combo This combo box
39351 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39352 * @param {Roo.form.ComboBox} combo This combo box
39353 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39359 if(this.transform){
39360 this.allowDomMove = false;
39361 var s = Roo.getDom(this.transform);
39362 if(!this.hiddenName){
39363 this.hiddenName = s.name;
39366 this.mode = 'local';
39367 var d = [], opts = s.options;
39368 for(var i = 0, len = opts.length;i < len; i++){
39370 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39372 this.value = value;
39374 d.push([value, o.text]);
39376 this.store = new Roo.data.SimpleStore({
39378 fields: ['value', 'text'],
39381 this.valueField = 'value';
39382 this.displayField = 'text';
39384 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39385 if(!this.lazyRender){
39386 this.target = true;
39387 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39388 s.parentNode.removeChild(s); // remove it
39389 this.render(this.el.parentNode);
39391 s.parentNode.removeChild(s); // remove it
39396 this.store = Roo.factory(this.store, Roo.data);
39399 this.selectedIndex = -1;
39400 if(this.mode == 'local'){
39401 if(config.queryDelay === undefined){
39402 this.queryDelay = 10;
39404 if(config.minChars === undefined){
39410 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39412 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39415 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39416 * rendering into an Roo.Editor, defaults to false)
39419 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39420 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39423 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39426 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39427 * the dropdown list (defaults to undefined, with no header element)
39431 * @cfg {String/Roo.Template} tpl The template to use to render the output
39435 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39437 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39439 listWidth: undefined,
39441 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39442 * mode = 'remote' or 'text' if mode = 'local')
39444 displayField: undefined,
39446 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39447 * mode = 'remote' or 'value' if mode = 'local').
39448 * Note: use of a valueField requires the user make a selection
39449 * in order for a value to be mapped.
39451 valueField: undefined,
39455 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39456 * field's data value (defaults to the underlying DOM element's name)
39458 hiddenName: undefined,
39460 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39464 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39466 selectedClass: 'x-combo-selected',
39468 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39469 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39470 * which displays a downward arrow icon).
39472 triggerClass : 'x-form-arrow-trigger',
39474 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39478 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39479 * anchor positions (defaults to 'tl-bl')
39481 listAlign: 'tl-bl?',
39483 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39487 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39488 * query specified by the allQuery config option (defaults to 'query')
39490 triggerAction: 'query',
39492 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39493 * (defaults to 4, does not apply if editable = false)
39497 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39498 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39502 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39503 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39507 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39508 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39512 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39513 * when editable = true (defaults to false)
39515 selectOnFocus:false,
39517 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39519 queryParam: 'query',
39521 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39522 * when mode = 'remote' (defaults to 'Loading...')
39524 loadingText: 'Loading...',
39526 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39530 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39534 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39535 * traditional select (defaults to true)
39539 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39543 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39547 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39548 * listWidth has a higher value)
39552 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39553 * allow the user to set arbitrary text into the field (defaults to false)
39555 forceSelection:false,
39557 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39558 * if typeAhead = true (defaults to 250)
39560 typeAheadDelay : 250,
39562 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39563 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39565 valueNotFoundText : undefined,
39567 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39569 blockFocus : false,
39572 * @cfg {Boolean} disableClear Disable showing of clear button.
39574 disableClear : false,
39576 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39578 alwaysQuery : false,
39584 // element that contains real text value.. (when hidden is used..)
39587 onRender : function(ct, position){
39588 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39589 if(this.hiddenName){
39590 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39592 this.hiddenField.value =
39593 this.hiddenValue !== undefined ? this.hiddenValue :
39594 this.value !== undefined ? this.value : '';
39596 // prevent input submission
39597 this.el.dom.removeAttribute('name');
39602 this.el.dom.setAttribute('autocomplete', 'off');
39605 var cls = 'x-combo-list';
39607 this.list = new Roo.Layer({
39608 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39611 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39612 this.list.setWidth(lw);
39613 this.list.swallowEvent('mousewheel');
39614 this.assetHeight = 0;
39617 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39618 this.assetHeight += this.header.getHeight();
39621 this.innerList = this.list.createChild({cls:cls+'-inner'});
39622 this.innerList.on('mouseover', this.onViewOver, this);
39623 this.innerList.on('mousemove', this.onViewMove, this);
39624 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39626 if(this.allowBlank && !this.pageSize && !this.disableClear){
39627 this.footer = this.list.createChild({cls:cls+'-ft'});
39628 this.pageTb = new Roo.Toolbar(this.footer);
39632 this.footer = this.list.createChild({cls:cls+'-ft'});
39633 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39634 {pageSize: this.pageSize});
39638 if (this.pageTb && this.allowBlank && !this.disableClear) {
39640 this.pageTb.add(new Roo.Toolbar.Fill(), {
39641 cls: 'x-btn-icon x-btn-clear',
39643 handler: function()
39646 _this.clearValue();
39647 _this.onSelect(false, -1);
39652 this.assetHeight += this.footer.getHeight();
39657 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39660 this.view = new Roo.View(this.innerList, this.tpl, {
39661 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39664 this.view.on('click', this.onViewClick, this);
39666 this.store.on('beforeload', this.onBeforeLoad, this);
39667 this.store.on('load', this.onLoad, this);
39668 this.store.on('loadexception', this.onLoadException, this);
39670 if(this.resizable){
39671 this.resizer = new Roo.Resizable(this.list, {
39672 pinned:true, handles:'se'
39674 this.resizer.on('resize', function(r, w, h){
39675 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39676 this.listWidth = w;
39677 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39678 this.restrictHeight();
39680 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39682 if(!this.editable){
39683 this.editable = true;
39684 this.setEditable(false);
39688 if (typeof(this.events.add.listeners) != 'undefined') {
39690 this.addicon = this.wrap.createChild(
39691 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39693 this.addicon.on('click', function(e) {
39694 this.fireEvent('add', this);
39697 if (typeof(this.events.edit.listeners) != 'undefined') {
39699 this.editicon = this.wrap.createChild(
39700 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39701 if (this.addicon) {
39702 this.editicon.setStyle('margin-left', '40px');
39704 this.editicon.on('click', function(e) {
39706 // we fire even if inothing is selected..
39707 this.fireEvent('edit', this, this.lastData );
39717 initEvents : function(){
39718 Roo.form.ComboBox.superclass.initEvents.call(this);
39720 this.keyNav = new Roo.KeyNav(this.el, {
39721 "up" : function(e){
39722 this.inKeyMode = true;
39726 "down" : function(e){
39727 if(!this.isExpanded()){
39728 this.onTriggerClick();
39730 this.inKeyMode = true;
39735 "enter" : function(e){
39736 this.onViewClick();
39740 "esc" : function(e){
39744 "tab" : function(e){
39745 this.onViewClick(false);
39746 this.fireEvent("specialkey", this, e);
39752 doRelay : function(foo, bar, hname){
39753 if(hname == 'down' || this.scope.isExpanded()){
39754 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39761 this.queryDelay = Math.max(this.queryDelay || 10,
39762 this.mode == 'local' ? 10 : 250);
39763 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39764 if(this.typeAhead){
39765 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39767 if(this.editable !== false){
39768 this.el.on("keyup", this.onKeyUp, this);
39770 if(this.forceSelection){
39771 this.on('blur', this.doForce, this);
39775 onDestroy : function(){
39777 this.view.setStore(null);
39778 this.view.el.removeAllListeners();
39779 this.view.el.remove();
39780 this.view.purgeListeners();
39783 this.list.destroy();
39786 this.store.un('beforeload', this.onBeforeLoad, this);
39787 this.store.un('load', this.onLoad, this);
39788 this.store.un('loadexception', this.onLoadException, this);
39790 Roo.form.ComboBox.superclass.onDestroy.call(this);
39794 fireKey : function(e){
39795 if(e.isNavKeyPress() && !this.list.isVisible()){
39796 this.fireEvent("specialkey", this, e);
39801 onResize: function(w, h){
39802 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39804 if(typeof w != 'number'){
39805 // we do not handle it!?!?
39808 var tw = this.trigger.getWidth();
39809 tw += this.addicon ? this.addicon.getWidth() : 0;
39810 tw += this.editicon ? this.editicon.getWidth() : 0;
39812 this.el.setWidth( this.adjustWidth('input', x));
39814 this.trigger.setStyle('left', x+'px');
39816 if(this.list && this.listWidth === undefined){
39817 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39818 this.list.setWidth(lw);
39819 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39827 * Allow or prevent the user from directly editing the field text. If false is passed,
39828 * the user will only be able to select from the items defined in the dropdown list. This method
39829 * is the runtime equivalent of setting the 'editable' config option at config time.
39830 * @param {Boolean} value True to allow the user to directly edit the field text
39832 setEditable : function(value){
39833 if(value == this.editable){
39836 this.editable = value;
39838 this.el.dom.setAttribute('readOnly', true);
39839 this.el.on('mousedown', this.onTriggerClick, this);
39840 this.el.addClass('x-combo-noedit');
39842 this.el.dom.setAttribute('readOnly', false);
39843 this.el.un('mousedown', this.onTriggerClick, this);
39844 this.el.removeClass('x-combo-noedit');
39849 onBeforeLoad : function(){
39850 if(!this.hasFocus){
39853 this.innerList.update(this.loadingText ?
39854 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39855 this.restrictHeight();
39856 this.selectedIndex = -1;
39860 onLoad : function(){
39861 if(!this.hasFocus){
39864 if(this.store.getCount() > 0){
39866 this.restrictHeight();
39867 if(this.lastQuery == this.allQuery){
39869 this.el.dom.select();
39871 if(!this.selectByValue(this.value, true)){
39872 this.select(0, true);
39876 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39877 this.taTask.delay(this.typeAheadDelay);
39881 this.onEmptyResults();
39886 onLoadException : function()
39889 Roo.log(this.store.reader.jsonData);
39890 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39891 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39897 onTypeAhead : function(){
39898 if(this.store.getCount() > 0){
39899 var r = this.store.getAt(0);
39900 var newValue = r.data[this.displayField];
39901 var len = newValue.length;
39902 var selStart = this.getRawValue().length;
39903 if(selStart != len){
39904 this.setRawValue(newValue);
39905 this.selectText(selStart, newValue.length);
39911 onSelect : function(record, index){
39912 if(this.fireEvent('beforeselect', this, record, index) !== false){
39913 this.setFromData(index > -1 ? record.data : false);
39915 this.fireEvent('select', this, record, index);
39920 * Returns the currently selected field value or empty string if no value is set.
39921 * @return {String} value The selected value
39923 getValue : function(){
39924 if(this.valueField){
39925 return typeof this.value != 'undefined' ? this.value : '';
39927 return Roo.form.ComboBox.superclass.getValue.call(this);
39931 * Clears any text/value currently set in the field
39933 clearValue : function(){
39934 if(this.hiddenField){
39935 this.hiddenField.value = '';
39938 this.setRawValue('');
39939 this.lastSelectionText = '';
39944 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39945 * will be displayed in the field. If the value does not match the data value of an existing item,
39946 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39947 * Otherwise the field will be blank (although the value will still be set).
39948 * @param {String} value The value to match
39950 setValue : function(v){
39952 if(this.valueField){
39953 var r = this.findRecord(this.valueField, v);
39955 text = r.data[this.displayField];
39956 }else if(this.valueNotFoundText !== undefined){
39957 text = this.valueNotFoundText;
39960 this.lastSelectionText = text;
39961 if(this.hiddenField){
39962 this.hiddenField.value = v;
39964 Roo.form.ComboBox.superclass.setValue.call(this, text);
39968 * @property {Object} the last set data for the element
39973 * Sets the value of the field based on a object which is related to the record format for the store.
39974 * @param {Object} value the value to set as. or false on reset?
39976 setFromData : function(o){
39977 var dv = ''; // display value
39978 var vv = ''; // value value..
39980 if (this.displayField) {
39981 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39983 // this is an error condition!!!
39984 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39987 if(this.valueField){
39988 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39990 if(this.hiddenField){
39991 this.hiddenField.value = vv;
39993 this.lastSelectionText = dv;
39994 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39998 // no hidden field.. - we store the value in 'value', but still display
39999 // display field!!!!
40000 this.lastSelectionText = dv;
40001 Roo.form.ComboBox.superclass.setValue.call(this, dv);
40007 reset : function(){
40008 // overridden so that last data is reset..
40009 this.setValue(this.resetValue);
40010 this.clearInvalid();
40011 this.lastData = false;
40013 this.view.clearSelections();
40017 findRecord : function(prop, value){
40019 if(this.store.getCount() > 0){
40020 this.store.each(function(r){
40021 if(r.data[prop] == value){
40031 getName: function()
40033 // returns hidden if it's set..
40034 if (!this.rendered) {return ''};
40035 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40039 onViewMove : function(e, t){
40040 this.inKeyMode = false;
40044 onViewOver : function(e, t){
40045 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
40048 var item = this.view.findItemFromChild(t);
40050 var index = this.view.indexOf(item);
40051 this.select(index, false);
40056 onViewClick : function(doFocus)
40058 var index = this.view.getSelectedIndexes()[0];
40059 var r = this.store.getAt(index);
40061 this.onSelect(r, index);
40063 if(doFocus !== false && !this.blockFocus){
40069 restrictHeight : function(){
40070 this.innerList.dom.style.height = '';
40071 var inner = this.innerList.dom;
40072 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
40073 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
40074 this.list.beginUpdate();
40075 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
40076 this.list.alignTo(this.el, this.listAlign);
40077 this.list.endUpdate();
40081 onEmptyResults : function(){
40086 * Returns true if the dropdown list is expanded, else false.
40088 isExpanded : function(){
40089 return this.list.isVisible();
40093 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
40094 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40095 * @param {String} value The data value of the item to select
40096 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40097 * selected item if it is not currently in view (defaults to true)
40098 * @return {Boolean} True if the value matched an item in the list, else false
40100 selectByValue : function(v, scrollIntoView){
40101 if(v !== undefined && v !== null){
40102 var r = this.findRecord(this.valueField || this.displayField, v);
40104 this.select(this.store.indexOf(r), scrollIntoView);
40112 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
40113 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40114 * @param {Number} index The zero-based index of the list item to select
40115 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40116 * selected item if it is not currently in view (defaults to true)
40118 select : function(index, scrollIntoView){
40119 this.selectedIndex = index;
40120 this.view.select(index);
40121 if(scrollIntoView !== false){
40122 var el = this.view.getNode(index);
40124 this.innerList.scrollChildIntoView(el, false);
40130 selectNext : function(){
40131 var ct = this.store.getCount();
40133 if(this.selectedIndex == -1){
40135 }else if(this.selectedIndex < ct-1){
40136 this.select(this.selectedIndex+1);
40142 selectPrev : function(){
40143 var ct = this.store.getCount();
40145 if(this.selectedIndex == -1){
40147 }else if(this.selectedIndex != 0){
40148 this.select(this.selectedIndex-1);
40154 onKeyUp : function(e){
40155 if(this.editable !== false && !e.isSpecialKey()){
40156 this.lastKey = e.getKey();
40157 this.dqTask.delay(this.queryDelay);
40162 validateBlur : function(){
40163 return !this.list || !this.list.isVisible();
40167 initQuery : function(){
40168 this.doQuery(this.getRawValue());
40172 doForce : function(){
40173 if(this.el.dom.value.length > 0){
40174 this.el.dom.value =
40175 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
40181 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
40182 * query allowing the query action to be canceled if needed.
40183 * @param {String} query The SQL query to execute
40184 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
40185 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
40186 * saved in the current store (defaults to false)
40188 doQuery : function(q, forceAll){
40189 if(q === undefined || q === null){
40194 forceAll: forceAll,
40198 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
40202 forceAll = qe.forceAll;
40203 if(forceAll === true || (q.length >= this.minChars)){
40204 if(this.lastQuery != q || this.alwaysQuery){
40205 this.lastQuery = q;
40206 if(this.mode == 'local'){
40207 this.selectedIndex = -1;
40209 this.store.clearFilter();
40211 this.store.filter(this.displayField, q);
40215 this.store.baseParams[this.queryParam] = q;
40217 params: this.getParams(q)
40222 this.selectedIndex = -1;
40229 getParams : function(q){
40231 //p[this.queryParam] = q;
40234 p.limit = this.pageSize;
40240 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40242 collapse : function(){
40243 if(!this.isExpanded()){
40247 Roo.get(document).un('mousedown', this.collapseIf, this);
40248 Roo.get(document).un('mousewheel', this.collapseIf, this);
40249 if (!this.editable) {
40250 Roo.get(document).un('keydown', this.listKeyPress, this);
40252 this.fireEvent('collapse', this);
40256 collapseIf : function(e){
40257 if(!e.within(this.wrap) && !e.within(this.list)){
40263 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40265 expand : function(){
40266 if(this.isExpanded() || !this.hasFocus){
40269 this.list.alignTo(this.el, this.listAlign);
40271 Roo.get(document).on('mousedown', this.collapseIf, this);
40272 Roo.get(document).on('mousewheel', this.collapseIf, this);
40273 if (!this.editable) {
40274 Roo.get(document).on('keydown', this.listKeyPress, this);
40277 this.fireEvent('expand', this);
40281 // Implements the default empty TriggerField.onTriggerClick function
40282 onTriggerClick : function(){
40286 if(this.isExpanded()){
40288 if (!this.blockFocus) {
40293 this.hasFocus = true;
40294 if(this.triggerAction == 'all') {
40295 this.doQuery(this.allQuery, true);
40297 this.doQuery(this.getRawValue());
40299 if (!this.blockFocus) {
40304 listKeyPress : function(e)
40306 //Roo.log('listkeypress');
40307 // scroll to first matching element based on key pres..
40308 if (e.isSpecialKey()) {
40311 var k = String.fromCharCode(e.getKey()).toUpperCase();
40314 var csel = this.view.getSelectedNodes();
40315 var cselitem = false;
40317 var ix = this.view.indexOf(csel[0]);
40318 cselitem = this.store.getAt(ix);
40319 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40325 this.store.each(function(v) {
40327 // start at existing selection.
40328 if (cselitem.id == v.id) {
40334 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40335 match = this.store.indexOf(v);
40340 if (match === false) {
40341 return true; // no more action?
40344 this.view.select(match);
40345 var sn = Roo.get(this.view.getSelectedNodes()[0])
40346 sn.scrollIntoView(sn.dom.parentNode, false);
40350 * @cfg {Boolean} grow
40354 * @cfg {Number} growMin
40358 * @cfg {Number} growMax
40366 * Copyright(c) 2010-2012, Roo J Solutions Limited
40373 * @class Roo.form.ComboBoxArray
40374 * @extends Roo.form.TextField
40375 * A facebook style adder... for lists of email / people / countries etc...
40376 * pick multiple items from a combo box, and shows each one.
40378 * Fred [x] Brian [x] [Pick another |v]
40381 * For this to work: it needs various extra information
40382 * - normal combo problay has
40384 * + displayField, valueField
40386 * For our purpose...
40389 * If we change from 'extends' to wrapping...
40396 * Create a new ComboBoxArray.
40397 * @param {Object} config Configuration options
40401 Roo.form.ComboBoxArray = function(config)
40405 * @event beforeremove
40406 * Fires before remove the value from the list
40407 * @param {Roo.form.ComboBoxArray} _self This combo box array
40408 * @param {Roo.form.ComboBoxArray.Item} item removed item
40410 'beforeremove' : true,
40413 * Fires when remove the value from the list
40414 * @param {Roo.form.ComboBoxArray} _self This combo box array
40415 * @param {Roo.form.ComboBoxArray.Item} item removed item
40422 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40424 this.items = new Roo.util.MixedCollection(false);
40426 // construct the child combo...
40436 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40439 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40444 // behavies liek a hiddne field
40445 inputType: 'hidden',
40447 * @cfg {Number} width The width of the box that displays the selected element
40454 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40458 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40460 hiddenName : false,
40463 // private the array of items that are displayed..
40465 // private - the hidden field el.
40467 // private - the filed el..
40470 //validateValue : function() { return true; }, // all values are ok!
40471 //onAddClick: function() { },
40473 onRender : function(ct, position)
40476 // create the standard hidden element
40477 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40480 // give fake names to child combo;
40481 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40482 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40484 this.combo = Roo.factory(this.combo, Roo.form);
40485 this.combo.onRender(ct, position);
40486 if (typeof(this.combo.width) != 'undefined') {
40487 this.combo.onResize(this.combo.width,0);
40490 this.combo.initEvents();
40492 // assigned so form know we need to do this..
40493 this.store = this.combo.store;
40494 this.valueField = this.combo.valueField;
40495 this.displayField = this.combo.displayField ;
40498 this.combo.wrap.addClass('x-cbarray-grp');
40500 var cbwrap = this.combo.wrap.createChild(
40501 {tag: 'div', cls: 'x-cbarray-cb'},
40506 this.hiddenEl = this.combo.wrap.createChild({
40507 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40509 this.el = this.combo.wrap.createChild({
40510 tag: 'input', type:'hidden' , name: this.name, value : ''
40512 // this.el.dom.removeAttribute("name");
40515 this.outerWrap = this.combo.wrap;
40516 this.wrap = cbwrap;
40518 this.outerWrap.setWidth(this.width);
40519 this.outerWrap.dom.removeChild(this.el.dom);
40521 this.wrap.dom.appendChild(this.el.dom);
40522 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40523 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40525 this.combo.trigger.setStyle('position','relative');
40526 this.combo.trigger.setStyle('left', '0px');
40527 this.combo.trigger.setStyle('top', '2px');
40529 this.combo.el.setStyle('vertical-align', 'text-bottom');
40531 //this.trigger.setStyle('vertical-align', 'top');
40533 // this should use the code from combo really... on('add' ....)
40537 this.adder = this.outerWrap.createChild(
40538 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40540 this.adder.on('click', function(e) {
40541 _t.fireEvent('adderclick', this, e);
40545 //this.adder.on('click', this.onAddClick, _t);
40548 this.combo.on('select', function(cb, rec, ix) {
40549 this.addItem(rec.data);
40552 cb.el.dom.value = '';
40553 //cb.lastData = rec.data;
40562 getName: function()
40564 // returns hidden if it's set..
40565 if (!this.rendered) {return ''};
40566 return this.hiddenName ? this.hiddenName : this.name;
40571 onResize: function(w, h){
40574 // not sure if this is needed..
40575 //this.combo.onResize(w,h);
40577 if(typeof w != 'number'){
40578 // we do not handle it!?!?
40581 var tw = this.combo.trigger.getWidth();
40582 tw += this.addicon ? this.addicon.getWidth() : 0;
40583 tw += this.editicon ? this.editicon.getWidth() : 0;
40585 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40587 this.combo.trigger.setStyle('left', '0px');
40589 if(this.list && this.listWidth === undefined){
40590 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40591 this.list.setWidth(lw);
40592 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40599 addItem: function(rec)
40601 var valueField = this.combo.valueField;
40602 var displayField = this.combo.displayField;
40603 if (this.items.indexOfKey(rec[valueField]) > -1) {
40604 //console.log("GOT " + rec.data.id);
40608 var x = new Roo.form.ComboBoxArray.Item({
40609 //id : rec[this.idField],
40611 displayField : displayField ,
40612 tipField : displayField ,
40616 this.items.add(rec[valueField],x);
40617 // add it before the element..
40618 this.updateHiddenEl();
40619 x.render(this.outerWrap, this.wrap.dom);
40620 // add the image handler..
40623 updateHiddenEl : function()
40626 if (!this.hiddenEl) {
40630 var idField = this.combo.valueField;
40632 this.items.each(function(f) {
40633 ar.push(f.data[idField]);
40636 this.hiddenEl.dom.value = ar.join(',');
40642 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40643 this.items.each(function(f) {
40646 this.el.dom.value = '';
40647 if (this.hiddenEl) {
40648 this.hiddenEl.dom.value = '';
40652 getValue: function()
40654 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40656 setValue: function(v) // not a valid action - must use addItems..
40663 if (this.store.isLocal && (typeof(v) == 'string')) {
40664 // then we can use the store to find the values..
40665 // comma seperated at present.. this needs to allow JSON based encoding..
40666 this.hiddenEl.value = v;
40668 Roo.each(v.split(','), function(k) {
40669 Roo.log("CHECK " + this.valueField + ',' + k);
40670 var li = this.store.query(this.valueField, k);
40675 add[this.valueField] = k;
40676 add[this.displayField] = li.item(0).data[this.displayField];
40682 if (typeof(v) == 'object' ) {
40683 // then let's assume it's an array of objects..
40684 Roo.each(v, function(l) {
40692 setFromData: function(v)
40694 // this recieves an object, if setValues is called.
40696 this.el.dom.value = v[this.displayField];
40697 this.hiddenEl.dom.value = v[this.valueField];
40698 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40701 var kv = v[this.valueField];
40702 var dv = v[this.displayField];
40703 kv = typeof(kv) != 'string' ? '' : kv;
40704 dv = typeof(dv) != 'string' ? '' : dv;
40707 var keys = kv.split(',');
40708 var display = dv.split(',');
40709 for (var i = 0 ; i < keys.length; i++) {
40712 add[this.valueField] = keys[i];
40713 add[this.displayField] = display[i];
40721 * Validates the combox array value
40722 * @return {Boolean} True if the value is valid, else false
40724 validate : function(){
40725 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40726 this.clearInvalid();
40732 validateValue : function(value){
40733 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40741 isDirty : function() {
40742 if(this.disabled) {
40747 var d = Roo.decode(String(this.originalValue));
40749 return String(this.getValue()) !== String(this.originalValue);
40752 var originalValue = [];
40754 for (var i = 0; i < d.length; i++){
40755 originalValue.push(d[i][this.valueField]);
40758 return String(this.getValue()) !== String(originalValue.join(','));
40767 * @class Roo.form.ComboBoxArray.Item
40768 * @extends Roo.BoxComponent
40769 * A selected item in the list
40770 * Fred [x] Brian [x] [Pick another |v]
40773 * Create a new item.
40774 * @param {Object} config Configuration options
40777 Roo.form.ComboBoxArray.Item = function(config) {
40778 config.id = Roo.id();
40779 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40782 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40785 displayField : false,
40789 defaultAutoCreate : {
40791 cls: 'x-cbarray-item',
40798 src : Roo.BLANK_IMAGE_URL ,
40806 onRender : function(ct, position)
40808 Roo.form.Field.superclass.onRender.call(this, ct, position);
40811 var cfg = this.getAutoCreate();
40812 this.el = ct.createChild(cfg, position);
40815 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40817 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40818 this.cb.renderer(this.data) :
40819 String.format('{0}',this.data[this.displayField]);
40822 this.el.child('div').dom.setAttribute('qtip',
40823 String.format('{0}',this.data[this.tipField])
40826 this.el.child('img').on('click', this.remove, this);
40830 remove : function()
40832 if(this.cb.disabled){
40836 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
40837 this.cb.items.remove(this);
40838 this.el.child('img').un('click', this.remove, this);
40840 this.cb.updateHiddenEl();
40842 this.cb.fireEvent('remove', this.cb, this);
40848 * Ext JS Library 1.1.1
40849 * Copyright(c) 2006-2007, Ext JS, LLC.
40851 * Originally Released Under LGPL - original licence link has changed is not relivant.
40854 * <script type="text/javascript">
40857 * @class Roo.form.Checkbox
40858 * @extends Roo.form.Field
40859 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40861 * Creates a new Checkbox
40862 * @param {Object} config Configuration options
40864 Roo.form.Checkbox = function(config){
40865 Roo.form.Checkbox.superclass.constructor.call(this, config);
40869 * Fires when the checkbox is checked or unchecked.
40870 * @param {Roo.form.Checkbox} this This checkbox
40871 * @param {Boolean} checked The new checked value
40877 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40879 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40881 focusClass : undefined,
40883 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40885 fieldClass: "x-form-field",
40887 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40891 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40892 * {tag: "input", type: "checkbox", autocomplete: "off"})
40894 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40896 * @cfg {String} boxLabel The text that appears beside the checkbox
40900 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40904 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40906 valueOff: '0', // value when not checked..
40908 actionMode : 'viewEl',
40911 itemCls : 'x-menu-check-item x-form-item',
40912 groupClass : 'x-menu-group-item',
40913 inputType : 'hidden',
40916 inSetChecked: false, // check that we are not calling self...
40918 inputElement: false, // real input element?
40919 basedOn: false, // ????
40921 isFormField: true, // not sure where this is needed!!!!
40923 onResize : function(){
40924 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40925 if(!this.boxLabel){
40926 this.el.alignTo(this.wrap, 'c-c');
40930 initEvents : function(){
40931 Roo.form.Checkbox.superclass.initEvents.call(this);
40932 this.el.on("click", this.onClick, this);
40933 this.el.on("change", this.onClick, this);
40937 getResizeEl : function(){
40941 getPositionEl : function(){
40946 onRender : function(ct, position){
40947 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40949 if(this.inputValue !== undefined){
40950 this.el.dom.value = this.inputValue;
40953 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40954 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40955 var viewEl = this.wrap.createChild({
40956 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40957 this.viewEl = viewEl;
40958 this.wrap.on('click', this.onClick, this);
40960 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40961 this.el.on('propertychange', this.setFromHidden, this); //ie
40966 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40967 // viewEl.on('click', this.onClick, this);
40969 //if(this.checked){
40970 this.setChecked(this.checked);
40972 //this.checked = this.el.dom;
40978 initValue : Roo.emptyFn,
40981 * Returns the checked state of the checkbox.
40982 * @return {Boolean} True if checked, else false
40984 getValue : function(){
40986 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40988 return this.valueOff;
40993 onClick : function(){
40994 if (this.disabled) {
40997 this.setChecked(!this.checked);
40999 //if(this.el.dom.checked != this.checked){
41000 // this.setValue(this.el.dom.checked);
41005 * Sets the checked state of the checkbox.
41006 * On is always based on a string comparison between inputValue and the param.
41007 * @param {Boolean/String} value - the value to set
41008 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
41010 setValue : function(v,suppressEvent){
41013 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
41014 //if(this.el && this.el.dom){
41015 // this.el.dom.checked = this.checked;
41016 // this.el.dom.defaultChecked = this.checked;
41018 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
41019 //this.fireEvent("check", this, this.checked);
41022 setChecked : function(state,suppressEvent)
41024 if (this.inSetChecked) {
41025 this.checked = state;
41031 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
41033 this.checked = state;
41034 if(suppressEvent !== true){
41035 this.fireEvent('check', this, state);
41037 this.inSetChecked = true;
41038 this.el.dom.value = state ? this.inputValue : this.valueOff;
41039 this.inSetChecked = false;
41042 // handle setting of hidden value by some other method!!?!?
41043 setFromHidden: function()
41048 //console.log("SET FROM HIDDEN");
41049 //alert('setFrom hidden');
41050 this.setValue(this.el.dom.value);
41053 onDestroy : function()
41056 Roo.get(this.viewEl).remove();
41059 Roo.form.Checkbox.superclass.onDestroy.call(this);
41064 * Ext JS Library 1.1.1
41065 * Copyright(c) 2006-2007, Ext JS, LLC.
41067 * Originally Released Under LGPL - original licence link has changed is not relivant.
41070 * <script type="text/javascript">
41074 * @class Roo.form.Radio
41075 * @extends Roo.form.Checkbox
41076 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
41077 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
41079 * Creates a new Radio
41080 * @param {Object} config Configuration options
41082 Roo.form.Radio = function(){
41083 Roo.form.Radio.superclass.constructor.apply(this, arguments);
41085 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
41086 inputType: 'radio',
41089 * If this radio is part of a group, it will return the selected value
41092 getGroupValue : function(){
41093 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
41097 onRender : function(ct, position){
41098 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
41100 if(this.inputValue !== undefined){
41101 this.el.dom.value = this.inputValue;
41104 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
41105 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
41106 //var viewEl = this.wrap.createChild({
41107 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
41108 //this.viewEl = viewEl;
41109 //this.wrap.on('click', this.onClick, this);
41111 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
41112 //this.el.on('propertychange', this.setFromHidden, this); //ie
41117 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
41118 // viewEl.on('click', this.onClick, this);
41121 this.el.dom.checked = 'checked' ;
41127 });//<script type="text/javascript">
41130 * Based Ext JS Library 1.1.1
41131 * Copyright(c) 2006-2007, Ext JS, LLC.
41137 * @class Roo.HtmlEditorCore
41138 * @extends Roo.Component
41139 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
41141 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
41144 Roo.HtmlEditorCore = function(config){
41147 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
41152 * @event initialize
41153 * Fires when the editor is fully initialized (including the iframe)
41154 * @param {Roo.HtmlEditorCore} this
41159 * Fires when the editor is first receives the focus. Any insertion must wait
41160 * until after this event.
41161 * @param {Roo.HtmlEditorCore} this
41165 * @event beforesync
41166 * Fires before the textarea is updated with content from the editor iframe. Return false
41167 * to cancel the sync.
41168 * @param {Roo.HtmlEditorCore} this
41169 * @param {String} html
41173 * @event beforepush
41174 * Fires before the iframe editor is updated with content from the textarea. Return false
41175 * to cancel the push.
41176 * @param {Roo.HtmlEditorCore} this
41177 * @param {String} html
41182 * Fires when the textarea is updated with content from the editor iframe.
41183 * @param {Roo.HtmlEditorCore} this
41184 * @param {String} html
41189 * Fires when the iframe editor is updated with content from the textarea.
41190 * @param {Roo.HtmlEditorCore} this
41191 * @param {String} html
41196 * @event editorevent
41197 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41198 * @param {Roo.HtmlEditorCore} this
41204 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
41206 // defaults : white / black...
41207 this.applyBlacklists();
41214 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41218 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41224 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41229 * @cfg {Number} height (in pixels)
41233 * @cfg {Number} width (in pixels)
41238 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41241 stylesheets: false,
41246 // private properties
41247 validationEvent : false,
41249 initialized : false,
41251 sourceEditMode : false,
41252 onFocus : Roo.emptyFn,
41254 hideMode:'offsets',
41258 // blacklist + whitelisted elements..
41265 * Protected method that will not generally be called directly. It
41266 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41267 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41269 getDocMarkup : function(){
41273 // inherit styels from page...??
41274 if (this.stylesheets === false) {
41276 Roo.get(document.head).select('style').each(function(node) {
41277 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41280 Roo.get(document.head).select('link').each(function(node) {
41281 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41284 } else if (!this.stylesheets.length) {
41286 st = '<style type="text/css">' +
41287 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41293 st += '<style type="text/css">' +
41294 'IMG { cursor: pointer } ' +
41298 return '<html><head>' + st +
41299 //<style type="text/css">' +
41300 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41302 ' </head><body class="roo-htmleditor-body"></body></html>';
41306 onRender : function(ct, position)
41309 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41310 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41313 this.el.dom.style.border = '0 none';
41314 this.el.dom.setAttribute('tabIndex', -1);
41315 this.el.addClass('x-hidden hide');
41319 if(Roo.isIE){ // fix IE 1px bogus margin
41320 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41324 this.frameId = Roo.id();
41328 var iframe = this.owner.wrap.createChild({
41330 cls: 'form-control', // bootstrap..
41332 name: this.frameId,
41333 frameBorder : 'no',
41334 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41339 this.iframe = iframe.dom;
41341 this.assignDocWin();
41343 this.doc.designMode = 'on';
41346 this.doc.write(this.getDocMarkup());
41350 var task = { // must defer to wait for browser to be ready
41352 //console.log("run task?" + this.doc.readyState);
41353 this.assignDocWin();
41354 if(this.doc.body || this.doc.readyState == 'complete'){
41356 this.doc.designMode="on";
41360 Roo.TaskMgr.stop(task);
41361 this.initEditor.defer(10, this);
41368 Roo.TaskMgr.start(task);
41373 onResize : function(w, h)
41375 Roo.log('resize: ' +w + ',' + h );
41376 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41380 if(typeof w == 'number'){
41382 this.iframe.style.width = w + 'px';
41384 if(typeof h == 'number'){
41386 this.iframe.style.height = h + 'px';
41388 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41395 * Toggles the editor between standard and source edit mode.
41396 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41398 toggleSourceEdit : function(sourceEditMode){
41400 this.sourceEditMode = sourceEditMode === true;
41402 if(this.sourceEditMode){
41404 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41407 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41408 //this.iframe.className = '';
41411 //this.setSize(this.owner.wrap.getSize());
41412 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41419 * Protected method that will not generally be called directly. If you need/want
41420 * custom HTML cleanup, this is the method you should override.
41421 * @param {String} html The HTML to be cleaned
41422 * return {String} The cleaned HTML
41424 cleanHtml : function(html){
41425 html = String(html);
41426 if(html.length > 5){
41427 if(Roo.isSafari){ // strip safari nonsense
41428 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41431 if(html == ' '){
41438 * HTML Editor -> Textarea
41439 * Protected method that will not generally be called directly. Syncs the contents
41440 * of the editor iframe with the textarea.
41442 syncValue : function(){
41443 if(this.initialized){
41444 var bd = (this.doc.body || this.doc.documentElement);
41445 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41446 var html = bd.innerHTML;
41448 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41449 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41451 html = '<div style="'+m[0]+'">' + html + '</div>';
41454 html = this.cleanHtml(html);
41455 // fix up the special chars.. normaly like back quotes in word...
41456 // however we do not want to do this with chinese..
41457 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41458 var cc = b.charCodeAt();
41460 (cc >= 0x4E00 && cc < 0xA000 ) ||
41461 (cc >= 0x3400 && cc < 0x4E00 ) ||
41462 (cc >= 0xf900 && cc < 0xfb00 )
41468 if(this.owner.fireEvent('beforesync', this, html) !== false){
41469 this.el.dom.value = html;
41470 this.owner.fireEvent('sync', this, html);
41476 * Protected method that will not generally be called directly. Pushes the value of the textarea
41477 * into the iframe editor.
41479 pushValue : function(){
41480 if(this.initialized){
41481 var v = this.el.dom.value.trim();
41483 // if(v.length < 1){
41487 if(this.owner.fireEvent('beforepush', this, v) !== false){
41488 var d = (this.doc.body || this.doc.documentElement);
41490 this.cleanUpPaste();
41491 this.el.dom.value = d.innerHTML;
41492 this.owner.fireEvent('push', this, v);
41498 deferFocus : function(){
41499 this.focus.defer(10, this);
41503 focus : function(){
41504 if(this.win && !this.sourceEditMode){
41511 assignDocWin: function()
41513 var iframe = this.iframe;
41516 this.doc = iframe.contentWindow.document;
41517 this.win = iframe.contentWindow;
41519 // if (!Roo.get(this.frameId)) {
41522 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41523 // this.win = Roo.get(this.frameId).dom.contentWindow;
41525 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
41529 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41530 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
41535 initEditor : function(){
41536 //console.log("INIT EDITOR");
41537 this.assignDocWin();
41541 this.doc.designMode="on";
41543 this.doc.write(this.getDocMarkup());
41546 var dbody = (this.doc.body || this.doc.documentElement);
41547 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41548 // this copies styles from the containing element into thsi one..
41549 // not sure why we need all of this..
41550 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41552 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41553 //ss['background-attachment'] = 'fixed'; // w3c
41554 dbody.bgProperties = 'fixed'; // ie
41555 //Roo.DomHelper.applyStyles(dbody, ss);
41556 Roo.EventManager.on(this.doc, {
41557 //'mousedown': this.onEditorEvent,
41558 'mouseup': this.onEditorEvent,
41559 'dblclick': this.onEditorEvent,
41560 'click': this.onEditorEvent,
41561 'keyup': this.onEditorEvent,
41566 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41568 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41569 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41571 this.initialized = true;
41573 this.owner.fireEvent('initialize', this);
41578 onDestroy : function(){
41584 //for (var i =0; i < this.toolbars.length;i++) {
41585 // // fixme - ask toolbars for heights?
41586 // this.toolbars[i].onDestroy();
41589 //this.wrap.dom.innerHTML = '';
41590 //this.wrap.remove();
41595 onFirstFocus : function(){
41597 this.assignDocWin();
41600 this.activated = true;
41603 if(Roo.isGecko){ // prevent silly gecko errors
41605 var s = this.win.getSelection();
41606 if(!s.focusNode || s.focusNode.nodeType != 3){
41607 var r = s.getRangeAt(0);
41608 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41613 this.execCmd('useCSS', true);
41614 this.execCmd('styleWithCSS', false);
41617 this.owner.fireEvent('activate', this);
41621 adjustFont: function(btn){
41622 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41623 //if(Roo.isSafari){ // safari
41626 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41627 if(Roo.isSafari){ // safari
41628 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41629 v = (v < 10) ? 10 : v;
41630 v = (v > 48) ? 48 : v;
41631 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41636 v = Math.max(1, v+adjust);
41638 this.execCmd('FontSize', v );
41641 onEditorEvent : function(e)
41643 this.owner.fireEvent('editorevent', this, e);
41644 // this.updateToolbar();
41645 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41648 insertTag : function(tg)
41650 // could be a bit smarter... -> wrap the current selected tRoo..
41651 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41653 range = this.createRange(this.getSelection());
41654 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41655 wrappingNode.appendChild(range.extractContents());
41656 range.insertNode(wrappingNode);
41663 this.execCmd("formatblock", tg);
41667 insertText : function(txt)
41671 var range = this.createRange();
41672 range.deleteContents();
41673 //alert(Sender.getAttribute('label'));
41675 range.insertNode(this.doc.createTextNode(txt));
41681 * Executes a Midas editor command on the editor document and performs necessary focus and
41682 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41683 * @param {String} cmd The Midas command
41684 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41686 relayCmd : function(cmd, value){
41688 this.execCmd(cmd, value);
41689 this.owner.fireEvent('editorevent', this);
41690 //this.updateToolbar();
41691 this.owner.deferFocus();
41695 * Executes a Midas editor command directly on the editor document.
41696 * For visual commands, you should use {@link #relayCmd} instead.
41697 * <b>This should only be called after the editor is initialized.</b>
41698 * @param {String} cmd The Midas command
41699 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41701 execCmd : function(cmd, value){
41702 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41709 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41711 * @param {String} text | dom node..
41713 insertAtCursor : function(text)
41718 if(!this.activated){
41724 var r = this.doc.selection.createRange();
41735 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41739 // from jquery ui (MIT licenced)
41741 var win = this.win;
41743 if (win.getSelection && win.getSelection().getRangeAt) {
41744 range = win.getSelection().getRangeAt(0);
41745 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41746 range.insertNode(node);
41747 } else if (win.document.selection && win.document.selection.createRange) {
41748 // no firefox support
41749 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41750 win.document.selection.createRange().pasteHTML(txt);
41752 // no firefox support
41753 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41754 this.execCmd('InsertHTML', txt);
41763 mozKeyPress : function(e){
41765 var c = e.getCharCode(), cmd;
41768 c = String.fromCharCode(c).toLowerCase();
41782 this.cleanUpPaste.defer(100, this);
41790 e.preventDefault();
41798 fixKeys : function(){ // load time branching for fastest keydown performance
41800 return function(e){
41801 var k = e.getKey(), r;
41804 r = this.doc.selection.createRange();
41807 r.pasteHTML('    ');
41814 r = this.doc.selection.createRange();
41816 var target = r.parentElement();
41817 if(!target || target.tagName.toLowerCase() != 'li'){
41819 r.pasteHTML('<br />');
41825 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41826 this.cleanUpPaste.defer(100, this);
41832 }else if(Roo.isOpera){
41833 return function(e){
41834 var k = e.getKey();
41838 this.execCmd('InsertHTML','    ');
41841 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41842 this.cleanUpPaste.defer(100, this);
41847 }else if(Roo.isSafari){
41848 return function(e){
41849 var k = e.getKey();
41853 this.execCmd('InsertText','\t');
41857 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41858 this.cleanUpPaste.defer(100, this);
41866 getAllAncestors: function()
41868 var p = this.getSelectedNode();
41871 a.push(p); // push blank onto stack..
41872 p = this.getParentElement();
41876 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41880 a.push(this.doc.body);
41884 lastSelNode : false,
41887 getSelection : function()
41889 this.assignDocWin();
41890 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41893 getSelectedNode: function()
41895 // this may only work on Gecko!!!
41897 // should we cache this!!!!
41902 var range = this.createRange(this.getSelection()).cloneRange();
41905 var parent = range.parentElement();
41907 var testRange = range.duplicate();
41908 testRange.moveToElementText(parent);
41909 if (testRange.inRange(range)) {
41912 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41915 parent = parent.parentElement;
41920 // is ancestor a text element.
41921 var ac = range.commonAncestorContainer;
41922 if (ac.nodeType == 3) {
41923 ac = ac.parentNode;
41926 var ar = ac.childNodes;
41929 var other_nodes = [];
41930 var has_other_nodes = false;
41931 for (var i=0;i<ar.length;i++) {
41932 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41935 // fullly contained node.
41937 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41942 // probably selected..
41943 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41944 other_nodes.push(ar[i]);
41948 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41953 has_other_nodes = true;
41955 if (!nodes.length && other_nodes.length) {
41956 nodes= other_nodes;
41958 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41964 createRange: function(sel)
41966 // this has strange effects when using with
41967 // top toolbar - not sure if it's a great idea.
41968 //this.editor.contentWindow.focus();
41969 if (typeof sel != "undefined") {
41971 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41973 return this.doc.createRange();
41976 return this.doc.createRange();
41979 getParentElement: function()
41982 this.assignDocWin();
41983 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41985 var range = this.createRange(sel);
41988 var p = range.commonAncestorContainer;
41989 while (p.nodeType == 3) { // text node
42000 * Range intersection.. the hard stuff...
42004 * [ -- selected range --- ]
42008 * if end is before start or hits it. fail.
42009 * if start is after end or hits it fail.
42011 * if either hits (but other is outside. - then it's not
42017 // @see http://www.thismuchiknow.co.uk/?p=64.
42018 rangeIntersectsNode : function(range, node)
42020 var nodeRange = node.ownerDocument.createRange();
42022 nodeRange.selectNode(node);
42024 nodeRange.selectNodeContents(node);
42027 var rangeStartRange = range.cloneRange();
42028 rangeStartRange.collapse(true);
42030 var rangeEndRange = range.cloneRange();
42031 rangeEndRange.collapse(false);
42033 var nodeStartRange = nodeRange.cloneRange();
42034 nodeStartRange.collapse(true);
42036 var nodeEndRange = nodeRange.cloneRange();
42037 nodeEndRange.collapse(false);
42039 return rangeStartRange.compareBoundaryPoints(
42040 Range.START_TO_START, nodeEndRange) == -1 &&
42041 rangeEndRange.compareBoundaryPoints(
42042 Range.START_TO_START, nodeStartRange) == 1;
42046 rangeCompareNode : function(range, node)
42048 var nodeRange = node.ownerDocument.createRange();
42050 nodeRange.selectNode(node);
42052 nodeRange.selectNodeContents(node);
42056 range.collapse(true);
42058 nodeRange.collapse(true);
42060 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
42061 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
42063 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
42065 var nodeIsBefore = ss == 1;
42066 var nodeIsAfter = ee == -1;
42068 if (nodeIsBefore && nodeIsAfter)
42070 if (!nodeIsBefore && nodeIsAfter)
42071 return 1; //right trailed.
42073 if (nodeIsBefore && !nodeIsAfter)
42074 return 2; // left trailed.
42079 // private? - in a new class?
42080 cleanUpPaste : function()
42082 // cleans up the whole document..
42083 Roo.log('cleanuppaste');
42085 this.cleanUpChildren(this.doc.body);
42086 var clean = this.cleanWordChars(this.doc.body.innerHTML);
42087 if (clean != this.doc.body.innerHTML) {
42088 this.doc.body.innerHTML = clean;
42093 cleanWordChars : function(input) {// change the chars to hex code
42094 var he = Roo.HtmlEditorCore;
42096 var output = input;
42097 Roo.each(he.swapCodes, function(sw) {
42098 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
42100 output = output.replace(swapper, sw[1]);
42107 cleanUpChildren : function (n)
42109 if (!n.childNodes.length) {
42112 for (var i = n.childNodes.length-1; i > -1 ; i--) {
42113 this.cleanUpChild(n.childNodes[i]);
42120 cleanUpChild : function (node)
42123 //console.log(node);
42124 if (node.nodeName == "#text") {
42125 // clean up silly Windows -- stuff?
42128 if (node.nodeName == "#comment") {
42129 node.parentNode.removeChild(node);
42130 // clean up silly Windows -- stuff?
42133 var lcname = node.tagName.toLowerCase();
42134 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
42135 // whitelist of tags..
42137 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
42139 node.parentNode.removeChild(node);
42144 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
42146 // remove <a name=....> as rendering on yahoo mailer is borked with this.
42147 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
42149 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
42150 // remove_keep_children = true;
42153 if (remove_keep_children) {
42154 this.cleanUpChildren(node);
42155 // inserts everything just before this node...
42156 while (node.childNodes.length) {
42157 var cn = node.childNodes[0];
42158 node.removeChild(cn);
42159 node.parentNode.insertBefore(cn, node);
42161 node.parentNode.removeChild(node);
42165 if (!node.attributes || !node.attributes.length) {
42166 this.cleanUpChildren(node);
42170 function cleanAttr(n,v)
42173 if (v.match(/^\./) || v.match(/^\//)) {
42176 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
42179 if (v.match(/^#/)) {
42182 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
42183 node.removeAttribute(n);
42187 var cwhite = this.cwhite;
42188 var cblack = this.cblack;
42190 function cleanStyle(n,v)
42192 if (v.match(/expression/)) { //XSS?? should we even bother..
42193 node.removeAttribute(n);
42197 var parts = v.split(/;/);
42200 Roo.each(parts, function(p) {
42201 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42205 var l = p.split(':').shift().replace(/\s+/g,'');
42206 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42208 if ( cwhite.length && cblack.indexOf(l) > -1) {
42209 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42210 //node.removeAttribute(n);
42214 // only allow 'c whitelisted system attributes'
42215 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42216 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42217 //node.removeAttribute(n);
42227 if (clean.length) {
42228 node.setAttribute(n, clean.join(';'));
42230 node.removeAttribute(n);
42236 for (var i = node.attributes.length-1; i > -1 ; i--) {
42237 var a = node.attributes[i];
42240 if (a.name.toLowerCase().substr(0,2)=='on') {
42241 node.removeAttribute(a.name);
42244 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42245 node.removeAttribute(a.name);
42248 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42249 cleanAttr(a.name,a.value); // fixme..
42252 if (a.name == 'style') {
42253 cleanStyle(a.name,a.value);
42256 /// clean up MS crap..
42257 // tecnically this should be a list of valid class'es..
42260 if (a.name == 'class') {
42261 if (a.value.match(/^Mso/)) {
42262 node.className = '';
42265 if (a.value.match(/body/)) {
42266 node.className = '';
42277 this.cleanUpChildren(node);
42283 * Clean up MS wordisms...
42285 cleanWord : function(node)
42290 this.cleanWord(this.doc.body);
42293 if (node.nodeName == "#text") {
42294 // clean up silly Windows -- stuff?
42297 if (node.nodeName == "#comment") {
42298 node.parentNode.removeChild(node);
42299 // clean up silly Windows -- stuff?
42303 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42304 node.parentNode.removeChild(node);
42308 // remove - but keep children..
42309 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42310 while (node.childNodes.length) {
42311 var cn = node.childNodes[0];
42312 node.removeChild(cn);
42313 node.parentNode.insertBefore(cn, node);
42315 node.parentNode.removeChild(node);
42316 this.iterateChildren(node, this.cleanWord);
42320 if (node.className.length) {
42322 var cn = node.className.split(/\W+/);
42324 Roo.each(cn, function(cls) {
42325 if (cls.match(/Mso[a-zA-Z]+/)) {
42330 node.className = cna.length ? cna.join(' ') : '';
42332 node.removeAttribute("class");
42336 if (node.hasAttribute("lang")) {
42337 node.removeAttribute("lang");
42340 if (node.hasAttribute("style")) {
42342 var styles = node.getAttribute("style").split(";");
42344 Roo.each(styles, function(s) {
42345 if (!s.match(/:/)) {
42348 var kv = s.split(":");
42349 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42352 // what ever is left... we allow.
42355 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42356 if (!nstyle.length) {
42357 node.removeAttribute('style');
42360 this.iterateChildren(node, this.cleanWord);
42366 * iterateChildren of a Node, calling fn each time, using this as the scole..
42367 * @param {DomNode} node node to iterate children of.
42368 * @param {Function} fn method of this class to call on each item.
42370 iterateChildren : function(node, fn)
42372 if (!node.childNodes.length) {
42375 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42376 fn.call(this, node.childNodes[i])
42382 * cleanTableWidths.
42384 * Quite often pasting from word etc.. results in tables with column and widths.
42385 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
42388 cleanTableWidths : function(node)
42393 this.cleanTableWidths(this.doc.body);
42398 if (node.nodeName == "#text" || node.nodeName == "#comment") {
42401 Roo.log(node.tagName);
42402 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
42403 this.iterateChildren(node, this.cleanTableWidths);
42406 if (node.hasAttribute('width')) {
42407 node.removeAttribute('width');
42411 if (node.hasAttribute("style")) {
42414 var styles = node.getAttribute("style").split(";");
42416 Roo.each(styles, function(s) {
42417 if (!s.match(/:/)) {
42420 var kv = s.split(":");
42421 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
42424 // what ever is left... we allow.
42427 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42428 if (!nstyle.length) {
42429 node.removeAttribute('style');
42433 this.iterateChildren(node, this.cleanTableWidths);
42441 domToHTML : function(currentElement, depth, nopadtext) {
42443 depth = depth || 0;
42444 nopadtext = nopadtext || false;
42446 if (!currentElement) {
42447 return this.domToHTML(this.doc.body);
42450 //Roo.log(currentElement);
42452 var allText = false;
42453 var nodeName = currentElement.nodeName;
42454 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42456 if (nodeName == '#text') {
42458 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
42463 if (nodeName != 'BODY') {
42466 // Prints the node tagName, such as <A>, <IMG>, etc
42469 for(i = 0; i < currentElement.attributes.length;i++) {
42471 var aname = currentElement.attributes.item(i).name;
42472 if (!currentElement.attributes.item(i).value.length) {
42475 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42478 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42487 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42490 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42495 // Traverse the tree
42497 var currentElementChild = currentElement.childNodes.item(i);
42498 var allText = true;
42499 var innerHTML = '';
42501 while (currentElementChild) {
42502 // Formatting code (indent the tree so it looks nice on the screen)
42503 var nopad = nopadtext;
42504 if (lastnode == 'SPAN') {
42508 if (currentElementChild.nodeName == '#text') {
42509 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42510 toadd = nopadtext ? toadd : toadd.trim();
42511 if (!nopad && toadd.length > 80) {
42512 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42514 innerHTML += toadd;
42517 currentElementChild = currentElement.childNodes.item(i);
42523 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42525 // Recursively traverse the tree structure of the child node
42526 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42527 lastnode = currentElementChild.nodeName;
42529 currentElementChild=currentElement.childNodes.item(i);
42535 // The remaining code is mostly for formatting the tree
42536 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42541 ret+= "</"+tagName+">";
42547 applyBlacklists : function()
42549 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
42550 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
42554 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
42555 if (b.indexOf(tag) > -1) {
42558 this.white.push(tag);
42562 Roo.each(w, function(tag) {
42563 if (b.indexOf(tag) > -1) {
42566 if (this.white.indexOf(tag) > -1) {
42569 this.white.push(tag);
42574 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
42575 if (w.indexOf(tag) > -1) {
42578 this.black.push(tag);
42582 Roo.each(b, function(tag) {
42583 if (w.indexOf(tag) > -1) {
42586 if (this.black.indexOf(tag) > -1) {
42589 this.black.push(tag);
42594 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
42595 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
42599 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
42600 if (b.indexOf(tag) > -1) {
42603 this.cwhite.push(tag);
42607 Roo.each(w, function(tag) {
42608 if (b.indexOf(tag) > -1) {
42611 if (this.cwhite.indexOf(tag) > -1) {
42614 this.cwhite.push(tag);
42619 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
42620 if (w.indexOf(tag) > -1) {
42623 this.cblack.push(tag);
42627 Roo.each(b, function(tag) {
42628 if (w.indexOf(tag) > -1) {
42631 if (this.cblack.indexOf(tag) > -1) {
42634 this.cblack.push(tag);
42639 setStylesheets : function(stylesheets)
42641 if(typeof(stylesheets) == 'string'){
42642 Roo.get(this.iframe.contentDocument.head).createChild({
42644 rel : 'stylesheet',
42653 Roo.each(stylesheets, function(s) {
42658 Roo.get(_this.iframe.contentDocument.head).createChild({
42660 rel : 'stylesheet',
42669 removeStylesheets : function()
42673 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
42678 // hide stuff that is not compatible
42692 * @event specialkey
42696 * @cfg {String} fieldClass @hide
42699 * @cfg {String} focusClass @hide
42702 * @cfg {String} autoCreate @hide
42705 * @cfg {String} inputType @hide
42708 * @cfg {String} invalidClass @hide
42711 * @cfg {String} invalidText @hide
42714 * @cfg {String} msgFx @hide
42717 * @cfg {String} validateOnBlur @hide
42721 Roo.HtmlEditorCore.white = [
42722 'area', 'br', 'img', 'input', 'hr', 'wbr',
42724 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42725 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42726 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42727 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42728 'table', 'ul', 'xmp',
42730 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42733 'dir', 'menu', 'ol', 'ul', 'dl',
42739 Roo.HtmlEditorCore.black = [
42740 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42742 'base', 'basefont', 'bgsound', 'blink', 'body',
42743 'frame', 'frameset', 'head', 'html', 'ilayer',
42744 'iframe', 'layer', 'link', 'meta', 'object',
42745 'script', 'style' ,'title', 'xml' // clean later..
42747 Roo.HtmlEditorCore.clean = [
42748 'script', 'style', 'title', 'xml'
42750 Roo.HtmlEditorCore.remove = [
42755 Roo.HtmlEditorCore.ablack = [
42759 Roo.HtmlEditorCore.aclean = [
42760 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42764 Roo.HtmlEditorCore.pwhite= [
42765 'http', 'https', 'mailto'
42768 // white listed style attributes.
42769 Roo.HtmlEditorCore.cwhite= [
42770 // 'text-align', /// default is to allow most things..
42776 // black listed style attributes.
42777 Roo.HtmlEditorCore.cblack= [
42778 // 'font-size' -- this can be set by the project
42782 Roo.HtmlEditorCore.swapCodes =[
42793 //<script type="text/javascript">
42796 * Ext JS Library 1.1.1
42797 * Copyright(c) 2006-2007, Ext JS, LLC.
42803 Roo.form.HtmlEditor = function(config){
42807 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42809 if (!this.toolbars) {
42810 this.toolbars = [];
42812 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42818 * @class Roo.form.HtmlEditor
42819 * @extends Roo.form.Field
42820 * Provides a lightweight HTML Editor component.
42822 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42824 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42825 * supported by this editor.</b><br/><br/>
42826 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42827 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42829 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42831 * @cfg {Boolean} clearUp
42835 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42840 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42845 * @cfg {Number} height (in pixels)
42849 * @cfg {Number} width (in pixels)
42854 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42857 stylesheets: false,
42861 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
42866 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
42872 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
42877 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
42885 // private properties
42886 validationEvent : false,
42888 initialized : false,
42891 onFocus : Roo.emptyFn,
42893 hideMode:'offsets',
42895 actionMode : 'container', // defaults to hiding it...
42897 defaultAutoCreate : { // modified by initCompnoent..
42899 style:"width:500px;height:300px;",
42900 autocomplete: "new-password"
42904 initComponent : function(){
42907 * @event initialize
42908 * Fires when the editor is fully initialized (including the iframe)
42909 * @param {HtmlEditor} this
42914 * Fires when the editor is first receives the focus. Any insertion must wait
42915 * until after this event.
42916 * @param {HtmlEditor} this
42920 * @event beforesync
42921 * Fires before the textarea is updated with content from the editor iframe. Return false
42922 * to cancel the sync.
42923 * @param {HtmlEditor} this
42924 * @param {String} html
42928 * @event beforepush
42929 * Fires before the iframe editor is updated with content from the textarea. Return false
42930 * to cancel the push.
42931 * @param {HtmlEditor} this
42932 * @param {String} html
42937 * Fires when the textarea is updated with content from the editor iframe.
42938 * @param {HtmlEditor} this
42939 * @param {String} html
42944 * Fires when the iframe editor is updated with content from the textarea.
42945 * @param {HtmlEditor} this
42946 * @param {String} html
42950 * @event editmodechange
42951 * Fires when the editor switches edit modes
42952 * @param {HtmlEditor} this
42953 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42955 editmodechange: true,
42957 * @event editorevent
42958 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42959 * @param {HtmlEditor} this
42963 * @event firstfocus
42964 * Fires when on first focus - needed by toolbars..
42965 * @param {HtmlEditor} this
42970 * Auto save the htmlEditor value as a file into Events
42971 * @param {HtmlEditor} this
42975 * @event savedpreview
42976 * preview the saved version of htmlEditor
42977 * @param {HtmlEditor} this
42979 savedpreview: true,
42982 * @event stylesheetsclick
42983 * Fires when press the Sytlesheets button
42984 * @param {Roo.HtmlEditorCore} this
42986 stylesheetsclick: true
42988 this.defaultAutoCreate = {
42990 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42991 autocomplete: "new-password"
42996 * Protected method that will not generally be called directly. It
42997 * is called when the editor creates its toolbar. Override this method if you need to
42998 * add custom toolbar buttons.
42999 * @param {HtmlEditor} editor
43001 createToolbar : function(editor){
43002 Roo.log("create toolbars");
43003 if (!editor.toolbars || !editor.toolbars.length) {
43004 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
43007 for (var i =0 ; i < editor.toolbars.length;i++) {
43008 editor.toolbars[i] = Roo.factory(
43009 typeof(editor.toolbars[i]) == 'string' ?
43010 { xtype: editor.toolbars[i]} : editor.toolbars[i],
43011 Roo.form.HtmlEditor);
43012 editor.toolbars[i].init(editor);
43020 onRender : function(ct, position)
43023 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
43025 this.wrap = this.el.wrap({
43026 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
43029 this.editorcore.onRender(ct, position);
43031 if (this.resizable) {
43032 this.resizeEl = new Roo.Resizable(this.wrap, {
43036 minHeight : this.height,
43037 height: this.height,
43038 handles : this.resizable,
43041 resize : function(r, w, h) {
43042 _t.onResize(w,h); // -something
43048 this.createToolbar(this);
43052 this.setSize(this.wrap.getSize());
43054 if (this.resizeEl) {
43055 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
43056 // should trigger onReize..
43059 this.keyNav = new Roo.KeyNav(this.el, {
43061 "tab" : function(e){
43062 e.preventDefault();
43064 var value = this.getValue();
43066 var start = this.el.dom.selectionStart;
43067 var end = this.el.dom.selectionEnd;
43071 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
43072 this.el.dom.setSelectionRange(end + 1, end + 1);
43076 var f = value.substring(0, start).split("\t");
43078 if(f.pop().length != 0){
43082 this.setValue(f.join("\t") + value.substring(end));
43083 this.el.dom.setSelectionRange(start - 1, start - 1);
43087 "home" : function(e){
43088 e.preventDefault();
43090 var curr = this.el.dom.selectionStart;
43091 var lines = this.getValue().split("\n");
43098 this.el.dom.setSelectionRange(0, 0);
43104 for (var i = 0; i < lines.length;i++) {
43105 pos += lines[i].length;
43115 pos -= lines[i].length;
43121 this.el.dom.setSelectionRange(pos, pos);
43125 this.el.dom.selectionStart = pos;
43126 this.el.dom.selectionEnd = curr;
43129 "end" : function(e){
43130 e.preventDefault();
43132 var curr = this.el.dom.selectionStart;
43133 var lines = this.getValue().split("\n");
43140 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
43146 for (var i = 0; i < lines.length;i++) {
43148 pos += lines[i].length;
43162 this.el.dom.setSelectionRange(pos, pos);
43166 this.el.dom.selectionStart = curr;
43167 this.el.dom.selectionEnd = pos;
43172 doRelay : function(foo, bar, hname){
43173 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
43179 // if(this.autosave && this.w){
43180 // this.autoSaveFn = setInterval(this.autosave, 1000);
43185 onResize : function(w, h)
43187 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
43192 if(typeof w == 'number'){
43193 var aw = w - this.wrap.getFrameWidth('lr');
43194 this.el.setWidth(this.adjustWidth('textarea', aw));
43197 if(typeof h == 'number'){
43199 for (var i =0; i < this.toolbars.length;i++) {
43200 // fixme - ask toolbars for heights?
43201 tbh += this.toolbars[i].tb.el.getHeight();
43202 if (this.toolbars[i].footer) {
43203 tbh += this.toolbars[i].footer.el.getHeight();
43210 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
43211 ah -= 5; // knock a few pixes off for look..
43213 this.el.setHeight(this.adjustWidth('textarea', ah));
43217 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
43218 this.editorcore.onResize(ew,eh);
43223 * Toggles the editor between standard and source edit mode.
43224 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43226 toggleSourceEdit : function(sourceEditMode)
43228 this.editorcore.toggleSourceEdit(sourceEditMode);
43230 if(this.editorcore.sourceEditMode){
43231 Roo.log('editor - showing textarea');
43234 // Roo.log(this.syncValue());
43235 this.editorcore.syncValue();
43236 this.el.removeClass('x-hidden');
43237 this.el.dom.removeAttribute('tabIndex');
43240 for (var i = 0; i < this.toolbars.length; i++) {
43241 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43242 this.toolbars[i].tb.hide();
43243 this.toolbars[i].footer.hide();
43248 Roo.log('editor - hiding textarea');
43250 // Roo.log(this.pushValue());
43251 this.editorcore.pushValue();
43253 this.el.addClass('x-hidden');
43254 this.el.dom.setAttribute('tabIndex', -1);
43256 for (var i = 0; i < this.toolbars.length; i++) {
43257 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43258 this.toolbars[i].tb.show();
43259 this.toolbars[i].footer.show();
43263 //this.deferFocus();
43266 this.setSize(this.wrap.getSize());
43267 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
43269 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
43272 // private (for BoxComponent)
43273 adjustSize : Roo.BoxComponent.prototype.adjustSize,
43275 // private (for BoxComponent)
43276 getResizeEl : function(){
43280 // private (for BoxComponent)
43281 getPositionEl : function(){
43286 initEvents : function(){
43287 this.originalValue = this.getValue();
43291 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43294 markInvalid : Roo.emptyFn,
43296 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43299 clearInvalid : Roo.emptyFn,
43301 setValue : function(v){
43302 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
43303 this.editorcore.pushValue();
43308 deferFocus : function(){
43309 this.focus.defer(10, this);
43313 focus : function(){
43314 this.editorcore.focus();
43320 onDestroy : function(){
43326 for (var i =0; i < this.toolbars.length;i++) {
43327 // fixme - ask toolbars for heights?
43328 this.toolbars[i].onDestroy();
43331 this.wrap.dom.innerHTML = '';
43332 this.wrap.remove();
43337 onFirstFocus : function(){
43338 //Roo.log("onFirstFocus");
43339 this.editorcore.onFirstFocus();
43340 for (var i =0; i < this.toolbars.length;i++) {
43341 this.toolbars[i].onFirstFocus();
43347 syncValue : function()
43349 this.editorcore.syncValue();
43352 pushValue : function()
43354 this.editorcore.pushValue();
43357 setStylesheets : function(stylesheets)
43359 this.editorcore.setStylesheets(stylesheets);
43362 removeStylesheets : function()
43364 this.editorcore.removeStylesheets();
43368 // hide stuff that is not compatible
43382 * @event specialkey
43386 * @cfg {String} fieldClass @hide
43389 * @cfg {String} focusClass @hide
43392 * @cfg {String} autoCreate @hide
43395 * @cfg {String} inputType @hide
43398 * @cfg {String} invalidClass @hide
43401 * @cfg {String} invalidText @hide
43404 * @cfg {String} msgFx @hide
43407 * @cfg {String} validateOnBlur @hide
43411 // <script type="text/javascript">
43414 * Ext JS Library 1.1.1
43415 * Copyright(c) 2006-2007, Ext JS, LLC.
43421 * @class Roo.form.HtmlEditorToolbar1
43426 new Roo.form.HtmlEditor({
43429 new Roo.form.HtmlEditorToolbar1({
43430 disable : { fonts: 1 , format: 1, ..., ... , ...],
43436 * @cfg {Object} disable List of elements to disable..
43437 * @cfg {Array} btns List of additional buttons.
43441 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
43444 Roo.form.HtmlEditor.ToolbarStandard = function(config)
43447 Roo.apply(this, config);
43449 // default disabled, based on 'good practice'..
43450 this.disable = this.disable || {};
43451 Roo.applyIf(this.disable, {
43454 specialElements : true
43458 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43459 // dont call parent... till later.
43462 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
43469 editorcore : false,
43471 * @cfg {Object} disable List of toolbar elements to disable
43478 * @cfg {String} createLinkText The default text for the create link prompt
43480 createLinkText : 'Please enter the URL for the link:',
43482 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
43484 defaultLinkValue : 'http:/'+'/',
43488 * @cfg {Array} fontFamilies An array of available font families
43506 // "á" , ?? a acute?
43511 "°" // , // degrees
43513 // "é" , // e ecute
43514 // "ú" , // u ecute?
43517 specialElements : [
43519 text: "Insert Table",
43522 ihtml : '<table><tr><td>Cell</td></tr></table>'
43526 text: "Insert Image",
43529 ihtml : '<img src="about:blank"/>'
43538 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
43539 "input:submit", "input:button", "select", "textarea", "label" ],
43542 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
43544 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
43552 * @cfg {String} defaultFont default font to use.
43554 defaultFont: 'tahoma',
43556 fontSelect : false,
43559 formatCombo : false,
43561 init : function(editor)
43563 this.editor = editor;
43564 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43565 var editorcore = this.editorcore;
43569 var fid = editorcore.frameId;
43571 function btn(id, toggle, handler){
43572 var xid = fid + '-'+ id ;
43576 cls : 'x-btn-icon x-edit-'+id,
43577 enableToggle:toggle !== false,
43578 scope: _t, // was editor...
43579 handler:handler||_t.relayBtnCmd,
43580 clickEvent:'mousedown',
43581 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43588 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43590 // stop form submits
43591 tb.el.on('click', function(e){
43592 e.preventDefault(); // what does this do?
43595 if(!this.disable.font) { // && !Roo.isSafari){
43596 /* why no safari for fonts
43597 editor.fontSelect = tb.el.createChild({
43600 cls:'x-font-select',
43601 html: this.createFontOptions()
43604 editor.fontSelect.on('change', function(){
43605 var font = editor.fontSelect.dom.value;
43606 editor.relayCmd('fontname', font);
43607 editor.deferFocus();
43611 editor.fontSelect.dom,
43617 if(!this.disable.formats){
43618 this.formatCombo = new Roo.form.ComboBox({
43619 store: new Roo.data.SimpleStore({
43622 data : this.formats // from states.js
43626 //autoCreate : {tag: "div", size: "20"},
43627 displayField:'tag',
43631 triggerAction: 'all',
43632 emptyText:'Add tag',
43633 selectOnFocus:true,
43636 'select': function(c, r, i) {
43637 editorcore.insertTag(r.get('tag'));
43643 tb.addField(this.formatCombo);
43647 if(!this.disable.format){
43654 if(!this.disable.fontSize){
43659 btn('increasefontsize', false, editorcore.adjustFont),
43660 btn('decreasefontsize', false, editorcore.adjustFont)
43665 if(!this.disable.colors){
43668 id:editorcore.frameId +'-forecolor',
43669 cls:'x-btn-icon x-edit-forecolor',
43670 clickEvent:'mousedown',
43671 tooltip: this.buttonTips['forecolor'] || undefined,
43673 menu : new Roo.menu.ColorMenu({
43674 allowReselect: true,
43675 focus: Roo.emptyFn,
43678 selectHandler: function(cp, color){
43679 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43680 editor.deferFocus();
43683 clickEvent:'mousedown'
43686 id:editorcore.frameId +'backcolor',
43687 cls:'x-btn-icon x-edit-backcolor',
43688 clickEvent:'mousedown',
43689 tooltip: this.buttonTips['backcolor'] || undefined,
43691 menu : new Roo.menu.ColorMenu({
43692 focus: Roo.emptyFn,
43695 allowReselect: true,
43696 selectHandler: function(cp, color){
43698 editorcore.execCmd('useCSS', false);
43699 editorcore.execCmd('hilitecolor', color);
43700 editorcore.execCmd('useCSS', true);
43701 editor.deferFocus();
43703 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43704 Roo.isSafari || Roo.isIE ? '#'+color : color);
43705 editor.deferFocus();
43709 clickEvent:'mousedown'
43714 // now add all the items...
43717 if(!this.disable.alignments){
43720 btn('justifyleft'),
43721 btn('justifycenter'),
43722 btn('justifyright')
43726 //if(!Roo.isSafari){
43727 if(!this.disable.links){
43730 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43734 if(!this.disable.lists){
43737 btn('insertorderedlist'),
43738 btn('insertunorderedlist')
43741 if(!this.disable.sourceEdit){
43744 btn('sourceedit', true, function(btn){
43745 this.toggleSourceEdit(btn.pressed);
43752 // special menu.. - needs to be tidied up..
43753 if (!this.disable.special) {
43756 cls: 'x-edit-none',
43762 for (var i =0; i < this.specialChars.length; i++) {
43763 smenu.menu.items.push({
43765 html: this.specialChars[i],
43766 handler: function(a,b) {
43767 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43768 //editor.insertAtCursor(a.html);
43782 if (!this.disable.cleanStyles) {
43784 cls: 'x-btn-icon x-btn-clear',
43790 for (var i =0; i < this.cleanStyles.length; i++) {
43791 cmenu.menu.items.push({
43792 actiontype : this.cleanStyles[i],
43793 html: 'Remove ' + this.cleanStyles[i],
43794 handler: function(a,b) {
43797 var c = Roo.get(editorcore.doc.body);
43798 c.select('[style]').each(function(s) {
43799 s.dom.style.removeProperty(a.actiontype);
43801 editorcore.syncValue();
43806 cmenu.menu.items.push({
43807 actiontype : 'tablewidths',
43808 html: 'Remove Table Widths',
43809 handler: function(a,b) {
43810 editorcore.cleanTableWidths();
43811 editorcore.syncValue();
43815 cmenu.menu.items.push({
43816 actiontype : 'word',
43817 html: 'Remove MS Word Formating',
43818 handler: function(a,b) {
43819 editorcore.cleanWord();
43820 editorcore.syncValue();
43825 cmenu.menu.items.push({
43826 actiontype : 'all',
43827 html: 'Remove All Styles',
43828 handler: function(a,b) {
43830 var c = Roo.get(editorcore.doc.body);
43831 c.select('[style]').each(function(s) {
43832 s.dom.removeAttribute('style');
43834 editorcore.syncValue();
43839 cmenu.menu.items.push({
43840 actiontype : 'all',
43841 html: 'Remove All CSS Classes',
43842 handler: function(a,b) {
43844 var c = Roo.get(editorcore.doc.body);
43845 c.select('[class]').each(function(s) {
43846 s.dom.className = '';
43848 editorcore.syncValue();
43853 cmenu.menu.items.push({
43854 actiontype : 'tidy',
43855 html: 'Tidy HTML Source',
43856 handler: function(a,b) {
43857 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43858 editorcore.syncValue();
43867 if (!this.disable.specialElements) {
43870 cls: 'x-edit-none',
43875 for (var i =0; i < this.specialElements.length; i++) {
43876 semenu.menu.items.push(
43878 handler: function(a,b) {
43879 editor.insertAtCursor(this.ihtml);
43881 }, this.specialElements[i])
43893 for(var i =0; i< this.btns.length;i++) {
43894 var b = Roo.factory(this.btns[i],Roo.form);
43895 b.cls = 'x-edit-none';
43897 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
43898 b.cls += ' x-init-enable';
43901 b.scope = editorcore;
43909 // disable everything...
43911 this.tb.items.each(function(item){
43914 item.id != editorcore.frameId+ '-sourceedit' &&
43915 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
43921 this.rendered = true;
43923 // the all the btns;
43924 editor.on('editorevent', this.updateToolbar, this);
43925 // other toolbars need to implement this..
43926 //editor.on('editmodechange', this.updateToolbar, this);
43930 relayBtnCmd : function(btn) {
43931 this.editorcore.relayCmd(btn.cmd);
43933 // private used internally
43934 createLink : function(){
43935 Roo.log("create link?");
43936 var url = prompt(this.createLinkText, this.defaultLinkValue);
43937 if(url && url != 'http:/'+'/'){
43938 this.editorcore.relayCmd('createlink', url);
43944 * Protected method that will not generally be called directly. It triggers
43945 * a toolbar update by reading the markup state of the current selection in the editor.
43947 updateToolbar: function(){
43949 if(!this.editorcore.activated){
43950 this.editor.onFirstFocus();
43954 var btns = this.tb.items.map,
43955 doc = this.editorcore.doc,
43956 frameId = this.editorcore.frameId;
43958 if(!this.disable.font && !Roo.isSafari){
43960 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43961 if(name != this.fontSelect.dom.value){
43962 this.fontSelect.dom.value = name;
43966 if(!this.disable.format){
43967 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43968 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43969 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43971 if(!this.disable.alignments){
43972 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43973 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43974 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43976 if(!Roo.isSafari && !this.disable.lists){
43977 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43978 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43981 var ans = this.editorcore.getAllAncestors();
43982 if (this.formatCombo) {
43985 var store = this.formatCombo.store;
43986 this.formatCombo.setValue("");
43987 for (var i =0; i < ans.length;i++) {
43988 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43990 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43998 // hides menus... - so this cant be on a menu...
43999 Roo.menu.MenuMgr.hideAll();
44001 //this.editorsyncValue();
44005 createFontOptions : function(){
44006 var buf = [], fs = this.fontFamilies, ff, lc;
44010 for(var i = 0, len = fs.length; i< len; i++){
44012 lc = ff.toLowerCase();
44014 '<option value="',lc,'" style="font-family:',ff,';"',
44015 (this.defaultFont == lc ? ' selected="true">' : '>'),
44020 return buf.join('');
44023 toggleSourceEdit : function(sourceEditMode){
44025 Roo.log("toolbar toogle");
44026 if(sourceEditMode === undefined){
44027 sourceEditMode = !this.sourceEditMode;
44029 this.sourceEditMode = sourceEditMode === true;
44030 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
44031 // just toggle the button?
44032 if(btn.pressed !== this.sourceEditMode){
44033 btn.toggle(this.sourceEditMode);
44037 if(sourceEditMode){
44038 Roo.log("disabling buttons");
44039 this.tb.items.each(function(item){
44040 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
44046 Roo.log("enabling buttons");
44047 if(this.editorcore.initialized){
44048 this.tb.items.each(function(item){
44054 Roo.log("calling toggole on editor");
44055 // tell the editor that it's been pressed..
44056 this.editor.toggleSourceEdit(sourceEditMode);
44060 * Object collection of toolbar tooltips for the buttons in the editor. The key
44061 * is the command id associated with that button and the value is a valid QuickTips object.
44066 title: 'Bold (Ctrl+B)',
44067 text: 'Make the selected text bold.',
44068 cls: 'x-html-editor-tip'
44071 title: 'Italic (Ctrl+I)',
44072 text: 'Make the selected text italic.',
44073 cls: 'x-html-editor-tip'
44081 title: 'Bold (Ctrl+B)',
44082 text: 'Make the selected text bold.',
44083 cls: 'x-html-editor-tip'
44086 title: 'Italic (Ctrl+I)',
44087 text: 'Make the selected text italic.',
44088 cls: 'x-html-editor-tip'
44091 title: 'Underline (Ctrl+U)',
44092 text: 'Underline the selected text.',
44093 cls: 'x-html-editor-tip'
44095 increasefontsize : {
44096 title: 'Grow Text',
44097 text: 'Increase the font size.',
44098 cls: 'x-html-editor-tip'
44100 decreasefontsize : {
44101 title: 'Shrink Text',
44102 text: 'Decrease the font size.',
44103 cls: 'x-html-editor-tip'
44106 title: 'Text Highlight Color',
44107 text: 'Change the background color of the selected text.',
44108 cls: 'x-html-editor-tip'
44111 title: 'Font Color',
44112 text: 'Change the color of the selected text.',
44113 cls: 'x-html-editor-tip'
44116 title: 'Align Text Left',
44117 text: 'Align text to the left.',
44118 cls: 'x-html-editor-tip'
44121 title: 'Center Text',
44122 text: 'Center text in the editor.',
44123 cls: 'x-html-editor-tip'
44126 title: 'Align Text Right',
44127 text: 'Align text to the right.',
44128 cls: 'x-html-editor-tip'
44130 insertunorderedlist : {
44131 title: 'Bullet List',
44132 text: 'Start a bulleted list.',
44133 cls: 'x-html-editor-tip'
44135 insertorderedlist : {
44136 title: 'Numbered List',
44137 text: 'Start a numbered list.',
44138 cls: 'x-html-editor-tip'
44141 title: 'Hyperlink',
44142 text: 'Make the selected text a hyperlink.',
44143 cls: 'x-html-editor-tip'
44146 title: 'Source Edit',
44147 text: 'Switch to source editing mode.',
44148 cls: 'x-html-editor-tip'
44152 onDestroy : function(){
44155 this.tb.items.each(function(item){
44157 item.menu.removeAll();
44159 item.menu.el.destroy();
44167 onFirstFocus: function() {
44168 this.tb.items.each(function(item){
44177 // <script type="text/javascript">
44180 * Ext JS Library 1.1.1
44181 * Copyright(c) 2006-2007, Ext JS, LLC.
44188 * @class Roo.form.HtmlEditor.ToolbarContext
44193 new Roo.form.HtmlEditor({
44196 { xtype: 'ToolbarStandard', styles : {} }
44197 { xtype: 'ToolbarContext', disable : {} }
44203 * @config : {Object} disable List of elements to disable.. (not done yet.)
44204 * @config : {Object} styles Map of styles available.
44208 Roo.form.HtmlEditor.ToolbarContext = function(config)
44211 Roo.apply(this, config);
44212 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44213 // dont call parent... till later.
44214 this.styles = this.styles || {};
44219 Roo.form.HtmlEditor.ToolbarContext.types = {
44231 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
44297 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
44302 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
44312 style : 'fontFamily',
44313 displayField: 'display',
44314 optname : 'font-family',
44363 // should we really allow this??
44364 // should this just be
44375 style : 'fontFamily',
44376 displayField: 'display',
44377 optname : 'font-family',
44384 style : 'fontFamily',
44385 displayField: 'display',
44386 optname : 'font-family',
44393 style : 'fontFamily',
44394 displayField: 'display',
44395 optname : 'font-family',
44406 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
44407 Roo.form.HtmlEditor.ToolbarContext.stores = false;
44409 Roo.form.HtmlEditor.ToolbarContext.options = {
44411 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
44412 [ 'Courier New', 'Courier New'],
44413 [ 'Tahoma', 'Tahoma'],
44414 [ 'Times New Roman,serif', 'Times'],
44415 [ 'Verdana','Verdana' ]
44419 // fixme - these need to be configurable..
44422 Roo.form.HtmlEditor.ToolbarContext.types
44425 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
44432 editorcore : false,
44434 * @cfg {Object} disable List of toolbar elements to disable
44439 * @cfg {Object} styles List of styles
44440 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
44442 * These must be defined in the page, so they get rendered correctly..
44453 init : function(editor)
44455 this.editor = editor;
44456 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44457 var editorcore = this.editorcore;
44459 var fid = editorcore.frameId;
44461 function btn(id, toggle, handler){
44462 var xid = fid + '-'+ id ;
44466 cls : 'x-btn-icon x-edit-'+id,
44467 enableToggle:toggle !== false,
44468 scope: editorcore, // was editor...
44469 handler:handler||editorcore.relayBtnCmd,
44470 clickEvent:'mousedown',
44471 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44475 // create a new element.
44476 var wdiv = editor.wrap.createChild({
44478 }, editor.wrap.dom.firstChild.nextSibling, true);
44480 // can we do this more than once??
44482 // stop form submits
44485 // disable everything...
44486 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44487 this.toolbars = {};
44489 for (var i in ty) {
44491 this.toolbars[i] = this.buildToolbar(ty[i],i);
44493 this.tb = this.toolbars.BODY;
44495 this.buildFooter();
44496 this.footer.show();
44497 editor.on('hide', function( ) { this.footer.hide() }, this);
44498 editor.on('show', function( ) { this.footer.show() }, this);
44501 this.rendered = true;
44503 // the all the btns;
44504 editor.on('editorevent', this.updateToolbar, this);
44505 // other toolbars need to implement this..
44506 //editor.on('editmodechange', this.updateToolbar, this);
44512 * Protected method that will not generally be called directly. It triggers
44513 * a toolbar update by reading the markup state of the current selection in the editor.
44515 * Note you can force an update by calling on('editorevent', scope, false)
44517 updateToolbar: function(editor,ev,sel){
44520 // capture mouse up - this is handy for selecting images..
44521 // perhaps should go somewhere else...
44522 if(!this.editorcore.activated){
44523 this.editor.onFirstFocus();
44529 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
44530 // selectNode - might want to handle IE?
44532 (ev.type == 'mouseup' || ev.type == 'click' ) &&
44533 ev.target && ev.target.tagName == 'IMG') {
44534 // they have click on an image...
44535 // let's see if we can change the selection...
44538 var nodeRange = sel.ownerDocument.createRange();
44540 nodeRange.selectNode(sel);
44542 nodeRange.selectNodeContents(sel);
44544 //nodeRange.collapse(true);
44545 var s = this.editorcore.win.getSelection();
44546 s.removeAllRanges();
44547 s.addRange(nodeRange);
44551 var updateFooter = sel ? false : true;
44554 var ans = this.editorcore.getAllAncestors();
44557 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44560 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
44561 sel = sel ? sel : this.editorcore.doc.body;
44562 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
44565 // pick a menu that exists..
44566 var tn = sel.tagName.toUpperCase();
44567 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
44569 tn = sel.tagName.toUpperCase();
44571 var lastSel = this.tb.selectedNode
44573 this.tb.selectedNode = sel;
44575 // if current menu does not match..
44577 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
44580 ///console.log("show: " + tn);
44581 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
44584 this.tb.items.first().el.innerHTML = tn + ': ';
44587 // update attributes
44588 if (this.tb.fields) {
44589 this.tb.fields.each(function(e) {
44591 e.setValue(sel.style[e.stylename]);
44594 e.setValue(sel.getAttribute(e.attrname));
44598 var hasStyles = false;
44599 for(var i in this.styles) {
44606 var st = this.tb.fields.item(0);
44608 st.store.removeAll();
44611 var cn = sel.className.split(/\s+/);
44614 if (this.styles['*']) {
44616 Roo.each(this.styles['*'], function(v) {
44617 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44620 if (this.styles[tn]) {
44621 Roo.each(this.styles[tn], function(v) {
44622 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44626 st.store.loadData(avs);
44630 // flag our selected Node.
44631 this.tb.selectedNode = sel;
44634 Roo.menu.MenuMgr.hideAll();
44638 if (!updateFooter) {
44639 //this.footDisp.dom.innerHTML = '';
44642 // update the footer
44646 this.footerEls = ans.reverse();
44647 Roo.each(this.footerEls, function(a,i) {
44648 if (!a) { return; }
44649 html += html.length ? ' > ' : '';
44651 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44656 var sz = this.footDisp.up('td').getSize();
44657 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44658 this.footDisp.dom.style.marginLeft = '5px';
44660 this.footDisp.dom.style.overflow = 'hidden';
44662 this.footDisp.dom.innerHTML = html;
44664 //this.editorsyncValue();
44671 onDestroy : function(){
44674 this.tb.items.each(function(item){
44676 item.menu.removeAll();
44678 item.menu.el.destroy();
44686 onFirstFocus: function() {
44687 // need to do this for all the toolbars..
44688 this.tb.items.each(function(item){
44692 buildToolbar: function(tlist, nm)
44694 var editor = this.editor;
44695 var editorcore = this.editorcore;
44696 // create a new element.
44697 var wdiv = editor.wrap.createChild({
44699 }, editor.wrap.dom.firstChild.nextSibling, true);
44702 var tb = new Roo.Toolbar(wdiv);
44705 tb.add(nm+ ": ");
44708 for(var i in this.styles) {
44713 if (styles && styles.length) {
44715 // this needs a multi-select checkbox...
44716 tb.addField( new Roo.form.ComboBox({
44717 store: new Roo.data.SimpleStore({
44719 fields: ['val', 'selected'],
44722 name : '-roo-edit-className',
44723 attrname : 'className',
44724 displayField: 'val',
44728 triggerAction: 'all',
44729 emptyText:'Select Style',
44730 selectOnFocus:true,
44733 'select': function(c, r, i) {
44734 // initial support only for on class per el..
44735 tb.selectedNode.className = r ? r.get('val') : '';
44736 editorcore.syncValue();
44743 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44744 var tbops = tbc.options;
44746 for (var i in tlist) {
44748 var item = tlist[i];
44749 tb.add(item.title + ": ");
44752 //optname == used so you can configure the options available..
44753 var opts = item.opts ? item.opts : false;
44754 if (item.optname) {
44755 opts = tbops[item.optname];
44760 // opts == pulldown..
44761 tb.addField( new Roo.form.ComboBox({
44762 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44764 fields: ['val', 'display'],
44767 name : '-roo-edit-' + i,
44769 stylename : item.style ? item.style : false,
44770 displayField: item.displayField ? item.displayField : 'val',
44771 valueField : 'val',
44773 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44775 triggerAction: 'all',
44776 emptyText:'Select',
44777 selectOnFocus:true,
44778 width: item.width ? item.width : 130,
44780 'select': function(c, r, i) {
44782 tb.selectedNode.style[c.stylename] = r.get('val');
44785 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44794 tb.addField( new Roo.form.TextField({
44797 //allowBlank:false,
44802 tb.addField( new Roo.form.TextField({
44803 name: '-roo-edit-' + i,
44810 'change' : function(f, nv, ov) {
44811 tb.selectedNode.setAttribute(f.attrname, nv);
44824 text: 'Stylesheets',
44827 click : function ()
44829 _this.editor.fireEvent('stylesheetsclick', _this.editor);
44837 text: 'Remove Tag',
44840 click : function ()
44843 // undo does not work.
44845 var sn = tb.selectedNode;
44847 var pn = sn.parentNode;
44849 var stn = sn.childNodes[0];
44850 var en = sn.childNodes[sn.childNodes.length - 1 ];
44851 while (sn.childNodes.length) {
44852 var node = sn.childNodes[0];
44853 sn.removeChild(node);
44855 pn.insertBefore(node, sn);
44858 pn.removeChild(sn);
44859 var range = editorcore.createRange();
44861 range.setStart(stn,0);
44862 range.setEnd(en,0); //????
44863 //range.selectNode(sel);
44866 var selection = editorcore.getSelection();
44867 selection.removeAllRanges();
44868 selection.addRange(range);
44872 //_this.updateToolbar(null, null, pn);
44873 _this.updateToolbar(null, null, null);
44874 _this.footDisp.dom.innerHTML = '';
44884 tb.el.on('click', function(e){
44885 e.preventDefault(); // what does this do?
44887 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44890 // dont need to disable them... as they will get hidden
44895 buildFooter : function()
44898 var fel = this.editor.wrap.createChild();
44899 this.footer = new Roo.Toolbar(fel);
44900 // toolbar has scrolly on left / right?
44901 var footDisp= new Roo.Toolbar.Fill();
44907 handler : function() {
44908 _t.footDisp.scrollTo('left',0,true)
44912 this.footer.add( footDisp );
44917 handler : function() {
44919 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44923 var fel = Roo.get(footDisp.el);
44924 fel.addClass('x-editor-context');
44925 this.footDispWrap = fel;
44926 this.footDispWrap.overflow = 'hidden';
44928 this.footDisp = fel.createChild();
44929 this.footDispWrap.on('click', this.onContextClick, this)
44933 onContextClick : function (ev,dom)
44935 ev.preventDefault();
44936 var cn = dom.className;
44938 if (!cn.match(/x-ed-loc-/)) {
44941 var n = cn.split('-').pop();
44942 var ans = this.footerEls;
44946 var range = this.editorcore.createRange();
44948 range.selectNodeContents(sel);
44949 //range.selectNode(sel);
44952 var selection = this.editorcore.getSelection();
44953 selection.removeAllRanges();
44954 selection.addRange(range);
44958 this.updateToolbar(null, null, sel);
44975 * Ext JS Library 1.1.1
44976 * Copyright(c) 2006-2007, Ext JS, LLC.
44978 * Originally Released Under LGPL - original licence link has changed is not relivant.
44981 * <script type="text/javascript">
44985 * @class Roo.form.BasicForm
44986 * @extends Roo.util.Observable
44987 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44989 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44990 * @param {Object} config Configuration options
44992 Roo.form.BasicForm = function(el, config){
44993 this.allItems = [];
44994 this.childForms = [];
44995 Roo.apply(this, config);
44997 * The Roo.form.Field items in this form.
44998 * @type MixedCollection
45002 this.items = new Roo.util.MixedCollection(false, function(o){
45003 return o.id || (o.id = Roo.id());
45007 * @event beforeaction
45008 * Fires before any action is performed. Return false to cancel the action.
45009 * @param {Form} this
45010 * @param {Action} action The action to be performed
45012 beforeaction: true,
45014 * @event actionfailed
45015 * Fires when an action fails.
45016 * @param {Form} this
45017 * @param {Action} action The action that failed
45019 actionfailed : true,
45021 * @event actioncomplete
45022 * Fires when an action is completed.
45023 * @param {Form} this
45024 * @param {Action} action The action that completed
45026 actioncomplete : true
45031 Roo.form.BasicForm.superclass.constructor.call(this);
45034 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
45036 * @cfg {String} method
45037 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
45040 * @cfg {DataReader} reader
45041 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
45042 * This is optional as there is built-in support for processing JSON.
45045 * @cfg {DataReader} errorReader
45046 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
45047 * This is completely optional as there is built-in support for processing JSON.
45050 * @cfg {String} url
45051 * The URL to use for form actions if one isn't supplied in the action options.
45054 * @cfg {Boolean} fileUpload
45055 * Set to true if this form is a file upload.
45059 * @cfg {Object} baseParams
45060 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
45065 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
45070 activeAction : null,
45073 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
45074 * or setValues() data instead of when the form was first created.
45076 trackResetOnLoad : false,
45080 * childForms - used for multi-tab forms
45083 childForms : false,
45086 * allItems - full list of fields.
45092 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
45093 * element by passing it or its id or mask the form itself by passing in true.
45096 waitMsgTarget : false,
45099 initEl : function(el){
45100 this.el = Roo.get(el);
45101 this.id = this.el.id || Roo.id();
45102 this.el.on('submit', this.onSubmit, this);
45103 this.el.addClass('x-form');
45107 onSubmit : function(e){
45112 * Returns true if client-side validation on the form is successful.
45115 isValid : function(){
45117 this.items.each(function(f){
45126 * Returns true if any fields in this form have changed since their original load.
45129 isDirty : function(){
45131 this.items.each(function(f){
45141 * Performs a predefined action (submit or load) or custom actions you define on this form.
45142 * @param {String} actionName The name of the action type
45143 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
45144 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
45145 * accept other config options):
45147 Property Type Description
45148 ---------------- --------------- ----------------------------------------------------------------------------------
45149 url String The url for the action (defaults to the form's url)
45150 method String The form method to use (defaults to the form's method, or POST if not defined)
45151 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
45152 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
45153 validate the form on the client (defaults to false)
45155 * @return {BasicForm} this
45157 doAction : function(action, options){
45158 if(typeof action == 'string'){
45159 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
45161 if(this.fireEvent('beforeaction', this, action) !== false){
45162 this.beforeAction(action);
45163 action.run.defer(100, action);
45169 * Shortcut to do a submit action.
45170 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45171 * @return {BasicForm} this
45173 submit : function(options){
45174 this.doAction('submit', options);
45179 * Shortcut to do a load action.
45180 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45181 * @return {BasicForm} this
45183 load : function(options){
45184 this.doAction('load', options);
45189 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
45190 * @param {Record} record The record to edit
45191 * @return {BasicForm} this
45193 updateRecord : function(record){
45194 record.beginEdit();
45195 var fs = record.fields;
45196 fs.each(function(f){
45197 var field = this.findField(f.name);
45199 record.set(f.name, field.getValue());
45207 * Loads an Roo.data.Record into this form.
45208 * @param {Record} record The record to load
45209 * @return {BasicForm} this
45211 loadRecord : function(record){
45212 this.setValues(record.data);
45217 beforeAction : function(action){
45218 var o = action.options;
45221 if(this.waitMsgTarget === true){
45222 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
45223 }else if(this.waitMsgTarget){
45224 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
45225 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
45227 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
45233 afterAction : function(action, success){
45234 this.activeAction = null;
45235 var o = action.options;
45237 if(this.waitMsgTarget === true){
45239 }else if(this.waitMsgTarget){
45240 this.waitMsgTarget.unmask();
45242 Roo.MessageBox.updateProgress(1);
45243 Roo.MessageBox.hide();
45250 Roo.callback(o.success, o.scope, [this, action]);
45251 this.fireEvent('actioncomplete', this, action);
45255 // failure condition..
45256 // we have a scenario where updates need confirming.
45257 // eg. if a locking scenario exists..
45258 // we look for { errors : { needs_confirm : true }} in the response.
45260 (typeof(action.result) != 'undefined') &&
45261 (typeof(action.result.errors) != 'undefined') &&
45262 (typeof(action.result.errors.needs_confirm) != 'undefined')
45265 Roo.MessageBox.confirm(
45266 "Change requires confirmation",
45267 action.result.errorMsg,
45272 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
45282 Roo.callback(o.failure, o.scope, [this, action]);
45283 // show an error message if no failed handler is set..
45284 if (!this.hasListener('actionfailed')) {
45285 Roo.MessageBox.alert("Error",
45286 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
45287 action.result.errorMsg :
45288 "Saving Failed, please check your entries or try again"
45292 this.fireEvent('actionfailed', this, action);
45298 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
45299 * @param {String} id The value to search for
45302 findField : function(id){
45303 var field = this.items.get(id);
45305 this.items.each(function(f){
45306 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
45312 return field || null;
45316 * Add a secondary form to this one,
45317 * Used to provide tabbed forms. One form is primary, with hidden values
45318 * which mirror the elements from the other forms.
45320 * @param {Roo.form.Form} form to add.
45323 addForm : function(form)
45326 if (this.childForms.indexOf(form) > -1) {
45330 this.childForms.push(form);
45332 Roo.each(form.allItems, function (fe) {
45334 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
45335 if (this.findField(n)) { // already added..
45338 var add = new Roo.form.Hidden({
45341 add.render(this.el);
45348 * Mark fields in this form invalid in bulk.
45349 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
45350 * @return {BasicForm} this
45352 markInvalid : function(errors){
45353 if(errors instanceof Array){
45354 for(var i = 0, len = errors.length; i < len; i++){
45355 var fieldError = errors[i];
45356 var f = this.findField(fieldError.id);
45358 f.markInvalid(fieldError.msg);
45364 if(typeof errors[id] != 'function' && (field = this.findField(id))){
45365 field.markInvalid(errors[id]);
45369 Roo.each(this.childForms || [], function (f) {
45370 f.markInvalid(errors);
45377 * Set values for fields in this form in bulk.
45378 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
45379 * @return {BasicForm} this
45381 setValues : function(values){
45382 if(values instanceof Array){ // array of objects
45383 for(var i = 0, len = values.length; i < len; i++){
45385 var f = this.findField(v.id);
45387 f.setValue(v.value);
45388 if(this.trackResetOnLoad){
45389 f.originalValue = f.getValue();
45393 }else{ // object hash
45396 if(typeof values[id] != 'function' && (field = this.findField(id))){
45398 if (field.setFromData &&
45399 field.valueField &&
45400 field.displayField &&
45401 // combos' with local stores can
45402 // be queried via setValue()
45403 // to set their value..
45404 (field.store && !field.store.isLocal)
45408 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
45409 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
45410 field.setFromData(sd);
45413 field.setValue(values[id]);
45417 if(this.trackResetOnLoad){
45418 field.originalValue = field.getValue();
45424 Roo.each(this.childForms || [], function (f) {
45425 f.setValues(values);
45432 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
45433 * they are returned as an array.
45434 * @param {Boolean} asString
45437 getValues : function(asString){
45438 if (this.childForms) {
45439 // copy values from the child forms
45440 Roo.each(this.childForms, function (f) {
45441 this.setValues(f.getValues());
45447 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
45448 if(asString === true){
45451 return Roo.urlDecode(fs);
45455 * Returns the fields in this form as an object with key/value pairs.
45456 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
45459 getFieldValues : function(with_hidden)
45461 if (this.childForms) {
45462 // copy values from the child forms
45463 // should this call getFieldValues - probably not as we do not currently copy
45464 // hidden fields when we generate..
45465 Roo.each(this.childForms, function (f) {
45466 this.setValues(f.getValues());
45471 this.items.each(function(f){
45472 if (!f.getName()) {
45475 var v = f.getValue();
45476 if (f.inputType =='radio') {
45477 if (typeof(ret[f.getName()]) == 'undefined') {
45478 ret[f.getName()] = ''; // empty..
45481 if (!f.el.dom.checked) {
45485 v = f.el.dom.value;
45489 // not sure if this supported any more..
45490 if ((typeof(v) == 'object') && f.getRawValue) {
45491 v = f.getRawValue() ; // dates..
45493 // combo boxes where name != hiddenName...
45494 if (f.name != f.getName()) {
45495 ret[f.name] = f.getRawValue();
45497 ret[f.getName()] = v;
45504 * Clears all invalid messages in this form.
45505 * @return {BasicForm} this
45507 clearInvalid : function(){
45508 this.items.each(function(f){
45512 Roo.each(this.childForms || [], function (f) {
45521 * Resets this form.
45522 * @return {BasicForm} this
45524 reset : function(){
45525 this.items.each(function(f){
45529 Roo.each(this.childForms || [], function (f) {
45538 * Add Roo.form components to this form.
45539 * @param {Field} field1
45540 * @param {Field} field2 (optional)
45541 * @param {Field} etc (optional)
45542 * @return {BasicForm} this
45545 this.items.addAll(Array.prototype.slice.call(arguments, 0));
45551 * Removes a field from the items collection (does NOT remove its markup).
45552 * @param {Field} field
45553 * @return {BasicForm} this
45555 remove : function(field){
45556 this.items.remove(field);
45561 * Looks at the fields in this form, checks them for an id attribute,
45562 * and calls applyTo on the existing dom element with that id.
45563 * @return {BasicForm} this
45565 render : function(){
45566 this.items.each(function(f){
45567 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
45575 * Calls {@link Ext#apply} for all fields in this form with the passed object.
45576 * @param {Object} values
45577 * @return {BasicForm} this
45579 applyToFields : function(o){
45580 this.items.each(function(f){
45587 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
45588 * @param {Object} values
45589 * @return {BasicForm} this
45591 applyIfToFields : function(o){
45592 this.items.each(function(f){
45600 Roo.BasicForm = Roo.form.BasicForm;/*
45602 * Ext JS Library 1.1.1
45603 * Copyright(c) 2006-2007, Ext JS, LLC.
45605 * Originally Released Under LGPL - original licence link has changed is not relivant.
45608 * <script type="text/javascript">
45612 * @class Roo.form.Form
45613 * @extends Roo.form.BasicForm
45614 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
45616 * @param {Object} config Configuration options
45618 Roo.form.Form = function(config){
45620 if (config.items) {
45621 xitems = config.items;
45622 delete config.items;
45626 Roo.form.Form.superclass.constructor.call(this, null, config);
45627 this.url = this.url || this.action;
45629 this.root = new Roo.form.Layout(Roo.applyIf({
45633 this.active = this.root;
45635 * Array of all the buttons that have been added to this form via {@link addButton}
45639 this.allItems = [];
45642 * @event clientvalidation
45643 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45644 * @param {Form} this
45645 * @param {Boolean} valid true if the form has passed client-side validation
45647 clientvalidation: true,
45650 * Fires when the form is rendered
45651 * @param {Roo.form.Form} form
45656 if (this.progressUrl) {
45657 // push a hidden field onto the list of fields..
45661 name : 'UPLOAD_IDENTIFIER'
45666 Roo.each(xitems, this.addxtype, this);
45672 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45674 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45677 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45680 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45682 buttonAlign:'center',
45685 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45690 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45691 * This property cascades to child containers if not set.
45696 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45697 * fires a looping event with that state. This is required to bind buttons to the valid
45698 * state using the config value formBind:true on the button.
45700 monitorValid : false,
45703 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45708 * @cfg {String} progressUrl - Url to return progress data
45711 progressUrl : false,
45714 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45715 * fields are added and the column is closed. If no fields are passed the column remains open
45716 * until end() is called.
45717 * @param {Object} config The config to pass to the column
45718 * @param {Field} field1 (optional)
45719 * @param {Field} field2 (optional)
45720 * @param {Field} etc (optional)
45721 * @return Column The column container object
45723 column : function(c){
45724 var col = new Roo.form.Column(c);
45726 if(arguments.length > 1){ // duplicate code required because of Opera
45727 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45734 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45735 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45736 * until end() is called.
45737 * @param {Object} config The config to pass to the fieldset
45738 * @param {Field} field1 (optional)
45739 * @param {Field} field2 (optional)
45740 * @param {Field} etc (optional)
45741 * @return FieldSet The fieldset container object
45743 fieldset : function(c){
45744 var fs = new Roo.form.FieldSet(c);
45746 if(arguments.length > 1){ // duplicate code required because of Opera
45747 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45754 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45755 * fields are added and the container is closed. If no fields are passed the container remains open
45756 * until end() is called.
45757 * @param {Object} config The config to pass to the Layout
45758 * @param {Field} field1 (optional)
45759 * @param {Field} field2 (optional)
45760 * @param {Field} etc (optional)
45761 * @return Layout The container object
45763 container : function(c){
45764 var l = new Roo.form.Layout(c);
45766 if(arguments.length > 1){ // duplicate code required because of Opera
45767 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45774 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45775 * @param {Object} container A Roo.form.Layout or subclass of Layout
45776 * @return {Form} this
45778 start : function(c){
45779 // cascade label info
45780 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45781 this.active.stack.push(c);
45782 c.ownerCt = this.active;
45788 * Closes the current open container
45789 * @return {Form} this
45792 if(this.active == this.root){
45795 this.active = this.active.ownerCt;
45800 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45801 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45802 * as the label of the field.
45803 * @param {Field} field1
45804 * @param {Field} field2 (optional)
45805 * @param {Field} etc. (optional)
45806 * @return {Form} this
45809 this.active.stack.push.apply(this.active.stack, arguments);
45810 this.allItems.push.apply(this.allItems,arguments);
45812 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45813 if(a[i].isFormField){
45818 Roo.form.Form.superclass.add.apply(this, r);
45828 * Find any element that has been added to a form, using it's ID or name
45829 * This can include framesets, columns etc. along with regular fields..
45830 * @param {String} id - id or name to find.
45832 * @return {Element} e - or false if nothing found.
45834 findbyId : function(id)
45840 Roo.each(this.allItems, function(f){
45841 if (f.id == id || f.name == id ){
45852 * Render this form into the passed container. This should only be called once!
45853 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45854 * @return {Form} this
45856 render : function(ct)
45862 var o = this.autoCreate || {
45864 method : this.method || 'POST',
45865 id : this.id || Roo.id()
45867 this.initEl(ct.createChild(o));
45869 this.root.render(this.el);
45873 this.items.each(function(f){
45874 f.render('x-form-el-'+f.id);
45877 if(this.buttons.length > 0){
45878 // tables are required to maintain order and for correct IE layout
45879 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45880 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45881 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45883 var tr = tb.getElementsByTagName('tr')[0];
45884 for(var i = 0, len = this.buttons.length; i < len; i++) {
45885 var b = this.buttons[i];
45886 var td = document.createElement('td');
45887 td.className = 'x-form-btn-td';
45888 b.render(tr.appendChild(td));
45891 if(this.monitorValid){ // initialize after render
45892 this.startMonitoring();
45894 this.fireEvent('rendered', this);
45899 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45900 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45901 * object or a valid Roo.DomHelper element config
45902 * @param {Function} handler The function called when the button is clicked
45903 * @param {Object} scope (optional) The scope of the handler function
45904 * @return {Roo.Button}
45906 addButton : function(config, handler, scope){
45910 minWidth: this.minButtonWidth,
45913 if(typeof config == "string"){
45916 Roo.apply(bc, config);
45918 var btn = new Roo.Button(null, bc);
45919 this.buttons.push(btn);
45924 * Adds a series of form elements (using the xtype property as the factory method.
45925 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45926 * @param {Object} config
45929 addxtype : function()
45931 var ar = Array.prototype.slice.call(arguments, 0);
45933 for(var i = 0; i < ar.length; i++) {
45935 continue; // skip -- if this happends something invalid got sent, we
45936 // should ignore it, as basically that interface element will not show up
45937 // and that should be pretty obvious!!
45940 if (Roo.form[ar[i].xtype]) {
45942 var fe = Roo.factory(ar[i], Roo.form);
45948 fe.store.form = this;
45953 this.allItems.push(fe);
45954 if (fe.items && fe.addxtype) {
45955 fe.addxtype.apply(fe, fe.items);
45965 // console.log('adding ' + ar[i].xtype);
45967 if (ar[i].xtype == 'Button') {
45968 //console.log('adding button');
45969 //console.log(ar[i]);
45970 this.addButton(ar[i]);
45971 this.allItems.push(fe);
45975 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45976 alert('end is not supported on xtype any more, use items');
45978 // //console.log('adding end');
45986 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45987 * option "monitorValid"
45989 startMonitoring : function(){
45992 Roo.TaskMgr.start({
45993 run : this.bindHandler,
45994 interval : this.monitorPoll || 200,
46001 * Stops monitoring of the valid state of this form
46003 stopMonitoring : function(){
46004 this.bound = false;
46008 bindHandler : function(){
46010 return false; // stops binding
46013 this.items.each(function(f){
46014 if(!f.isValid(true)){
46019 for(var i = 0, len = this.buttons.length; i < len; i++){
46020 var btn = this.buttons[i];
46021 if(btn.formBind === true && btn.disabled === valid){
46022 btn.setDisabled(!valid);
46025 this.fireEvent('clientvalidation', this, valid);
46039 Roo.Form = Roo.form.Form;
46042 * Ext JS Library 1.1.1
46043 * Copyright(c) 2006-2007, Ext JS, LLC.
46045 * Originally Released Under LGPL - original licence link has changed is not relivant.
46048 * <script type="text/javascript">
46051 // as we use this in bootstrap.
46052 Roo.namespace('Roo.form');
46054 * @class Roo.form.Action
46055 * Internal Class used to handle form actions
46057 * @param {Roo.form.BasicForm} el The form element or its id
46058 * @param {Object} config Configuration options
46063 // define the action interface
46064 Roo.form.Action = function(form, options){
46066 this.options = options || {};
46069 * Client Validation Failed
46072 Roo.form.Action.CLIENT_INVALID = 'client';
46074 * Server Validation Failed
46077 Roo.form.Action.SERVER_INVALID = 'server';
46079 * Connect to Server Failed
46082 Roo.form.Action.CONNECT_FAILURE = 'connect';
46084 * Reading Data from Server Failed
46087 Roo.form.Action.LOAD_FAILURE = 'load';
46089 Roo.form.Action.prototype = {
46091 failureType : undefined,
46092 response : undefined,
46093 result : undefined,
46095 // interface method
46096 run : function(options){
46100 // interface method
46101 success : function(response){
46105 // interface method
46106 handleResponse : function(response){
46110 // default connection failure
46111 failure : function(response){
46113 this.response = response;
46114 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46115 this.form.afterAction(this, false);
46118 processResponse : function(response){
46119 this.response = response;
46120 if(!response.responseText){
46123 this.result = this.handleResponse(response);
46124 return this.result;
46127 // utility functions used internally
46128 getUrl : function(appendParams){
46129 var url = this.options.url || this.form.url || this.form.el.dom.action;
46131 var p = this.getParams();
46133 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
46139 getMethod : function(){
46140 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
46143 getParams : function(){
46144 var bp = this.form.baseParams;
46145 var p = this.options.params;
46147 if(typeof p == "object"){
46148 p = Roo.urlEncode(Roo.applyIf(p, bp));
46149 }else if(typeof p == 'string' && bp){
46150 p += '&' + Roo.urlEncode(bp);
46153 p = Roo.urlEncode(bp);
46158 createCallback : function(){
46160 success: this.success,
46161 failure: this.failure,
46163 timeout: (this.form.timeout*1000),
46164 upload: this.form.fileUpload ? this.success : undefined
46169 Roo.form.Action.Submit = function(form, options){
46170 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
46173 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
46176 haveProgress : false,
46177 uploadComplete : false,
46179 // uploadProgress indicator.
46180 uploadProgress : function()
46182 if (!this.form.progressUrl) {
46186 if (!this.haveProgress) {
46187 Roo.MessageBox.progress("Uploading", "Uploading");
46189 if (this.uploadComplete) {
46190 Roo.MessageBox.hide();
46194 this.haveProgress = true;
46196 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
46198 var c = new Roo.data.Connection();
46200 url : this.form.progressUrl,
46205 success : function(req){
46206 //console.log(data);
46210 rdata = Roo.decode(req.responseText)
46212 Roo.log("Invalid data from server..");
46216 if (!rdata || !rdata.success) {
46218 Roo.MessageBox.alert(Roo.encode(rdata));
46221 var data = rdata.data;
46223 if (this.uploadComplete) {
46224 Roo.MessageBox.hide();
46229 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
46230 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
46233 this.uploadProgress.defer(2000,this);
46236 failure: function(data) {
46237 Roo.log('progress url failed ');
46248 // run get Values on the form, so it syncs any secondary forms.
46249 this.form.getValues();
46251 var o = this.options;
46252 var method = this.getMethod();
46253 var isPost = method == 'POST';
46254 if(o.clientValidation === false || this.form.isValid()){
46256 if (this.form.progressUrl) {
46257 this.form.findField('UPLOAD_IDENTIFIER').setValue(
46258 (new Date() * 1) + '' + Math.random());
46263 Roo.Ajax.request(Roo.apply(this.createCallback(), {
46264 form:this.form.el.dom,
46265 url:this.getUrl(!isPost),
46267 params:isPost ? this.getParams() : null,
46268 isUpload: this.form.fileUpload
46271 this.uploadProgress();
46273 }else if (o.clientValidation !== false){ // client validation failed
46274 this.failureType = Roo.form.Action.CLIENT_INVALID;
46275 this.form.afterAction(this, false);
46279 success : function(response)
46281 this.uploadComplete= true;
46282 if (this.haveProgress) {
46283 Roo.MessageBox.hide();
46287 var result = this.processResponse(response);
46288 if(result === true || result.success){
46289 this.form.afterAction(this, true);
46293 this.form.markInvalid(result.errors);
46294 this.failureType = Roo.form.Action.SERVER_INVALID;
46296 this.form.afterAction(this, false);
46298 failure : function(response)
46300 this.uploadComplete= true;
46301 if (this.haveProgress) {
46302 Roo.MessageBox.hide();
46305 this.response = response;
46306 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46307 this.form.afterAction(this, false);
46310 handleResponse : function(response){
46311 if(this.form.errorReader){
46312 var rs = this.form.errorReader.read(response);
46315 for(var i = 0, len = rs.records.length; i < len; i++) {
46316 var r = rs.records[i];
46317 errors[i] = r.data;
46320 if(errors.length < 1){
46324 success : rs.success,
46330 ret = Roo.decode(response.responseText);
46334 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
46344 Roo.form.Action.Load = function(form, options){
46345 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
46346 this.reader = this.form.reader;
46349 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
46354 Roo.Ajax.request(Roo.apply(
46355 this.createCallback(), {
46356 method:this.getMethod(),
46357 url:this.getUrl(false),
46358 params:this.getParams()
46362 success : function(response){
46364 var result = this.processResponse(response);
46365 if(result === true || !result.success || !result.data){
46366 this.failureType = Roo.form.Action.LOAD_FAILURE;
46367 this.form.afterAction(this, false);
46370 this.form.clearInvalid();
46371 this.form.setValues(result.data);
46372 this.form.afterAction(this, true);
46375 handleResponse : function(response){
46376 if(this.form.reader){
46377 var rs = this.form.reader.read(response);
46378 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
46380 success : rs.success,
46384 return Roo.decode(response.responseText);
46388 Roo.form.Action.ACTION_TYPES = {
46389 'load' : Roo.form.Action.Load,
46390 'submit' : Roo.form.Action.Submit
46393 * Ext JS Library 1.1.1
46394 * Copyright(c) 2006-2007, Ext JS, LLC.
46396 * Originally Released Under LGPL - original licence link has changed is not relivant.
46399 * <script type="text/javascript">
46403 * @class Roo.form.Layout
46404 * @extends Roo.Component
46405 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
46407 * @param {Object} config Configuration options
46409 Roo.form.Layout = function(config){
46411 if (config.items) {
46412 xitems = config.items;
46413 delete config.items;
46415 Roo.form.Layout.superclass.constructor.call(this, config);
46417 Roo.each(xitems, this.addxtype, this);
46421 Roo.extend(Roo.form.Layout, Roo.Component, {
46423 * @cfg {String/Object} autoCreate
46424 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
46427 * @cfg {String/Object/Function} style
46428 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
46429 * a function which returns such a specification.
46432 * @cfg {String} labelAlign
46433 * Valid values are "left," "top" and "right" (defaults to "left")
46436 * @cfg {Number} labelWidth
46437 * Fixed width in pixels of all field labels (defaults to undefined)
46440 * @cfg {Boolean} clear
46441 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
46445 * @cfg {String} labelSeparator
46446 * The separator to use after field labels (defaults to ':')
46448 labelSeparator : ':',
46450 * @cfg {Boolean} hideLabels
46451 * True to suppress the display of field labels in this layout (defaults to false)
46453 hideLabels : false,
46456 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
46461 onRender : function(ct, position){
46462 if(this.el){ // from markup
46463 this.el = Roo.get(this.el);
46464 }else { // generate
46465 var cfg = this.getAutoCreate();
46466 this.el = ct.createChild(cfg, position);
46469 this.el.applyStyles(this.style);
46471 if(this.labelAlign){
46472 this.el.addClass('x-form-label-'+this.labelAlign);
46474 if(this.hideLabels){
46475 this.labelStyle = "display:none";
46476 this.elementStyle = "padding-left:0;";
46478 if(typeof this.labelWidth == 'number'){
46479 this.labelStyle = "width:"+this.labelWidth+"px;";
46480 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
46482 if(this.labelAlign == 'top'){
46483 this.labelStyle = "width:auto;";
46484 this.elementStyle = "padding-left:0;";
46487 var stack = this.stack;
46488 var slen = stack.length;
46490 if(!this.fieldTpl){
46491 var t = new Roo.Template(
46492 '<div class="x-form-item {5}">',
46493 '<label for="{0}" style="{2}">{1}{4}</label>',
46494 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46496 '</div><div class="x-form-clear-left"></div>'
46498 t.disableFormats = true;
46500 Roo.form.Layout.prototype.fieldTpl = t;
46502 for(var i = 0; i < slen; i++) {
46503 if(stack[i].isFormField){
46504 this.renderField(stack[i]);
46506 this.renderComponent(stack[i]);
46511 this.el.createChild({cls:'x-form-clear'});
46516 renderField : function(f){
46517 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
46520 f.labelStyle||this.labelStyle||'', //2
46521 this.elementStyle||'', //3
46522 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
46523 f.itemCls||this.itemCls||'' //5
46524 ], true).getPrevSibling());
46528 renderComponent : function(c){
46529 c.render(c.isLayout ? this.el : this.el.createChild());
46532 * Adds a object form elements (using the xtype property as the factory method.)
46533 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
46534 * @param {Object} config
46536 addxtype : function(o)
46538 // create the lement.
46539 o.form = this.form;
46540 var fe = Roo.factory(o, Roo.form);
46541 this.form.allItems.push(fe);
46542 this.stack.push(fe);
46544 if (fe.isFormField) {
46545 this.form.items.add(fe);
46553 * @class Roo.form.Column
46554 * @extends Roo.form.Layout
46555 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
46557 * @param {Object} config Configuration options
46559 Roo.form.Column = function(config){
46560 Roo.form.Column.superclass.constructor.call(this, config);
46563 Roo.extend(Roo.form.Column, Roo.form.Layout, {
46565 * @cfg {Number/String} width
46566 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46569 * @cfg {String/Object} autoCreate
46570 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
46574 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
46577 onRender : function(ct, position){
46578 Roo.form.Column.superclass.onRender.call(this, ct, position);
46580 this.el.setWidth(this.width);
46587 * @class Roo.form.Row
46588 * @extends Roo.form.Layout
46589 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
46591 * @param {Object} config Configuration options
46595 Roo.form.Row = function(config){
46596 Roo.form.Row.superclass.constructor.call(this, config);
46599 Roo.extend(Roo.form.Row, Roo.form.Layout, {
46601 * @cfg {Number/String} width
46602 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46605 * @cfg {Number/String} height
46606 * The fixed height of the column in pixels or CSS value (defaults to "auto")
46608 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
46612 onRender : function(ct, position){
46613 //console.log('row render');
46615 var t = new Roo.Template(
46616 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
46617 '<label for="{0}" style="{2}">{1}{4}</label>',
46618 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46622 t.disableFormats = true;
46624 Roo.form.Layout.prototype.rowTpl = t;
46626 this.fieldTpl = this.rowTpl;
46628 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46629 var labelWidth = 100;
46631 if ((this.labelAlign != 'top')) {
46632 if (typeof this.labelWidth == 'number') {
46633 labelWidth = this.labelWidth
46635 this.padWidth = 20 + labelWidth;
46639 Roo.form.Column.superclass.onRender.call(this, ct, position);
46641 this.el.setWidth(this.width);
46644 this.el.setHeight(this.height);
46649 renderField : function(f){
46650 f.fieldEl = this.fieldTpl.append(this.el, [
46651 f.id, f.fieldLabel,
46652 f.labelStyle||this.labelStyle||'',
46653 this.elementStyle||'',
46654 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46655 f.itemCls||this.itemCls||'',
46656 f.width ? f.width + this.padWidth : 160 + this.padWidth
46663 * @class Roo.form.FieldSet
46664 * @extends Roo.form.Layout
46665 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46667 * @param {Object} config Configuration options
46669 Roo.form.FieldSet = function(config){
46670 Roo.form.FieldSet.superclass.constructor.call(this, config);
46673 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46675 * @cfg {String} legend
46676 * The text to display as the legend for the FieldSet (defaults to '')
46679 * @cfg {String/Object} autoCreate
46680 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46684 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46687 onRender : function(ct, position){
46688 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46690 this.setLegend(this.legend);
46695 setLegend : function(text){
46697 this.el.child('legend').update(text);
46702 * Ext JS Library 1.1.1
46703 * Copyright(c) 2006-2007, Ext JS, LLC.
46705 * Originally Released Under LGPL - original licence link has changed is not relivant.
46708 * <script type="text/javascript">
46711 * @class Roo.form.VTypes
46712 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46715 Roo.form.VTypes = function(){
46716 // closure these in so they are only created once.
46717 var alpha = /^[a-zA-Z_]+$/;
46718 var alphanum = /^[a-zA-Z0-9_]+$/;
46719 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46720 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46722 // All these messages and functions are configurable
46725 * The function used to validate email addresses
46726 * @param {String} value The email address
46728 'email' : function(v){
46729 return email.test(v);
46732 * The error text to display when the email validation function returns false
46735 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46737 * The keystroke filter mask to be applied on email input
46740 'emailMask' : /[a-z0-9_\.\-@]/i,
46743 * The function used to validate URLs
46744 * @param {String} value The URL
46746 'url' : function(v){
46747 return url.test(v);
46750 * The error text to display when the url validation function returns false
46753 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46756 * The function used to validate alpha values
46757 * @param {String} value The value
46759 'alpha' : function(v){
46760 return alpha.test(v);
46763 * The error text to display when the alpha validation function returns false
46766 'alphaText' : 'This field should only contain letters and _',
46768 * The keystroke filter mask to be applied on alpha input
46771 'alphaMask' : /[a-z_]/i,
46774 * The function used to validate alphanumeric values
46775 * @param {String} value The value
46777 'alphanum' : function(v){
46778 return alphanum.test(v);
46781 * The error text to display when the alphanumeric validation function returns false
46784 'alphanumText' : 'This field should only contain letters, numbers and _',
46786 * The keystroke filter mask to be applied on alphanumeric input
46789 'alphanumMask' : /[a-z0-9_]/i
46791 }();//<script type="text/javascript">
46794 * @class Roo.form.FCKeditor
46795 * @extends Roo.form.TextArea
46796 * Wrapper around the FCKEditor http://www.fckeditor.net
46798 * Creates a new FCKeditor
46799 * @param {Object} config Configuration options
46801 Roo.form.FCKeditor = function(config){
46802 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46805 * @event editorinit
46806 * Fired when the editor is initialized - you can add extra handlers here..
46807 * @param {FCKeditor} this
46808 * @param {Object} the FCK object.
46815 Roo.form.FCKeditor.editors = { };
46816 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46818 //defaultAutoCreate : {
46819 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46823 * @cfg {Object} fck options - see fck manual for details.
46828 * @cfg {Object} fck toolbar set (Basic or Default)
46830 toolbarSet : 'Basic',
46832 * @cfg {Object} fck BasePath
46834 basePath : '/fckeditor/',
46842 onRender : function(ct, position)
46845 this.defaultAutoCreate = {
46847 style:"width:300px;height:60px;",
46848 autocomplete: "new-password"
46851 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46854 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46855 if(this.preventScrollbars){
46856 this.el.setStyle("overflow", "hidden");
46858 this.el.setHeight(this.growMin);
46861 //console.log('onrender' + this.getId() );
46862 Roo.form.FCKeditor.editors[this.getId()] = this;
46865 this.replaceTextarea() ;
46869 getEditor : function() {
46870 return this.fckEditor;
46873 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46874 * @param {Mixed} value The value to set
46878 setValue : function(value)
46880 //console.log('setValue: ' + value);
46882 if(typeof(value) == 'undefined') { // not sure why this is happending...
46885 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46887 //if(!this.el || !this.getEditor()) {
46888 // this.value = value;
46889 //this.setValue.defer(100,this,[value]);
46893 if(!this.getEditor()) {
46897 this.getEditor().SetData(value);
46904 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46905 * @return {Mixed} value The field value
46907 getValue : function()
46910 if (this.frame && this.frame.dom.style.display == 'none') {
46911 return Roo.form.FCKeditor.superclass.getValue.call(this);
46914 if(!this.el || !this.getEditor()) {
46916 // this.getValue.defer(100,this);
46921 var value=this.getEditor().GetData();
46922 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46923 return Roo.form.FCKeditor.superclass.getValue.call(this);
46929 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46930 * @return {Mixed} value The field value
46932 getRawValue : function()
46934 if (this.frame && this.frame.dom.style.display == 'none') {
46935 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46938 if(!this.el || !this.getEditor()) {
46939 //this.getRawValue.defer(100,this);
46946 var value=this.getEditor().GetData();
46947 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46948 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46952 setSize : function(w,h) {
46956 //if (this.frame && this.frame.dom.style.display == 'none') {
46957 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46960 //if(!this.el || !this.getEditor()) {
46961 // this.setSize.defer(100,this, [w,h]);
46967 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46969 this.frame.dom.setAttribute('width', w);
46970 this.frame.dom.setAttribute('height', h);
46971 this.frame.setSize(w,h);
46975 toggleSourceEdit : function(value) {
46979 this.el.dom.style.display = value ? '' : 'none';
46980 this.frame.dom.style.display = value ? 'none' : '';
46985 focus: function(tag)
46987 if (this.frame.dom.style.display == 'none') {
46988 return Roo.form.FCKeditor.superclass.focus.call(this);
46990 if(!this.el || !this.getEditor()) {
46991 this.focus.defer(100,this, [tag]);
46998 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46999 this.getEditor().Focus();
47001 if (!this.getEditor().Selection.GetSelection()) {
47002 this.focus.defer(100,this, [tag]);
47007 var r = this.getEditor().EditorDocument.createRange();
47008 r.setStart(tgs[0],0);
47009 r.setEnd(tgs[0],0);
47010 this.getEditor().Selection.GetSelection().removeAllRanges();
47011 this.getEditor().Selection.GetSelection().addRange(r);
47012 this.getEditor().Focus();
47019 replaceTextarea : function()
47021 if ( document.getElementById( this.getId() + '___Frame' ) )
47023 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
47025 // We must check the elements firstly using the Id and then the name.
47026 var oTextarea = document.getElementById( this.getId() );
47028 var colElementsByName = document.getElementsByName( this.getId() ) ;
47030 oTextarea.style.display = 'none' ;
47032 if ( oTextarea.tabIndex ) {
47033 this.TabIndex = oTextarea.tabIndex ;
47036 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
47037 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
47038 this.frame = Roo.get(this.getId() + '___Frame')
47041 _getConfigHtml : function()
47045 for ( var o in this.fckconfig ) {
47046 sConfig += sConfig.length > 0 ? '&' : '';
47047 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
47050 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
47054 _getIFrameHtml : function()
47056 var sFile = 'fckeditor.html' ;
47057 /* no idea what this is about..
47060 if ( (/fcksource=true/i).test( window.top.location.search ) )
47061 sFile = 'fckeditor.original.html' ;
47066 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
47067 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
47070 var html = '<iframe id="' + this.getId() +
47071 '___Frame" src="' + sLink +
47072 '" width="' + this.width +
47073 '" height="' + this.height + '"' +
47074 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
47075 ' frameborder="0" scrolling="no"></iframe>' ;
47080 _insertHtmlBefore : function( html, element )
47082 if ( element.insertAdjacentHTML ) {
47084 element.insertAdjacentHTML( 'beforeBegin', html ) ;
47086 var oRange = document.createRange() ;
47087 oRange.setStartBefore( element ) ;
47088 var oFragment = oRange.createContextualFragment( html );
47089 element.parentNode.insertBefore( oFragment, element ) ;
47102 //Roo.reg('fckeditor', Roo.form.FCKeditor);
47104 function FCKeditor_OnComplete(editorInstance){
47105 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
47106 f.fckEditor = editorInstance;
47107 //console.log("loaded");
47108 f.fireEvent('editorinit', f, editorInstance);
47128 //<script type="text/javascript">
47130 * @class Roo.form.GridField
47131 * @extends Roo.form.Field
47132 * Embed a grid (or editable grid into a form)
47135 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
47137 * xgrid.store = Roo.data.Store
47138 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
47139 * xgrid.store.reader = Roo.data.JsonReader
47143 * Creates a new GridField
47144 * @param {Object} config Configuration options
47146 Roo.form.GridField = function(config){
47147 Roo.form.GridField.superclass.constructor.call(this, config);
47151 Roo.extend(Roo.form.GridField, Roo.form.Field, {
47153 * @cfg {Number} width - used to restrict width of grid..
47157 * @cfg {Number} height - used to restrict height of grid..
47161 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
47167 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47168 * {tag: "input", type: "checkbox", autocomplete: "off"})
47170 // defaultAutoCreate : { tag: 'div' },
47171 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
47173 * @cfg {String} addTitle Text to include for adding a title.
47177 onResize : function(){
47178 Roo.form.Field.superclass.onResize.apply(this, arguments);
47181 initEvents : function(){
47182 // Roo.form.Checkbox.superclass.initEvents.call(this);
47183 // has no events...
47188 getResizeEl : function(){
47192 getPositionEl : function(){
47197 onRender : function(ct, position){
47199 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
47200 var style = this.style;
47203 Roo.form.GridField.superclass.onRender.call(this, ct, position);
47204 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
47205 this.viewEl = this.wrap.createChild({ tag: 'div' });
47207 this.viewEl.applyStyles(style);
47210 this.viewEl.setWidth(this.width);
47213 this.viewEl.setHeight(this.height);
47215 //if(this.inputValue !== undefined){
47216 //this.setValue(this.value);
47219 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
47222 this.grid.render();
47223 this.grid.getDataSource().on('remove', this.refreshValue, this);
47224 this.grid.getDataSource().on('update', this.refreshValue, this);
47225 this.grid.on('afteredit', this.refreshValue, this);
47231 * Sets the value of the item.
47232 * @param {String} either an object or a string..
47234 setValue : function(v){
47236 v = v || []; // empty set..
47237 // this does not seem smart - it really only affects memoryproxy grids..
47238 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
47239 var ds = this.grid.getDataSource();
47240 // assumes a json reader..
47242 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
47243 ds.loadData( data);
47245 // clear selection so it does not get stale.
47246 if (this.grid.sm) {
47247 this.grid.sm.clearSelections();
47250 Roo.form.GridField.superclass.setValue.call(this, v);
47251 this.refreshValue();
47252 // should load data in the grid really....
47256 refreshValue: function() {
47258 this.grid.getDataSource().each(function(r) {
47261 this.el.dom.value = Roo.encode(val);
47269 * Ext JS Library 1.1.1
47270 * Copyright(c) 2006-2007, Ext JS, LLC.
47272 * Originally Released Under LGPL - original licence link has changed is not relivant.
47275 * <script type="text/javascript">
47278 * @class Roo.form.DisplayField
47279 * @extends Roo.form.Field
47280 * A generic Field to display non-editable data.
47282 * Creates a new Display Field item.
47283 * @param {Object} config Configuration options
47285 Roo.form.DisplayField = function(config){
47286 Roo.form.DisplayField.superclass.constructor.call(this, config);
47290 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
47291 inputType: 'hidden',
47297 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47299 focusClass : undefined,
47301 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47303 fieldClass: 'x-form-field',
47306 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
47308 valueRenderer: undefined,
47312 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47313 * {tag: "input", type: "checkbox", autocomplete: "off"})
47316 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
47318 onResize : function(){
47319 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
47323 initEvents : function(){
47324 // Roo.form.Checkbox.superclass.initEvents.call(this);
47325 // has no events...
47330 getResizeEl : function(){
47334 getPositionEl : function(){
47339 onRender : function(ct, position){
47341 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
47342 //if(this.inputValue !== undefined){
47343 this.wrap = this.el.wrap();
47345 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
47347 if (this.bodyStyle) {
47348 this.viewEl.applyStyles(this.bodyStyle);
47350 //this.viewEl.setStyle('padding', '2px');
47352 this.setValue(this.value);
47357 initValue : Roo.emptyFn,
47362 onClick : function(){
47367 * Sets the checked state of the checkbox.
47368 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
47370 setValue : function(v){
47372 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
47373 // this might be called before we have a dom element..
47374 if (!this.viewEl) {
47377 this.viewEl.dom.innerHTML = html;
47378 Roo.form.DisplayField.superclass.setValue.call(this, v);
47388 * @class Roo.form.DayPicker
47389 * @extends Roo.form.Field
47390 * A Day picker show [M] [T] [W] ....
47392 * Creates a new Day Picker
47393 * @param {Object} config Configuration options
47395 Roo.form.DayPicker= function(config){
47396 Roo.form.DayPicker.superclass.constructor.call(this, config);
47400 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
47402 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47404 focusClass : undefined,
47406 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47408 fieldClass: "x-form-field",
47411 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47412 * {tag: "input", type: "checkbox", autocomplete: "off"})
47414 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
47417 actionMode : 'viewEl',
47421 inputType : 'hidden',
47424 inputElement: false, // real input element?
47425 basedOn: false, // ????
47427 isFormField: true, // not sure where this is needed!!!!
47429 onResize : function(){
47430 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
47431 if(!this.boxLabel){
47432 this.el.alignTo(this.wrap, 'c-c');
47436 initEvents : function(){
47437 Roo.form.Checkbox.superclass.initEvents.call(this);
47438 this.el.on("click", this.onClick, this);
47439 this.el.on("change", this.onClick, this);
47443 getResizeEl : function(){
47447 getPositionEl : function(){
47453 onRender : function(ct, position){
47454 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
47456 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
47458 var r1 = '<table><tr>';
47459 var r2 = '<tr class="x-form-daypick-icons">';
47460 for (var i=0; i < 7; i++) {
47461 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
47462 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
47465 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
47466 viewEl.select('img').on('click', this.onClick, this);
47467 this.viewEl = viewEl;
47470 // this will not work on Chrome!!!
47471 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
47472 this.el.on('propertychange', this.setFromHidden, this); //ie
47480 initValue : Roo.emptyFn,
47483 * Returns the checked state of the checkbox.
47484 * @return {Boolean} True if checked, else false
47486 getValue : function(){
47487 return this.el.dom.value;
47492 onClick : function(e){
47493 //this.setChecked(!this.checked);
47494 Roo.get(e.target).toggleClass('x-menu-item-checked');
47495 this.refreshValue();
47496 //if(this.el.dom.checked != this.checked){
47497 // this.setValue(this.el.dom.checked);
47502 refreshValue : function()
47505 this.viewEl.select('img',true).each(function(e,i,n) {
47506 val += e.is(".x-menu-item-checked") ? String(n) : '';
47508 this.setValue(val, true);
47512 * Sets the checked state of the checkbox.
47513 * On is always based on a string comparison between inputValue and the param.
47514 * @param {Boolean/String} value - the value to set
47515 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
47517 setValue : function(v,suppressEvent){
47518 if (!this.el.dom) {
47521 var old = this.el.dom.value ;
47522 this.el.dom.value = v;
47523 if (suppressEvent) {
47527 // update display..
47528 this.viewEl.select('img',true).each(function(e,i,n) {
47530 var on = e.is(".x-menu-item-checked");
47531 var newv = v.indexOf(String(n)) > -1;
47533 e.toggleClass('x-menu-item-checked');
47539 this.fireEvent('change', this, v, old);
47544 // handle setting of hidden value by some other method!!?!?
47545 setFromHidden: function()
47550 //console.log("SET FROM HIDDEN");
47551 //alert('setFrom hidden');
47552 this.setValue(this.el.dom.value);
47555 onDestroy : function()
47558 Roo.get(this.viewEl).remove();
47561 Roo.form.DayPicker.superclass.onDestroy.call(this);
47565 * RooJS Library 1.1.1
47566 * Copyright(c) 2008-2011 Alan Knowles
47573 * @class Roo.form.ComboCheck
47574 * @extends Roo.form.ComboBox
47575 * A combobox for multiple select items.
47577 * FIXME - could do with a reset button..
47580 * Create a new ComboCheck
47581 * @param {Object} config Configuration options
47583 Roo.form.ComboCheck = function(config){
47584 Roo.form.ComboCheck.superclass.constructor.call(this, config);
47585 // should verify some data...
47587 // hiddenName = required..
47588 // displayField = required
47589 // valudField == required
47590 var req= [ 'hiddenName', 'displayField', 'valueField' ];
47592 Roo.each(req, function(e) {
47593 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
47594 throw "Roo.form.ComboCheck : missing value for: " + e;
47601 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
47606 selectedClass: 'x-menu-item-checked',
47609 onRender : function(ct, position){
47615 var cls = 'x-combo-list';
47618 this.tpl = new Roo.Template({
47619 html : '<div class="'+cls+'-item x-menu-check-item">' +
47620 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47621 '<span>{' + this.displayField + '}</span>' +
47628 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47629 this.view.singleSelect = false;
47630 this.view.multiSelect = true;
47631 this.view.toggleSelect = true;
47632 this.pageTb.add(new Roo.Toolbar.Fill(), {
47635 handler: function()
47642 onViewOver : function(e, t){
47648 onViewClick : function(doFocus,index){
47652 select: function () {
47653 //Roo.log("SELECT CALLED");
47656 selectByValue : function(xv, scrollIntoView){
47657 var ar = this.getValueArray();
47660 Roo.each(ar, function(v) {
47661 if(v === undefined || v === null){
47664 var r = this.findRecord(this.valueField, v);
47666 sels.push(this.store.indexOf(r))
47670 this.view.select(sels);
47676 onSelect : function(record, index){
47677 // Roo.log("onselect Called");
47678 // this is only called by the clear button now..
47679 this.view.clearSelections();
47680 this.setValue('[]');
47681 if (this.value != this.valueBefore) {
47682 this.fireEvent('change', this, this.value, this.valueBefore);
47683 this.valueBefore = this.value;
47686 getValueArray : function()
47691 //Roo.log(this.value);
47692 if (typeof(this.value) == 'undefined') {
47695 var ar = Roo.decode(this.value);
47696 return ar instanceof Array ? ar : []; //?? valid?
47699 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47704 expand : function ()
47707 Roo.form.ComboCheck.superclass.expand.call(this);
47708 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47709 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47714 collapse : function(){
47715 Roo.form.ComboCheck.superclass.collapse.call(this);
47716 var sl = this.view.getSelectedIndexes();
47717 var st = this.store;
47721 Roo.each(sl, function(i) {
47723 nv.push(r.get(this.valueField));
47725 this.setValue(Roo.encode(nv));
47726 if (this.value != this.valueBefore) {
47728 this.fireEvent('change', this, this.value, this.valueBefore);
47729 this.valueBefore = this.value;
47734 setValue : function(v){
47738 var vals = this.getValueArray();
47740 Roo.each(vals, function(k) {
47741 var r = this.findRecord(this.valueField, k);
47743 tv.push(r.data[this.displayField]);
47744 }else if(this.valueNotFoundText !== undefined){
47745 tv.push( this.valueNotFoundText );
47750 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47751 this.hiddenField.value = v;
47757 * Ext JS Library 1.1.1
47758 * Copyright(c) 2006-2007, Ext JS, LLC.
47760 * Originally Released Under LGPL - original licence link has changed is not relivant.
47763 * <script type="text/javascript">
47767 * @class Roo.form.Signature
47768 * @extends Roo.form.Field
47772 * @param {Object} config Configuration options
47775 Roo.form.Signature = function(config){
47776 Roo.form.Signature.superclass.constructor.call(this, config);
47778 this.addEvents({// not in used??
47781 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47782 * @param {Roo.form.Signature} combo This combo box
47787 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47788 * @param {Roo.form.ComboBox} combo This combo box
47789 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47795 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47797 * @cfg {Object} labels Label to use when rendering a form.
47801 * confirm : "Confirm"
47806 confirm : "Confirm"
47809 * @cfg {Number} width The signature panel width (defaults to 300)
47813 * @cfg {Number} height The signature panel height (defaults to 100)
47817 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47819 allowBlank : false,
47822 // {Object} signPanel The signature SVG panel element (defaults to {})
47824 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47825 isMouseDown : false,
47826 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47827 isConfirmed : false,
47828 // {String} signatureTmp SVG mapping string (defaults to empty string)
47832 defaultAutoCreate : { // modified by initCompnoent..
47838 onRender : function(ct, position){
47840 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47842 this.wrap = this.el.wrap({
47843 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47846 this.createToolbar(this);
47847 this.signPanel = this.wrap.createChild({
47849 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47853 this.svgID = Roo.id();
47854 this.svgEl = this.signPanel.createChild({
47855 xmlns : 'http://www.w3.org/2000/svg',
47857 id : this.svgID + "-svg",
47859 height: this.height,
47860 viewBox: '0 0 '+this.width+' '+this.height,
47864 id: this.svgID + "-svg-r",
47866 height: this.height,
47871 id: this.svgID + "-svg-l",
47873 y1: (this.height*0.8), // start set the line in 80% of height
47874 x2: this.width, // end
47875 y2: (this.height*0.8), // end set the line in 80% of height
47877 'stroke-width': "1",
47878 'stroke-dasharray': "3",
47879 'shape-rendering': "crispEdges",
47880 'pointer-events': "none"
47884 id: this.svgID + "-svg-p",
47886 'stroke-width': "3",
47888 'pointer-events': 'none'
47893 this.svgBox = this.svgEl.dom.getScreenCTM();
47895 createSVG : function(){
47896 var svg = this.signPanel;
47897 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47900 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47901 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47902 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47903 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47904 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47905 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47906 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47909 isTouchEvent : function(e){
47910 return e.type.match(/^touch/);
47912 getCoords : function (e) {
47913 var pt = this.svgEl.dom.createSVGPoint();
47916 if (this.isTouchEvent(e)) {
47917 pt.x = e.targetTouches[0].clientX
47918 pt.y = e.targetTouches[0].clientY;
47920 var a = this.svgEl.dom.getScreenCTM();
47921 var b = a.inverse();
47922 var mx = pt.matrixTransform(b);
47923 return mx.x + ',' + mx.y;
47925 //mouse event headler
47926 down : function (e) {
47927 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47928 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47930 this.isMouseDown = true;
47932 e.preventDefault();
47934 move : function (e) {
47935 if (this.isMouseDown) {
47936 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47937 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47940 e.preventDefault();
47942 up : function (e) {
47943 this.isMouseDown = false;
47944 var sp = this.signatureTmp.split(' ');
47947 if(!sp[sp.length-2].match(/^L/)){
47951 this.signatureTmp = sp.join(" ");
47954 if(this.getValue() != this.signatureTmp){
47955 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47956 this.isConfirmed = false;
47958 e.preventDefault();
47962 * Protected method that will not generally be called directly. It
47963 * is called when the editor creates its toolbar. Override this method if you need to
47964 * add custom toolbar buttons.
47965 * @param {HtmlEditor} editor
47967 createToolbar : function(editor){
47968 function btn(id, toggle, handler){
47969 var xid = fid + '-'+ id ;
47973 cls : 'x-btn-icon x-edit-'+id,
47974 enableToggle:toggle !== false,
47975 scope: editor, // was editor...
47976 handler:handler||editor.relayBtnCmd,
47977 clickEvent:'mousedown',
47978 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47984 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47988 cls : ' x-signature-btn x-signature-'+id,
47989 scope: editor, // was editor...
47990 handler: this.reset,
47991 clickEvent:'mousedown',
47992 text: this.labels.clear
47999 cls : ' x-signature-btn x-signature-'+id,
48000 scope: editor, // was editor...
48001 handler: this.confirmHandler,
48002 clickEvent:'mousedown',
48003 text: this.labels.confirm
48010 * when user is clicked confirm then show this image.....
48012 * @return {String} Image Data URI
48014 getImageDataURI : function(){
48015 var svg = this.svgEl.dom.parentNode.innerHTML;
48016 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
48021 * @return {Boolean} this.isConfirmed
48023 getConfirmed : function(){
48024 return this.isConfirmed;
48028 * @return {Number} this.width
48030 getWidth : function(){
48035 * @return {Number} this.height
48037 getHeight : function(){
48038 return this.height;
48041 getSignature : function(){
48042 return this.signatureTmp;
48045 reset : function(){
48046 this.signatureTmp = '';
48047 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48048 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
48049 this.isConfirmed = false;
48050 Roo.form.Signature.superclass.reset.call(this);
48052 setSignature : function(s){
48053 this.signatureTmp = s;
48054 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48055 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
48057 this.isConfirmed = false;
48058 Roo.form.Signature.superclass.reset.call(this);
48061 // Roo.log(this.signPanel.dom.contentWindow.up())
48064 setConfirmed : function(){
48068 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
48071 confirmHandler : function(){
48072 if(!this.getSignature()){
48076 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
48077 this.setValue(this.getSignature());
48078 this.isConfirmed = true;
48080 this.fireEvent('confirm', this);
48083 // Subclasses should provide the validation implementation by overriding this
48084 validateValue : function(value){
48085 if(this.allowBlank){
48089 if(this.isConfirmed){
48096 * Ext JS Library 1.1.1
48097 * Copyright(c) 2006-2007, Ext JS, LLC.
48099 * Originally Released Under LGPL - original licence link has changed is not relivant.
48102 * <script type="text/javascript">
48107 * @class Roo.form.ComboBox
48108 * @extends Roo.form.TriggerField
48109 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
48111 * Create a new ComboBox.
48112 * @param {Object} config Configuration options
48114 Roo.form.Select = function(config){
48115 Roo.form.Select.superclass.constructor.call(this, config);
48119 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
48121 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
48124 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
48125 * rendering into an Roo.Editor, defaults to false)
48128 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
48129 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
48132 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
48135 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
48136 * the dropdown list (defaults to undefined, with no header element)
48140 * @cfg {String/Roo.Template} tpl The template to use to render the output
48144 defaultAutoCreate : {tag: "select" },
48146 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
48148 listWidth: undefined,
48150 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
48151 * mode = 'remote' or 'text' if mode = 'local')
48153 displayField: undefined,
48155 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
48156 * mode = 'remote' or 'value' if mode = 'local').
48157 * Note: use of a valueField requires the user make a selection
48158 * in order for a value to be mapped.
48160 valueField: undefined,
48164 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
48165 * field's data value (defaults to the underlying DOM element's name)
48167 hiddenName: undefined,
48169 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
48173 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
48175 selectedClass: 'x-combo-selected',
48177 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
48178 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
48179 * which displays a downward arrow icon).
48181 triggerClass : 'x-form-arrow-trigger',
48183 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
48187 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
48188 * anchor positions (defaults to 'tl-bl')
48190 listAlign: 'tl-bl?',
48192 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
48196 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
48197 * query specified by the allQuery config option (defaults to 'query')
48199 triggerAction: 'query',
48201 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
48202 * (defaults to 4, does not apply if editable = false)
48206 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
48207 * delay (typeAheadDelay) if it matches a known value (defaults to false)
48211 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
48212 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
48216 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
48217 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
48221 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
48222 * when editable = true (defaults to false)
48224 selectOnFocus:false,
48226 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
48228 queryParam: 'query',
48230 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
48231 * when mode = 'remote' (defaults to 'Loading...')
48233 loadingText: 'Loading...',
48235 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
48239 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
48243 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
48244 * traditional select (defaults to true)
48248 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
48252 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
48256 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
48257 * listWidth has a higher value)
48261 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
48262 * allow the user to set arbitrary text into the field (defaults to false)
48264 forceSelection:false,
48266 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
48267 * if typeAhead = true (defaults to 250)
48269 typeAheadDelay : 250,
48271 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
48272 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
48274 valueNotFoundText : undefined,
48277 * @cfg {String} defaultValue The value displayed after loading the store.
48282 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
48284 blockFocus : false,
48287 * @cfg {Boolean} disableClear Disable showing of clear button.
48289 disableClear : false,
48291 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
48293 alwaysQuery : false,
48299 // element that contains real text value.. (when hidden is used..)
48302 onRender : function(ct, position){
48303 Roo.form.Field.prototype.onRender.call(this, ct, position);
48306 this.store.on('beforeload', this.onBeforeLoad, this);
48307 this.store.on('load', this.onLoad, this);
48308 this.store.on('loadexception', this.onLoadException, this);
48309 this.store.load({});
48317 initEvents : function(){
48318 //Roo.form.ComboBox.superclass.initEvents.call(this);
48322 onDestroy : function(){
48325 this.store.un('beforeload', this.onBeforeLoad, this);
48326 this.store.un('load', this.onLoad, this);
48327 this.store.un('loadexception', this.onLoadException, this);
48329 //Roo.form.ComboBox.superclass.onDestroy.call(this);
48333 fireKey : function(e){
48334 if(e.isNavKeyPress() && !this.list.isVisible()){
48335 this.fireEvent("specialkey", this, e);
48340 onResize: function(w, h){
48348 * Allow or prevent the user from directly editing the field text. If false is passed,
48349 * the user will only be able to select from the items defined in the dropdown list. This method
48350 * is the runtime equivalent of setting the 'editable' config option at config time.
48351 * @param {Boolean} value True to allow the user to directly edit the field text
48353 setEditable : function(value){
48358 onBeforeLoad : function(){
48360 Roo.log("Select before load");
48363 this.innerList.update(this.loadingText ?
48364 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
48365 //this.restrictHeight();
48366 this.selectedIndex = -1;
48370 onLoad : function(){
48373 var dom = this.el.dom;
48374 dom.innerHTML = '';
48375 var od = dom.ownerDocument;
48377 if (this.emptyText) {
48378 var op = od.createElement('option');
48379 op.setAttribute('value', '');
48380 op.innerHTML = String.format('{0}', this.emptyText);
48381 dom.appendChild(op);
48383 if(this.store.getCount() > 0){
48385 var vf = this.valueField;
48386 var df = this.displayField;
48387 this.store.data.each(function(r) {
48388 // which colmsn to use... testing - cdoe / title..
48389 var op = od.createElement('option');
48390 op.setAttribute('value', r.data[vf]);
48391 op.innerHTML = String.format('{0}', r.data[df]);
48392 dom.appendChild(op);
48394 if (typeof(this.defaultValue != 'undefined')) {
48395 this.setValue(this.defaultValue);
48400 //this.onEmptyResults();
48405 onLoadException : function()
48407 dom.innerHTML = '';
48409 Roo.log("Select on load exception");
48413 Roo.log(this.store.reader.jsonData);
48414 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
48415 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
48421 onTypeAhead : function(){
48426 onSelect : function(record, index){
48427 Roo.log('on select?');
48429 if(this.fireEvent('beforeselect', this, record, index) !== false){
48430 this.setFromData(index > -1 ? record.data : false);
48432 this.fireEvent('select', this, record, index);
48437 * Returns the currently selected field value or empty string if no value is set.
48438 * @return {String} value The selected value
48440 getValue : function(){
48441 var dom = this.el.dom;
48442 this.value = dom.options[dom.selectedIndex].value;
48448 * Clears any text/value currently set in the field
48450 clearValue : function(){
48452 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
48457 * Sets the specified value into the field. If the value finds a match, the corresponding record text
48458 * will be displayed in the field. If the value does not match the data value of an existing item,
48459 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
48460 * Otherwise the field will be blank (although the value will still be set).
48461 * @param {String} value The value to match
48463 setValue : function(v){
48464 var d = this.el.dom;
48465 for (var i =0; i < d.options.length;i++) {
48466 if (v == d.options[i].value) {
48467 d.selectedIndex = i;
48475 * @property {Object} the last set data for the element
48480 * Sets the value of the field based on a object which is related to the record format for the store.
48481 * @param {Object} value the value to set as. or false on reset?
48483 setFromData : function(o){
48484 Roo.log('setfrom data?');
48490 reset : function(){
48494 findRecord : function(prop, value){
48499 if(this.store.getCount() > 0){
48500 this.store.each(function(r){
48501 if(r.data[prop] == value){
48511 getName: function()
48513 // returns hidden if it's set..
48514 if (!this.rendered) {return ''};
48515 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
48523 onEmptyResults : function(){
48524 Roo.log('empty results');
48529 * Returns true if the dropdown list is expanded, else false.
48531 isExpanded : function(){
48536 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
48537 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48538 * @param {String} value The data value of the item to select
48539 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48540 * selected item if it is not currently in view (defaults to true)
48541 * @return {Boolean} True if the value matched an item in the list, else false
48543 selectByValue : function(v, scrollIntoView){
48544 Roo.log('select By Value');
48547 if(v !== undefined && v !== null){
48548 var r = this.findRecord(this.valueField || this.displayField, v);
48550 this.select(this.store.indexOf(r), scrollIntoView);
48558 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
48559 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48560 * @param {Number} index The zero-based index of the list item to select
48561 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48562 * selected item if it is not currently in view (defaults to true)
48564 select : function(index, scrollIntoView){
48565 Roo.log('select ');
48568 this.selectedIndex = index;
48569 this.view.select(index);
48570 if(scrollIntoView !== false){
48571 var el = this.view.getNode(index);
48573 this.innerList.scrollChildIntoView(el, false);
48581 validateBlur : function(){
48588 initQuery : function(){
48589 this.doQuery(this.getRawValue());
48593 doForce : function(){
48594 if(this.el.dom.value.length > 0){
48595 this.el.dom.value =
48596 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
48602 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
48603 * query allowing the query action to be canceled if needed.
48604 * @param {String} query The SQL query to execute
48605 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
48606 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
48607 * saved in the current store (defaults to false)
48609 doQuery : function(q, forceAll){
48611 Roo.log('doQuery?');
48612 if(q === undefined || q === null){
48617 forceAll: forceAll,
48621 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48625 forceAll = qe.forceAll;
48626 if(forceAll === true || (q.length >= this.minChars)){
48627 if(this.lastQuery != q || this.alwaysQuery){
48628 this.lastQuery = q;
48629 if(this.mode == 'local'){
48630 this.selectedIndex = -1;
48632 this.store.clearFilter();
48634 this.store.filter(this.displayField, q);
48638 this.store.baseParams[this.queryParam] = q;
48640 params: this.getParams(q)
48645 this.selectedIndex = -1;
48652 getParams : function(q){
48654 //p[this.queryParam] = q;
48657 p.limit = this.pageSize;
48663 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48665 collapse : function(){
48670 collapseIf : function(e){
48675 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48677 expand : function(){
48685 * @cfg {Boolean} grow
48689 * @cfg {Number} growMin
48693 * @cfg {Number} growMax
48701 setWidth : function()
48705 getResizeEl : function(){
48708 });//<script type="text/javasscript">
48712 * @class Roo.DDView
48713 * A DnD enabled version of Roo.View.
48714 * @param {Element/String} container The Element in which to create the View.
48715 * @param {String} tpl The template string used to create the markup for each element of the View
48716 * @param {Object} config The configuration properties. These include all the config options of
48717 * {@link Roo.View} plus some specific to this class.<br>
48719 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48720 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48722 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48723 .x-view-drag-insert-above {
48724 border-top:1px dotted #3366cc;
48726 .x-view-drag-insert-below {
48727 border-bottom:1px dotted #3366cc;
48733 Roo.DDView = function(container, tpl, config) {
48734 Roo.DDView.superclass.constructor.apply(this, arguments);
48735 this.getEl().setStyle("outline", "0px none");
48736 this.getEl().unselectable();
48737 if (this.dragGroup) {
48738 this.setDraggable(this.dragGroup.split(","));
48740 if (this.dropGroup) {
48741 this.setDroppable(this.dropGroup.split(","));
48743 if (this.deletable) {
48744 this.setDeletable();
48746 this.isDirtyFlag = false;
48752 Roo.extend(Roo.DDView, Roo.View, {
48753 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48754 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48755 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48756 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48760 reset: Roo.emptyFn,
48762 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48764 validate: function() {
48768 destroy: function() {
48769 this.purgeListeners();
48770 this.getEl.removeAllListeners();
48771 this.getEl().remove();
48772 if (this.dragZone) {
48773 if (this.dragZone.destroy) {
48774 this.dragZone.destroy();
48777 if (this.dropZone) {
48778 if (this.dropZone.destroy) {
48779 this.dropZone.destroy();
48784 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48785 getName: function() {
48789 /** Loads the View from a JSON string representing the Records to put into the Store. */
48790 setValue: function(v) {
48792 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48795 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48796 this.store.proxy = new Roo.data.MemoryProxy(data);
48800 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48801 getValue: function() {
48803 this.store.each(function(rec) {
48804 result += rec.id + ',';
48806 return result.substr(0, result.length - 1) + ')';
48809 getIds: function() {
48810 var i = 0, result = new Array(this.store.getCount());
48811 this.store.each(function(rec) {
48812 result[i++] = rec.id;
48817 isDirty: function() {
48818 return this.isDirtyFlag;
48822 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48823 * whole Element becomes the target, and this causes the drop gesture to append.
48825 getTargetFromEvent : function(e) {
48826 var target = e.getTarget();
48827 while ((target !== null) && (target.parentNode != this.el.dom)) {
48828 target = target.parentNode;
48831 target = this.el.dom.lastChild || this.el.dom;
48837 * Create the drag data which consists of an object which has the property "ddel" as
48838 * the drag proxy element.
48840 getDragData : function(e) {
48841 var target = this.findItemFromChild(e.getTarget());
48843 this.handleSelection(e);
48844 var selNodes = this.getSelectedNodes();
48847 copy: this.copy || (this.allowCopy && e.ctrlKey),
48851 var selectedIndices = this.getSelectedIndexes();
48852 for (var i = 0; i < selectedIndices.length; i++) {
48853 dragData.records.push(this.store.getAt(selectedIndices[i]));
48855 if (selNodes.length == 1) {
48856 dragData.ddel = target.cloneNode(true); // the div element
48858 var div = document.createElement('div'); // create the multi element drag "ghost"
48859 div.className = 'multi-proxy';
48860 for (var i = 0, len = selNodes.length; i < len; i++) {
48861 div.appendChild(selNodes[i].cloneNode(true));
48863 dragData.ddel = div;
48865 //console.log(dragData)
48866 //console.log(dragData.ddel.innerHTML)
48869 //console.log('nodragData')
48873 /** Specify to which ddGroup items in this DDView may be dragged. */
48874 setDraggable: function(ddGroup) {
48875 if (ddGroup instanceof Array) {
48876 Roo.each(ddGroup, this.setDraggable, this);
48879 if (this.dragZone) {
48880 this.dragZone.addToGroup(ddGroup);
48882 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48883 containerScroll: true,
48887 // Draggability implies selection. DragZone's mousedown selects the element.
48888 if (!this.multiSelect) { this.singleSelect = true; }
48890 // Wire the DragZone's handlers up to methods in *this*
48891 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48895 /** Specify from which ddGroup this DDView accepts drops. */
48896 setDroppable: function(ddGroup) {
48897 if (ddGroup instanceof Array) {
48898 Roo.each(ddGroup, this.setDroppable, this);
48901 if (this.dropZone) {
48902 this.dropZone.addToGroup(ddGroup);
48904 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48905 containerScroll: true,
48909 // Wire the DropZone's handlers up to methods in *this*
48910 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48911 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48912 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48913 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48914 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48918 /** Decide whether to drop above or below a View node. */
48919 getDropPoint : function(e, n, dd){
48920 if (n == this.el.dom) { return "above"; }
48921 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48922 var c = t + (b - t) / 2;
48923 var y = Roo.lib.Event.getPageY(e);
48931 onNodeEnter : function(n, dd, e, data){
48935 onNodeOver : function(n, dd, e, data){
48936 var pt = this.getDropPoint(e, n, dd);
48937 // set the insert point style on the target node
48938 var dragElClass = this.dropNotAllowed;
48941 if (pt == "above"){
48942 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48943 targetElClass = "x-view-drag-insert-above";
48945 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48946 targetElClass = "x-view-drag-insert-below";
48948 if (this.lastInsertClass != targetElClass){
48949 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48950 this.lastInsertClass = targetElClass;
48953 return dragElClass;
48956 onNodeOut : function(n, dd, e, data){
48957 this.removeDropIndicators(n);
48960 onNodeDrop : function(n, dd, e, data){
48961 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48964 var pt = this.getDropPoint(e, n, dd);
48965 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48966 if (pt == "below") { insertAt++; }
48967 for (var i = 0; i < data.records.length; i++) {
48968 var r = data.records[i];
48969 var dup = this.store.getById(r.id);
48970 if (dup && (dd != this.dragZone)) {
48971 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48974 this.store.insert(insertAt++, r.copy());
48976 data.source.isDirtyFlag = true;
48978 this.store.insert(insertAt++, r);
48980 this.isDirtyFlag = true;
48983 this.dragZone.cachedTarget = null;
48987 removeDropIndicators : function(n){
48989 Roo.fly(n).removeClass([
48990 "x-view-drag-insert-above",
48991 "x-view-drag-insert-below"]);
48992 this.lastInsertClass = "_noclass";
48997 * Utility method. Add a delete option to the DDView's context menu.
48998 * @param {String} imageUrl The URL of the "delete" icon image.
49000 setDeletable: function(imageUrl) {
49001 if (!this.singleSelect && !this.multiSelect) {
49002 this.singleSelect = true;
49004 var c = this.getContextMenu();
49005 this.contextMenu.on("itemclick", function(item) {
49008 this.remove(this.getSelectedIndexes());
49012 this.contextMenu.add({
49019 /** Return the context menu for this DDView. */
49020 getContextMenu: function() {
49021 if (!this.contextMenu) {
49022 // Create the View's context menu
49023 this.contextMenu = new Roo.menu.Menu({
49024 id: this.id + "-contextmenu"
49026 this.el.on("contextmenu", this.showContextMenu, this);
49028 return this.contextMenu;
49031 disableContextMenu: function() {
49032 if (this.contextMenu) {
49033 this.el.un("contextmenu", this.showContextMenu, this);
49037 showContextMenu: function(e, item) {
49038 item = this.findItemFromChild(e.getTarget());
49041 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
49042 this.contextMenu.showAt(e.getXY());
49047 * Remove {@link Roo.data.Record}s at the specified indices.
49048 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
49050 remove: function(selectedIndices) {
49051 selectedIndices = [].concat(selectedIndices);
49052 for (var i = 0; i < selectedIndices.length; i++) {
49053 var rec = this.store.getAt(selectedIndices[i]);
49054 this.store.remove(rec);
49059 * Double click fires the event, but also, if this is draggable, and there is only one other
49060 * related DropZone, it transfers the selected node.
49062 onDblClick : function(e){
49063 var item = this.findItemFromChild(e.getTarget());
49065 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
49068 if (this.dragGroup) {
49069 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
49070 while (targets.indexOf(this.dropZone) > -1) {
49071 targets.remove(this.dropZone);
49073 if (targets.length == 1) {
49074 this.dragZone.cachedTarget = null;
49075 var el = Roo.get(targets[0].getEl());
49076 var box = el.getBox(true);
49077 targets[0].onNodeDrop(el.dom, {
49079 xy: [box.x, box.y + box.height - 1]
49080 }, null, this.getDragData(e));
49086 handleSelection: function(e) {
49087 this.dragZone.cachedTarget = null;
49088 var item = this.findItemFromChild(e.getTarget());
49090 this.clearSelections(true);
49093 if (item && (this.multiSelect || this.singleSelect)){
49094 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
49095 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
49096 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
49097 this.unselect(item);
49099 this.select(item, this.multiSelect && e.ctrlKey);
49100 this.lastSelection = item;
49105 onItemClick : function(item, index, e){
49106 if(this.fireEvent("beforeclick", this, index, item, e) === false){
49112 unselect : function(nodeInfo, suppressEvent){
49113 var node = this.getNode(nodeInfo);
49114 if(node && this.isSelected(node)){
49115 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
49116 Roo.fly(node).removeClass(this.selectedClass);
49117 this.selections.remove(node);
49118 if(!suppressEvent){
49119 this.fireEvent("selectionchange", this, this.selections);
49127 * Ext JS Library 1.1.1
49128 * Copyright(c) 2006-2007, Ext JS, LLC.
49130 * Originally Released Under LGPL - original licence link has changed is not relivant.
49133 * <script type="text/javascript">
49137 * @class Roo.LayoutManager
49138 * @extends Roo.util.Observable
49139 * Base class for layout managers.
49141 Roo.LayoutManager = function(container, config){
49142 Roo.LayoutManager.superclass.constructor.call(this);
49143 this.el = Roo.get(container);
49144 // ie scrollbar fix
49145 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
49146 document.body.scroll = "no";
49147 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
49148 this.el.position('relative');
49150 this.id = this.el.id;
49151 this.el.addClass("x-layout-container");
49152 /** false to disable window resize monitoring @type Boolean */
49153 this.monitorWindowResize = true;
49158 * Fires when a layout is performed.
49159 * @param {Roo.LayoutManager} this
49163 * @event regionresized
49164 * Fires when the user resizes a region.
49165 * @param {Roo.LayoutRegion} region The resized region
49166 * @param {Number} newSize The new size (width for east/west, height for north/south)
49168 "regionresized" : true,
49170 * @event regioncollapsed
49171 * Fires when a region is collapsed.
49172 * @param {Roo.LayoutRegion} region The collapsed region
49174 "regioncollapsed" : true,
49176 * @event regionexpanded
49177 * Fires when a region is expanded.
49178 * @param {Roo.LayoutRegion} region The expanded region
49180 "regionexpanded" : true
49182 this.updating = false;
49183 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
49186 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
49188 * Returns true if this layout is currently being updated
49189 * @return {Boolean}
49191 isUpdating : function(){
49192 return this.updating;
49196 * Suspend the LayoutManager from doing auto-layouts while
49197 * making multiple add or remove calls
49199 beginUpdate : function(){
49200 this.updating = true;
49204 * Restore auto-layouts and optionally disable the manager from performing a layout
49205 * @param {Boolean} noLayout true to disable a layout update
49207 endUpdate : function(noLayout){
49208 this.updating = false;
49214 layout: function(){
49218 onRegionResized : function(region, newSize){
49219 this.fireEvent("regionresized", region, newSize);
49223 onRegionCollapsed : function(region){
49224 this.fireEvent("regioncollapsed", region);
49227 onRegionExpanded : function(region){
49228 this.fireEvent("regionexpanded", region);
49232 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
49233 * performs box-model adjustments.
49234 * @return {Object} The size as an object {width: (the width), height: (the height)}
49236 getViewSize : function(){
49238 if(this.el.dom != document.body){
49239 size = this.el.getSize();
49241 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
49243 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
49244 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
49249 * Returns the Element this layout is bound to.
49250 * @return {Roo.Element}
49252 getEl : function(){
49257 * Returns the specified region.
49258 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
49259 * @return {Roo.LayoutRegion}
49261 getRegion : function(target){
49262 return this.regions[target.toLowerCase()];
49265 onWindowResize : function(){
49266 if(this.monitorWindowResize){
49272 * Ext JS Library 1.1.1
49273 * Copyright(c) 2006-2007, Ext JS, LLC.
49275 * Originally Released Under LGPL - original licence link has changed is not relivant.
49278 * <script type="text/javascript">
49281 * @class Roo.BorderLayout
49282 * @extends Roo.LayoutManager
49283 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
49284 * please see: <br><br>
49285 * <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>
49286 * <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>
49289 var layout = new Roo.BorderLayout(document.body, {
49323 preferredTabWidth: 150
49328 var CP = Roo.ContentPanel;
49330 layout.beginUpdate();
49331 layout.add("north", new CP("north", "North"));
49332 layout.add("south", new CP("south", {title: "South", closable: true}));
49333 layout.add("west", new CP("west", {title: "West"}));
49334 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
49335 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
49336 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
49337 layout.getRegion("center").showPanel("center1");
49338 layout.endUpdate();
49341 <b>The container the layout is rendered into can be either the body element or any other element.
49342 If it is not the body element, the container needs to either be an absolute positioned element,
49343 or you will need to add "position:relative" to the css of the container. You will also need to specify
49344 the container size if it is not the body element.</b>
49347 * Create a new BorderLayout
49348 * @param {String/HTMLElement/Element} container The container this layout is bound to
49349 * @param {Object} config Configuration options
49351 Roo.BorderLayout = function(container, config){
49352 config = config || {};
49353 Roo.BorderLayout.superclass.constructor.call(this, container, config);
49354 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
49355 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
49356 var target = this.factory.validRegions[i];
49357 if(config[target]){
49358 this.addRegion(target, config[target]);
49363 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
49365 * Creates and adds a new region if it doesn't already exist.
49366 * @param {String} target The target region key (north, south, east, west or center).
49367 * @param {Object} config The regions config object
49368 * @return {BorderLayoutRegion} The new region
49370 addRegion : function(target, config){
49371 if(!this.regions[target]){
49372 var r = this.factory.create(target, this, config);
49373 this.bindRegion(target, r);
49375 return this.regions[target];
49379 bindRegion : function(name, r){
49380 this.regions[name] = r;
49381 r.on("visibilitychange", this.layout, this);
49382 r.on("paneladded", this.layout, this);
49383 r.on("panelremoved", this.layout, this);
49384 r.on("invalidated", this.layout, this);
49385 r.on("resized", this.onRegionResized, this);
49386 r.on("collapsed", this.onRegionCollapsed, this);
49387 r.on("expanded", this.onRegionExpanded, this);
49391 * Performs a layout update.
49393 layout : function(){
49394 if(this.updating) return;
49395 var size = this.getViewSize();
49396 var w = size.width;
49397 var h = size.height;
49402 //var x = 0, y = 0;
49404 var rs = this.regions;
49405 var north = rs["north"];
49406 var south = rs["south"];
49407 var west = rs["west"];
49408 var east = rs["east"];
49409 var center = rs["center"];
49410 //if(this.hideOnLayout){ // not supported anymore
49411 //c.el.setStyle("display", "none");
49413 if(north && north.isVisible()){
49414 var b = north.getBox();
49415 var m = north.getMargins();
49416 b.width = w - (m.left+m.right);
49419 centerY = b.height + b.y + m.bottom;
49420 centerH -= centerY;
49421 north.updateBox(this.safeBox(b));
49423 if(south && south.isVisible()){
49424 var b = south.getBox();
49425 var m = south.getMargins();
49426 b.width = w - (m.left+m.right);
49428 var totalHeight = (b.height + m.top + m.bottom);
49429 b.y = h - totalHeight + m.top;
49430 centerH -= totalHeight;
49431 south.updateBox(this.safeBox(b));
49433 if(west && west.isVisible()){
49434 var b = west.getBox();
49435 var m = west.getMargins();
49436 b.height = centerH - (m.top+m.bottom);
49438 b.y = centerY + m.top;
49439 var totalWidth = (b.width + m.left + m.right);
49440 centerX += totalWidth;
49441 centerW -= totalWidth;
49442 west.updateBox(this.safeBox(b));
49444 if(east && east.isVisible()){
49445 var b = east.getBox();
49446 var m = east.getMargins();
49447 b.height = centerH - (m.top+m.bottom);
49448 var totalWidth = (b.width + m.left + m.right);
49449 b.x = w - totalWidth + m.left;
49450 b.y = centerY + m.top;
49451 centerW -= totalWidth;
49452 east.updateBox(this.safeBox(b));
49455 var m = center.getMargins();
49457 x: centerX + m.left,
49458 y: centerY + m.top,
49459 width: centerW - (m.left+m.right),
49460 height: centerH - (m.top+m.bottom)
49462 //if(this.hideOnLayout){
49463 //center.el.setStyle("display", "block");
49465 center.updateBox(this.safeBox(centerBox));
49468 this.fireEvent("layout", this);
49472 safeBox : function(box){
49473 box.width = Math.max(0, box.width);
49474 box.height = Math.max(0, box.height);
49479 * Adds a ContentPanel (or subclass) to this layout.
49480 * @param {String} target The target region key (north, south, east, west or center).
49481 * @param {Roo.ContentPanel} panel The panel to add
49482 * @return {Roo.ContentPanel} The added panel
49484 add : function(target, panel){
49486 target = target.toLowerCase();
49487 return this.regions[target].add(panel);
49491 * Remove a ContentPanel (or subclass) to this layout.
49492 * @param {String} target The target region key (north, south, east, west or center).
49493 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
49494 * @return {Roo.ContentPanel} The removed panel
49496 remove : function(target, panel){
49497 target = target.toLowerCase();
49498 return this.regions[target].remove(panel);
49502 * Searches all regions for a panel with the specified id
49503 * @param {String} panelId
49504 * @return {Roo.ContentPanel} The panel or null if it wasn't found
49506 findPanel : function(panelId){
49507 var rs = this.regions;
49508 for(var target in rs){
49509 if(typeof rs[target] != "function"){
49510 var p = rs[target].getPanel(panelId);
49520 * Searches all regions for a panel with the specified id and activates (shows) it.
49521 * @param {String/ContentPanel} panelId The panels id or the panel itself
49522 * @return {Roo.ContentPanel} The shown panel or null
49524 showPanel : function(panelId) {
49525 var rs = this.regions;
49526 for(var target in rs){
49527 var r = rs[target];
49528 if(typeof r != "function"){
49529 if(r.hasPanel(panelId)){
49530 return r.showPanel(panelId);
49538 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
49539 * @param {Roo.state.Provider} provider (optional) An alternate state provider
49541 restoreState : function(provider){
49543 provider = Roo.state.Manager;
49545 var sm = new Roo.LayoutStateManager();
49546 sm.init(this, provider);
49550 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
49551 * object should contain properties for each region to add ContentPanels to, and each property's value should be
49552 * a valid ContentPanel config object. Example:
49554 // Create the main layout
49555 var layout = new Roo.BorderLayout('main-ct', {
49566 // Create and add multiple ContentPanels at once via configs
49569 id: 'source-files',
49571 title:'Ext Source Files',
49584 * @param {Object} regions An object containing ContentPanel configs by region name
49586 batchAdd : function(regions){
49587 this.beginUpdate();
49588 for(var rname in regions){
49589 var lr = this.regions[rname];
49591 this.addTypedPanels(lr, regions[rname]);
49598 addTypedPanels : function(lr, ps){
49599 if(typeof ps == 'string'){
49600 lr.add(new Roo.ContentPanel(ps));
49602 else if(ps instanceof Array){
49603 for(var i =0, len = ps.length; i < len; i++){
49604 this.addTypedPanels(lr, ps[i]);
49607 else if(!ps.events){ // raw config?
49609 delete ps.el; // prevent conflict
49610 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
49612 else { // panel object assumed!
49617 * Adds a xtype elements to the layout.
49621 xtype : 'ContentPanel',
49628 xtype : 'NestedLayoutPanel',
49634 items : [ ... list of content panels or nested layout panels.. ]
49638 * @param {Object} cfg Xtype definition of item to add.
49640 addxtype : function(cfg)
49642 // basically accepts a pannel...
49643 // can accept a layout region..!?!?
49644 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49646 if (!cfg.xtype.match(/Panel$/)) {
49651 if (typeof(cfg.region) == 'undefined') {
49652 Roo.log("Failed to add Panel, region was not set");
49656 var region = cfg.region;
49662 xitems = cfg.items;
49669 case 'ContentPanel': // ContentPanel (el, cfg)
49670 case 'ScrollPanel': // ContentPanel (el, cfg)
49672 if(cfg.autoCreate) {
49673 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49675 var el = this.el.createChild();
49676 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49679 this.add(region, ret);
49683 case 'TreePanel': // our new panel!
49684 cfg.el = this.el.createChild();
49685 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49686 this.add(region, ret);
49689 case 'NestedLayoutPanel':
49690 // create a new Layout (which is a Border Layout...
49691 var el = this.el.createChild();
49692 var clayout = cfg.layout;
49694 clayout.items = clayout.items || [];
49695 // replace this exitems with the clayout ones..
49696 xitems = clayout.items;
49699 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49700 cfg.background = false;
49702 var layout = new Roo.BorderLayout(el, clayout);
49704 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49705 //console.log('adding nested layout panel ' + cfg.toSource());
49706 this.add(region, ret);
49707 nb = {}; /// find first...
49712 // needs grid and region
49714 //var el = this.getRegion(region).el.createChild();
49715 var el = this.el.createChild();
49716 // create the grid first...
49718 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49720 if (region == 'center' && this.active ) {
49721 cfg.background = false;
49723 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49725 this.add(region, ret);
49726 if (cfg.background) {
49727 ret.on('activate', function(gp) {
49728 if (!gp.grid.rendered) {
49743 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49745 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49746 this.add(region, ret);
49749 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49753 // GridPanel (grid, cfg)
49756 this.beginUpdate();
49760 Roo.each(xitems, function(i) {
49761 region = nb && i.region ? i.region : false;
49763 var add = ret.addxtype(i);
49766 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49767 if (!i.background) {
49768 abn[region] = nb[region] ;
49775 // make the last non-background panel active..
49776 //if (nb) { Roo.log(abn); }
49779 for(var r in abn) {
49780 region = this.getRegion(r);
49782 // tried using nb[r], but it does not work..
49784 region.showPanel(abn[r]);
49795 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49796 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49797 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49798 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49801 var CP = Roo.ContentPanel;
49803 var layout = Roo.BorderLayout.create({
49807 panels: [new CP("north", "North")]
49816 panels: [new CP("west", {title: "West"})]
49825 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49834 panels: [new CP("south", {title: "South", closable: true})]
49841 preferredTabWidth: 150,
49843 new CP("center1", {title: "Close Me", closable: true}),
49844 new CP("center2", {title: "Center Panel", closable: false})
49849 layout.getRegion("center").showPanel("center1");
49854 Roo.BorderLayout.create = function(config, targetEl){
49855 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49856 layout.beginUpdate();
49857 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49858 for(var j = 0, jlen = regions.length; j < jlen; j++){
49859 var lr = regions[j];
49860 if(layout.regions[lr] && config[lr].panels){
49861 var r = layout.regions[lr];
49862 var ps = config[lr].panels;
49863 layout.addTypedPanels(r, ps);
49866 layout.endUpdate();
49871 Roo.BorderLayout.RegionFactory = {
49873 validRegions : ["north","south","east","west","center"],
49876 create : function(target, mgr, config){
49877 target = target.toLowerCase();
49878 if(config.lightweight || config.basic){
49879 return new Roo.BasicLayoutRegion(mgr, config, target);
49883 return new Roo.NorthLayoutRegion(mgr, config);
49885 return new Roo.SouthLayoutRegion(mgr, config);
49887 return new Roo.EastLayoutRegion(mgr, config);
49889 return new Roo.WestLayoutRegion(mgr, config);
49891 return new Roo.CenterLayoutRegion(mgr, config);
49893 throw 'Layout region "'+target+'" not supported.';
49897 * Ext JS Library 1.1.1
49898 * Copyright(c) 2006-2007, Ext JS, LLC.
49900 * Originally Released Under LGPL - original licence link has changed is not relivant.
49903 * <script type="text/javascript">
49907 * @class Roo.BasicLayoutRegion
49908 * @extends Roo.util.Observable
49909 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49910 * and does not have a titlebar, tabs or any other features. All it does is size and position
49911 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49913 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49915 this.position = pos;
49918 * @scope Roo.BasicLayoutRegion
49922 * @event beforeremove
49923 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49924 * @param {Roo.LayoutRegion} this
49925 * @param {Roo.ContentPanel} panel The panel
49926 * @param {Object} e The cancel event object
49928 "beforeremove" : true,
49930 * @event invalidated
49931 * Fires when the layout for this region is changed.
49932 * @param {Roo.LayoutRegion} this
49934 "invalidated" : true,
49936 * @event visibilitychange
49937 * Fires when this region is shown or hidden
49938 * @param {Roo.LayoutRegion} this
49939 * @param {Boolean} visibility true or false
49941 "visibilitychange" : true,
49943 * @event paneladded
49944 * Fires when a panel is added.
49945 * @param {Roo.LayoutRegion} this
49946 * @param {Roo.ContentPanel} panel The panel
49948 "paneladded" : true,
49950 * @event panelremoved
49951 * Fires when a panel is removed.
49952 * @param {Roo.LayoutRegion} this
49953 * @param {Roo.ContentPanel} panel The panel
49955 "panelremoved" : true,
49958 * Fires when this region is collapsed.
49959 * @param {Roo.LayoutRegion} this
49961 "collapsed" : true,
49964 * Fires when this region is expanded.
49965 * @param {Roo.LayoutRegion} this
49970 * Fires when this region is slid into view.
49971 * @param {Roo.LayoutRegion} this
49973 "slideshow" : true,
49976 * Fires when this region slides out of view.
49977 * @param {Roo.LayoutRegion} this
49979 "slidehide" : true,
49981 * @event panelactivated
49982 * Fires when a panel is activated.
49983 * @param {Roo.LayoutRegion} this
49984 * @param {Roo.ContentPanel} panel The activated panel
49986 "panelactivated" : true,
49989 * Fires when the user resizes this region.
49990 * @param {Roo.LayoutRegion} this
49991 * @param {Number} newSize The new size (width for east/west, height for north/south)
49995 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49996 this.panels = new Roo.util.MixedCollection();
49997 this.panels.getKey = this.getPanelId.createDelegate(this);
49999 this.activePanel = null;
50000 // ensure listeners are added...
50002 if (config.listeners || config.events) {
50003 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
50004 listeners : config.listeners || {},
50005 events : config.events || {}
50009 if(skipConfig !== true){
50010 this.applyConfig(config);
50014 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
50015 getPanelId : function(p){
50019 applyConfig : function(config){
50020 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50021 this.config = config;
50026 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
50027 * the width, for horizontal (north, south) the height.
50028 * @param {Number} newSize The new width or height
50030 resizeTo : function(newSize){
50031 var el = this.el ? this.el :
50032 (this.activePanel ? this.activePanel.getEl() : null);
50034 switch(this.position){
50037 el.setWidth(newSize);
50038 this.fireEvent("resized", this, newSize);
50042 el.setHeight(newSize);
50043 this.fireEvent("resized", this, newSize);
50049 getBox : function(){
50050 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
50053 getMargins : function(){
50054 return this.margins;
50057 updateBox : function(box){
50059 var el = this.activePanel.getEl();
50060 el.dom.style.left = box.x + "px";
50061 el.dom.style.top = box.y + "px";
50062 this.activePanel.setSize(box.width, box.height);
50066 * Returns the container element for this region.
50067 * @return {Roo.Element}
50069 getEl : function(){
50070 return this.activePanel;
50074 * Returns true if this region is currently visible.
50075 * @return {Boolean}
50077 isVisible : function(){
50078 return this.activePanel ? true : false;
50081 setActivePanel : function(panel){
50082 panel = this.getPanel(panel);
50083 if(this.activePanel && this.activePanel != panel){
50084 this.activePanel.setActiveState(false);
50085 this.activePanel.getEl().setLeftTop(-10000,-10000);
50087 this.activePanel = panel;
50088 panel.setActiveState(true);
50090 panel.setSize(this.box.width, this.box.height);
50092 this.fireEvent("panelactivated", this, panel);
50093 this.fireEvent("invalidated");
50097 * Show the specified panel.
50098 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
50099 * @return {Roo.ContentPanel} The shown panel or null
50101 showPanel : function(panel){
50102 if(panel = this.getPanel(panel)){
50103 this.setActivePanel(panel);
50109 * Get the active panel for this region.
50110 * @return {Roo.ContentPanel} The active panel or null
50112 getActivePanel : function(){
50113 return this.activePanel;
50117 * Add the passed ContentPanel(s)
50118 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50119 * @return {Roo.ContentPanel} The panel added (if only one was added)
50121 add : function(panel){
50122 if(arguments.length > 1){
50123 for(var i = 0, len = arguments.length; i < len; i++) {
50124 this.add(arguments[i]);
50128 if(this.hasPanel(panel)){
50129 this.showPanel(panel);
50132 var el = panel.getEl();
50133 if(el.dom.parentNode != this.mgr.el.dom){
50134 this.mgr.el.dom.appendChild(el.dom);
50136 if(panel.setRegion){
50137 panel.setRegion(this);
50139 this.panels.add(panel);
50140 el.setStyle("position", "absolute");
50141 if(!panel.background){
50142 this.setActivePanel(panel);
50143 if(this.config.initialSize && this.panels.getCount()==1){
50144 this.resizeTo(this.config.initialSize);
50147 this.fireEvent("paneladded", this, panel);
50152 * Returns true if the panel is in this region.
50153 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50154 * @return {Boolean}
50156 hasPanel : function(panel){
50157 if(typeof panel == "object"){ // must be panel obj
50158 panel = panel.getId();
50160 return this.getPanel(panel) ? true : false;
50164 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50165 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50166 * @param {Boolean} preservePanel Overrides the config preservePanel option
50167 * @return {Roo.ContentPanel} The panel that was removed
50169 remove : function(panel, preservePanel){
50170 panel = this.getPanel(panel);
50175 this.fireEvent("beforeremove", this, panel, e);
50176 if(e.cancel === true){
50179 var panelId = panel.getId();
50180 this.panels.removeKey(panelId);
50185 * Returns the panel specified or null if it's not in this region.
50186 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50187 * @return {Roo.ContentPanel}
50189 getPanel : function(id){
50190 if(typeof id == "object"){ // must be panel obj
50193 return this.panels.get(id);
50197 * Returns this regions position (north/south/east/west/center).
50200 getPosition: function(){
50201 return this.position;
50205 * Ext JS Library 1.1.1
50206 * Copyright(c) 2006-2007, Ext JS, LLC.
50208 * Originally Released Under LGPL - original licence link has changed is not relivant.
50211 * <script type="text/javascript">
50215 * @class Roo.LayoutRegion
50216 * @extends Roo.BasicLayoutRegion
50217 * This class represents a region in a layout manager.
50218 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
50219 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
50220 * @cfg {Boolean} floatable False to disable floating (defaults to true)
50221 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
50222 * @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})
50223 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
50224 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
50225 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
50226 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
50227 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
50228 * @cfg {String} title The title for the region (overrides panel titles)
50229 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
50230 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
50231 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
50232 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
50233 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
50234 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
50235 * the space available, similar to FireFox 1.5 tabs (defaults to false)
50236 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
50237 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
50238 * @cfg {Boolean} showPin True to show a pin button
50239 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
50240 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
50241 * @cfg {Boolean} disableTabTips True to disable tab tooltips
50242 * @cfg {Number} width For East/West panels
50243 * @cfg {Number} height For North/South panels
50244 * @cfg {Boolean} split To show the splitter
50245 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
50247 Roo.LayoutRegion = function(mgr, config, pos){
50248 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
50249 var dh = Roo.DomHelper;
50250 /** This region's container element
50251 * @type Roo.Element */
50252 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
50253 /** This region's title element
50254 * @type Roo.Element */
50256 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
50257 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
50258 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
50260 this.titleEl.enableDisplayMode();
50261 /** This region's title text element
50262 * @type HTMLElement */
50263 this.titleTextEl = this.titleEl.dom.firstChild;
50264 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
50265 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
50266 this.closeBtn.enableDisplayMode();
50267 this.closeBtn.on("click", this.closeClicked, this);
50268 this.closeBtn.hide();
50270 this.createBody(config);
50271 this.visible = true;
50272 this.collapsed = false;
50274 if(config.hideWhenEmpty){
50276 this.on("paneladded", this.validateVisibility, this);
50277 this.on("panelremoved", this.validateVisibility, this);
50279 this.applyConfig(config);
50282 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
50284 createBody : function(){
50285 /** This region's body element
50286 * @type Roo.Element */
50287 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
50290 applyConfig : function(c){
50291 if(c.collapsible && this.position != "center" && !this.collapsedEl){
50292 var dh = Roo.DomHelper;
50293 if(c.titlebar !== false){
50294 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
50295 this.collapseBtn.on("click", this.collapse, this);
50296 this.collapseBtn.enableDisplayMode();
50298 if(c.showPin === true || this.showPin){
50299 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
50300 this.stickBtn.enableDisplayMode();
50301 this.stickBtn.on("click", this.expand, this);
50302 this.stickBtn.hide();
50305 /** This region's collapsed element
50306 * @type Roo.Element */
50307 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
50308 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
50310 if(c.floatable !== false){
50311 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
50312 this.collapsedEl.on("click", this.collapseClick, this);
50315 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
50316 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
50317 id: "message", unselectable: "on", style:{"float":"left"}});
50318 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
50320 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
50321 this.expandBtn.on("click", this.expand, this);
50323 if(this.collapseBtn){
50324 this.collapseBtn.setVisible(c.collapsible == true);
50326 this.cmargins = c.cmargins || this.cmargins ||
50327 (this.position == "west" || this.position == "east" ?
50328 {top: 0, left: 2, right:2, bottom: 0} :
50329 {top: 2, left: 0, right:0, bottom: 2});
50330 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50331 this.bottomTabs = c.tabPosition != "top";
50332 this.autoScroll = c.autoScroll || false;
50333 if(this.autoScroll){
50334 this.bodyEl.setStyle("overflow", "auto");
50336 this.bodyEl.setStyle("overflow", "hidden");
50338 //if(c.titlebar !== false){
50339 if((!c.titlebar && !c.title) || c.titlebar === false){
50340 this.titleEl.hide();
50342 this.titleEl.show();
50344 this.titleTextEl.innerHTML = c.title;
50348 this.duration = c.duration || .30;
50349 this.slideDuration = c.slideDuration || .45;
50352 this.collapse(true);
50359 * Returns true if this region is currently visible.
50360 * @return {Boolean}
50362 isVisible : function(){
50363 return this.visible;
50367 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
50368 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
50370 setCollapsedTitle : function(title){
50371 title = title || " ";
50372 if(this.collapsedTitleTextEl){
50373 this.collapsedTitleTextEl.innerHTML = title;
50377 getBox : function(){
50379 if(!this.collapsed){
50380 b = this.el.getBox(false, true);
50382 b = this.collapsedEl.getBox(false, true);
50387 getMargins : function(){
50388 return this.collapsed ? this.cmargins : this.margins;
50391 highlight : function(){
50392 this.el.addClass("x-layout-panel-dragover");
50395 unhighlight : function(){
50396 this.el.removeClass("x-layout-panel-dragover");
50399 updateBox : function(box){
50401 if(!this.collapsed){
50402 this.el.dom.style.left = box.x + "px";
50403 this.el.dom.style.top = box.y + "px";
50404 this.updateBody(box.width, box.height);
50406 this.collapsedEl.dom.style.left = box.x + "px";
50407 this.collapsedEl.dom.style.top = box.y + "px";
50408 this.collapsedEl.setSize(box.width, box.height);
50411 this.tabs.autoSizeTabs();
50415 updateBody : function(w, h){
50417 this.el.setWidth(w);
50418 w -= this.el.getBorderWidth("rl");
50419 if(this.config.adjustments){
50420 w += this.config.adjustments[0];
50424 this.el.setHeight(h);
50425 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
50426 h -= this.el.getBorderWidth("tb");
50427 if(this.config.adjustments){
50428 h += this.config.adjustments[1];
50430 this.bodyEl.setHeight(h);
50432 h = this.tabs.syncHeight(h);
50435 if(this.panelSize){
50436 w = w !== null ? w : this.panelSize.width;
50437 h = h !== null ? h : this.panelSize.height;
50439 if(this.activePanel){
50440 var el = this.activePanel.getEl();
50441 w = w !== null ? w : el.getWidth();
50442 h = h !== null ? h : el.getHeight();
50443 this.panelSize = {width: w, height: h};
50444 this.activePanel.setSize(w, h);
50446 if(Roo.isIE && this.tabs){
50447 this.tabs.el.repaint();
50452 * Returns the container element for this region.
50453 * @return {Roo.Element}
50455 getEl : function(){
50460 * Hides this region.
50463 if(!this.collapsed){
50464 this.el.dom.style.left = "-2000px";
50467 this.collapsedEl.dom.style.left = "-2000px";
50468 this.collapsedEl.hide();
50470 this.visible = false;
50471 this.fireEvent("visibilitychange", this, false);
50475 * Shows this region if it was previously hidden.
50478 if(!this.collapsed){
50481 this.collapsedEl.show();
50483 this.visible = true;
50484 this.fireEvent("visibilitychange", this, true);
50487 closeClicked : function(){
50488 if(this.activePanel){
50489 this.remove(this.activePanel);
50493 collapseClick : function(e){
50495 e.stopPropagation();
50498 e.stopPropagation();
50504 * Collapses this region.
50505 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
50507 collapse : function(skipAnim){
50508 if(this.collapsed) return;
50509 this.collapsed = true;
50511 this.split.el.hide();
50513 if(this.config.animate && skipAnim !== true){
50514 this.fireEvent("invalidated", this);
50515 this.animateCollapse();
50517 this.el.setLocation(-20000,-20000);
50519 this.collapsedEl.show();
50520 this.fireEvent("collapsed", this);
50521 this.fireEvent("invalidated", this);
50525 animateCollapse : function(){
50530 * Expands this region if it was previously collapsed.
50531 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
50532 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
50534 expand : function(e, skipAnim){
50535 if(e) e.stopPropagation();
50536 if(!this.collapsed || this.el.hasActiveFx()) return;
50538 this.afterSlideIn();
50541 this.collapsed = false;
50542 if(this.config.animate && skipAnim !== true){
50543 this.animateExpand();
50547 this.split.el.show();
50549 this.collapsedEl.setLocation(-2000,-2000);
50550 this.collapsedEl.hide();
50551 this.fireEvent("invalidated", this);
50552 this.fireEvent("expanded", this);
50556 animateExpand : function(){
50560 initTabs : function()
50562 this.bodyEl.setStyle("overflow", "hidden");
50563 var ts = new Roo.TabPanel(
50566 tabPosition: this.bottomTabs ? 'bottom' : 'top',
50567 disableTooltips: this.config.disableTabTips,
50568 toolbar : this.config.toolbar
50571 if(this.config.hideTabs){
50572 ts.stripWrap.setDisplayed(false);
50575 ts.resizeTabs = this.config.resizeTabs === true;
50576 ts.minTabWidth = this.config.minTabWidth || 40;
50577 ts.maxTabWidth = this.config.maxTabWidth || 250;
50578 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
50579 ts.monitorResize = false;
50580 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50581 ts.bodyEl.addClass('x-layout-tabs-body');
50582 this.panels.each(this.initPanelAsTab, this);
50585 initPanelAsTab : function(panel){
50586 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
50587 this.config.closeOnTab && panel.isClosable());
50588 if(panel.tabTip !== undefined){
50589 ti.setTooltip(panel.tabTip);
50591 ti.on("activate", function(){
50592 this.setActivePanel(panel);
50594 if(this.config.closeOnTab){
50595 ti.on("beforeclose", function(t, e){
50597 this.remove(panel);
50603 updatePanelTitle : function(panel, title){
50604 if(this.activePanel == panel){
50605 this.updateTitle(title);
50608 var ti = this.tabs.getTab(panel.getEl().id);
50610 if(panel.tabTip !== undefined){
50611 ti.setTooltip(panel.tabTip);
50616 updateTitle : function(title){
50617 if(this.titleTextEl && !this.config.title){
50618 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50622 setActivePanel : function(panel){
50623 panel = this.getPanel(panel);
50624 if(this.activePanel && this.activePanel != panel){
50625 this.activePanel.setActiveState(false);
50627 this.activePanel = panel;
50628 panel.setActiveState(true);
50629 if(this.panelSize){
50630 panel.setSize(this.panelSize.width, this.panelSize.height);
50633 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50635 this.updateTitle(panel.getTitle());
50637 this.fireEvent("invalidated", this);
50639 this.fireEvent("panelactivated", this, panel);
50643 * Shows the specified panel.
50644 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50645 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50647 showPanel : function(panel)
50649 panel = this.getPanel(panel);
50652 var tab = this.tabs.getTab(panel.getEl().id);
50653 if(tab.isHidden()){
50654 this.tabs.unhideTab(tab.id);
50658 this.setActivePanel(panel);
50665 * Get the active panel for this region.
50666 * @return {Roo.ContentPanel} The active panel or null
50668 getActivePanel : function(){
50669 return this.activePanel;
50672 validateVisibility : function(){
50673 if(this.panels.getCount() < 1){
50674 this.updateTitle(" ");
50675 this.closeBtn.hide();
50678 if(!this.isVisible()){
50685 * Adds the passed ContentPanel(s) to this region.
50686 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50687 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50689 add : function(panel){
50690 if(arguments.length > 1){
50691 for(var i = 0, len = arguments.length; i < len; i++) {
50692 this.add(arguments[i]);
50696 if(this.hasPanel(panel)){
50697 this.showPanel(panel);
50700 panel.setRegion(this);
50701 this.panels.add(panel);
50702 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50703 this.bodyEl.dom.appendChild(panel.getEl().dom);
50704 if(panel.background !== true){
50705 this.setActivePanel(panel);
50707 this.fireEvent("paneladded", this, panel);
50713 this.initPanelAsTab(panel);
50715 if(panel.background !== true){
50716 this.tabs.activate(panel.getEl().id);
50718 this.fireEvent("paneladded", this, panel);
50723 * Hides the tab for the specified panel.
50724 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50726 hidePanel : function(panel){
50727 if(this.tabs && (panel = this.getPanel(panel))){
50728 this.tabs.hideTab(panel.getEl().id);
50733 * Unhides the tab for a previously hidden panel.
50734 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50736 unhidePanel : function(panel){
50737 if(this.tabs && (panel = this.getPanel(panel))){
50738 this.tabs.unhideTab(panel.getEl().id);
50742 clearPanels : function(){
50743 while(this.panels.getCount() > 0){
50744 this.remove(this.panels.first());
50749 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50750 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50751 * @param {Boolean} preservePanel Overrides the config preservePanel option
50752 * @return {Roo.ContentPanel} The panel that was removed
50754 remove : function(panel, preservePanel){
50755 panel = this.getPanel(panel);
50760 this.fireEvent("beforeremove", this, panel, e);
50761 if(e.cancel === true){
50764 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50765 var panelId = panel.getId();
50766 this.panels.removeKey(panelId);
50768 document.body.appendChild(panel.getEl().dom);
50771 this.tabs.removeTab(panel.getEl().id);
50772 }else if (!preservePanel){
50773 this.bodyEl.dom.removeChild(panel.getEl().dom);
50775 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50776 var p = this.panels.first();
50777 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50778 tempEl.appendChild(p.getEl().dom);
50779 this.bodyEl.update("");
50780 this.bodyEl.dom.appendChild(p.getEl().dom);
50782 this.updateTitle(p.getTitle());
50784 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50785 this.setActivePanel(p);
50787 panel.setRegion(null);
50788 if(this.activePanel == panel){
50789 this.activePanel = null;
50791 if(this.config.autoDestroy !== false && preservePanel !== true){
50792 try{panel.destroy();}catch(e){}
50794 this.fireEvent("panelremoved", this, panel);
50799 * Returns the TabPanel component used by this region
50800 * @return {Roo.TabPanel}
50802 getTabs : function(){
50806 createTool : function(parentEl, className){
50807 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50808 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50809 btn.addClassOnOver("x-layout-tools-button-over");
50814 * Ext JS Library 1.1.1
50815 * Copyright(c) 2006-2007, Ext JS, LLC.
50817 * Originally Released Under LGPL - original licence link has changed is not relivant.
50820 * <script type="text/javascript">
50826 * @class Roo.SplitLayoutRegion
50827 * @extends Roo.LayoutRegion
50828 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50830 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50831 this.cursor = cursor;
50832 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50835 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50836 splitTip : "Drag to resize.",
50837 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50838 useSplitTips : false,
50840 applyConfig : function(config){
50841 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50844 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50845 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50846 /** The SplitBar for this region
50847 * @type Roo.SplitBar */
50848 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50849 this.split.on("moved", this.onSplitMove, this);
50850 this.split.useShim = config.useShim === true;
50851 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50852 if(this.useSplitTips){
50853 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50855 if(config.collapsible){
50856 this.split.el.on("dblclick", this.collapse, this);
50859 if(typeof config.minSize != "undefined"){
50860 this.split.minSize = config.minSize;
50862 if(typeof config.maxSize != "undefined"){
50863 this.split.maxSize = config.maxSize;
50865 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50866 this.hideSplitter();
50871 getHMaxSize : function(){
50872 var cmax = this.config.maxSize || 10000;
50873 var center = this.mgr.getRegion("center");
50874 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50877 getVMaxSize : function(){
50878 var cmax = this.config.maxSize || 10000;
50879 var center = this.mgr.getRegion("center");
50880 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50883 onSplitMove : function(split, newSize){
50884 this.fireEvent("resized", this, newSize);
50888 * Returns the {@link Roo.SplitBar} for this region.
50889 * @return {Roo.SplitBar}
50891 getSplitBar : function(){
50896 this.hideSplitter();
50897 Roo.SplitLayoutRegion.superclass.hide.call(this);
50900 hideSplitter : function(){
50902 this.split.el.setLocation(-2000,-2000);
50903 this.split.el.hide();
50909 this.split.el.show();
50911 Roo.SplitLayoutRegion.superclass.show.call(this);
50914 beforeSlide: function(){
50915 if(Roo.isGecko){// firefox overflow auto bug workaround
50916 this.bodyEl.clip();
50917 if(this.tabs) this.tabs.bodyEl.clip();
50918 if(this.activePanel){
50919 this.activePanel.getEl().clip();
50921 if(this.activePanel.beforeSlide){
50922 this.activePanel.beforeSlide();
50928 afterSlide : function(){
50929 if(Roo.isGecko){// firefox overflow auto bug workaround
50930 this.bodyEl.unclip();
50931 if(this.tabs) this.tabs.bodyEl.unclip();
50932 if(this.activePanel){
50933 this.activePanel.getEl().unclip();
50934 if(this.activePanel.afterSlide){
50935 this.activePanel.afterSlide();
50941 initAutoHide : function(){
50942 if(this.autoHide !== false){
50943 if(!this.autoHideHd){
50944 var st = new Roo.util.DelayedTask(this.slideIn, this);
50945 this.autoHideHd = {
50946 "mouseout": function(e){
50947 if(!e.within(this.el, true)){
50951 "mouseover" : function(e){
50957 this.el.on(this.autoHideHd);
50961 clearAutoHide : function(){
50962 if(this.autoHide !== false){
50963 this.el.un("mouseout", this.autoHideHd.mouseout);
50964 this.el.un("mouseover", this.autoHideHd.mouseover);
50968 clearMonitor : function(){
50969 Roo.get(document).un("click", this.slideInIf, this);
50972 // these names are backwards but not changed for compat
50973 slideOut : function(){
50974 if(this.isSlid || this.el.hasActiveFx()){
50977 this.isSlid = true;
50978 if(this.collapseBtn){
50979 this.collapseBtn.hide();
50981 this.closeBtnState = this.closeBtn.getStyle('display');
50982 this.closeBtn.hide();
50984 this.stickBtn.show();
50987 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50988 this.beforeSlide();
50989 this.el.setStyle("z-index", 10001);
50990 this.el.slideIn(this.getSlideAnchor(), {
50991 callback: function(){
50993 this.initAutoHide();
50994 Roo.get(document).on("click", this.slideInIf, this);
50995 this.fireEvent("slideshow", this);
51002 afterSlideIn : function(){
51003 this.clearAutoHide();
51004 this.isSlid = false;
51005 this.clearMonitor();
51006 this.el.setStyle("z-index", "");
51007 if(this.collapseBtn){
51008 this.collapseBtn.show();
51010 this.closeBtn.setStyle('display', this.closeBtnState);
51012 this.stickBtn.hide();
51014 this.fireEvent("slidehide", this);
51017 slideIn : function(cb){
51018 if(!this.isSlid || this.el.hasActiveFx()){
51022 this.isSlid = false;
51023 this.beforeSlide();
51024 this.el.slideOut(this.getSlideAnchor(), {
51025 callback: function(){
51026 this.el.setLeftTop(-10000, -10000);
51028 this.afterSlideIn();
51036 slideInIf : function(e){
51037 if(!e.within(this.el)){
51042 animateCollapse : function(){
51043 this.beforeSlide();
51044 this.el.setStyle("z-index", 20000);
51045 var anchor = this.getSlideAnchor();
51046 this.el.slideOut(anchor, {
51047 callback : function(){
51048 this.el.setStyle("z-index", "");
51049 this.collapsedEl.slideIn(anchor, {duration:.3});
51051 this.el.setLocation(-10000,-10000);
51053 this.fireEvent("collapsed", this);
51060 animateExpand : function(){
51061 this.beforeSlide();
51062 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
51063 this.el.setStyle("z-index", 20000);
51064 this.collapsedEl.hide({
51067 this.el.slideIn(this.getSlideAnchor(), {
51068 callback : function(){
51069 this.el.setStyle("z-index", "");
51072 this.split.el.show();
51074 this.fireEvent("invalidated", this);
51075 this.fireEvent("expanded", this);
51103 getAnchor : function(){
51104 return this.anchors[this.position];
51107 getCollapseAnchor : function(){
51108 return this.canchors[this.position];
51111 getSlideAnchor : function(){
51112 return this.sanchors[this.position];
51115 getAlignAdj : function(){
51116 var cm = this.cmargins;
51117 switch(this.position){
51133 getExpandAdj : function(){
51134 var c = this.collapsedEl, cm = this.cmargins;
51135 switch(this.position){
51137 return [-(cm.right+c.getWidth()+cm.left), 0];
51140 return [cm.right+c.getWidth()+cm.left, 0];
51143 return [0, -(cm.top+cm.bottom+c.getHeight())];
51146 return [0, cm.top+cm.bottom+c.getHeight()];
51152 * Ext JS Library 1.1.1
51153 * Copyright(c) 2006-2007, Ext JS, LLC.
51155 * Originally Released Under LGPL - original licence link has changed is not relivant.
51158 * <script type="text/javascript">
51161 * These classes are private internal classes
51163 Roo.CenterLayoutRegion = function(mgr, config){
51164 Roo.LayoutRegion.call(this, mgr, config, "center");
51165 this.visible = true;
51166 this.minWidth = config.minWidth || 20;
51167 this.minHeight = config.minHeight || 20;
51170 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
51172 // center panel can't be hidden
51176 // center panel can't be hidden
51179 getMinWidth: function(){
51180 return this.minWidth;
51183 getMinHeight: function(){
51184 return this.minHeight;
51189 Roo.NorthLayoutRegion = function(mgr, config){
51190 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
51192 this.split.placement = Roo.SplitBar.TOP;
51193 this.split.orientation = Roo.SplitBar.VERTICAL;
51194 this.split.el.addClass("x-layout-split-v");
51196 var size = config.initialSize || config.height;
51197 if(typeof size != "undefined"){
51198 this.el.setHeight(size);
51201 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
51202 orientation: Roo.SplitBar.VERTICAL,
51203 getBox : function(){
51204 if(this.collapsed){
51205 return this.collapsedEl.getBox();
51207 var box = this.el.getBox();
51209 box.height += this.split.el.getHeight();
51214 updateBox : function(box){
51215 if(this.split && !this.collapsed){
51216 box.height -= this.split.el.getHeight();
51217 this.split.el.setLeft(box.x);
51218 this.split.el.setTop(box.y+box.height);
51219 this.split.el.setWidth(box.width);
51221 if(this.collapsed){
51222 this.updateBody(box.width, null);
51224 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51228 Roo.SouthLayoutRegion = function(mgr, config){
51229 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
51231 this.split.placement = Roo.SplitBar.BOTTOM;
51232 this.split.orientation = Roo.SplitBar.VERTICAL;
51233 this.split.el.addClass("x-layout-split-v");
51235 var size = config.initialSize || config.height;
51236 if(typeof size != "undefined"){
51237 this.el.setHeight(size);
51240 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
51241 orientation: Roo.SplitBar.VERTICAL,
51242 getBox : function(){
51243 if(this.collapsed){
51244 return this.collapsedEl.getBox();
51246 var box = this.el.getBox();
51248 var sh = this.split.el.getHeight();
51255 updateBox : function(box){
51256 if(this.split && !this.collapsed){
51257 var sh = this.split.el.getHeight();
51260 this.split.el.setLeft(box.x);
51261 this.split.el.setTop(box.y-sh);
51262 this.split.el.setWidth(box.width);
51264 if(this.collapsed){
51265 this.updateBody(box.width, null);
51267 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51271 Roo.EastLayoutRegion = function(mgr, config){
51272 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
51274 this.split.placement = Roo.SplitBar.RIGHT;
51275 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51276 this.split.el.addClass("x-layout-split-h");
51278 var size = config.initialSize || config.width;
51279 if(typeof size != "undefined"){
51280 this.el.setWidth(size);
51283 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
51284 orientation: Roo.SplitBar.HORIZONTAL,
51285 getBox : function(){
51286 if(this.collapsed){
51287 return this.collapsedEl.getBox();
51289 var box = this.el.getBox();
51291 var sw = this.split.el.getWidth();
51298 updateBox : function(box){
51299 if(this.split && !this.collapsed){
51300 var sw = this.split.el.getWidth();
51302 this.split.el.setLeft(box.x);
51303 this.split.el.setTop(box.y);
51304 this.split.el.setHeight(box.height);
51307 if(this.collapsed){
51308 this.updateBody(null, box.height);
51310 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51314 Roo.WestLayoutRegion = function(mgr, config){
51315 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
51317 this.split.placement = Roo.SplitBar.LEFT;
51318 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51319 this.split.el.addClass("x-layout-split-h");
51321 var size = config.initialSize || config.width;
51322 if(typeof size != "undefined"){
51323 this.el.setWidth(size);
51326 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
51327 orientation: Roo.SplitBar.HORIZONTAL,
51328 getBox : function(){
51329 if(this.collapsed){
51330 return this.collapsedEl.getBox();
51332 var box = this.el.getBox();
51334 box.width += this.split.el.getWidth();
51339 updateBox : function(box){
51340 if(this.split && !this.collapsed){
51341 var sw = this.split.el.getWidth();
51343 this.split.el.setLeft(box.x+box.width);
51344 this.split.el.setTop(box.y);
51345 this.split.el.setHeight(box.height);
51347 if(this.collapsed){
51348 this.updateBody(null, box.height);
51350 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51355 * Ext JS Library 1.1.1
51356 * Copyright(c) 2006-2007, Ext JS, LLC.
51358 * Originally Released Under LGPL - original licence link has changed is not relivant.
51361 * <script type="text/javascript">
51366 * Private internal class for reading and applying state
51368 Roo.LayoutStateManager = function(layout){
51369 // default empty state
51378 Roo.LayoutStateManager.prototype = {
51379 init : function(layout, provider){
51380 this.provider = provider;
51381 var state = provider.get(layout.id+"-layout-state");
51383 var wasUpdating = layout.isUpdating();
51385 layout.beginUpdate();
51387 for(var key in state){
51388 if(typeof state[key] != "function"){
51389 var rstate = state[key];
51390 var r = layout.getRegion(key);
51393 r.resizeTo(rstate.size);
51395 if(rstate.collapsed == true){
51398 r.expand(null, true);
51404 layout.endUpdate();
51406 this.state = state;
51408 this.layout = layout;
51409 layout.on("regionresized", this.onRegionResized, this);
51410 layout.on("regioncollapsed", this.onRegionCollapsed, this);
51411 layout.on("regionexpanded", this.onRegionExpanded, this);
51414 storeState : function(){
51415 this.provider.set(this.layout.id+"-layout-state", this.state);
51418 onRegionResized : function(region, newSize){
51419 this.state[region.getPosition()].size = newSize;
51423 onRegionCollapsed : function(region){
51424 this.state[region.getPosition()].collapsed = true;
51428 onRegionExpanded : function(region){
51429 this.state[region.getPosition()].collapsed = false;
51434 * Ext JS Library 1.1.1
51435 * Copyright(c) 2006-2007, Ext JS, LLC.
51437 * Originally Released Under LGPL - original licence link has changed is not relivant.
51440 * <script type="text/javascript">
51443 * @class Roo.ContentPanel
51444 * @extends Roo.util.Observable
51445 * A basic ContentPanel element.
51446 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
51447 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
51448 * @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
51449 * @cfg {Boolean} closable True if the panel can be closed/removed
51450 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
51451 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
51452 * @cfg {Toolbar} toolbar A toolbar for this panel
51453 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
51454 * @cfg {String} title The title for this panel
51455 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
51456 * @cfg {String} url Calls {@link #setUrl} with this value
51457 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
51458 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
51459 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
51460 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
51463 * Create a new ContentPanel.
51464 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
51465 * @param {String/Object} config A string to set only the title or a config object
51466 * @param {String} content (optional) Set the HTML content for this panel
51467 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
51469 Roo.ContentPanel = function(el, config, content){
51473 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
51477 if (config && config.parentLayout) {
51478 el = config.parentLayout.el.createChild();
51481 if(el.autoCreate){ // xtype is available if this is called from factory
51485 this.el = Roo.get(el);
51486 if(!this.el && config && config.autoCreate){
51487 if(typeof config.autoCreate == "object"){
51488 if(!config.autoCreate.id){
51489 config.autoCreate.id = config.id||el;
51491 this.el = Roo.DomHelper.append(document.body,
51492 config.autoCreate, true);
51494 this.el = Roo.DomHelper.append(document.body,
51495 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
51498 this.closable = false;
51499 this.loaded = false;
51500 this.active = false;
51501 if(typeof config == "string"){
51502 this.title = config;
51504 Roo.apply(this, config);
51507 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
51508 this.wrapEl = this.el.wrap();
51509 this.toolbar.container = this.el.insertSibling(false, 'before');
51510 this.toolbar = new Roo.Toolbar(this.toolbar);
51513 // xtype created footer. - not sure if will work as we normally have to render first..
51514 if (this.footer && !this.footer.el && this.footer.xtype) {
51515 if (!this.wrapEl) {
51516 this.wrapEl = this.el.wrap();
51519 this.footer.container = this.wrapEl.createChild();
51521 this.footer = Roo.factory(this.footer, Roo);
51526 this.resizeEl = Roo.get(this.resizeEl, true);
51528 this.resizeEl = this.el;
51530 // handle view.xtype
51538 * Fires when this panel is activated.
51539 * @param {Roo.ContentPanel} this
51543 * @event deactivate
51544 * Fires when this panel is activated.
51545 * @param {Roo.ContentPanel} this
51547 "deactivate" : true,
51551 * Fires when this panel is resized if fitToFrame is true.
51552 * @param {Roo.ContentPanel} this
51553 * @param {Number} width The width after any component adjustments
51554 * @param {Number} height The height after any component adjustments
51560 * Fires when this tab is created
51561 * @param {Roo.ContentPanel} this
51572 if(this.autoScroll){
51573 this.resizeEl.setStyle("overflow", "auto");
51575 // fix randome scrolling
51576 this.el.on('scroll', function() {
51577 Roo.log('fix random scolling');
51578 this.scrollTo('top',0);
51581 content = content || this.content;
51583 this.setContent(content);
51585 if(config && config.url){
51586 this.setUrl(this.url, this.params, this.loadOnce);
51591 Roo.ContentPanel.superclass.constructor.call(this);
51593 if (this.view && typeof(this.view.xtype) != 'undefined') {
51594 this.view.el = this.el.appendChild(document.createElement("div"));
51595 this.view = Roo.factory(this.view);
51596 this.view.render && this.view.render(false, '');
51600 this.fireEvent('render', this);
51603 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
51605 setRegion : function(region){
51606 this.region = region;
51608 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
51610 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
51615 * Returns the toolbar for this Panel if one was configured.
51616 * @return {Roo.Toolbar}
51618 getToolbar : function(){
51619 return this.toolbar;
51622 setActiveState : function(active){
51623 this.active = active;
51625 this.fireEvent("deactivate", this);
51627 this.fireEvent("activate", this);
51631 * Updates this panel's element
51632 * @param {String} content The new content
51633 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51635 setContent : function(content, loadScripts){
51636 this.el.update(content, loadScripts);
51639 ignoreResize : function(w, h){
51640 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51643 this.lastSize = {width: w, height: h};
51648 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51649 * @return {Roo.UpdateManager} The UpdateManager
51651 getUpdateManager : function(){
51652 return this.el.getUpdateManager();
51655 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51656 * @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:
51659 url: "your-url.php",
51660 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51661 callback: yourFunction,
51662 scope: yourObject, //(optional scope)
51665 text: "Loading...",
51670 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51671 * 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.
51672 * @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}
51673 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51674 * @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.
51675 * @return {Roo.ContentPanel} this
51678 var um = this.el.getUpdateManager();
51679 um.update.apply(um, arguments);
51685 * 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.
51686 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51687 * @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)
51688 * @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)
51689 * @return {Roo.UpdateManager} The UpdateManager
51691 setUrl : function(url, params, loadOnce){
51692 if(this.refreshDelegate){
51693 this.removeListener("activate", this.refreshDelegate);
51695 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51696 this.on("activate", this.refreshDelegate);
51697 return this.el.getUpdateManager();
51700 _handleRefresh : function(url, params, loadOnce){
51701 if(!loadOnce || !this.loaded){
51702 var updater = this.el.getUpdateManager();
51703 updater.update(url, params, this._setLoaded.createDelegate(this));
51707 _setLoaded : function(){
51708 this.loaded = true;
51712 * Returns this panel's id
51715 getId : function(){
51720 * Returns this panel's element - used by regiosn to add.
51721 * @return {Roo.Element}
51723 getEl : function(){
51724 return this.wrapEl || this.el;
51727 adjustForComponents : function(width, height)
51729 //Roo.log('adjustForComponents ');
51730 if(this.resizeEl != this.el){
51731 width -= this.el.getFrameWidth('lr');
51732 height -= this.el.getFrameWidth('tb');
51735 var te = this.toolbar.getEl();
51736 height -= te.getHeight();
51737 te.setWidth(width);
51740 var te = this.footer.getEl();
51741 Roo.log("footer:" + te.getHeight());
51743 height -= te.getHeight();
51744 te.setWidth(width);
51748 if(this.adjustments){
51749 width += this.adjustments[0];
51750 height += this.adjustments[1];
51752 return {"width": width, "height": height};
51755 setSize : function(width, height){
51756 if(this.fitToFrame && !this.ignoreResize(width, height)){
51757 if(this.fitContainer && this.resizeEl != this.el){
51758 this.el.setSize(width, height);
51760 var size = this.adjustForComponents(width, height);
51761 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51762 this.fireEvent('resize', this, size.width, size.height);
51767 * Returns this panel's title
51770 getTitle : function(){
51775 * Set this panel's title
51776 * @param {String} title
51778 setTitle : function(title){
51779 this.title = title;
51781 this.region.updatePanelTitle(this, title);
51786 * Returns true is this panel was configured to be closable
51787 * @return {Boolean}
51789 isClosable : function(){
51790 return this.closable;
51793 beforeSlide : function(){
51795 this.resizeEl.clip();
51798 afterSlide : function(){
51800 this.resizeEl.unclip();
51804 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51805 * Will fail silently if the {@link #setUrl} method has not been called.
51806 * This does not activate the panel, just updates its content.
51808 refresh : function(){
51809 if(this.refreshDelegate){
51810 this.loaded = false;
51811 this.refreshDelegate();
51816 * Destroys this panel
51818 destroy : function(){
51819 this.el.removeAllListeners();
51820 var tempEl = document.createElement("span");
51821 tempEl.appendChild(this.el.dom);
51822 tempEl.innerHTML = "";
51828 * form - if the content panel contains a form - this is a reference to it.
51829 * @type {Roo.form.Form}
51833 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51834 * This contains a reference to it.
51840 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51850 * @param {Object} cfg Xtype definition of item to add.
51853 addxtype : function(cfg) {
51855 if (cfg.xtype.match(/^Form$/)) {
51858 //if (this.footer) {
51859 // el = this.footer.container.insertSibling(false, 'before');
51861 el = this.el.createChild();
51864 this.form = new Roo.form.Form(cfg);
51867 if ( this.form.allItems.length) this.form.render(el.dom);
51870 // should only have one of theses..
51871 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51872 // views.. should not be just added - used named prop 'view''
51874 cfg.el = this.el.appendChild(document.createElement("div"));
51877 var ret = new Roo.factory(cfg);
51879 ret.render && ret.render(false, ''); // render blank..
51888 * @class Roo.GridPanel
51889 * @extends Roo.ContentPanel
51891 * Create a new GridPanel.
51892 * @param {Roo.grid.Grid} grid The grid for this panel
51893 * @param {String/Object} config A string to set only the panel's title, or a config object
51895 Roo.GridPanel = function(grid, config){
51898 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51899 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51901 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51903 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51906 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51908 // xtype created footer. - not sure if will work as we normally have to render first..
51909 if (this.footer && !this.footer.el && this.footer.xtype) {
51911 this.footer.container = this.grid.getView().getFooterPanel(true);
51912 this.footer.dataSource = this.grid.dataSource;
51913 this.footer = Roo.factory(this.footer, Roo);
51917 grid.monitorWindowResize = false; // turn off autosizing
51918 grid.autoHeight = false;
51919 grid.autoWidth = false;
51921 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51924 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51925 getId : function(){
51926 return this.grid.id;
51930 * Returns the grid for this panel
51931 * @return {Roo.grid.Grid}
51933 getGrid : function(){
51937 setSize : function(width, height){
51938 if(!this.ignoreResize(width, height)){
51939 var grid = this.grid;
51940 var size = this.adjustForComponents(width, height);
51941 grid.getGridEl().setSize(size.width, size.height);
51946 beforeSlide : function(){
51947 this.grid.getView().scroller.clip();
51950 afterSlide : function(){
51951 this.grid.getView().scroller.unclip();
51954 destroy : function(){
51955 this.grid.destroy();
51957 Roo.GridPanel.superclass.destroy.call(this);
51963 * @class Roo.NestedLayoutPanel
51964 * @extends Roo.ContentPanel
51966 * Create a new NestedLayoutPanel.
51969 * @param {Roo.BorderLayout} layout The layout for this panel
51970 * @param {String/Object} config A string to set only the title or a config object
51972 Roo.NestedLayoutPanel = function(layout, config)
51974 // construct with only one argument..
51975 /* FIXME - implement nicer consturctors
51976 if (layout.layout) {
51978 layout = config.layout;
51979 delete config.layout;
51981 if (layout.xtype && !layout.getEl) {
51982 // then layout needs constructing..
51983 layout = Roo.factory(layout, Roo);
51988 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51990 layout.monitorWindowResize = false; // turn off autosizing
51991 this.layout = layout;
51992 this.layout.getEl().addClass("x-layout-nested-layout");
51999 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
52001 setSize : function(width, height){
52002 if(!this.ignoreResize(width, height)){
52003 var size = this.adjustForComponents(width, height);
52004 var el = this.layout.getEl();
52005 el.setSize(size.width, size.height);
52006 var touch = el.dom.offsetWidth;
52007 this.layout.layout();
52008 // ie requires a double layout on the first pass
52009 if(Roo.isIE && !this.initialized){
52010 this.initialized = true;
52011 this.layout.layout();
52016 // activate all subpanels if not currently active..
52018 setActiveState : function(active){
52019 this.active = active;
52021 this.fireEvent("deactivate", this);
52025 this.fireEvent("activate", this);
52026 // not sure if this should happen before or after..
52027 if (!this.layout) {
52028 return; // should not happen..
52031 for (var r in this.layout.regions) {
52032 reg = this.layout.getRegion(r);
52033 if (reg.getActivePanel()) {
52034 //reg.showPanel(reg.getActivePanel()); // force it to activate..
52035 reg.setActivePanel(reg.getActivePanel());
52038 if (!reg.panels.length) {
52041 reg.showPanel(reg.getPanel(0));
52050 * Returns the nested BorderLayout for this panel
52051 * @return {Roo.BorderLayout}
52053 getLayout : function(){
52054 return this.layout;
52058 * Adds a xtype elements to the layout of the nested panel
52062 xtype : 'ContentPanel',
52069 xtype : 'NestedLayoutPanel',
52075 items : [ ... list of content panels or nested layout panels.. ]
52079 * @param {Object} cfg Xtype definition of item to add.
52081 addxtype : function(cfg) {
52082 return this.layout.addxtype(cfg);
52087 Roo.ScrollPanel = function(el, config, content){
52088 config = config || {};
52089 config.fitToFrame = true;
52090 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
52092 this.el.dom.style.overflow = "hidden";
52093 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
52094 this.el.removeClass("x-layout-inactive-content");
52095 this.el.on("mousewheel", this.onWheel, this);
52097 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
52098 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
52099 up.unselectable(); down.unselectable();
52100 up.on("click", this.scrollUp, this);
52101 down.on("click", this.scrollDown, this);
52102 up.addClassOnOver("x-scroller-btn-over");
52103 down.addClassOnOver("x-scroller-btn-over");
52104 up.addClassOnClick("x-scroller-btn-click");
52105 down.addClassOnClick("x-scroller-btn-click");
52106 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
52108 this.resizeEl = this.el;
52109 this.el = wrap; this.up = up; this.down = down;
52112 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
52114 wheelIncrement : 5,
52115 scrollUp : function(){
52116 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
52119 scrollDown : function(){
52120 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
52123 afterScroll : function(){
52124 var el = this.resizeEl;
52125 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
52126 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52127 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52130 setSize : function(){
52131 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
52132 this.afterScroll();
52135 onWheel : function(e){
52136 var d = e.getWheelDelta();
52137 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
52138 this.afterScroll();
52142 setContent : function(content, loadScripts){
52143 this.resizeEl.update(content, loadScripts);
52157 * @class Roo.TreePanel
52158 * @extends Roo.ContentPanel
52160 * Create a new TreePanel. - defaults to fit/scoll contents.
52161 * @param {String/Object} config A string to set only the panel's title, or a config object
52162 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
52164 Roo.TreePanel = function(config){
52165 var el = config.el;
52166 var tree = config.tree;
52167 delete config.tree;
52168 delete config.el; // hopefull!
52170 // wrapper for IE7 strict & safari scroll issue
52172 var treeEl = el.createChild();
52173 config.resizeEl = treeEl;
52177 Roo.TreePanel.superclass.constructor.call(this, el, config);
52180 this.tree = new Roo.tree.TreePanel(treeEl , tree);
52181 //console.log(tree);
52182 this.on('activate', function()
52184 if (this.tree.rendered) {
52187 //console.log('render tree');
52188 this.tree.render();
52190 // this should not be needed.. - it's actually the 'el' that resizes?
52191 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
52193 //this.on('resize', function (cp, w, h) {
52194 // this.tree.innerCt.setWidth(w);
52195 // this.tree.innerCt.setHeight(h);
52196 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
52203 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
52220 * Ext JS Library 1.1.1
52221 * Copyright(c) 2006-2007, Ext JS, LLC.
52223 * Originally Released Under LGPL - original licence link has changed is not relivant.
52226 * <script type="text/javascript">
52231 * @class Roo.ReaderLayout
52232 * @extends Roo.BorderLayout
52233 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
52234 * center region containing two nested regions (a top one for a list view and one for item preview below),
52235 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
52236 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
52237 * expedites the setup of the overall layout and regions for this common application style.
52240 var reader = new Roo.ReaderLayout();
52241 var CP = Roo.ContentPanel; // shortcut for adding
52243 reader.beginUpdate();
52244 reader.add("north", new CP("north", "North"));
52245 reader.add("west", new CP("west", {title: "West"}));
52246 reader.add("east", new CP("east", {title: "East"}));
52248 reader.regions.listView.add(new CP("listView", "List"));
52249 reader.regions.preview.add(new CP("preview", "Preview"));
52250 reader.endUpdate();
52253 * Create a new ReaderLayout
52254 * @param {Object} config Configuration options
52255 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
52256 * document.body if omitted)
52258 Roo.ReaderLayout = function(config, renderTo){
52259 var c = config || {size:{}};
52260 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
52261 north: c.north !== false ? Roo.apply({
52265 }, c.north) : false,
52266 west: c.west !== false ? Roo.apply({
52274 margins:{left:5,right:0,bottom:5,top:5},
52275 cmargins:{left:5,right:5,bottom:5,top:5}
52276 }, c.west) : false,
52277 east: c.east !== false ? Roo.apply({
52285 margins:{left:0,right:5,bottom:5,top:5},
52286 cmargins:{left:5,right:5,bottom:5,top:5}
52287 }, c.east) : false,
52288 center: Roo.apply({
52289 tabPosition: 'top',
52293 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
52297 this.el.addClass('x-reader');
52299 this.beginUpdate();
52301 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
52302 south: c.preview !== false ? Roo.apply({
52309 cmargins:{top:5,left:0, right:0, bottom:0}
52310 }, c.preview) : false,
52311 center: Roo.apply({
52317 this.add('center', new Roo.NestedLayoutPanel(inner,
52318 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
52322 this.regions.preview = inner.getRegion('south');
52323 this.regions.listView = inner.getRegion('center');
52326 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
52328 * Ext JS Library 1.1.1
52329 * Copyright(c) 2006-2007, Ext JS, LLC.
52331 * Originally Released Under LGPL - original licence link has changed is not relivant.
52334 * <script type="text/javascript">
52338 * @class Roo.grid.Grid
52339 * @extends Roo.util.Observable
52340 * This class represents the primary interface of a component based grid control.
52341 * <br><br>Usage:<pre><code>
52342 var grid = new Roo.grid.Grid("my-container-id", {
52345 selModel: mySelectionModel,
52346 autoSizeColumns: true,
52347 monitorWindowResize: false,
52348 trackMouseOver: true
52353 * <b>Common Problems:</b><br/>
52354 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
52355 * element will correct this<br/>
52356 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
52357 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
52358 * are unpredictable.<br/>
52359 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
52360 * grid to calculate dimensions/offsets.<br/>
52362 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
52363 * The container MUST have some type of size defined for the grid to fill. The container will be
52364 * automatically set to position relative if it isn't already.
52365 * @param {Object} config A config object that sets properties on this grid.
52367 Roo.grid.Grid = function(container, config){
52368 // initialize the container
52369 this.container = Roo.get(container);
52370 this.container.update("");
52371 this.container.setStyle("overflow", "hidden");
52372 this.container.addClass('x-grid-container');
52374 this.id = this.container.id;
52376 Roo.apply(this, config);
52377 // check and correct shorthanded configs
52379 this.dataSource = this.ds;
52383 this.colModel = this.cm;
52387 this.selModel = this.sm;
52391 if (this.selModel) {
52392 this.selModel = Roo.factory(this.selModel, Roo.grid);
52393 this.sm = this.selModel;
52394 this.sm.xmodule = this.xmodule || false;
52396 if (typeof(this.colModel.config) == 'undefined') {
52397 this.colModel = new Roo.grid.ColumnModel(this.colModel);
52398 this.cm = this.colModel;
52399 this.cm.xmodule = this.xmodule || false;
52401 if (this.dataSource) {
52402 this.dataSource= Roo.factory(this.dataSource, Roo.data);
52403 this.ds = this.dataSource;
52404 this.ds.xmodule = this.xmodule || false;
52411 this.container.setWidth(this.width);
52415 this.container.setHeight(this.height);
52422 * The raw click event for the entire grid.
52423 * @param {Roo.EventObject} e
52428 * The raw dblclick event for the entire grid.
52429 * @param {Roo.EventObject} e
52433 * @event contextmenu
52434 * The raw contextmenu event for the entire grid.
52435 * @param {Roo.EventObject} e
52437 "contextmenu" : true,
52440 * The raw mousedown event for the entire grid.
52441 * @param {Roo.EventObject} e
52443 "mousedown" : true,
52446 * The raw mouseup event for the entire grid.
52447 * @param {Roo.EventObject} e
52452 * The raw mouseover event for the entire grid.
52453 * @param {Roo.EventObject} e
52455 "mouseover" : true,
52458 * The raw mouseout event for the entire grid.
52459 * @param {Roo.EventObject} e
52464 * The raw keypress event for the entire grid.
52465 * @param {Roo.EventObject} e
52470 * The raw keydown event for the entire grid.
52471 * @param {Roo.EventObject} e
52479 * Fires when a cell is clicked
52480 * @param {Grid} this
52481 * @param {Number} rowIndex
52482 * @param {Number} columnIndex
52483 * @param {Roo.EventObject} e
52485 "cellclick" : true,
52487 * @event celldblclick
52488 * Fires when a cell is double clicked
52489 * @param {Grid} this
52490 * @param {Number} rowIndex
52491 * @param {Number} columnIndex
52492 * @param {Roo.EventObject} e
52494 "celldblclick" : true,
52497 * Fires when a row is clicked
52498 * @param {Grid} this
52499 * @param {Number} rowIndex
52500 * @param {Roo.EventObject} e
52504 * @event rowdblclick
52505 * Fires when a row is double clicked
52506 * @param {Grid} this
52507 * @param {Number} rowIndex
52508 * @param {Roo.EventObject} e
52510 "rowdblclick" : true,
52512 * @event headerclick
52513 * Fires when a header is clicked
52514 * @param {Grid} this
52515 * @param {Number} columnIndex
52516 * @param {Roo.EventObject} e
52518 "headerclick" : true,
52520 * @event headerdblclick
52521 * Fires when a header cell is double clicked
52522 * @param {Grid} this
52523 * @param {Number} columnIndex
52524 * @param {Roo.EventObject} e
52526 "headerdblclick" : true,
52528 * @event rowcontextmenu
52529 * Fires when a row is right clicked
52530 * @param {Grid} this
52531 * @param {Number} rowIndex
52532 * @param {Roo.EventObject} e
52534 "rowcontextmenu" : true,
52536 * @event cellcontextmenu
52537 * Fires when a cell is right clicked
52538 * @param {Grid} this
52539 * @param {Number} rowIndex
52540 * @param {Number} cellIndex
52541 * @param {Roo.EventObject} e
52543 "cellcontextmenu" : true,
52545 * @event headercontextmenu
52546 * Fires when a header is right clicked
52547 * @param {Grid} this
52548 * @param {Number} columnIndex
52549 * @param {Roo.EventObject} e
52551 "headercontextmenu" : true,
52553 * @event bodyscroll
52554 * Fires when the body element is scrolled
52555 * @param {Number} scrollLeft
52556 * @param {Number} scrollTop
52558 "bodyscroll" : true,
52560 * @event columnresize
52561 * Fires when the user resizes a column
52562 * @param {Number} columnIndex
52563 * @param {Number} newSize
52565 "columnresize" : true,
52567 * @event columnmove
52568 * Fires when the user moves a column
52569 * @param {Number} oldIndex
52570 * @param {Number} newIndex
52572 "columnmove" : true,
52575 * Fires when row(s) start being dragged
52576 * @param {Grid} this
52577 * @param {Roo.GridDD} dd The drag drop object
52578 * @param {event} e The raw browser event
52580 "startdrag" : true,
52583 * Fires when a drag operation is complete
52584 * @param {Grid} this
52585 * @param {Roo.GridDD} dd The drag drop object
52586 * @param {event} e The raw browser event
52591 * Fires when dragged row(s) are dropped on a valid DD target
52592 * @param {Grid} this
52593 * @param {Roo.GridDD} dd The drag drop object
52594 * @param {String} targetId The target drag drop object
52595 * @param {event} e The raw browser event
52600 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
52601 * @param {Grid} this
52602 * @param {Roo.GridDD} dd The drag drop object
52603 * @param {String} targetId The target drag drop object
52604 * @param {event} e The raw browser event
52609 * Fires when the dragged row(s) first cross another DD target while being dragged
52610 * @param {Grid} this
52611 * @param {Roo.GridDD} dd The drag drop object
52612 * @param {String} targetId The target drag drop object
52613 * @param {event} e The raw browser event
52615 "dragenter" : true,
52618 * Fires when the dragged row(s) leave another DD target while being dragged
52619 * @param {Grid} this
52620 * @param {Roo.GridDD} dd The drag drop object
52621 * @param {String} targetId The target drag drop object
52622 * @param {event} e The raw browser event
52627 * Fires when a row is rendered, so you can change add a style to it.
52628 * @param {GridView} gridview The grid view
52629 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52635 * Fires when the grid is rendered
52636 * @param {Grid} grid
52641 Roo.grid.Grid.superclass.constructor.call(this);
52643 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52646 * @cfg {String} ddGroup - drag drop group.
52650 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52652 minColumnWidth : 25,
52655 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52656 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52657 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52659 autoSizeColumns : false,
52662 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52664 autoSizeHeaders : true,
52667 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52669 monitorWindowResize : true,
52672 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52673 * rows measured to get a columns size. Default is 0 (all rows).
52675 maxRowsToMeasure : 0,
52678 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52680 trackMouseOver : true,
52683 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52687 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52689 enableDragDrop : false,
52692 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52694 enableColumnMove : true,
52697 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52699 enableColumnHide : true,
52702 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52704 enableRowHeightSync : false,
52707 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52712 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52714 autoHeight : false,
52717 * @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.
52719 autoExpandColumn : false,
52722 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52725 autoExpandMin : 50,
52728 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52730 autoExpandMax : 1000,
52733 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52738 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52742 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52752 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52753 * of a fixed width. Default is false.
52756 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52759 * Called once after all setup has been completed and the grid is ready to be rendered.
52760 * @return {Roo.grid.Grid} this
52762 render : function()
52764 var c = this.container;
52765 // try to detect autoHeight/width mode
52766 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52767 this.autoHeight = true;
52769 var view = this.getView();
52772 c.on("click", this.onClick, this);
52773 c.on("dblclick", this.onDblClick, this);
52774 c.on("contextmenu", this.onContextMenu, this);
52775 c.on("keydown", this.onKeyDown, this);
52777 c.on("touchstart", this.onTouchStart, this);
52780 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52782 this.getSelectionModel().init(this);
52787 this.loadMask = new Roo.LoadMask(this.container,
52788 Roo.apply({store:this.dataSource}, this.loadMask));
52792 if (this.toolbar && this.toolbar.xtype) {
52793 this.toolbar.container = this.getView().getHeaderPanel(true);
52794 this.toolbar = new Roo.Toolbar(this.toolbar);
52796 if (this.footer && this.footer.xtype) {
52797 this.footer.dataSource = this.getDataSource();
52798 this.footer.container = this.getView().getFooterPanel(true);
52799 this.footer = Roo.factory(this.footer, Roo);
52801 if (this.dropTarget && this.dropTarget.xtype) {
52802 delete this.dropTarget.xtype;
52803 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52807 this.rendered = true;
52808 this.fireEvent('render', this);
52813 * Reconfigures the grid to use a different Store and Column Model.
52814 * The View will be bound to the new objects and refreshed.
52815 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52816 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52818 reconfigure : function(dataSource, colModel){
52820 this.loadMask.destroy();
52821 this.loadMask = new Roo.LoadMask(this.container,
52822 Roo.apply({store:dataSource}, this.loadMask));
52824 this.view.bind(dataSource, colModel);
52825 this.dataSource = dataSource;
52826 this.colModel = colModel;
52827 this.view.refresh(true);
52831 onKeyDown : function(e){
52832 this.fireEvent("keydown", e);
52836 * Destroy this grid.
52837 * @param {Boolean} removeEl True to remove the element
52839 destroy : function(removeEl, keepListeners){
52841 this.loadMask.destroy();
52843 var c = this.container;
52844 c.removeAllListeners();
52845 this.view.destroy();
52846 this.colModel.purgeListeners();
52847 if(!keepListeners){
52848 this.purgeListeners();
52851 if(removeEl === true){
52857 processEvent : function(name, e){
52858 // does this fire select???
52859 //Roo.log('grid:processEvent ' + name);
52861 if (name != 'touchstart' ) {
52862 this.fireEvent(name, e);
52865 var t = e.getTarget();
52867 var header = v.findHeaderIndex(t);
52868 if(header !== false){
52869 var ename = name == 'touchstart' ? 'click' : name;
52871 this.fireEvent("header" + ename, this, header, e);
52873 var row = v.findRowIndex(t);
52874 var cell = v.findCellIndex(t);
52875 if (name == 'touchstart') {
52876 // first touch is always a click.
52877 // hopefull this happens after selection is updated.?
52880 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52881 var cs = this.selModel.getSelectedCell();
52882 if (row == cs[0] && cell == cs[1]){
52886 if (typeof(this.selModel.getSelections) != 'undefined') {
52887 var cs = this.selModel.getSelections();
52888 var ds = this.dataSource;
52889 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52900 this.fireEvent("row" + name, this, row, e);
52901 if(cell !== false){
52902 this.fireEvent("cell" + name, this, row, cell, e);
52909 onClick : function(e){
52910 this.processEvent("click", e);
52913 onTouchStart : function(e){
52914 this.processEvent("touchstart", e);
52918 onContextMenu : function(e, t){
52919 this.processEvent("contextmenu", e);
52923 onDblClick : function(e){
52924 this.processEvent("dblclick", e);
52928 walkCells : function(row, col, step, fn, scope){
52929 var cm = this.colModel, clen = cm.getColumnCount();
52930 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52942 if(fn.call(scope || this, row, col, cm) === true){
52960 if(fn.call(scope || this, row, col, cm) === true){
52972 getSelections : function(){
52973 return this.selModel.getSelections();
52977 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52978 * but if manual update is required this method will initiate it.
52980 autoSize : function(){
52982 this.view.layout();
52983 if(this.view.adjustForScroll){
52984 this.view.adjustForScroll();
52990 * Returns the grid's underlying element.
52991 * @return {Element} The element
52993 getGridEl : function(){
52994 return this.container;
52997 // private for compatibility, overridden by editor grid
52998 stopEditing : function(){},
53001 * Returns the grid's SelectionModel.
53002 * @return {SelectionModel}
53004 getSelectionModel : function(){
53005 if(!this.selModel){
53006 this.selModel = new Roo.grid.RowSelectionModel();
53008 return this.selModel;
53012 * Returns the grid's DataSource.
53013 * @return {DataSource}
53015 getDataSource : function(){
53016 return this.dataSource;
53020 * Returns the grid's ColumnModel.
53021 * @return {ColumnModel}
53023 getColumnModel : function(){
53024 return this.colModel;
53028 * Returns the grid's GridView object.
53029 * @return {GridView}
53031 getView : function(){
53033 this.view = new Roo.grid.GridView(this.viewConfig);
53038 * Called to get grid's drag proxy text, by default returns this.ddText.
53041 getDragDropText : function(){
53042 var count = this.selModel.getCount();
53043 return String.format(this.ddText, count, count == 1 ? '' : 's');
53047 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
53048 * %0 is replaced with the number of selected rows.
53051 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
53053 * Ext JS Library 1.1.1
53054 * Copyright(c) 2006-2007, Ext JS, LLC.
53056 * Originally Released Under LGPL - original licence link has changed is not relivant.
53059 * <script type="text/javascript">
53062 Roo.grid.AbstractGridView = function(){
53066 "beforerowremoved" : true,
53067 "beforerowsinserted" : true,
53068 "beforerefresh" : true,
53069 "rowremoved" : true,
53070 "rowsinserted" : true,
53071 "rowupdated" : true,
53074 Roo.grid.AbstractGridView.superclass.constructor.call(this);
53077 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
53078 rowClass : "x-grid-row",
53079 cellClass : "x-grid-cell",
53080 tdClass : "x-grid-td",
53081 hdClass : "x-grid-hd",
53082 splitClass : "x-grid-hd-split",
53084 init: function(grid){
53086 var cid = this.grid.getGridEl().id;
53087 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
53088 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
53089 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
53090 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
53093 getColumnRenderers : function(){
53094 var renderers = [];
53095 var cm = this.grid.colModel;
53096 var colCount = cm.getColumnCount();
53097 for(var i = 0; i < colCount; i++){
53098 renderers[i] = cm.getRenderer(i);
53103 getColumnIds : function(){
53105 var cm = this.grid.colModel;
53106 var colCount = cm.getColumnCount();
53107 for(var i = 0; i < colCount; i++){
53108 ids[i] = cm.getColumnId(i);
53113 getDataIndexes : function(){
53114 if(!this.indexMap){
53115 this.indexMap = this.buildIndexMap();
53117 return this.indexMap.colToData;
53120 getColumnIndexByDataIndex : function(dataIndex){
53121 if(!this.indexMap){
53122 this.indexMap = this.buildIndexMap();
53124 return this.indexMap.dataToCol[dataIndex];
53128 * Set a css style for a column dynamically.
53129 * @param {Number} colIndex The index of the column
53130 * @param {String} name The css property name
53131 * @param {String} value The css value
53133 setCSSStyle : function(colIndex, name, value){
53134 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
53135 Roo.util.CSS.updateRule(selector, name, value);
53138 generateRules : function(cm){
53139 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
53140 Roo.util.CSS.removeStyleSheet(rulesId);
53141 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53142 var cid = cm.getColumnId(i);
53143 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
53144 this.tdSelector, cid, " {\n}\n",
53145 this.hdSelector, cid, " {\n}\n",
53146 this.splitSelector, cid, " {\n}\n");
53148 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53152 * Ext JS Library 1.1.1
53153 * Copyright(c) 2006-2007, Ext JS, LLC.
53155 * Originally Released Under LGPL - original licence link has changed is not relivant.
53158 * <script type="text/javascript">
53162 // This is a support class used internally by the Grid components
53163 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
53165 this.view = grid.getView();
53166 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53167 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
53169 this.setHandleElId(Roo.id(hd));
53170 this.setOuterHandleElId(Roo.id(hd2));
53172 this.scroll = false;
53174 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
53176 getDragData : function(e){
53177 var t = Roo.lib.Event.getTarget(e);
53178 var h = this.view.findHeaderCell(t);
53180 return {ddel: h.firstChild, header:h};
53185 onInitDrag : function(e){
53186 this.view.headersDisabled = true;
53187 var clone = this.dragData.ddel.cloneNode(true);
53188 clone.id = Roo.id();
53189 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
53190 this.proxy.update(clone);
53194 afterValidDrop : function(){
53196 setTimeout(function(){
53197 v.headersDisabled = false;
53201 afterInvalidDrop : function(){
53203 setTimeout(function(){
53204 v.headersDisabled = false;
53210 * Ext JS Library 1.1.1
53211 * Copyright(c) 2006-2007, Ext JS, LLC.
53213 * Originally Released Under LGPL - original licence link has changed is not relivant.
53216 * <script type="text/javascript">
53219 // This is a support class used internally by the Grid components
53220 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
53222 this.view = grid.getView();
53223 // split the proxies so they don't interfere with mouse events
53224 this.proxyTop = Roo.DomHelper.append(document.body, {
53225 cls:"col-move-top", html:" "
53227 this.proxyBottom = Roo.DomHelper.append(document.body, {
53228 cls:"col-move-bottom", html:" "
53230 this.proxyTop.hide = this.proxyBottom.hide = function(){
53231 this.setLeftTop(-100,-100);
53232 this.setStyle("visibility", "hidden");
53234 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53235 // temporarily disabled
53236 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
53237 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
53239 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
53240 proxyOffsets : [-4, -9],
53241 fly: Roo.Element.fly,
53243 getTargetFromEvent : function(e){
53244 var t = Roo.lib.Event.getTarget(e);
53245 var cindex = this.view.findCellIndex(t);
53246 if(cindex !== false){
53247 return this.view.getHeaderCell(cindex);
53252 nextVisible : function(h){
53253 var v = this.view, cm = this.grid.colModel;
53256 if(!cm.isHidden(v.getCellIndex(h))){
53264 prevVisible : function(h){
53265 var v = this.view, cm = this.grid.colModel;
53268 if(!cm.isHidden(v.getCellIndex(h))){
53276 positionIndicator : function(h, n, e){
53277 var x = Roo.lib.Event.getPageX(e);
53278 var r = Roo.lib.Dom.getRegion(n.firstChild);
53279 var px, pt, py = r.top + this.proxyOffsets[1];
53280 if((r.right - x) <= (r.right-r.left)/2){
53281 px = r.right+this.view.borderWidth;
53287 var oldIndex = this.view.getCellIndex(h);
53288 var newIndex = this.view.getCellIndex(n);
53290 if(this.grid.colModel.isFixed(newIndex)){
53294 var locked = this.grid.colModel.isLocked(newIndex);
53299 if(oldIndex < newIndex){
53302 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
53305 px += this.proxyOffsets[0];
53306 this.proxyTop.setLeftTop(px, py);
53307 this.proxyTop.show();
53308 if(!this.bottomOffset){
53309 this.bottomOffset = this.view.mainHd.getHeight();
53311 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
53312 this.proxyBottom.show();
53316 onNodeEnter : function(n, dd, e, data){
53317 if(data.header != n){
53318 this.positionIndicator(data.header, n, e);
53322 onNodeOver : function(n, dd, e, data){
53323 var result = false;
53324 if(data.header != n){
53325 result = this.positionIndicator(data.header, n, e);
53328 this.proxyTop.hide();
53329 this.proxyBottom.hide();
53331 return result ? this.dropAllowed : this.dropNotAllowed;
53334 onNodeOut : function(n, dd, e, data){
53335 this.proxyTop.hide();
53336 this.proxyBottom.hide();
53339 onNodeDrop : function(n, dd, e, data){
53340 var h = data.header;
53342 var cm = this.grid.colModel;
53343 var x = Roo.lib.Event.getPageX(e);
53344 var r = Roo.lib.Dom.getRegion(n.firstChild);
53345 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
53346 var oldIndex = this.view.getCellIndex(h);
53347 var newIndex = this.view.getCellIndex(n);
53348 var locked = cm.isLocked(newIndex);
53352 if(oldIndex < newIndex){
53355 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
53358 cm.setLocked(oldIndex, locked, true);
53359 cm.moveColumn(oldIndex, newIndex);
53360 this.grid.fireEvent("columnmove", oldIndex, newIndex);
53368 * Ext JS Library 1.1.1
53369 * Copyright(c) 2006-2007, Ext JS, LLC.
53371 * Originally Released Under LGPL - original licence link has changed is not relivant.
53374 * <script type="text/javascript">
53378 * @class Roo.grid.GridView
53379 * @extends Roo.util.Observable
53382 * @param {Object} config
53384 Roo.grid.GridView = function(config){
53385 Roo.grid.GridView.superclass.constructor.call(this);
53388 Roo.apply(this, config);
53391 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
53393 unselectable : 'unselectable="on"',
53394 unselectableCls : 'x-unselectable',
53397 rowClass : "x-grid-row",
53399 cellClass : "x-grid-col",
53401 tdClass : "x-grid-td",
53403 hdClass : "x-grid-hd",
53405 splitClass : "x-grid-split",
53407 sortClasses : ["sort-asc", "sort-desc"],
53409 enableMoveAnim : false,
53413 dh : Roo.DomHelper,
53415 fly : Roo.Element.fly,
53417 css : Roo.util.CSS,
53423 scrollIncrement : 22,
53425 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
53427 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
53429 bind : function(ds, cm){
53431 this.ds.un("load", this.onLoad, this);
53432 this.ds.un("datachanged", this.onDataChange, this);
53433 this.ds.un("add", this.onAdd, this);
53434 this.ds.un("remove", this.onRemove, this);
53435 this.ds.un("update", this.onUpdate, this);
53436 this.ds.un("clear", this.onClear, this);
53439 ds.on("load", this.onLoad, this);
53440 ds.on("datachanged", this.onDataChange, this);
53441 ds.on("add", this.onAdd, this);
53442 ds.on("remove", this.onRemove, this);
53443 ds.on("update", this.onUpdate, this);
53444 ds.on("clear", this.onClear, this);
53449 this.cm.un("widthchange", this.onColWidthChange, this);
53450 this.cm.un("headerchange", this.onHeaderChange, this);
53451 this.cm.un("hiddenchange", this.onHiddenChange, this);
53452 this.cm.un("columnmoved", this.onColumnMove, this);
53453 this.cm.un("columnlockchange", this.onColumnLock, this);
53456 this.generateRules(cm);
53457 cm.on("widthchange", this.onColWidthChange, this);
53458 cm.on("headerchange", this.onHeaderChange, this);
53459 cm.on("hiddenchange", this.onHiddenChange, this);
53460 cm.on("columnmoved", this.onColumnMove, this);
53461 cm.on("columnlockchange", this.onColumnLock, this);
53466 init: function(grid){
53467 Roo.grid.GridView.superclass.init.call(this, grid);
53469 this.bind(grid.dataSource, grid.colModel);
53471 grid.on("headerclick", this.handleHeaderClick, this);
53473 if(grid.trackMouseOver){
53474 grid.on("mouseover", this.onRowOver, this);
53475 grid.on("mouseout", this.onRowOut, this);
53477 grid.cancelTextSelection = function(){};
53478 this.gridId = grid.id;
53480 var tpls = this.templates || {};
53483 tpls.master = new Roo.Template(
53484 '<div class="x-grid" hidefocus="true">',
53485 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
53486 '<div class="x-grid-topbar"></div>',
53487 '<div class="x-grid-scroller"><div></div></div>',
53488 '<div class="x-grid-locked">',
53489 '<div class="x-grid-header">{lockedHeader}</div>',
53490 '<div class="x-grid-body">{lockedBody}</div>',
53492 '<div class="x-grid-viewport">',
53493 '<div class="x-grid-header">{header}</div>',
53494 '<div class="x-grid-body">{body}</div>',
53496 '<div class="x-grid-bottombar"></div>',
53498 '<div class="x-grid-resize-proxy"> </div>',
53501 tpls.master.disableformats = true;
53505 tpls.header = new Roo.Template(
53506 '<table border="0" cellspacing="0" cellpadding="0">',
53507 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
53510 tpls.header.disableformats = true;
53512 tpls.header.compile();
53515 tpls.hcell = new Roo.Template(
53516 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
53517 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
53520 tpls.hcell.disableFormats = true;
53522 tpls.hcell.compile();
53525 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
53526 this.unselectableCls + '" ' + this.unselectable +'> </div>');
53527 tpls.hsplit.disableFormats = true;
53529 tpls.hsplit.compile();
53532 tpls.body = new Roo.Template(
53533 '<table border="0" cellspacing="0" cellpadding="0">',
53534 "<tbody>{rows}</tbody>",
53537 tpls.body.disableFormats = true;
53539 tpls.body.compile();
53542 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
53543 tpls.row.disableFormats = true;
53545 tpls.row.compile();
53548 tpls.cell = new Roo.Template(
53549 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
53550 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
53551 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
53554 tpls.cell.disableFormats = true;
53556 tpls.cell.compile();
53558 this.templates = tpls;
53561 // remap these for backwards compat
53562 onColWidthChange : function(){
53563 this.updateColumns.apply(this, arguments);
53565 onHeaderChange : function(){
53566 this.updateHeaders.apply(this, arguments);
53568 onHiddenChange : function(){
53569 this.handleHiddenChange.apply(this, arguments);
53571 onColumnMove : function(){
53572 this.handleColumnMove.apply(this, arguments);
53574 onColumnLock : function(){
53575 this.handleLockChange.apply(this, arguments);
53578 onDataChange : function(){
53580 this.updateHeaderSortState();
53583 onClear : function(){
53587 onUpdate : function(ds, record){
53588 this.refreshRow(record);
53591 refreshRow : function(record){
53592 var ds = this.ds, index;
53593 if(typeof record == 'number'){
53595 record = ds.getAt(index);
53597 index = ds.indexOf(record);
53599 this.insertRows(ds, index, index, true);
53600 this.onRemove(ds, record, index+1, true);
53601 this.syncRowHeights(index, index);
53603 this.fireEvent("rowupdated", this, index, record);
53606 onAdd : function(ds, records, index){
53607 this.insertRows(ds, index, index + (records.length-1));
53610 onRemove : function(ds, record, index, isUpdate){
53611 if(isUpdate !== true){
53612 this.fireEvent("beforerowremoved", this, index, record);
53614 var bt = this.getBodyTable(), lt = this.getLockedTable();
53615 if(bt.rows[index]){
53616 bt.firstChild.removeChild(bt.rows[index]);
53618 if(lt.rows[index]){
53619 lt.firstChild.removeChild(lt.rows[index]);
53621 if(isUpdate !== true){
53622 this.stripeRows(index);
53623 this.syncRowHeights(index, index);
53625 this.fireEvent("rowremoved", this, index, record);
53629 onLoad : function(){
53630 this.scrollToTop();
53634 * Scrolls the grid to the top
53636 scrollToTop : function(){
53638 this.scroller.dom.scrollTop = 0;
53644 * Gets a panel in the header of the grid that can be used for toolbars etc.
53645 * After modifying the contents of this panel a call to grid.autoSize() may be
53646 * required to register any changes in size.
53647 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
53648 * @return Roo.Element
53650 getHeaderPanel : function(doShow){
53652 this.headerPanel.show();
53654 return this.headerPanel;
53658 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53659 * After modifying the contents of this panel a call to grid.autoSize() may be
53660 * required to register any changes in size.
53661 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53662 * @return Roo.Element
53664 getFooterPanel : function(doShow){
53666 this.footerPanel.show();
53668 return this.footerPanel;
53671 initElements : function(){
53672 var E = Roo.Element;
53673 var el = this.grid.getGridEl().dom.firstChild;
53674 var cs = el.childNodes;
53676 this.el = new E(el);
53678 this.focusEl = new E(el.firstChild);
53679 this.focusEl.swallowEvent("click", true);
53681 this.headerPanel = new E(cs[1]);
53682 this.headerPanel.enableDisplayMode("block");
53684 this.scroller = new E(cs[2]);
53685 this.scrollSizer = new E(this.scroller.dom.firstChild);
53687 this.lockedWrap = new E(cs[3]);
53688 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53689 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53691 this.mainWrap = new E(cs[4]);
53692 this.mainHd = new E(this.mainWrap.dom.firstChild);
53693 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53695 this.footerPanel = new E(cs[5]);
53696 this.footerPanel.enableDisplayMode("block");
53698 this.resizeProxy = new E(cs[6]);
53700 this.headerSelector = String.format(
53701 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53702 this.lockedHd.id, this.mainHd.id
53705 this.splitterSelector = String.format(
53706 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53707 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53710 idToCssName : function(s)
53712 return s.replace(/[^a-z0-9]+/ig, '-');
53715 getHeaderCell : function(index){
53716 return Roo.DomQuery.select(this.headerSelector)[index];
53719 getHeaderCellMeasure : function(index){
53720 return this.getHeaderCell(index).firstChild;
53723 getHeaderCellText : function(index){
53724 return this.getHeaderCell(index).firstChild.firstChild;
53727 getLockedTable : function(){
53728 return this.lockedBody.dom.firstChild;
53731 getBodyTable : function(){
53732 return this.mainBody.dom.firstChild;
53735 getLockedRow : function(index){
53736 return this.getLockedTable().rows[index];
53739 getRow : function(index){
53740 return this.getBodyTable().rows[index];
53743 getRowComposite : function(index){
53745 this.rowEl = new Roo.CompositeElementLite();
53747 var els = [], lrow, mrow;
53748 if(lrow = this.getLockedRow(index)){
53751 if(mrow = this.getRow(index)){
53754 this.rowEl.elements = els;
53758 * Gets the 'td' of the cell
53760 * @param {Integer} rowIndex row to select
53761 * @param {Integer} colIndex column to select
53765 getCell : function(rowIndex, colIndex){
53766 var locked = this.cm.getLockedCount();
53768 if(colIndex < locked){
53769 source = this.lockedBody.dom.firstChild;
53771 source = this.mainBody.dom.firstChild;
53772 colIndex -= locked;
53774 return source.rows[rowIndex].childNodes[colIndex];
53777 getCellText : function(rowIndex, colIndex){
53778 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53781 getCellBox : function(cell){
53782 var b = this.fly(cell).getBox();
53783 if(Roo.isOpera){ // opera fails to report the Y
53784 b.y = cell.offsetTop + this.mainBody.getY();
53789 getCellIndex : function(cell){
53790 var id = String(cell.className).match(this.cellRE);
53792 return parseInt(id[1], 10);
53797 findHeaderIndex : function(n){
53798 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53799 return r ? this.getCellIndex(r) : false;
53802 findHeaderCell : function(n){
53803 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53804 return r ? r : false;
53807 findRowIndex : function(n){
53811 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53812 return r ? r.rowIndex : false;
53815 findCellIndex : function(node){
53816 var stop = this.el.dom;
53817 while(node && node != stop){
53818 if(this.findRE.test(node.className)){
53819 return this.getCellIndex(node);
53821 node = node.parentNode;
53826 getColumnId : function(index){
53827 return this.cm.getColumnId(index);
53830 getSplitters : function()
53832 if(this.splitterSelector){
53833 return Roo.DomQuery.select(this.splitterSelector);
53839 getSplitter : function(index){
53840 return this.getSplitters()[index];
53843 onRowOver : function(e, t){
53845 if((row = this.findRowIndex(t)) !== false){
53846 this.getRowComposite(row).addClass("x-grid-row-over");
53850 onRowOut : function(e, t){
53852 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53853 this.getRowComposite(row).removeClass("x-grid-row-over");
53857 renderHeaders : function(){
53859 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53860 var cb = [], lb = [], sb = [], lsb = [], p = {};
53861 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53862 p.cellId = "x-grid-hd-0-" + i;
53863 p.splitId = "x-grid-csplit-0-" + i;
53864 p.id = cm.getColumnId(i);
53865 p.title = cm.getColumnTooltip(i) || "";
53866 p.value = cm.getColumnHeader(i) || "";
53867 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53868 if(!cm.isLocked(i)){
53869 cb[cb.length] = ct.apply(p);
53870 sb[sb.length] = st.apply(p);
53872 lb[lb.length] = ct.apply(p);
53873 lsb[lsb.length] = st.apply(p);
53876 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53877 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53880 updateHeaders : function(){
53881 var html = this.renderHeaders();
53882 this.lockedHd.update(html[0]);
53883 this.mainHd.update(html[1]);
53887 * Focuses the specified row.
53888 * @param {Number} row The row index
53890 focusRow : function(row)
53892 //Roo.log('GridView.focusRow');
53893 var x = this.scroller.dom.scrollLeft;
53894 this.focusCell(row, 0, false);
53895 this.scroller.dom.scrollLeft = x;
53899 * Focuses the specified cell.
53900 * @param {Number} row The row index
53901 * @param {Number} col The column index
53902 * @param {Boolean} hscroll false to disable horizontal scrolling
53904 focusCell : function(row, col, hscroll)
53906 //Roo.log('GridView.focusCell');
53907 var el = this.ensureVisible(row, col, hscroll);
53908 this.focusEl.alignTo(el, "tl-tl");
53910 this.focusEl.focus();
53912 this.focusEl.focus.defer(1, this.focusEl);
53917 * Scrolls the specified cell into view
53918 * @param {Number} row The row index
53919 * @param {Number} col The column index
53920 * @param {Boolean} hscroll false to disable horizontal scrolling
53922 ensureVisible : function(row, col, hscroll)
53924 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53925 //return null; //disable for testing.
53926 if(typeof row != "number"){
53927 row = row.rowIndex;
53929 if(row < 0 && row >= this.ds.getCount()){
53932 col = (col !== undefined ? col : 0);
53933 var cm = this.grid.colModel;
53934 while(cm.isHidden(col)){
53938 var el = this.getCell(row, col);
53942 var c = this.scroller.dom;
53944 var ctop = parseInt(el.offsetTop, 10);
53945 var cleft = parseInt(el.offsetLeft, 10);
53946 var cbot = ctop + el.offsetHeight;
53947 var cright = cleft + el.offsetWidth;
53949 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53950 var stop = parseInt(c.scrollTop, 10);
53951 var sleft = parseInt(c.scrollLeft, 10);
53952 var sbot = stop + ch;
53953 var sright = sleft + c.clientWidth;
53955 Roo.log('GridView.ensureVisible:' +
53957 ' c.clientHeight:' + c.clientHeight +
53958 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53966 c.scrollTop = ctop;
53967 //Roo.log("set scrolltop to ctop DISABLE?");
53968 }else if(cbot > sbot){
53969 //Roo.log("set scrolltop to cbot-ch");
53970 c.scrollTop = cbot-ch;
53973 if(hscroll !== false){
53975 c.scrollLeft = cleft;
53976 }else if(cright > sright){
53977 c.scrollLeft = cright-c.clientWidth;
53984 updateColumns : function(){
53985 this.grid.stopEditing();
53986 var cm = this.grid.colModel, colIds = this.getColumnIds();
53987 //var totalWidth = cm.getTotalWidth();
53989 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53990 //if(cm.isHidden(i)) continue;
53991 var w = cm.getColumnWidth(i);
53992 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53993 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53995 this.updateSplitters();
53998 generateRules : function(cm){
53999 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
54000 Roo.util.CSS.removeStyleSheet(rulesId);
54001 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54002 var cid = cm.getColumnId(i);
54004 if(cm.config[i].align){
54005 align = 'text-align:'+cm.config[i].align+';';
54008 if(cm.isHidden(i)){
54009 hidden = 'display:none;';
54011 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
54013 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
54014 this.hdSelector, cid, " {\n", align, width, "}\n",
54015 this.tdSelector, cid, " {\n",hidden,"\n}\n",
54016 this.splitSelector, cid, " {\n", hidden , "\n}\n");
54018 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54021 updateSplitters : function(){
54022 var cm = this.cm, s = this.getSplitters();
54023 if(s){ // splitters not created yet
54024 var pos = 0, locked = true;
54025 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54026 if(cm.isHidden(i)) continue;
54027 var w = cm.getColumnWidth(i); // make sure it's a number
54028 if(!cm.isLocked(i) && locked){
54033 s[i].style.left = (pos-this.splitOffset) + "px";
54038 handleHiddenChange : function(colModel, colIndex, hidden){
54040 this.hideColumn(colIndex);
54042 this.unhideColumn(colIndex);
54046 hideColumn : function(colIndex){
54047 var cid = this.getColumnId(colIndex);
54048 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
54049 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
54051 this.updateHeaders();
54053 this.updateSplitters();
54057 unhideColumn : function(colIndex){
54058 var cid = this.getColumnId(colIndex);
54059 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
54060 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
54063 this.updateHeaders();
54065 this.updateSplitters();
54069 insertRows : function(dm, firstRow, lastRow, isUpdate){
54070 if(firstRow == 0 && lastRow == dm.getCount()-1){
54074 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
54076 var s = this.getScrollState();
54077 var markup = this.renderRows(firstRow, lastRow);
54078 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
54079 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
54080 this.restoreScroll(s);
54082 this.fireEvent("rowsinserted", this, firstRow, lastRow);
54083 this.syncRowHeights(firstRow, lastRow);
54084 this.stripeRows(firstRow);
54090 bufferRows : function(markup, target, index){
54091 var before = null, trows = target.rows, tbody = target.tBodies[0];
54092 if(index < trows.length){
54093 before = trows[index];
54095 var b = document.createElement("div");
54096 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
54097 var rows = b.firstChild.rows;
54098 for(var i = 0, len = rows.length; i < len; i++){
54100 tbody.insertBefore(rows[0], before);
54102 tbody.appendChild(rows[0]);
54109 deleteRows : function(dm, firstRow, lastRow){
54110 if(dm.getRowCount()<1){
54111 this.fireEvent("beforerefresh", this);
54112 this.mainBody.update("");
54113 this.lockedBody.update("");
54114 this.fireEvent("refresh", this);
54116 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
54117 var bt = this.getBodyTable();
54118 var tbody = bt.firstChild;
54119 var rows = bt.rows;
54120 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
54121 tbody.removeChild(rows[firstRow]);
54123 this.stripeRows(firstRow);
54124 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
54128 updateRows : function(dataSource, firstRow, lastRow){
54129 var s = this.getScrollState();
54131 this.restoreScroll(s);
54134 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
54138 this.updateHeaderSortState();
54141 getScrollState : function(){
54143 var sb = this.scroller.dom;
54144 return {left: sb.scrollLeft, top: sb.scrollTop};
54147 stripeRows : function(startRow){
54148 if(!this.grid.stripeRows || this.ds.getCount() < 1){
54151 startRow = startRow || 0;
54152 var rows = this.getBodyTable().rows;
54153 var lrows = this.getLockedTable().rows;
54154 var cls = ' x-grid-row-alt ';
54155 for(var i = startRow, len = rows.length; i < len; i++){
54156 var row = rows[i], lrow = lrows[i];
54157 var isAlt = ((i+1) % 2 == 0);
54158 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
54159 if(isAlt == hasAlt){
54163 row.className += " x-grid-row-alt";
54165 row.className = row.className.replace("x-grid-row-alt", "");
54168 lrow.className = row.className;
54173 restoreScroll : function(state){
54174 //Roo.log('GridView.restoreScroll');
54175 var sb = this.scroller.dom;
54176 sb.scrollLeft = state.left;
54177 sb.scrollTop = state.top;
54181 syncScroll : function(){
54182 //Roo.log('GridView.syncScroll');
54183 var sb = this.scroller.dom;
54184 var sh = this.mainHd.dom;
54185 var bs = this.mainBody.dom;
54186 var lv = this.lockedBody.dom;
54187 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
54188 lv.scrollTop = bs.scrollTop = sb.scrollTop;
54191 handleScroll : function(e){
54193 var sb = this.scroller.dom;
54194 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
54198 handleWheel : function(e){
54199 var d = e.getWheelDelta();
54200 this.scroller.dom.scrollTop -= d*22;
54201 // set this here to prevent jumpy scrolling on large tables
54202 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
54206 renderRows : function(startRow, endRow){
54207 // pull in all the crap needed to render rows
54208 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
54209 var colCount = cm.getColumnCount();
54211 if(ds.getCount() < 1){
54215 // build a map for all the columns
54217 for(var i = 0; i < colCount; i++){
54218 var name = cm.getDataIndex(i);
54220 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
54221 renderer : cm.getRenderer(i),
54222 id : cm.getColumnId(i),
54223 locked : cm.isLocked(i)
54227 startRow = startRow || 0;
54228 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
54230 // records to render
54231 var rs = ds.getRange(startRow, endRow);
54233 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
54236 // As much as I hate to duplicate code, this was branched because FireFox really hates
54237 // [].join("") on strings. The performance difference was substantial enough to
54238 // branch this function
54239 doRender : Roo.isGecko ?
54240 function(cs, rs, ds, startRow, colCount, stripe){
54241 var ts = this.templates, ct = ts.cell, rt = ts.row;
54243 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54245 var hasListener = this.grid.hasListener('rowclass');
54247 for(var j = 0, len = rs.length; j < len; j++){
54248 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
54249 for(var i = 0; i < colCount; i++){
54251 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54253 p.css = p.attr = "";
54254 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54255 if(p.value == undefined || p.value === "") p.value = " ";
54256 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54257 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54259 var markup = ct.apply(p);
54267 if(stripe && ((rowIndex+1) % 2 == 0)){
54268 alt.push("x-grid-row-alt")
54271 alt.push( " x-grid-dirty-row");
54274 if(this.getRowClass){
54275 alt.push(this.getRowClass(r, rowIndex));
54281 rowIndex : rowIndex,
54284 this.grid.fireEvent('rowclass', this, rowcfg);
54285 alt.push(rowcfg.rowClass);
54287 rp.alt = alt.join(" ");
54288 lbuf+= rt.apply(rp);
54290 buf+= rt.apply(rp);
54292 return [lbuf, buf];
54294 function(cs, rs, ds, startRow, colCount, stripe){
54295 var ts = this.templates, ct = ts.cell, rt = ts.row;
54297 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54298 var hasListener = this.grid.hasListener('rowclass');
54301 for(var j = 0, len = rs.length; j < len; j++){
54302 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
54303 for(var i = 0; i < colCount; i++){
54305 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54307 p.css = p.attr = "";
54308 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54309 if(p.value == undefined || p.value === "") p.value = " ";
54310 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54311 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54314 var markup = ct.apply(p);
54316 cb[cb.length] = markup;
54318 lcb[lcb.length] = markup;
54322 if(stripe && ((rowIndex+1) % 2 == 0)){
54323 alt.push( "x-grid-row-alt");
54326 alt.push(" x-grid-dirty-row");
54329 if(this.getRowClass){
54330 alt.push( this.getRowClass(r, rowIndex));
54336 rowIndex : rowIndex,
54339 this.grid.fireEvent('rowclass', this, rowcfg);
54340 alt.push(rowcfg.rowClass);
54342 rp.alt = alt.join(" ");
54343 rp.cells = lcb.join("");
54344 lbuf[lbuf.length] = rt.apply(rp);
54345 rp.cells = cb.join("");
54346 buf[buf.length] = rt.apply(rp);
54348 return [lbuf.join(""), buf.join("")];
54351 renderBody : function(){
54352 var markup = this.renderRows();
54353 var bt = this.templates.body;
54354 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
54358 * Refreshes the grid
54359 * @param {Boolean} headersToo
54361 refresh : function(headersToo){
54362 this.fireEvent("beforerefresh", this);
54363 this.grid.stopEditing();
54364 var result = this.renderBody();
54365 this.lockedBody.update(result[0]);
54366 this.mainBody.update(result[1]);
54367 if(headersToo === true){
54368 this.updateHeaders();
54369 this.updateColumns();
54370 this.updateSplitters();
54371 this.updateHeaderSortState();
54373 this.syncRowHeights();
54375 this.fireEvent("refresh", this);
54378 handleColumnMove : function(cm, oldIndex, newIndex){
54379 this.indexMap = null;
54380 var s = this.getScrollState();
54381 this.refresh(true);
54382 this.restoreScroll(s);
54383 this.afterMove(newIndex);
54386 afterMove : function(colIndex){
54387 if(this.enableMoveAnim && Roo.enableFx){
54388 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
54390 // if multisort - fix sortOrder, and reload..
54391 if (this.grid.dataSource.multiSort) {
54392 // the we can call sort again..
54393 var dm = this.grid.dataSource;
54394 var cm = this.grid.colModel;
54396 for(var i = 0; i < cm.config.length; i++ ) {
54398 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
54399 continue; // dont' bother, it's not in sort list or being set.
54402 so.push(cm.config[i].dataIndex);
54405 dm.load(dm.lastOptions);
54412 updateCell : function(dm, rowIndex, dataIndex){
54413 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
54414 if(typeof colIndex == "undefined"){ // not present in grid
54417 var cm = this.grid.colModel;
54418 var cell = this.getCell(rowIndex, colIndex);
54419 var cellText = this.getCellText(rowIndex, colIndex);
54422 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
54423 id : cm.getColumnId(colIndex),
54424 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
54426 var renderer = cm.getRenderer(colIndex);
54427 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
54428 if(typeof val == "undefined" || val === "") val = " ";
54429 cellText.innerHTML = val;
54430 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
54431 this.syncRowHeights(rowIndex, rowIndex);
54434 calcColumnWidth : function(colIndex, maxRowsToMeasure){
54436 if(this.grid.autoSizeHeaders){
54437 var h = this.getHeaderCellMeasure(colIndex);
54438 maxWidth = Math.max(maxWidth, h.scrollWidth);
54441 if(this.cm.isLocked(colIndex)){
54442 tb = this.getLockedTable();
54445 tb = this.getBodyTable();
54446 index = colIndex - this.cm.getLockedCount();
54449 var rows = tb.rows;
54450 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
54451 for(var i = 0; i < stopIndex; i++){
54452 var cell = rows[i].childNodes[index].firstChild;
54453 maxWidth = Math.max(maxWidth, cell.scrollWidth);
54456 return maxWidth + /*margin for error in IE*/ 5;
54459 * Autofit a column to its content.
54460 * @param {Number} colIndex
54461 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
54463 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
54464 if(this.cm.isHidden(colIndex)){
54465 return; // can't calc a hidden column
54468 var cid = this.cm.getColumnId(colIndex);
54469 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
54470 if(this.grid.autoSizeHeaders){
54471 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
54474 var newWidth = this.calcColumnWidth(colIndex);
54475 this.cm.setColumnWidth(colIndex,
54476 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
54477 if(!suppressEvent){
54478 this.grid.fireEvent("columnresize", colIndex, newWidth);
54483 * Autofits all columns to their content and then expands to fit any extra space in the grid
54485 autoSizeColumns : function(){
54486 var cm = this.grid.colModel;
54487 var colCount = cm.getColumnCount();
54488 for(var i = 0; i < colCount; i++){
54489 this.autoSizeColumn(i, true, true);
54491 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
54494 this.updateColumns();
54500 * Autofits all columns to the grid's width proportionate with their current size
54501 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
54503 fitColumns : function(reserveScrollSpace){
54504 var cm = this.grid.colModel;
54505 var colCount = cm.getColumnCount();
54509 for (i = 0; i < colCount; i++){
54510 if(!cm.isHidden(i) && !cm.isFixed(i)){
54511 w = cm.getColumnWidth(i);
54517 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
54518 if(reserveScrollSpace){
54521 var frac = (avail - cm.getTotalWidth())/width;
54522 while (cols.length){
54525 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
54527 this.updateColumns();
54531 onRowSelect : function(rowIndex){
54532 var row = this.getRowComposite(rowIndex);
54533 row.addClass("x-grid-row-selected");
54536 onRowDeselect : function(rowIndex){
54537 var row = this.getRowComposite(rowIndex);
54538 row.removeClass("x-grid-row-selected");
54541 onCellSelect : function(row, col){
54542 var cell = this.getCell(row, col);
54544 Roo.fly(cell).addClass("x-grid-cell-selected");
54548 onCellDeselect : function(row, col){
54549 var cell = this.getCell(row, col);
54551 Roo.fly(cell).removeClass("x-grid-cell-selected");
54555 updateHeaderSortState : function(){
54557 // sort state can be single { field: xxx, direction : yyy}
54558 // or { xxx=>ASC , yyy : DESC ..... }
54561 if (!this.ds.multiSort) {
54562 var state = this.ds.getSortState();
54566 mstate[state.field] = state.direction;
54567 // FIXME... - this is not used here.. but might be elsewhere..
54568 this.sortState = state;
54571 mstate = this.ds.sortToggle;
54573 //remove existing sort classes..
54575 var sc = this.sortClasses;
54576 var hds = this.el.select(this.headerSelector).removeClass(sc);
54578 for(var f in mstate) {
54580 var sortColumn = this.cm.findColumnIndex(f);
54582 if(sortColumn != -1){
54583 var sortDir = mstate[f];
54584 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
54593 handleHeaderClick : function(g, index,e){
54595 Roo.log("header click");
54598 // touch events on header are handled by context
54599 this.handleHdCtx(g,index,e);
54604 if(this.headersDisabled){
54607 var dm = g.dataSource, cm = g.colModel;
54608 if(!cm.isSortable(index)){
54613 if (dm.multiSort) {
54614 // update the sortOrder
54616 for(var i = 0; i < cm.config.length; i++ ) {
54618 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
54619 continue; // dont' bother, it's not in sort list or being set.
54622 so.push(cm.config[i].dataIndex);
54628 dm.sort(cm.getDataIndex(index));
54632 destroy : function(){
54634 this.colMenu.removeAll();
54635 Roo.menu.MenuMgr.unregister(this.colMenu);
54636 this.colMenu.getEl().remove();
54637 delete this.colMenu;
54640 this.hmenu.removeAll();
54641 Roo.menu.MenuMgr.unregister(this.hmenu);
54642 this.hmenu.getEl().remove();
54645 if(this.grid.enableColumnMove){
54646 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54648 for(var dd in dds){
54649 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54650 var elid = dds[dd].dragElId;
54652 Roo.get(elid).remove();
54653 } else if(dds[dd].config.isTarget){
54654 dds[dd].proxyTop.remove();
54655 dds[dd].proxyBottom.remove();
54658 if(Roo.dd.DDM.locationCache[dd]){
54659 delete Roo.dd.DDM.locationCache[dd];
54662 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54665 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54666 this.bind(null, null);
54667 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54670 handleLockChange : function(){
54671 this.refresh(true);
54674 onDenyColumnLock : function(){
54678 onDenyColumnHide : function(){
54682 handleHdMenuClick : function(item){
54683 var index = this.hdCtxIndex;
54684 var cm = this.cm, ds = this.ds;
54687 ds.sort(cm.getDataIndex(index), "ASC");
54690 ds.sort(cm.getDataIndex(index), "DESC");
54693 var lc = cm.getLockedCount();
54694 if(cm.getColumnCount(true) <= lc+1){
54695 this.onDenyColumnLock();
54699 cm.setLocked(index, true, true);
54700 cm.moveColumn(index, lc);
54701 this.grid.fireEvent("columnmove", index, lc);
54703 cm.setLocked(index, true);
54707 var lc = cm.getLockedCount();
54708 if((lc-1) != index){
54709 cm.setLocked(index, false, true);
54710 cm.moveColumn(index, lc-1);
54711 this.grid.fireEvent("columnmove", index, lc-1);
54713 cm.setLocked(index, false);
54716 case 'wider': // used to expand cols on touch..
54718 var cw = cm.getColumnWidth(index);
54719 cw += (item.id == 'wider' ? 1 : -1) * 50;
54720 cw = Math.max(0, cw);
54721 cw = Math.min(cw,4000);
54722 cm.setColumnWidth(index, cw);
54726 index = cm.getIndexById(item.id.substr(4));
54728 if(item.checked && cm.getColumnCount(true) <= 1){
54729 this.onDenyColumnHide();
54732 cm.setHidden(index, item.checked);
54738 beforeColMenuShow : function(){
54739 var cm = this.cm, colCount = cm.getColumnCount();
54740 this.colMenu.removeAll();
54741 for(var i = 0; i < colCount; i++){
54742 this.colMenu.add(new Roo.menu.CheckItem({
54743 id: "col-"+cm.getColumnId(i),
54744 text: cm.getColumnHeader(i),
54745 checked: !cm.isHidden(i),
54751 handleHdCtx : function(g, index, e){
54753 var hd = this.getHeaderCell(index);
54754 this.hdCtxIndex = index;
54755 var ms = this.hmenu.items, cm = this.cm;
54756 ms.get("asc").setDisabled(!cm.isSortable(index));
54757 ms.get("desc").setDisabled(!cm.isSortable(index));
54758 if(this.grid.enableColLock !== false){
54759 ms.get("lock").setDisabled(cm.isLocked(index));
54760 ms.get("unlock").setDisabled(!cm.isLocked(index));
54762 this.hmenu.show(hd, "tl-bl");
54765 handleHdOver : function(e){
54766 var hd = this.findHeaderCell(e.getTarget());
54767 if(hd && !this.headersDisabled){
54768 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54769 this.fly(hd).addClass("x-grid-hd-over");
54774 handleHdOut : function(e){
54775 var hd = this.findHeaderCell(e.getTarget());
54777 this.fly(hd).removeClass("x-grid-hd-over");
54781 handleSplitDblClick : function(e, t){
54782 var i = this.getCellIndex(t);
54783 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54784 this.autoSizeColumn(i, true);
54789 render : function(){
54792 var colCount = cm.getColumnCount();
54794 if(this.grid.monitorWindowResize === true){
54795 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54797 var header = this.renderHeaders();
54798 var body = this.templates.body.apply({rows:""});
54799 var html = this.templates.master.apply({
54802 lockedHeader: header[0],
54806 //this.updateColumns();
54808 this.grid.getGridEl().dom.innerHTML = html;
54810 this.initElements();
54812 // a kludge to fix the random scolling effect in webkit
54813 this.el.on("scroll", function() {
54814 this.el.dom.scrollTop=0; // hopefully not recursive..
54817 this.scroller.on("scroll", this.handleScroll, this);
54818 this.lockedBody.on("mousewheel", this.handleWheel, this);
54819 this.mainBody.on("mousewheel", this.handleWheel, this);
54821 this.mainHd.on("mouseover", this.handleHdOver, this);
54822 this.mainHd.on("mouseout", this.handleHdOut, this);
54823 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54824 {delegate: "."+this.splitClass});
54826 this.lockedHd.on("mouseover", this.handleHdOver, this);
54827 this.lockedHd.on("mouseout", this.handleHdOut, this);
54828 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54829 {delegate: "."+this.splitClass});
54831 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54832 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54835 this.updateSplitters();
54837 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54838 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54839 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54842 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54843 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54845 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54846 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54848 if(this.grid.enableColLock !== false){
54849 this.hmenu.add('-',
54850 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54851 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54855 this.hmenu.add('-',
54856 {id:"wider", text: this.columnsWiderText},
54857 {id:"narrow", text: this.columnsNarrowText }
54863 if(this.grid.enableColumnHide !== false){
54865 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54866 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54867 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54869 this.hmenu.add('-',
54870 {id:"columns", text: this.columnsText, menu: this.colMenu}
54873 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54875 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54878 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54879 this.dd = new Roo.grid.GridDragZone(this.grid, {
54880 ddGroup : this.grid.ddGroup || 'GridDD'
54886 for(var i = 0; i < colCount; i++){
54887 if(cm.isHidden(i)){
54888 this.hideColumn(i);
54890 if(cm.config[i].align){
54891 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54892 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54896 this.updateHeaderSortState();
54898 this.beforeInitialResize();
54901 // two part rendering gives faster view to the user
54902 this.renderPhase2.defer(1, this);
54905 renderPhase2 : function(){
54906 // render the rows now
54908 if(this.grid.autoSizeColumns){
54909 this.autoSizeColumns();
54913 beforeInitialResize : function(){
54917 onColumnSplitterMoved : function(i, w){
54918 this.userResized = true;
54919 var cm = this.grid.colModel;
54920 cm.setColumnWidth(i, w, true);
54921 var cid = cm.getColumnId(i);
54922 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54923 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54924 this.updateSplitters();
54926 this.grid.fireEvent("columnresize", i, w);
54929 syncRowHeights : function(startIndex, endIndex){
54930 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54931 startIndex = startIndex || 0;
54932 var mrows = this.getBodyTable().rows;
54933 var lrows = this.getLockedTable().rows;
54934 var len = mrows.length-1;
54935 endIndex = Math.min(endIndex || len, len);
54936 for(var i = startIndex; i <= endIndex; i++){
54937 var m = mrows[i], l = lrows[i];
54938 var h = Math.max(m.offsetHeight, l.offsetHeight);
54939 m.style.height = l.style.height = h + "px";
54944 layout : function(initialRender, is2ndPass){
54946 var auto = g.autoHeight;
54947 var scrollOffset = 16;
54948 var c = g.getGridEl(), cm = this.cm,
54949 expandCol = g.autoExpandColumn,
54951 //c.beginMeasure();
54953 if(!c.dom.offsetWidth){ // display:none?
54955 this.lockedWrap.show();
54956 this.mainWrap.show();
54961 var hasLock = this.cm.isLocked(0);
54963 var tbh = this.headerPanel.getHeight();
54964 var bbh = this.footerPanel.getHeight();
54967 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54968 var newHeight = ch + c.getBorderWidth("tb");
54970 newHeight = Math.min(g.maxHeight, newHeight);
54972 c.setHeight(newHeight);
54976 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54979 var s = this.scroller;
54981 var csize = c.getSize(true);
54983 this.el.setSize(csize.width, csize.height);
54985 this.headerPanel.setWidth(csize.width);
54986 this.footerPanel.setWidth(csize.width);
54988 var hdHeight = this.mainHd.getHeight();
54989 var vw = csize.width;
54990 var vh = csize.height - (tbh + bbh);
54994 var bt = this.getBodyTable();
54995 var ltWidth = hasLock ?
54996 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54998 var scrollHeight = bt.offsetHeight;
54999 var scrollWidth = ltWidth + bt.offsetWidth;
55000 var vscroll = false, hscroll = false;
55002 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
55004 var lw = this.lockedWrap, mw = this.mainWrap;
55005 var lb = this.lockedBody, mb = this.mainBody;
55007 setTimeout(function(){
55008 var t = s.dom.offsetTop;
55009 var w = s.dom.clientWidth,
55010 h = s.dom.clientHeight;
55013 lw.setSize(ltWidth, h);
55015 mw.setLeftTop(ltWidth, t);
55016 mw.setSize(w-ltWidth, h);
55018 lb.setHeight(h-hdHeight);
55019 mb.setHeight(h-hdHeight);
55021 if(is2ndPass !== true && !gv.userResized && expandCol){
55022 // high speed resize without full column calculation
55024 var ci = cm.getIndexById(expandCol);
55026 ci = cm.findColumnIndex(expandCol);
55028 ci = Math.max(0, ci); // make sure it's got at least the first col.
55029 var expandId = cm.getColumnId(ci);
55030 var tw = cm.getTotalWidth(false);
55031 var currentWidth = cm.getColumnWidth(ci);
55032 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
55033 if(currentWidth != cw){
55034 cm.setColumnWidth(ci, cw, true);
55035 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
55036 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
55037 gv.updateSplitters();
55038 gv.layout(false, true);
55050 onWindowResize : function(){
55051 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
55057 appendFooter : function(parentEl){
55061 sortAscText : "Sort Ascending",
55062 sortDescText : "Sort Descending",
55063 lockText : "Lock Column",
55064 unlockText : "Unlock Column",
55065 columnsText : "Columns",
55067 columnsWiderText : "Wider",
55068 columnsNarrowText : "Thinner"
55072 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
55073 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
55074 this.proxy.el.addClass('x-grid3-col-dd');
55077 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
55078 handleMouseDown : function(e){
55082 callHandleMouseDown : function(e){
55083 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
55088 * Ext JS Library 1.1.1
55089 * Copyright(c) 2006-2007, Ext JS, LLC.
55091 * Originally Released Under LGPL - original licence link has changed is not relivant.
55094 * <script type="text/javascript">
55098 // This is a support class used internally by the Grid components
55099 Roo.grid.SplitDragZone = function(grid, hd, hd2){
55101 this.view = grid.getView();
55102 this.proxy = this.view.resizeProxy;
55103 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
55104 "gridSplitters" + this.grid.getGridEl().id, {
55105 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
55107 this.setHandleElId(Roo.id(hd));
55108 this.setOuterHandleElId(Roo.id(hd2));
55109 this.scroll = false;
55111 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
55112 fly: Roo.Element.fly,
55114 b4StartDrag : function(x, y){
55115 this.view.headersDisabled = true;
55116 this.proxy.setHeight(this.view.mainWrap.getHeight());
55117 var w = this.cm.getColumnWidth(this.cellIndex);
55118 var minw = Math.max(w-this.grid.minColumnWidth, 0);
55119 this.resetConstraints();
55120 this.setXConstraint(minw, 1000);
55121 this.setYConstraint(0, 0);
55122 this.minX = x - minw;
55123 this.maxX = x + 1000;
55125 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
55129 handleMouseDown : function(e){
55130 ev = Roo.EventObject.setEvent(e);
55131 var t = this.fly(ev.getTarget());
55132 if(t.hasClass("x-grid-split")){
55133 this.cellIndex = this.view.getCellIndex(t.dom);
55134 this.split = t.dom;
55135 this.cm = this.grid.colModel;
55136 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
55137 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
55142 endDrag : function(e){
55143 this.view.headersDisabled = false;
55144 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
55145 var diff = endX - this.startPos;
55146 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
55149 autoOffset : function(){
55150 this.setDelta(0,0);
55154 * Ext JS Library 1.1.1
55155 * Copyright(c) 2006-2007, Ext JS, LLC.
55157 * Originally Released Under LGPL - original licence link has changed is not relivant.
55160 * <script type="text/javascript">
55164 // This is a support class used internally by the Grid components
55165 Roo.grid.GridDragZone = function(grid, config){
55166 this.view = grid.getView();
55167 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
55168 if(this.view.lockedBody){
55169 this.setHandleElId(Roo.id(this.view.mainBody.dom));
55170 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
55172 this.scroll = false;
55174 this.ddel = document.createElement('div');
55175 this.ddel.className = 'x-grid-dd-wrap';
55178 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
55179 ddGroup : "GridDD",
55181 getDragData : function(e){
55182 var t = Roo.lib.Event.getTarget(e);
55183 var rowIndex = this.view.findRowIndex(t);
55184 var sm = this.grid.selModel;
55186 //Roo.log(rowIndex);
55188 if (sm.getSelectedCell) {
55189 // cell selection..
55190 if (!sm.getSelectedCell()) {
55193 if (rowIndex != sm.getSelectedCell()[0]) {
55199 if(rowIndex !== false){
55204 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
55206 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
55209 if (e.hasModifier()){
55210 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
55213 Roo.log("getDragData");
55218 rowIndex: rowIndex,
55219 selections:sm.getSelections ? sm.getSelections() : (
55220 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
55227 onInitDrag : function(e){
55228 var data = this.dragData;
55229 this.ddel.innerHTML = this.grid.getDragDropText();
55230 this.proxy.update(this.ddel);
55231 // fire start drag?
55234 afterRepair : function(){
55235 this.dragging = false;
55238 getRepairXY : function(e, data){
55242 onEndDrag : function(data, e){
55246 onValidDrop : function(dd, e, id){
55251 beforeInvalidDrop : function(e, id){
55256 * Ext JS Library 1.1.1
55257 * Copyright(c) 2006-2007, Ext JS, LLC.
55259 * Originally Released Under LGPL - original licence link has changed is not relivant.
55262 * <script type="text/javascript">
55267 * @class Roo.grid.ColumnModel
55268 * @extends Roo.util.Observable
55269 * This is the default implementation of a ColumnModel used by the Grid. It defines
55270 * the columns in the grid.
55273 var colModel = new Roo.grid.ColumnModel([
55274 {header: "Ticker", width: 60, sortable: true, locked: true},
55275 {header: "Company Name", width: 150, sortable: true},
55276 {header: "Market Cap.", width: 100, sortable: true},
55277 {header: "$ Sales", width: 100, sortable: true, renderer: money},
55278 {header: "Employees", width: 100, sortable: true, resizable: false}
55283 * The config options listed for this class are options which may appear in each
55284 * individual column definition.
55285 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
55287 * @param {Object} config An Array of column config objects. See this class's
55288 * config objects for details.
55290 Roo.grid.ColumnModel = function(config){
55292 * The config passed into the constructor
55294 this.config = config;
55297 // if no id, create one
55298 // if the column does not have a dataIndex mapping,
55299 // map it to the order it is in the config
55300 for(var i = 0, len = config.length; i < len; i++){
55302 if(typeof c.dataIndex == "undefined"){
55305 if(typeof c.renderer == "string"){
55306 c.renderer = Roo.util.Format[c.renderer];
55308 if(typeof c.id == "undefined"){
55311 if(c.editor && c.editor.xtype){
55312 c.editor = Roo.factory(c.editor, Roo.grid);
55314 if(c.editor && c.editor.isFormField){
55315 c.editor = new Roo.grid.GridEditor(c.editor);
55317 this.lookup[c.id] = c;
55321 * The width of columns which have no width specified (defaults to 100)
55324 this.defaultWidth = 100;
55327 * Default sortable of columns which have no sortable specified (defaults to false)
55330 this.defaultSortable = false;
55334 * @event widthchange
55335 * Fires when the width of a column changes.
55336 * @param {ColumnModel} this
55337 * @param {Number} columnIndex The column index
55338 * @param {Number} newWidth The new width
55340 "widthchange": true,
55342 * @event headerchange
55343 * Fires when the text of a header changes.
55344 * @param {ColumnModel} this
55345 * @param {Number} columnIndex The column index
55346 * @param {Number} newText The new header text
55348 "headerchange": true,
55350 * @event hiddenchange
55351 * Fires when a column is hidden or "unhidden".
55352 * @param {ColumnModel} this
55353 * @param {Number} columnIndex The column index
55354 * @param {Boolean} hidden true if hidden, false otherwise
55356 "hiddenchange": true,
55358 * @event columnmoved
55359 * Fires when a column is moved.
55360 * @param {ColumnModel} this
55361 * @param {Number} oldIndex
55362 * @param {Number} newIndex
55364 "columnmoved" : true,
55366 * @event columlockchange
55367 * Fires when a column's locked state is changed
55368 * @param {ColumnModel} this
55369 * @param {Number} colIndex
55370 * @param {Boolean} locked true if locked
55372 "columnlockchange" : true
55374 Roo.grid.ColumnModel.superclass.constructor.call(this);
55376 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
55378 * @cfg {String} header The header text to display in the Grid view.
55381 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
55382 * {@link Roo.data.Record} definition from which to draw the column's value. If not
55383 * specified, the column's index is used as an index into the Record's data Array.
55386 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
55387 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
55390 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
55391 * Defaults to the value of the {@link #defaultSortable} property.
55392 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
55395 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
55398 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
55401 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
55404 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
55407 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
55408 * given the cell's data value. See {@link #setRenderer}. If not specified, the
55409 * default renderer uses the raw data value. If an object is returned (bootstrap only)
55410 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
55413 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
55416 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
55419 * @cfg {String} cursor (Optional)
55422 * @cfg {String} tooltip (Optional)
55425 * Returns the id of the column at the specified index.
55426 * @param {Number} index The column index
55427 * @return {String} the id
55429 getColumnId : function(index){
55430 return this.config[index].id;
55434 * Returns the column for a specified id.
55435 * @param {String} id The column id
55436 * @return {Object} the column
55438 getColumnById : function(id){
55439 return this.lookup[id];
55444 * Returns the column for a specified dataIndex.
55445 * @param {String} dataIndex The column dataIndex
55446 * @return {Object|Boolean} the column or false if not found
55448 getColumnByDataIndex: function(dataIndex){
55449 var index = this.findColumnIndex(dataIndex);
55450 return index > -1 ? this.config[index] : false;
55454 * Returns the index for a specified column id.
55455 * @param {String} id The column id
55456 * @return {Number} the index, or -1 if not found
55458 getIndexById : function(id){
55459 for(var i = 0, len = this.config.length; i < len; i++){
55460 if(this.config[i].id == id){
55468 * Returns the index for a specified column dataIndex.
55469 * @param {String} dataIndex The column dataIndex
55470 * @return {Number} the index, or -1 if not found
55473 findColumnIndex : function(dataIndex){
55474 for(var i = 0, len = this.config.length; i < len; i++){
55475 if(this.config[i].dataIndex == dataIndex){
55483 moveColumn : function(oldIndex, newIndex){
55484 var c = this.config[oldIndex];
55485 this.config.splice(oldIndex, 1);
55486 this.config.splice(newIndex, 0, c);
55487 this.dataMap = null;
55488 this.fireEvent("columnmoved", this, oldIndex, newIndex);
55491 isLocked : function(colIndex){
55492 return this.config[colIndex].locked === true;
55495 setLocked : function(colIndex, value, suppressEvent){
55496 if(this.isLocked(colIndex) == value){
55499 this.config[colIndex].locked = value;
55500 if(!suppressEvent){
55501 this.fireEvent("columnlockchange", this, colIndex, value);
55505 getTotalLockedWidth : function(){
55506 var totalWidth = 0;
55507 for(var i = 0; i < this.config.length; i++){
55508 if(this.isLocked(i) && !this.isHidden(i)){
55509 this.totalWidth += this.getColumnWidth(i);
55515 getLockedCount : function(){
55516 for(var i = 0, len = this.config.length; i < len; i++){
55517 if(!this.isLocked(i)){
55524 * Returns the number of columns.
55527 getColumnCount : function(visibleOnly){
55528 if(visibleOnly === true){
55530 for(var i = 0, len = this.config.length; i < len; i++){
55531 if(!this.isHidden(i)){
55537 return this.config.length;
55541 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
55542 * @param {Function} fn
55543 * @param {Object} scope (optional)
55544 * @return {Array} result
55546 getColumnsBy : function(fn, scope){
55548 for(var i = 0, len = this.config.length; i < len; i++){
55549 var c = this.config[i];
55550 if(fn.call(scope||this, c, i) === true){
55558 * Returns true if the specified column is sortable.
55559 * @param {Number} col The column index
55560 * @return {Boolean}
55562 isSortable : function(col){
55563 if(typeof this.config[col].sortable == "undefined"){
55564 return this.defaultSortable;
55566 return this.config[col].sortable;
55570 * Returns the rendering (formatting) function defined for the column.
55571 * @param {Number} col The column index.
55572 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
55574 getRenderer : function(col){
55575 if(!this.config[col].renderer){
55576 return Roo.grid.ColumnModel.defaultRenderer;
55578 return this.config[col].renderer;
55582 * Sets the rendering (formatting) function for a column.
55583 * @param {Number} col The column index
55584 * @param {Function} fn The function to use to process the cell's raw data
55585 * to return HTML markup for the grid view. The render function is called with
55586 * the following parameters:<ul>
55587 * <li>Data value.</li>
55588 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
55589 * <li>css A CSS style string to apply to the table cell.</li>
55590 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
55591 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
55592 * <li>Row index</li>
55593 * <li>Column index</li>
55594 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
55596 setRenderer : function(col, fn){
55597 this.config[col].renderer = fn;
55601 * Returns the width for the specified column.
55602 * @param {Number} col The column index
55605 getColumnWidth : function(col){
55606 return this.config[col].width * 1 || this.defaultWidth;
55610 * Sets the width for a column.
55611 * @param {Number} col The column index
55612 * @param {Number} width The new width
55614 setColumnWidth : function(col, width, suppressEvent){
55615 this.config[col].width = width;
55616 this.totalWidth = null;
55617 if(!suppressEvent){
55618 this.fireEvent("widthchange", this, col, width);
55623 * Returns the total width of all columns.
55624 * @param {Boolean} includeHidden True to include hidden column widths
55627 getTotalWidth : function(includeHidden){
55628 if(!this.totalWidth){
55629 this.totalWidth = 0;
55630 for(var i = 0, len = this.config.length; i < len; i++){
55631 if(includeHidden || !this.isHidden(i)){
55632 this.totalWidth += this.getColumnWidth(i);
55636 return this.totalWidth;
55640 * Returns the header for the specified column.
55641 * @param {Number} col The column index
55644 getColumnHeader : function(col){
55645 return this.config[col].header;
55649 * Sets the header for a column.
55650 * @param {Number} col The column index
55651 * @param {String} header The new header
55653 setColumnHeader : function(col, header){
55654 this.config[col].header = header;
55655 this.fireEvent("headerchange", this, col, header);
55659 * Returns the tooltip for the specified column.
55660 * @param {Number} col The column index
55663 getColumnTooltip : function(col){
55664 return this.config[col].tooltip;
55667 * Sets the tooltip for a column.
55668 * @param {Number} col The column index
55669 * @param {String} tooltip The new tooltip
55671 setColumnTooltip : function(col, tooltip){
55672 this.config[col].tooltip = tooltip;
55676 * Returns the dataIndex for the specified column.
55677 * @param {Number} col The column index
55680 getDataIndex : function(col){
55681 return this.config[col].dataIndex;
55685 * Sets the dataIndex for a column.
55686 * @param {Number} col The column index
55687 * @param {Number} dataIndex The new dataIndex
55689 setDataIndex : function(col, dataIndex){
55690 this.config[col].dataIndex = dataIndex;
55696 * Returns true if the cell is editable.
55697 * @param {Number} colIndex The column index
55698 * @param {Number} rowIndex The row index
55699 * @return {Boolean}
55701 isCellEditable : function(colIndex, rowIndex){
55702 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55706 * Returns the editor defined for the cell/column.
55707 * return false or null to disable editing.
55708 * @param {Number} colIndex The column index
55709 * @param {Number} rowIndex The row index
55712 getCellEditor : function(colIndex, rowIndex){
55713 return this.config[colIndex].editor;
55717 * Sets if a column is editable.
55718 * @param {Number} col The column index
55719 * @param {Boolean} editable True if the column is editable
55721 setEditable : function(col, editable){
55722 this.config[col].editable = editable;
55727 * Returns true if the column is hidden.
55728 * @param {Number} colIndex The column index
55729 * @return {Boolean}
55731 isHidden : function(colIndex){
55732 return this.config[colIndex].hidden;
55737 * Returns true if the column width cannot be changed
55739 isFixed : function(colIndex){
55740 return this.config[colIndex].fixed;
55744 * Returns true if the column can be resized
55745 * @return {Boolean}
55747 isResizable : function(colIndex){
55748 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55751 * Sets if a column is hidden.
55752 * @param {Number} colIndex The column index
55753 * @param {Boolean} hidden True if the column is hidden
55755 setHidden : function(colIndex, hidden){
55756 this.config[colIndex].hidden = hidden;
55757 this.totalWidth = null;
55758 this.fireEvent("hiddenchange", this, colIndex, hidden);
55762 * Sets the editor for a column.
55763 * @param {Number} col The column index
55764 * @param {Object} editor The editor object
55766 setEditor : function(col, editor){
55767 this.config[col].editor = editor;
55771 Roo.grid.ColumnModel.defaultRenderer = function(value){
55772 if(typeof value == "string" && value.length < 1){
55778 // Alias for backwards compatibility
55779 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55782 * Ext JS Library 1.1.1
55783 * Copyright(c) 2006-2007, Ext JS, LLC.
55785 * Originally Released Under LGPL - original licence link has changed is not relivant.
55788 * <script type="text/javascript">
55792 * @class Roo.grid.AbstractSelectionModel
55793 * @extends Roo.util.Observable
55794 * Abstract base class for grid SelectionModels. It provides the interface that should be
55795 * implemented by descendant classes. This class should not be directly instantiated.
55798 Roo.grid.AbstractSelectionModel = function(){
55799 this.locked = false;
55800 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55803 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55804 /** @ignore Called by the grid automatically. Do not call directly. */
55805 init : function(grid){
55811 * Locks the selections.
55814 this.locked = true;
55818 * Unlocks the selections.
55820 unlock : function(){
55821 this.locked = false;
55825 * Returns true if the selections are locked.
55826 * @return {Boolean}
55828 isLocked : function(){
55829 return this.locked;
55833 * Ext JS Library 1.1.1
55834 * Copyright(c) 2006-2007, Ext JS, LLC.
55836 * Originally Released Under LGPL - original licence link has changed is not relivant.
55839 * <script type="text/javascript">
55842 * @extends Roo.grid.AbstractSelectionModel
55843 * @class Roo.grid.RowSelectionModel
55844 * The default SelectionModel used by {@link Roo.grid.Grid}.
55845 * It supports multiple selections and keyboard selection/navigation.
55847 * @param {Object} config
55849 Roo.grid.RowSelectionModel = function(config){
55850 Roo.apply(this, config);
55851 this.selections = new Roo.util.MixedCollection(false, function(o){
55856 this.lastActive = false;
55860 * @event selectionchange
55861 * Fires when the selection changes
55862 * @param {SelectionModel} this
55864 "selectionchange" : true,
55866 * @event afterselectionchange
55867 * Fires after the selection changes (eg. by key press or clicking)
55868 * @param {SelectionModel} this
55870 "afterselectionchange" : true,
55872 * @event beforerowselect
55873 * Fires when a row is selected being selected, return false to cancel.
55874 * @param {SelectionModel} this
55875 * @param {Number} rowIndex The selected index
55876 * @param {Boolean} keepExisting False if other selections will be cleared
55878 "beforerowselect" : true,
55881 * Fires when a row is selected.
55882 * @param {SelectionModel} this
55883 * @param {Number} rowIndex The selected index
55884 * @param {Roo.data.Record} r The record
55886 "rowselect" : true,
55888 * @event rowdeselect
55889 * Fires when a row is deselected.
55890 * @param {SelectionModel} this
55891 * @param {Number} rowIndex The selected index
55893 "rowdeselect" : true
55895 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55896 this.locked = false;
55899 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55901 * @cfg {Boolean} singleSelect
55902 * True to allow selection of only one row at a time (defaults to false)
55904 singleSelect : false,
55907 initEvents : function(){
55909 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55910 this.grid.on("mousedown", this.handleMouseDown, this);
55911 }else{ // allow click to work like normal
55912 this.grid.on("rowclick", this.handleDragableRowClick, this);
55915 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55916 "up" : function(e){
55918 this.selectPrevious(e.shiftKey);
55919 }else if(this.last !== false && this.lastActive !== false){
55920 var last = this.last;
55921 this.selectRange(this.last, this.lastActive-1);
55922 this.grid.getView().focusRow(this.lastActive);
55923 if(last !== false){
55927 this.selectFirstRow();
55929 this.fireEvent("afterselectionchange", this);
55931 "down" : function(e){
55933 this.selectNext(e.shiftKey);
55934 }else if(this.last !== false && this.lastActive !== false){
55935 var last = this.last;
55936 this.selectRange(this.last, this.lastActive+1);
55937 this.grid.getView().focusRow(this.lastActive);
55938 if(last !== false){
55942 this.selectFirstRow();
55944 this.fireEvent("afterselectionchange", this);
55949 var view = this.grid.view;
55950 view.on("refresh", this.onRefresh, this);
55951 view.on("rowupdated", this.onRowUpdated, this);
55952 view.on("rowremoved", this.onRemove, this);
55956 onRefresh : function(){
55957 var ds = this.grid.dataSource, i, v = this.grid.view;
55958 var s = this.selections;
55959 s.each(function(r){
55960 if((i = ds.indexOfId(r.id)) != -1){
55962 s.add(ds.getAt(i)); // updating the selection relate data
55970 onRemove : function(v, index, r){
55971 this.selections.remove(r);
55975 onRowUpdated : function(v, index, r){
55976 if(this.isSelected(r)){
55977 v.onRowSelect(index);
55983 * @param {Array} records The records to select
55984 * @param {Boolean} keepExisting (optional) True to keep existing selections
55986 selectRecords : function(records, keepExisting){
55988 this.clearSelections();
55990 var ds = this.grid.dataSource;
55991 for(var i = 0, len = records.length; i < len; i++){
55992 this.selectRow(ds.indexOf(records[i]), true);
55997 * Gets the number of selected rows.
56000 getCount : function(){
56001 return this.selections.length;
56005 * Selects the first row in the grid.
56007 selectFirstRow : function(){
56012 * Select the last row.
56013 * @param {Boolean} keepExisting (optional) True to keep existing selections
56015 selectLastRow : function(keepExisting){
56016 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
56020 * Selects the row immediately following the last selected row.
56021 * @param {Boolean} keepExisting (optional) True to keep existing selections
56023 selectNext : function(keepExisting){
56024 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
56025 this.selectRow(this.last+1, keepExisting);
56026 this.grid.getView().focusRow(this.last);
56031 * Selects the row that precedes the last selected row.
56032 * @param {Boolean} keepExisting (optional) True to keep existing selections
56034 selectPrevious : function(keepExisting){
56036 this.selectRow(this.last-1, keepExisting);
56037 this.grid.getView().focusRow(this.last);
56042 * Returns the selected records
56043 * @return {Array} Array of selected records
56045 getSelections : function(){
56046 return [].concat(this.selections.items);
56050 * Returns the first selected record.
56053 getSelected : function(){
56054 return this.selections.itemAt(0);
56059 * Clears all selections.
56061 clearSelections : function(fast){
56062 if(this.locked) return;
56064 var ds = this.grid.dataSource;
56065 var s = this.selections;
56066 s.each(function(r){
56067 this.deselectRow(ds.indexOfId(r.id));
56071 this.selections.clear();
56078 * Selects all rows.
56080 selectAll : function(){
56081 if(this.locked) return;
56082 this.selections.clear();
56083 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
56084 this.selectRow(i, true);
56089 * Returns True if there is a selection.
56090 * @return {Boolean}
56092 hasSelection : function(){
56093 return this.selections.length > 0;
56097 * Returns True if the specified row is selected.
56098 * @param {Number/Record} record The record or index of the record to check
56099 * @return {Boolean}
56101 isSelected : function(index){
56102 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
56103 return (r && this.selections.key(r.id) ? true : false);
56107 * Returns True if the specified record id is selected.
56108 * @param {String} id The id of record to check
56109 * @return {Boolean}
56111 isIdSelected : function(id){
56112 return (this.selections.key(id) ? true : false);
56116 handleMouseDown : function(e, t){
56117 var view = this.grid.getView(), rowIndex;
56118 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
56121 if(e.shiftKey && this.last !== false){
56122 var last = this.last;
56123 this.selectRange(last, rowIndex, e.ctrlKey);
56124 this.last = last; // reset the last
56125 view.focusRow(rowIndex);
56127 var isSelected = this.isSelected(rowIndex);
56128 if(e.button !== 0 && isSelected){
56129 view.focusRow(rowIndex);
56130 }else if(e.ctrlKey && isSelected){
56131 this.deselectRow(rowIndex);
56132 }else if(!isSelected){
56133 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
56134 view.focusRow(rowIndex);
56137 this.fireEvent("afterselectionchange", this);
56140 handleDragableRowClick : function(grid, rowIndex, e)
56142 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
56143 this.selectRow(rowIndex, false);
56144 grid.view.focusRow(rowIndex);
56145 this.fireEvent("afterselectionchange", this);
56150 * Selects multiple rows.
56151 * @param {Array} rows Array of the indexes of the row to select
56152 * @param {Boolean} keepExisting (optional) True to keep existing selections
56154 selectRows : function(rows, keepExisting){
56156 this.clearSelections();
56158 for(var i = 0, len = rows.length; i < len; i++){
56159 this.selectRow(rows[i], true);
56164 * Selects a range of rows. All rows in between startRow and endRow are also selected.
56165 * @param {Number} startRow The index of the first row in the range
56166 * @param {Number} endRow The index of the last row in the range
56167 * @param {Boolean} keepExisting (optional) True to retain existing selections
56169 selectRange : function(startRow, endRow, keepExisting){
56170 if(this.locked) return;
56172 this.clearSelections();
56174 if(startRow <= endRow){
56175 for(var i = startRow; i <= endRow; i++){
56176 this.selectRow(i, true);
56179 for(var i = startRow; i >= endRow; i--){
56180 this.selectRow(i, true);
56186 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
56187 * @param {Number} startRow The index of the first row in the range
56188 * @param {Number} endRow The index of the last row in the range
56190 deselectRange : function(startRow, endRow, preventViewNotify){
56191 if(this.locked) return;
56192 for(var i = startRow; i <= endRow; i++){
56193 this.deselectRow(i, preventViewNotify);
56199 * @param {Number} row The index of the row to select
56200 * @param {Boolean} keepExisting (optional) True to keep existing selections
56202 selectRow : function(index, keepExisting, preventViewNotify){
56203 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
56204 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
56205 if(!keepExisting || this.singleSelect){
56206 this.clearSelections();
56208 var r = this.grid.dataSource.getAt(index);
56209 this.selections.add(r);
56210 this.last = this.lastActive = index;
56211 if(!preventViewNotify){
56212 this.grid.getView().onRowSelect(index);
56214 this.fireEvent("rowselect", this, index, r);
56215 this.fireEvent("selectionchange", this);
56221 * @param {Number} row The index of the row to deselect
56223 deselectRow : function(index, preventViewNotify){
56224 if(this.locked) return;
56225 if(this.last == index){
56228 if(this.lastActive == index){
56229 this.lastActive = false;
56231 var r = this.grid.dataSource.getAt(index);
56232 this.selections.remove(r);
56233 if(!preventViewNotify){
56234 this.grid.getView().onRowDeselect(index);
56236 this.fireEvent("rowdeselect", this, index);
56237 this.fireEvent("selectionchange", this);
56241 restoreLast : function(){
56243 this.last = this._last;
56248 acceptsNav : function(row, col, cm){
56249 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56253 onEditorKey : function(field, e){
56254 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
56259 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56261 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56263 }else if(k == e.ENTER && !e.ctrlKey){
56267 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
56269 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
56271 }else if(k == e.ESC){
56275 g.startEditing(newCell[0], newCell[1]);
56280 * Ext JS Library 1.1.1
56281 * Copyright(c) 2006-2007, Ext JS, LLC.
56283 * Originally Released Under LGPL - original licence link has changed is not relivant.
56286 * <script type="text/javascript">
56289 * @class Roo.grid.CellSelectionModel
56290 * @extends Roo.grid.AbstractSelectionModel
56291 * This class provides the basic implementation for cell selection in a grid.
56293 * @param {Object} config The object containing the configuration of this model.
56294 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
56296 Roo.grid.CellSelectionModel = function(config){
56297 Roo.apply(this, config);
56299 this.selection = null;
56303 * @event beforerowselect
56304 * Fires before a cell is selected.
56305 * @param {SelectionModel} this
56306 * @param {Number} rowIndex The selected row index
56307 * @param {Number} colIndex The selected cell index
56309 "beforecellselect" : true,
56311 * @event cellselect
56312 * Fires when a cell is selected.
56313 * @param {SelectionModel} this
56314 * @param {Number} rowIndex The selected row index
56315 * @param {Number} colIndex The selected cell index
56317 "cellselect" : true,
56319 * @event selectionchange
56320 * Fires when the active selection changes.
56321 * @param {SelectionModel} this
56322 * @param {Object} selection null for no selection or an object (o) with two properties
56324 <li>o.record: the record object for the row the selection is in</li>
56325 <li>o.cell: An array of [rowIndex, columnIndex]</li>
56328 "selectionchange" : true,
56331 * Fires when the tab (or enter) was pressed on the last editable cell
56332 * You can use this to trigger add new row.
56333 * @param {SelectionModel} this
56337 * @event beforeeditnext
56338 * Fires before the next editable sell is made active
56339 * You can use this to skip to another cell or fire the tabend
56340 * if you set cell to false
56341 * @param {Object} eventdata object : { cell : [ row, col ] }
56343 "beforeeditnext" : true
56345 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
56348 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
56350 enter_is_tab: false,
56353 initEvents : function(){
56354 this.grid.on("mousedown", this.handleMouseDown, this);
56355 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
56356 var view = this.grid.view;
56357 view.on("refresh", this.onViewChange, this);
56358 view.on("rowupdated", this.onRowUpdated, this);
56359 view.on("beforerowremoved", this.clearSelections, this);
56360 view.on("beforerowsinserted", this.clearSelections, this);
56361 if(this.grid.isEditor){
56362 this.grid.on("beforeedit", this.beforeEdit, this);
56367 beforeEdit : function(e){
56368 this.select(e.row, e.column, false, true, e.record);
56372 onRowUpdated : function(v, index, r){
56373 if(this.selection && this.selection.record == r){
56374 v.onCellSelect(index, this.selection.cell[1]);
56379 onViewChange : function(){
56380 this.clearSelections(true);
56384 * Returns the currently selected cell,.
56385 * @return {Array} The selected cell (row, column) or null if none selected.
56387 getSelectedCell : function(){
56388 return this.selection ? this.selection.cell : null;
56392 * Clears all selections.
56393 * @param {Boolean} true to prevent the gridview from being notified about the change.
56395 clearSelections : function(preventNotify){
56396 var s = this.selection;
56398 if(preventNotify !== true){
56399 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
56401 this.selection = null;
56402 this.fireEvent("selectionchange", this, null);
56407 * Returns true if there is a selection.
56408 * @return {Boolean}
56410 hasSelection : function(){
56411 return this.selection ? true : false;
56415 handleMouseDown : function(e, t){
56416 var v = this.grid.getView();
56417 if(this.isLocked()){
56420 var row = v.findRowIndex(t);
56421 var cell = v.findCellIndex(t);
56422 if(row !== false && cell !== false){
56423 this.select(row, cell);
56429 * @param {Number} rowIndex
56430 * @param {Number} collIndex
56432 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
56433 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
56434 this.clearSelections();
56435 r = r || this.grid.dataSource.getAt(rowIndex);
56438 cell : [rowIndex, colIndex]
56440 if(!preventViewNotify){
56441 var v = this.grid.getView();
56442 v.onCellSelect(rowIndex, colIndex);
56443 if(preventFocus !== true){
56444 v.focusCell(rowIndex, colIndex);
56447 this.fireEvent("cellselect", this, rowIndex, colIndex);
56448 this.fireEvent("selectionchange", this, this.selection);
56453 isSelectable : function(rowIndex, colIndex, cm){
56454 return !cm.isHidden(colIndex);
56458 handleKeyDown : function(e){
56459 //Roo.log('Cell Sel Model handleKeyDown');
56460 if(!e.isNavKeyPress()){
56463 var g = this.grid, s = this.selection;
56466 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
56468 this.select(cell[0], cell[1]);
56473 var walk = function(row, col, step){
56474 return g.walkCells(row, col, step, sm.isSelectable, sm);
56476 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
56483 // handled by onEditorKey
56484 if (g.isEditor && g.editing) {
56488 newCell = walk(r, c-1, -1);
56490 newCell = walk(r, c+1, 1);
56495 newCell = walk(r+1, c, 1);
56499 newCell = walk(r-1, c, -1);
56503 newCell = walk(r, c+1, 1);
56507 newCell = walk(r, c-1, -1);
56512 if(g.isEditor && !g.editing){
56513 g.startEditing(r, c);
56522 this.select(newCell[0], newCell[1]);
56528 acceptsNav : function(row, col, cm){
56529 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56533 * @param {Number} field (not used) - as it's normally used as a listener
56534 * @param {Number} e - event - fake it by using
56536 * var e = Roo.EventObjectImpl.prototype;
56537 * e.keyCode = e.TAB
56541 onEditorKey : function(field, e){
56543 var k = e.getKey(),
56546 ed = g.activeEditor,
56548 ///Roo.log('onEditorKey' + k);
56551 if (this.enter_is_tab && k == e.ENTER) {
56557 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56559 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56565 } else if(k == e.ENTER && !e.ctrlKey){
56568 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56570 } else if(k == e.ESC){
56575 var ecall = { cell : newCell, forward : forward };
56576 this.fireEvent('beforeeditnext', ecall );
56577 newCell = ecall.cell;
56578 forward = ecall.forward;
56582 //Roo.log('next cell after edit');
56583 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
56584 } else if (forward) {
56585 // tabbed past last
56586 this.fireEvent.defer(100, this, ['tabend',this]);
56591 * Ext JS Library 1.1.1
56592 * Copyright(c) 2006-2007, Ext JS, LLC.
56594 * Originally Released Under LGPL - original licence link has changed is not relivant.
56597 * <script type="text/javascript">
56601 * @class Roo.grid.EditorGrid
56602 * @extends Roo.grid.Grid
56603 * Class for creating and editable grid.
56604 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56605 * The container MUST have some type of size defined for the grid to fill. The container will be
56606 * automatically set to position relative if it isn't already.
56607 * @param {Object} dataSource The data model to bind to
56608 * @param {Object} colModel The column model with info about this grid's columns
56610 Roo.grid.EditorGrid = function(container, config){
56611 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
56612 this.getGridEl().addClass("xedit-grid");
56614 if(!this.selModel){
56615 this.selModel = new Roo.grid.CellSelectionModel();
56618 this.activeEditor = null;
56622 * @event beforeedit
56623 * Fires before cell editing is triggered. The edit event object has the following properties <br />
56624 * <ul style="padding:5px;padding-left:16px;">
56625 * <li>grid - This grid</li>
56626 * <li>record - The record being edited</li>
56627 * <li>field - The field name being edited</li>
56628 * <li>value - The value for the field being edited.</li>
56629 * <li>row - The grid row index</li>
56630 * <li>column - The grid column index</li>
56631 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56633 * @param {Object} e An edit event (see above for description)
56635 "beforeedit" : true,
56638 * Fires after a cell is edited. <br />
56639 * <ul style="padding:5px;padding-left:16px;">
56640 * <li>grid - This grid</li>
56641 * <li>record - The record being edited</li>
56642 * <li>field - The field name being edited</li>
56643 * <li>value - The value being set</li>
56644 * <li>originalValue - The original value for the field, before the edit.</li>
56645 * <li>row - The grid row index</li>
56646 * <li>column - The grid column index</li>
56648 * @param {Object} e An edit event (see above for description)
56650 "afteredit" : true,
56652 * @event validateedit
56653 * Fires after a cell is edited, but before the value is set in the record.
56654 * You can use this to modify the value being set in the field, Return false
56655 * to cancel the change. The edit event object has the following properties <br />
56656 * <ul style="padding:5px;padding-left:16px;">
56657 * <li>editor - This editor</li>
56658 * <li>grid - This grid</li>
56659 * <li>record - The record being edited</li>
56660 * <li>field - The field name being edited</li>
56661 * <li>value - The value being set</li>
56662 * <li>originalValue - The original value for the field, before the edit.</li>
56663 * <li>row - The grid row index</li>
56664 * <li>column - The grid column index</li>
56665 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56667 * @param {Object} e An edit event (see above for description)
56669 "validateedit" : true
56671 this.on("bodyscroll", this.stopEditing, this);
56672 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56675 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56677 * @cfg {Number} clicksToEdit
56678 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56685 trackMouseOver: false, // causes very odd FF errors
56687 onCellDblClick : function(g, row, col){
56688 this.startEditing(row, col);
56691 onEditComplete : function(ed, value, startValue){
56692 this.editing = false;
56693 this.activeEditor = null;
56694 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56696 var field = this.colModel.getDataIndex(ed.col);
56701 originalValue: startValue,
56708 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56711 if(String(value) !== String(startValue)){
56713 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56714 r.set(field, e.value);
56715 // if we are dealing with a combo box..
56716 // then we also set the 'name' colum to be the displayField
56717 if (ed.field.displayField && ed.field.name) {
56718 r.set(ed.field.name, ed.field.el.dom.value);
56721 delete e.cancel; //?? why!!!
56722 this.fireEvent("afteredit", e);
56725 this.fireEvent("afteredit", e); // always fire it!
56727 this.view.focusCell(ed.row, ed.col);
56731 * Starts editing the specified for the specified row/column
56732 * @param {Number} rowIndex
56733 * @param {Number} colIndex
56735 startEditing : function(row, col){
56736 this.stopEditing();
56737 if(this.colModel.isCellEditable(col, row)){
56738 this.view.ensureVisible(row, col, true);
56740 var r = this.dataSource.getAt(row);
56741 var field = this.colModel.getDataIndex(col);
56742 var cell = Roo.get(this.view.getCell(row,col));
56747 value: r.data[field],
56752 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56753 this.editing = true;
56754 var ed = this.colModel.getCellEditor(col, row);
56760 ed.render(ed.parentEl || document.body);
56766 (function(){ // complex but required for focus issues in safari, ie and opera
56770 ed.on("complete", this.onEditComplete, this, {single: true});
56771 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56772 this.activeEditor = ed;
56773 var v = r.data[field];
56774 ed.startEdit(this.view.getCell(row, col), v);
56775 // combo's with 'displayField and name set
56776 if (ed.field.displayField && ed.field.name) {
56777 ed.field.el.dom.value = r.data[ed.field.name];
56781 }).defer(50, this);
56787 * Stops any active editing
56789 stopEditing : function(){
56790 if(this.activeEditor){
56791 this.activeEditor.completeEdit();
56793 this.activeEditor = null;
56797 * Called to get grid's drag proxy text, by default returns this.ddText.
56800 getDragDropText : function(){
56801 var count = this.selModel.getSelectedCell() ? 1 : 0;
56802 return String.format(this.ddText, count, count == 1 ? '' : 's');
56807 * Ext JS Library 1.1.1
56808 * Copyright(c) 2006-2007, Ext JS, LLC.
56810 * Originally Released Under LGPL - original licence link has changed is not relivant.
56813 * <script type="text/javascript">
56816 // private - not really -- you end up using it !
56817 // This is a support class used internally by the Grid components
56820 * @class Roo.grid.GridEditor
56821 * @extends Roo.Editor
56822 * Class for creating and editable grid elements.
56823 * @param {Object} config any settings (must include field)
56825 Roo.grid.GridEditor = function(field, config){
56826 if (!config && field.field) {
56828 field = Roo.factory(config.field, Roo.form);
56830 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56831 field.monitorTab = false;
56834 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56837 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56840 alignment: "tl-tl",
56843 cls: "x-small-editor x-grid-editor",
56848 * Ext JS Library 1.1.1
56849 * Copyright(c) 2006-2007, Ext JS, LLC.
56851 * Originally Released Under LGPL - original licence link has changed is not relivant.
56854 * <script type="text/javascript">
56859 Roo.grid.PropertyRecord = Roo.data.Record.create([
56860 {name:'name',type:'string'}, 'value'
56864 Roo.grid.PropertyStore = function(grid, source){
56866 this.store = new Roo.data.Store({
56867 recordType : Roo.grid.PropertyRecord
56869 this.store.on('update', this.onUpdate, this);
56871 this.setSource(source);
56873 Roo.grid.PropertyStore.superclass.constructor.call(this);
56878 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56879 setSource : function(o){
56881 this.store.removeAll();
56884 if(this.isEditableValue(o[k])){
56885 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56888 this.store.loadRecords({records: data}, {}, true);
56891 onUpdate : function(ds, record, type){
56892 if(type == Roo.data.Record.EDIT){
56893 var v = record.data['value'];
56894 var oldValue = record.modified['value'];
56895 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56896 this.source[record.id] = v;
56898 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56905 getProperty : function(row){
56906 return this.store.getAt(row);
56909 isEditableValue: function(val){
56910 if(val && val instanceof Date){
56912 }else if(typeof val == 'object' || typeof val == 'function'){
56918 setValue : function(prop, value){
56919 this.source[prop] = value;
56920 this.store.getById(prop).set('value', value);
56923 getSource : function(){
56924 return this.source;
56928 Roo.grid.PropertyColumnModel = function(grid, store){
56931 g.PropertyColumnModel.superclass.constructor.call(this, [
56932 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56933 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56935 this.store = store;
56936 this.bselect = Roo.DomHelper.append(document.body, {
56937 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56938 {tag: 'option', value: 'true', html: 'true'},
56939 {tag: 'option', value: 'false', html: 'false'}
56942 Roo.id(this.bselect);
56945 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56946 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56947 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56948 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56949 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56951 this.renderCellDelegate = this.renderCell.createDelegate(this);
56952 this.renderPropDelegate = this.renderProp.createDelegate(this);
56955 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56959 valueText : 'Value',
56961 dateFormat : 'm/j/Y',
56964 renderDate : function(dateVal){
56965 return dateVal.dateFormat(this.dateFormat);
56968 renderBool : function(bVal){
56969 return bVal ? 'true' : 'false';
56972 isCellEditable : function(colIndex, rowIndex){
56973 return colIndex == 1;
56976 getRenderer : function(col){
56978 this.renderCellDelegate : this.renderPropDelegate;
56981 renderProp : function(v){
56982 return this.getPropertyName(v);
56985 renderCell : function(val){
56987 if(val instanceof Date){
56988 rv = this.renderDate(val);
56989 }else if(typeof val == 'boolean'){
56990 rv = this.renderBool(val);
56992 return Roo.util.Format.htmlEncode(rv);
56995 getPropertyName : function(name){
56996 var pn = this.grid.propertyNames;
56997 return pn && pn[name] ? pn[name] : name;
57000 getCellEditor : function(colIndex, rowIndex){
57001 var p = this.store.getProperty(rowIndex);
57002 var n = p.data['name'], val = p.data['value'];
57004 if(typeof(this.grid.customEditors[n]) == 'string'){
57005 return this.editors[this.grid.customEditors[n]];
57007 if(typeof(this.grid.customEditors[n]) != 'undefined'){
57008 return this.grid.customEditors[n];
57010 if(val instanceof Date){
57011 return this.editors['date'];
57012 }else if(typeof val == 'number'){
57013 return this.editors['number'];
57014 }else if(typeof val == 'boolean'){
57015 return this.editors['boolean'];
57017 return this.editors['string'];
57023 * @class Roo.grid.PropertyGrid
57024 * @extends Roo.grid.EditorGrid
57025 * This class represents the interface of a component based property grid control.
57026 * <br><br>Usage:<pre><code>
57027 var grid = new Roo.grid.PropertyGrid("my-container-id", {
57035 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57036 * The container MUST have some type of size defined for the grid to fill. The container will be
57037 * automatically set to position relative if it isn't already.
57038 * @param {Object} config A config object that sets properties on this grid.
57040 Roo.grid.PropertyGrid = function(container, config){
57041 config = config || {};
57042 var store = new Roo.grid.PropertyStore(this);
57043 this.store = store;
57044 var cm = new Roo.grid.PropertyColumnModel(this, store);
57045 store.store.sort('name', 'ASC');
57046 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
57049 enableColLock:false,
57050 enableColumnMove:false,
57052 trackMouseOver: false,
57055 this.getGridEl().addClass('x-props-grid');
57056 this.lastEditRow = null;
57057 this.on('columnresize', this.onColumnResize, this);
57060 * @event beforepropertychange
57061 * Fires before a property changes (return false to stop?)
57062 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57063 * @param {String} id Record Id
57064 * @param {String} newval New Value
57065 * @param {String} oldval Old Value
57067 "beforepropertychange": true,
57069 * @event propertychange
57070 * Fires after a property changes
57071 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57072 * @param {String} id Record Id
57073 * @param {String} newval New Value
57074 * @param {String} oldval Old Value
57076 "propertychange": true
57078 this.customEditors = this.customEditors || {};
57080 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
57083 * @cfg {Object} customEditors map of colnames=> custom editors.
57084 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
57085 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
57086 * false disables editing of the field.
57090 * @cfg {Object} propertyNames map of property Names to their displayed value
57093 render : function(){
57094 Roo.grid.PropertyGrid.superclass.render.call(this);
57095 this.autoSize.defer(100, this);
57098 autoSize : function(){
57099 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
57101 this.view.fitColumns();
57105 onColumnResize : function(){
57106 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
57110 * Sets the data for the Grid
57111 * accepts a Key => Value object of all the elements avaiable.
57112 * @param {Object} data to appear in grid.
57114 setSource : function(source){
57115 this.store.setSource(source);
57119 * Gets all the data from the grid.
57120 * @return {Object} data data stored in grid
57122 getSource : function(){
57123 return this.store.getSource();
57132 * @class Roo.grid.Calendar
57133 * @extends Roo.util.Grid
57134 * This class extends the Grid to provide a calendar widget
57135 * <br><br>Usage:<pre><code>
57136 var grid = new Roo.grid.Calendar("my-container-id", {
57139 selModel: mySelectionModel,
57140 autoSizeColumns: true,
57141 monitorWindowResize: false,
57142 trackMouseOver: true
57143 eventstore : real data store..
57149 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57150 * The container MUST have some type of size defined for the grid to fill. The container will be
57151 * automatically set to position relative if it isn't already.
57152 * @param {Object} config A config object that sets properties on this grid.
57154 Roo.grid.Calendar = function(container, config){
57155 // initialize the container
57156 this.container = Roo.get(container);
57157 this.container.update("");
57158 this.container.setStyle("overflow", "hidden");
57159 this.container.addClass('x-grid-container');
57161 this.id = this.container.id;
57163 Roo.apply(this, config);
57164 // check and correct shorthanded configs
57168 for (var r = 0;r < 6;r++) {
57171 for (var c =0;c < 7;c++) {
57175 if (this.eventStore) {
57176 this.eventStore= Roo.factory(this.eventStore, Roo.data);
57177 this.eventStore.on('load',this.onLoad, this);
57178 this.eventStore.on('beforeload',this.clearEvents, this);
57182 this.dataSource = new Roo.data.Store({
57183 proxy: new Roo.data.MemoryProxy(rows),
57184 reader: new Roo.data.ArrayReader({}, [
57185 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
57188 this.dataSource.load();
57189 this.ds = this.dataSource;
57190 this.ds.xmodule = this.xmodule || false;
57193 var cellRender = function(v,x,r)
57195 return String.format(
57196 '<div class="fc-day fc-widget-content"><div>' +
57197 '<div class="fc-event-container"></div>' +
57198 '<div class="fc-day-number">{0}</div>'+
57200 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
57201 '</div></div>', v);
57206 this.colModel = new Roo.grid.ColumnModel( [
57208 xtype: 'ColumnModel',
57210 dataIndex : 'weekday0',
57212 renderer : cellRender
57215 xtype: 'ColumnModel',
57217 dataIndex : 'weekday1',
57219 renderer : cellRender
57222 xtype: 'ColumnModel',
57224 dataIndex : 'weekday2',
57225 header : 'Tuesday',
57226 renderer : cellRender
57229 xtype: 'ColumnModel',
57231 dataIndex : 'weekday3',
57232 header : 'Wednesday',
57233 renderer : cellRender
57236 xtype: 'ColumnModel',
57238 dataIndex : 'weekday4',
57239 header : 'Thursday',
57240 renderer : cellRender
57243 xtype: 'ColumnModel',
57245 dataIndex : 'weekday5',
57247 renderer : cellRender
57250 xtype: 'ColumnModel',
57252 dataIndex : 'weekday6',
57253 header : 'Saturday',
57254 renderer : cellRender
57257 this.cm = this.colModel;
57258 this.cm.xmodule = this.xmodule || false;
57262 //this.selModel = new Roo.grid.CellSelectionModel();
57263 //this.sm = this.selModel;
57264 //this.selModel.init(this);
57268 this.container.setWidth(this.width);
57272 this.container.setHeight(this.height);
57279 * The raw click event for the entire grid.
57280 * @param {Roo.EventObject} e
57285 * The raw dblclick event for the entire grid.
57286 * @param {Roo.EventObject} e
57290 * @event contextmenu
57291 * The raw contextmenu event for the entire grid.
57292 * @param {Roo.EventObject} e
57294 "contextmenu" : true,
57297 * The raw mousedown event for the entire grid.
57298 * @param {Roo.EventObject} e
57300 "mousedown" : true,
57303 * The raw mouseup event for the entire grid.
57304 * @param {Roo.EventObject} e
57309 * The raw mouseover event for the entire grid.
57310 * @param {Roo.EventObject} e
57312 "mouseover" : true,
57315 * The raw mouseout event for the entire grid.
57316 * @param {Roo.EventObject} e
57321 * The raw keypress event for the entire grid.
57322 * @param {Roo.EventObject} e
57327 * The raw keydown event for the entire grid.
57328 * @param {Roo.EventObject} e
57336 * Fires when a cell is clicked
57337 * @param {Grid} this
57338 * @param {Number} rowIndex
57339 * @param {Number} columnIndex
57340 * @param {Roo.EventObject} e
57342 "cellclick" : true,
57344 * @event celldblclick
57345 * Fires when a cell is double clicked
57346 * @param {Grid} this
57347 * @param {Number} rowIndex
57348 * @param {Number} columnIndex
57349 * @param {Roo.EventObject} e
57351 "celldblclick" : true,
57354 * Fires when a row is clicked
57355 * @param {Grid} this
57356 * @param {Number} rowIndex
57357 * @param {Roo.EventObject} e
57361 * @event rowdblclick
57362 * Fires when a row is double clicked
57363 * @param {Grid} this
57364 * @param {Number} rowIndex
57365 * @param {Roo.EventObject} e
57367 "rowdblclick" : true,
57369 * @event headerclick
57370 * Fires when a header is clicked
57371 * @param {Grid} this
57372 * @param {Number} columnIndex
57373 * @param {Roo.EventObject} e
57375 "headerclick" : true,
57377 * @event headerdblclick
57378 * Fires when a header cell is double clicked
57379 * @param {Grid} this
57380 * @param {Number} columnIndex
57381 * @param {Roo.EventObject} e
57383 "headerdblclick" : true,
57385 * @event rowcontextmenu
57386 * Fires when a row is right clicked
57387 * @param {Grid} this
57388 * @param {Number} rowIndex
57389 * @param {Roo.EventObject} e
57391 "rowcontextmenu" : true,
57393 * @event cellcontextmenu
57394 * Fires when a cell is right clicked
57395 * @param {Grid} this
57396 * @param {Number} rowIndex
57397 * @param {Number} cellIndex
57398 * @param {Roo.EventObject} e
57400 "cellcontextmenu" : true,
57402 * @event headercontextmenu
57403 * Fires when a header is right clicked
57404 * @param {Grid} this
57405 * @param {Number} columnIndex
57406 * @param {Roo.EventObject} e
57408 "headercontextmenu" : true,
57410 * @event bodyscroll
57411 * Fires when the body element is scrolled
57412 * @param {Number} scrollLeft
57413 * @param {Number} scrollTop
57415 "bodyscroll" : true,
57417 * @event columnresize
57418 * Fires when the user resizes a column
57419 * @param {Number} columnIndex
57420 * @param {Number} newSize
57422 "columnresize" : true,
57424 * @event columnmove
57425 * Fires when the user moves a column
57426 * @param {Number} oldIndex
57427 * @param {Number} newIndex
57429 "columnmove" : true,
57432 * Fires when row(s) start being dragged
57433 * @param {Grid} this
57434 * @param {Roo.GridDD} dd The drag drop object
57435 * @param {event} e The raw browser event
57437 "startdrag" : true,
57440 * Fires when a drag operation is complete
57441 * @param {Grid} this
57442 * @param {Roo.GridDD} dd The drag drop object
57443 * @param {event} e The raw browser event
57448 * Fires when dragged row(s) are dropped on a valid DD target
57449 * @param {Grid} this
57450 * @param {Roo.GridDD} dd The drag drop object
57451 * @param {String} targetId The target drag drop object
57452 * @param {event} e The raw browser event
57457 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
57458 * @param {Grid} this
57459 * @param {Roo.GridDD} dd The drag drop object
57460 * @param {String} targetId The target drag drop object
57461 * @param {event} e The raw browser event
57466 * Fires when the dragged row(s) first cross another DD target while being dragged
57467 * @param {Grid} this
57468 * @param {Roo.GridDD} dd The drag drop object
57469 * @param {String} targetId The target drag drop object
57470 * @param {event} e The raw browser event
57472 "dragenter" : true,
57475 * Fires when the dragged row(s) leave another DD target while being dragged
57476 * @param {Grid} this
57477 * @param {Roo.GridDD} dd The drag drop object
57478 * @param {String} targetId The target drag drop object
57479 * @param {event} e The raw browser event
57484 * Fires when a row is rendered, so you can change add a style to it.
57485 * @param {GridView} gridview The grid view
57486 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
57492 * Fires when the grid is rendered
57493 * @param {Grid} grid
57498 * Fires when a date is selected
57499 * @param {DatePicker} this
57500 * @param {Date} date The selected date
57504 * @event monthchange
57505 * Fires when the displayed month changes
57506 * @param {DatePicker} this
57507 * @param {Date} date The selected month
57509 'monthchange': true,
57511 * @event evententer
57512 * Fires when mouse over an event
57513 * @param {Calendar} this
57514 * @param {event} Event
57516 'evententer': true,
57518 * @event eventleave
57519 * Fires when the mouse leaves an
57520 * @param {Calendar} this
57523 'eventleave': true,
57525 * @event eventclick
57526 * Fires when the mouse click an
57527 * @param {Calendar} this
57530 'eventclick': true,
57532 * @event eventrender
57533 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
57534 * @param {Calendar} this
57535 * @param {data} data to be modified
57537 'eventrender': true
57541 Roo.grid.Grid.superclass.constructor.call(this);
57542 this.on('render', function() {
57543 this.view.el.addClass('x-grid-cal');
57545 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
57549 if (!Roo.grid.Calendar.style) {
57550 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
57553 '.x-grid-cal .x-grid-col' : {
57554 height: 'auto !important',
57555 'vertical-align': 'top'
57557 '.x-grid-cal .fc-event-hori' : {
57568 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
57570 * @cfg {Store} eventStore The store that loads events.
57575 activeDate : false,
57578 monitorWindowResize : false,
57581 resizeColumns : function() {
57582 var col = (this.view.el.getWidth() / 7) - 3;
57583 // loop through cols, and setWidth
57584 for(var i =0 ; i < 7 ; i++){
57585 this.cm.setColumnWidth(i, col);
57588 setDate :function(date) {
57590 Roo.log('setDate?');
57592 this.resizeColumns();
57593 var vd = this.activeDate;
57594 this.activeDate = date;
57595 // if(vd && this.el){
57596 // var t = date.getTime();
57597 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
57598 // Roo.log('using add remove');
57600 // this.fireEvent('monthchange', this, date);
57602 // this.cells.removeClass("fc-state-highlight");
57603 // this.cells.each(function(c){
57604 // if(c.dateValue == t){
57605 // c.addClass("fc-state-highlight");
57606 // setTimeout(function(){
57607 // try{c.dom.firstChild.focus();}catch(e){}
57617 var days = date.getDaysInMonth();
57619 var firstOfMonth = date.getFirstDateOfMonth();
57620 var startingPos = firstOfMonth.getDay()-this.startDay;
57622 if(startingPos < this.startDay){
57626 var pm = date.add(Date.MONTH, -1);
57627 var prevStart = pm.getDaysInMonth()-startingPos;
57631 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57633 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57634 //this.cells.addClassOnOver('fc-state-hover');
57636 var cells = this.cells.elements;
57637 var textEls = this.textNodes;
57639 //Roo.each(cells, function(cell){
57640 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57643 days += startingPos;
57645 // convert everything to numbers so it's fast
57646 var day = 86400000;
57647 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57650 //Roo.log(prevStart);
57652 var today = new Date().clearTime().getTime();
57653 var sel = date.clearTime().getTime();
57654 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57655 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57656 var ddMatch = this.disabledDatesRE;
57657 var ddText = this.disabledDatesText;
57658 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57659 var ddaysText = this.disabledDaysText;
57660 var format = this.format;
57662 var setCellClass = function(cal, cell){
57664 //Roo.log('set Cell Class');
57666 var t = d.getTime();
57671 cell.dateValue = t;
57673 cell.className += " fc-today";
57674 cell.className += " fc-state-highlight";
57675 cell.title = cal.todayText;
57678 // disable highlight in other month..
57679 cell.className += " fc-state-highlight";
57684 //cell.className = " fc-state-disabled";
57685 cell.title = cal.minText;
57689 //cell.className = " fc-state-disabled";
57690 cell.title = cal.maxText;
57694 if(ddays.indexOf(d.getDay()) != -1){
57695 // cell.title = ddaysText;
57696 // cell.className = " fc-state-disabled";
57699 if(ddMatch && format){
57700 var fvalue = d.dateFormat(format);
57701 if(ddMatch.test(fvalue)){
57702 cell.title = ddText.replace("%0", fvalue);
57703 cell.className = " fc-state-disabled";
57707 if (!cell.initialClassName) {
57708 cell.initialClassName = cell.dom.className;
57711 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57716 for(; i < startingPos; i++) {
57717 cells[i].dayName = (++prevStart);
57718 Roo.log(textEls[i]);
57719 d.setDate(d.getDate()+1);
57721 //cells[i].className = "fc-past fc-other-month";
57722 setCellClass(this, cells[i]);
57727 for(; i < days; i++){
57728 intDay = i - startingPos + 1;
57729 cells[i].dayName = (intDay);
57730 d.setDate(d.getDate()+1);
57732 cells[i].className = ''; // "x-date-active";
57733 setCellClass(this, cells[i]);
57737 for(; i < 42; i++) {
57738 //textEls[i].innerHTML = (++extraDays);
57740 d.setDate(d.getDate()+1);
57741 cells[i].dayName = (++extraDays);
57742 cells[i].className = "fc-future fc-other-month";
57743 setCellClass(this, cells[i]);
57746 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57748 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57750 // this will cause all the cells to mis
57753 for (var r = 0;r < 6;r++) {
57754 for (var c =0;c < 7;c++) {
57755 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57759 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57760 for(i=0;i<cells.length;i++) {
57762 this.cells.elements[i].dayName = cells[i].dayName ;
57763 this.cells.elements[i].className = cells[i].className;
57764 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57765 this.cells.elements[i].title = cells[i].title ;
57766 this.cells.elements[i].dateValue = cells[i].dateValue ;
57772 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57773 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57775 ////if(totalRows != 6){
57776 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57777 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57780 this.fireEvent('monthchange', this, date);
57785 * Returns the grid's SelectionModel.
57786 * @return {SelectionModel}
57788 getSelectionModel : function(){
57789 if(!this.selModel){
57790 this.selModel = new Roo.grid.CellSelectionModel();
57792 return this.selModel;
57796 this.eventStore.load()
57802 findCell : function(dt) {
57803 dt = dt.clearTime().getTime();
57805 this.cells.each(function(c){
57806 //Roo.log("check " +c.dateValue + '?=' + dt);
57807 if(c.dateValue == dt){
57817 findCells : function(rec) {
57818 var s = rec.data.start_dt.clone().clearTime().getTime();
57820 var e= rec.data.end_dt.clone().clearTime().getTime();
57823 this.cells.each(function(c){
57824 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57826 if(c.dateValue > e){
57829 if(c.dateValue < s){
57838 findBestRow: function(cells)
57842 for (var i =0 ; i < cells.length;i++) {
57843 ret = Math.max(cells[i].rows || 0,ret);
57850 addItem : function(rec)
57852 // look for vertical location slot in
57853 var cells = this.findCells(rec);
57855 rec.row = this.findBestRow(cells);
57857 // work out the location.
57861 for(var i =0; i < cells.length; i++) {
57869 if (crow.start.getY() == cells[i].getY()) {
57871 crow.end = cells[i];
57887 for (var i = 0; i < cells.length;i++) {
57888 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57895 clearEvents: function() {
57897 if (!this.eventStore.getCount()) {
57900 // reset number of rows in cells.
57901 Roo.each(this.cells.elements, function(c){
57905 this.eventStore.each(function(e) {
57906 this.clearEvent(e);
57911 clearEvent : function(ev)
57914 Roo.each(ev.els, function(el) {
57915 el.un('mouseenter' ,this.onEventEnter, this);
57916 el.un('mouseleave' ,this.onEventLeave, this);
57924 renderEvent : function(ev,ctr) {
57926 ctr = this.view.el.select('.fc-event-container',true).first();
57930 this.clearEvent(ev);
57936 var cells = ev.cells;
57937 var rows = ev.rows;
57938 this.fireEvent('eventrender', this, ev);
57940 for(var i =0; i < rows.length; i++) {
57944 cls += ' fc-event-start';
57946 if ((i+1) == rows.length) {
57947 cls += ' fc-event-end';
57950 //Roo.log(ev.data);
57951 // how many rows should it span..
57952 var cg = this.eventTmpl.append(ctr,Roo.apply({
57955 }, ev.data) , true);
57958 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57959 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57960 cg.on('click', this.onEventClick, this, ev);
57964 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57965 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57968 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57969 cg.setWidth(ebox.right - sbox.x -2);
57973 renderEvents: function()
57975 // first make sure there is enough space..
57977 if (!this.eventTmpl) {
57978 this.eventTmpl = new Roo.Template(
57979 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57980 '<div class="fc-event-inner">' +
57981 '<span class="fc-event-time">{time}</span>' +
57982 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57984 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57992 this.cells.each(function(c) {
57993 //Roo.log(c.select('.fc-day-content div',true).first());
57994 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57997 var ctr = this.view.el.select('.fc-event-container',true).first();
58000 this.eventStore.each(function(ev){
58002 this.renderEvent(ev);
58006 this.view.layout();
58010 onEventEnter: function (e, el,event,d) {
58011 this.fireEvent('evententer', this, el, event);
58014 onEventLeave: function (e, el,event,d) {
58015 this.fireEvent('eventleave', this, el, event);
58018 onEventClick: function (e, el,event,d) {
58019 this.fireEvent('eventclick', this, el, event);
58022 onMonthChange: function () {
58026 onLoad: function () {
58028 //Roo.log('calendar onload');
58030 if(this.eventStore.getCount() > 0){
58034 this.eventStore.each(function(d){
58039 if (typeof(add.end_dt) == 'undefined') {
58040 Roo.log("Missing End time in calendar data: ");
58044 if (typeof(add.start_dt) == 'undefined') {
58045 Roo.log("Missing Start time in calendar data: ");
58049 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
58050 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
58051 add.id = add.id || d.id;
58052 add.title = add.title || '??';
58060 this.renderEvents();
58070 render : function ()
58074 if (!this.view.el.hasClass('course-timesheet')) {
58075 this.view.el.addClass('course-timesheet');
58077 if (this.tsStyle) {
58082 Roo.log(_this.grid.view.el.getWidth());
58085 this.tsStyle = Roo.util.CSS.createStyleSheet({
58086 '.course-timesheet .x-grid-row' : {
58089 '.x-grid-row td' : {
58090 'vertical-align' : 0
58092 '.course-edit-link' : {
58094 'text-overflow' : 'ellipsis',
58095 'overflow' : 'hidden',
58096 'white-space' : 'nowrap',
58097 'cursor' : 'pointer'
58102 '.de-act-sup-link' : {
58103 'color' : 'purple',
58104 'text-decoration' : 'line-through'
58108 'text-decoration' : 'line-through'
58110 '.course-timesheet .course-highlight' : {
58111 'border-top-style': 'dashed !important',
58112 'border-bottom-bottom': 'dashed !important'
58114 '.course-timesheet .course-item' : {
58115 'font-family' : 'tahoma, arial, helvetica',
58116 'font-size' : '11px',
58117 'overflow' : 'hidden',
58118 'padding-left' : '10px',
58119 'padding-right' : '10px',
58120 'padding-top' : '10px'
58128 monitorWindowResize : false,
58129 cellrenderer : function(v,x,r)
58134 xtype: 'CellSelectionModel',
58141 beforeload : function (_self, options)
58143 options.params = options.params || {};
58144 options.params._month = _this.monthField.getValue();
58145 options.params.limit = 9999;
58146 options.params['sort'] = 'when_dt';
58147 options.params['dir'] = 'ASC';
58148 this.proxy.loadResponse = this.loadResponse;
58150 //this.addColumns();
58152 load : function (_self, records, options)
58154 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
58155 // if you click on the translation.. you can edit it...
58156 var el = Roo.get(this);
58157 var id = el.dom.getAttribute('data-id');
58158 var d = el.dom.getAttribute('data-date');
58159 var t = el.dom.getAttribute('data-time');
58160 //var id = this.child('span').dom.textContent;
58163 Pman.Dialog.CourseCalendar.show({
58167 productitem_active : id ? 1 : 0
58169 _this.grid.ds.load({});
58174 _this.panel.fireEvent('resize', [ '', '' ]);
58177 loadResponse : function(o, success, response){
58178 // this is overridden on before load..
58180 Roo.log("our code?");
58181 //Roo.log(success);
58182 //Roo.log(response)
58183 delete this.activeRequest;
58185 this.fireEvent("loadexception", this, o, response);
58186 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58191 result = o.reader.read(response);
58193 Roo.log("load exception?");
58194 this.fireEvent("loadexception", this, o, response, e);
58195 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58198 Roo.log("ready...");
58199 // loop through result.records;
58200 // and set this.tdate[date] = [] << array of records..
58202 Roo.each(result.records, function(r){
58204 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
58205 _this.tdata[r.data.when_dt.format('j')] = [];
58207 _this.tdata[r.data.when_dt.format('j')].push(r.data);
58210 //Roo.log(_this.tdata);
58212 result.records = [];
58213 result.totalRecords = 6;
58215 // let's generate some duumy records for the rows.
58216 //var st = _this.dateField.getValue();
58218 // work out monday..
58219 //st = st.add(Date.DAY, -1 * st.format('w'));
58221 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58223 var firstOfMonth = date.getFirstDayOfMonth();
58224 var days = date.getDaysInMonth();
58226 var firstAdded = false;
58227 for (var i = 0; i < result.totalRecords ; i++) {
58228 //var d= st.add(Date.DAY, i);
58231 for(var w = 0 ; w < 7 ; w++){
58232 if(!firstAdded && firstOfMonth != w){
58239 var dd = (d > 0 && d < 10) ? "0"+d : d;
58240 row['weekday'+w] = String.format(
58241 '<span style="font-size: 16px;"><b>{0}</b></span>'+
58242 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
58244 date.format('Y-m-')+dd
58247 if(typeof(_this.tdata[d]) != 'undefined'){
58248 Roo.each(_this.tdata[d], function(r){
58252 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
58253 if(r.parent_id*1>0){
58254 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
58257 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
58258 deactive = 'de-act-link';
58261 row['weekday'+w] += String.format(
58262 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
58264 r.product_id_name, //1
58265 r.when_dt.format('h:ia'), //2
58275 // only do this if something added..
58277 result.records.push(_this.grid.dataSource.reader.newRow(row));
58281 // push it twice. (second one with an hour..
58285 this.fireEvent("load", this, o, o.request.arg);
58286 o.request.callback.call(o.request.scope, result, o.request.arg, true);
58288 sortInfo : {field: 'when_dt', direction : 'ASC' },
58290 xtype: 'HttpProxy',
58293 url : baseURL + '/Roo/Shop_course.php'
58296 xtype: 'JsonReader',
58313 'name': 'parent_id',
58317 'name': 'product_id',
58321 'name': 'productitem_id',
58339 click : function (_self, e)
58341 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58342 sd.setMonth(sd.getMonth()-1);
58343 _this.monthField.setValue(sd.format('Y-m-d'));
58344 _this.grid.ds.load({});
58350 xtype: 'Separator',
58354 xtype: 'MonthField',
58357 render : function (_self)
58359 _this.monthField = _self;
58360 // _this.monthField.set today
58362 select : function (combo, date)
58364 _this.grid.ds.load({});
58367 value : (function() { return new Date(); })()
58370 xtype: 'Separator',
58376 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
58386 click : function (_self, e)
58388 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58389 sd.setMonth(sd.getMonth()+1);
58390 _this.monthField.setValue(sd.format('Y-m-d'));
58391 _this.grid.ds.load({});
58404 * Ext JS Library 1.1.1
58405 * Copyright(c) 2006-2007, Ext JS, LLC.
58407 * Originally Released Under LGPL - original licence link has changed is not relivant.
58410 * <script type="text/javascript">
58414 * @class Roo.LoadMask
58415 * A simple utility class for generically masking elements while loading data. If the element being masked has
58416 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
58417 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
58418 * element's UpdateManager load indicator and will be destroyed after the initial load.
58420 * Create a new LoadMask
58421 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
58422 * @param {Object} config The config object
58424 Roo.LoadMask = function(el, config){
58425 this.el = Roo.get(el);
58426 Roo.apply(this, config);
58428 this.store.on('beforeload', this.onBeforeLoad, this);
58429 this.store.on('load', this.onLoad, this);
58430 this.store.on('loadexception', this.onLoadException, this);
58431 this.removeMask = false;
58433 var um = this.el.getUpdateManager();
58434 um.showLoadIndicator = false; // disable the default indicator
58435 um.on('beforeupdate', this.onBeforeLoad, this);
58436 um.on('update', this.onLoad, this);
58437 um.on('failure', this.onLoad, this);
58438 this.removeMask = true;
58442 Roo.LoadMask.prototype = {
58444 * @cfg {Boolean} removeMask
58445 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
58446 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
58449 * @cfg {String} msg
58450 * The text to display in a centered loading message box (defaults to 'Loading...')
58452 msg : 'Loading...',
58454 * @cfg {String} msgCls
58455 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
58457 msgCls : 'x-mask-loading',
58460 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
58466 * Disables the mask to prevent it from being displayed
58468 disable : function(){
58469 this.disabled = true;
58473 * Enables the mask so that it can be displayed
58475 enable : function(){
58476 this.disabled = false;
58479 onLoadException : function()
58481 Roo.log(arguments);
58483 if (typeof(arguments[3]) != 'undefined') {
58484 Roo.MessageBox.alert("Error loading",arguments[3]);
58488 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
58489 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
58498 this.el.unmask(this.removeMask);
58501 onLoad : function()
58503 this.el.unmask(this.removeMask);
58507 onBeforeLoad : function(){
58508 if(!this.disabled){
58509 this.el.mask(this.msg, this.msgCls);
58514 destroy : function(){
58516 this.store.un('beforeload', this.onBeforeLoad, this);
58517 this.store.un('load', this.onLoad, this);
58518 this.store.un('loadexception', this.onLoadException, this);
58520 var um = this.el.getUpdateManager();
58521 um.un('beforeupdate', this.onBeforeLoad, this);
58522 um.un('update', this.onLoad, this);
58523 um.un('failure', this.onLoad, this);
58528 * Ext JS Library 1.1.1
58529 * Copyright(c) 2006-2007, Ext JS, LLC.
58531 * Originally Released Under LGPL - original licence link has changed is not relivant.
58534 * <script type="text/javascript">
58539 * @class Roo.XTemplate
58540 * @extends Roo.Template
58541 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
58543 var t = new Roo.XTemplate(
58544 '<select name="{name}">',
58545 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
58549 // then append, applying the master template values
58552 * Supported features:
58557 {a_variable} - output encoded.
58558 {a_variable.format:("Y-m-d")} - call a method on the variable
58559 {a_variable:raw} - unencoded output
58560 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
58561 {a_variable:this.method_on_template(...)} - call a method on the template object.
58566 <tpl for="a_variable or condition.."></tpl>
58567 <tpl if="a_variable or condition"></tpl>
58568 <tpl exec="some javascript"></tpl>
58569 <tpl name="named_template"></tpl> (experimental)
58571 <tpl for="."></tpl> - just iterate the property..
58572 <tpl for=".."></tpl> - iterates with the parent (probably the template)
58576 Roo.XTemplate = function()
58578 Roo.XTemplate.superclass.constructor.apply(this, arguments);
58585 Roo.extend(Roo.XTemplate, Roo.Template, {
58588 * The various sub templates
58593 * basic tag replacing syntax
58596 * // you can fake an object call by doing this
58600 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
58603 * compile the template
58605 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
58608 compile: function()
58612 s = ['<tpl>', s, '</tpl>'].join('');
58614 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
58615 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
58616 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
58617 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
58618 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
58623 while(true == !!(m = s.match(re))){
58624 var forMatch = m[0].match(nameRe),
58625 ifMatch = m[0].match(ifRe),
58626 execMatch = m[0].match(execRe),
58627 namedMatch = m[0].match(namedRe),
58632 name = forMatch && forMatch[1] ? forMatch[1] : '';
58635 // if - puts fn into test..
58636 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58638 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58643 // exec - calls a function... returns empty if true is returned.
58644 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58646 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58654 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58655 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58656 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58659 var uid = namedMatch ? namedMatch[1] : id;
58663 id: namedMatch ? namedMatch[1] : id,
58670 s = s.replace(m[0], '');
58672 s = s.replace(m[0], '{xtpl'+ id + '}');
58677 for(var i = tpls.length-1; i >= 0; --i){
58678 this.compileTpl(tpls[i]);
58679 this.tpls[tpls[i].id] = tpls[i];
58681 this.master = tpls[tpls.length-1];
58685 * same as applyTemplate, except it's done to one of the subTemplates
58686 * when using named templates, you can do:
58688 * var str = pl.applySubTemplate('your-name', values);
58691 * @param {Number} id of the template
58692 * @param {Object} values to apply to template
58693 * @param {Object} parent (normaly the instance of this object)
58695 applySubTemplate : function(id, values, parent)
58699 var t = this.tpls[id];
58703 if(t.test && !t.test.call(this, values, parent)){
58707 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58708 Roo.log(e.toString());
58714 if(t.exec && t.exec.call(this, values, parent)){
58718 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58719 Roo.log(e.toString());
58724 var vs = t.target ? t.target.call(this, values, parent) : values;
58725 parent = t.target ? values : parent;
58726 if(t.target && vs instanceof Array){
58728 for(var i = 0, len = vs.length; i < len; i++){
58729 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58731 return buf.join('');
58733 return t.compiled.call(this, vs, parent);
58735 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58736 Roo.log(e.toString());
58737 Roo.log(t.compiled);
58742 compileTpl : function(tpl)
58744 var fm = Roo.util.Format;
58745 var useF = this.disableFormats !== true;
58746 var sep = Roo.isGecko ? "+" : ",";
58747 var undef = function(str) {
58748 Roo.log("Property not found :" + str);
58752 var fn = function(m, name, format, args)
58754 //Roo.log(arguments);
58755 args = args ? args.replace(/\\'/g,"'") : args;
58756 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58757 if (typeof(format) == 'undefined') {
58758 format= 'htmlEncode';
58760 if (format == 'raw' ) {
58764 if(name.substr(0, 4) == 'xtpl'){
58765 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58768 // build an array of options to determine if value is undefined..
58770 // basically get 'xxxx.yyyy' then do
58771 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58772 // (function () { Roo.log("Property not found"); return ''; })() :
58777 Roo.each(name.split('.'), function(st) {
58778 lookfor += (lookfor.length ? '.': '') + st;
58779 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58782 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58785 if(format && useF){
58787 args = args ? ',' + args : "";
58789 if(format.substr(0, 5) != "this."){
58790 format = "fm." + format + '(';
58792 format = 'this.call("'+ format.substr(5) + '", ';
58796 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58800 // called with xxyx.yuu:(test,test)
58802 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58804 // raw.. - :raw modifier..
58805 return "'"+ sep + udef_st + name + ")"+sep+"'";
58809 // branched to use + in gecko and [].join() in others
58811 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58812 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58815 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58816 body.push(tpl.body.replace(/(\r\n|\n)/g,
58817 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58818 body.push("'].join('');};};");
58819 body = body.join('');
58822 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58824 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58830 applyTemplate : function(values){
58831 return this.master.compiled.call(this, values, {});
58832 //var s = this.subs;
58835 apply : function(){
58836 return this.applyTemplate.apply(this, arguments);
58841 Roo.XTemplate.from = function(el){
58842 el = Roo.getDom(el);
58843 return new Roo.XTemplate(el.value || el.innerHTML);