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);
987 * Ext JS Library 1.1.1
988 * Copyright(c) 2006-2007, Ext JS, LLC.
990 * Originally Released Under LGPL - original licence link has changed is not relivant.
993 * <script type="text/javascript">
999 * The date parsing and format syntax is a subset of
1000 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1001 * supported will provide results equivalent to their PHP versions.
1003 * Following is the list of all currently supported formats:
1006 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1008 Format Output Description
1009 ------ ---------- --------------------------------------------------------------
1010 d 10 Day of the month, 2 digits with leading zeros
1011 D Wed A textual representation of a day, three letters
1012 j 10 Day of the month without leading zeros
1013 l Wednesday A full textual representation of the day of the week
1014 S th English ordinal day of month suffix, 2 chars (use with j)
1015 w 3 Numeric representation of the day of the week
1016 z 9 The julian date, or day of the year (0-365)
1017 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1018 F January A full textual representation of the month
1019 m 01 Numeric representation of a month, with leading zeros
1020 M Jan Month name abbreviation, three letters
1021 n 1 Numeric representation of a month, without leading zeros
1022 t 31 Number of days in the given month
1023 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1024 Y 2007 A full numeric representation of a year, 4 digits
1025 y 07 A two digit representation of a year
1026 a pm Lowercase Ante meridiem and Post meridiem
1027 A PM Uppercase Ante meridiem and Post meridiem
1028 g 3 12-hour format of an hour without leading zeros
1029 G 15 24-hour format of an hour without leading zeros
1030 h 03 12-hour format of an hour with leading zeros
1031 H 15 24-hour format of an hour with leading zeros
1032 i 05 Minutes with leading zeros
1033 s 01 Seconds, with leading zeros
1034 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1035 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1036 T CST Timezone setting of the machine running the code
1037 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1040 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1042 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1043 document.write(dt.format('Y-m-d')); //2007-01-10
1044 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1045 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
1048 * Here are some standard date/time patterns that you might find helpful. They
1049 * are not part of the source of Date.js, but to use them you can simply copy this
1050 * block of code into any script that is included after Date.js and they will also become
1051 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1054 ISO8601Long:"Y-m-d H:i:s",
1055 ISO8601Short:"Y-m-d",
1057 LongDate: "l, F d, Y",
1058 FullDateTime: "l, F d, Y g:i:s A",
1061 LongTime: "g:i:s A",
1062 SortableDateTime: "Y-m-d\\TH:i:s",
1063 UniversalSortableDateTime: "Y-m-d H:i:sO",
1070 var dt = new Date();
1071 document.write(dt.format(Date.patterns.ShortDate));
1076 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1077 * They generate precompiled functions from date formats instead of parsing and
1078 * processing the pattern every time you format a date. These functions are available
1079 * on every Date object (any javascript function).
1081 * The original article and download are here:
1082 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1089 Returns the number of milliseconds between this date and date
1090 @param {Date} date (optional) Defaults to now
1091 @return {Number} The diff in milliseconds
1092 @member Date getElapsed
1094 Date.prototype.getElapsed = function(date) {
1095 return Math.abs((date || new Date()).getTime()-this.getTime());
1097 // was in date file..
1101 Date.parseFunctions = {count:0};
1103 Date.parseRegexes = [];
1105 Date.formatFunctions = {count:0};
1108 Date.prototype.dateFormat = function(format) {
1109 if (Date.formatFunctions[format] == null) {
1110 Date.createNewFormat(format);
1112 var func = Date.formatFunctions[format];
1113 return this[func]();
1118 * Formats a date given the supplied format string
1119 * @param {String} format The format string
1120 * @return {String} The formatted date
1123 Date.prototype.format = Date.prototype.dateFormat;
1126 Date.createNewFormat = function(format) {
1127 var funcName = "format" + Date.formatFunctions.count++;
1128 Date.formatFunctions[format] = funcName;
1129 var code = "Date.prototype." + funcName + " = function(){return ";
1130 var special = false;
1132 for (var i = 0; i < format.length; ++i) {
1133 ch = format.charAt(i);
1134 if (!special && ch == "\\") {
1139 code += "'" + String.escape(ch) + "' + ";
1142 code += Date.getFormatCode(ch);
1145 /** eval:var:zzzzzzzzzzzzz */
1146 eval(code.substring(0, code.length - 3) + ";}");
1150 Date.getFormatCode = function(character) {
1151 switch (character) {
1153 return "String.leftPad(this.getDate(), 2, '0') + ";
1155 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1157 return "this.getDate() + ";
1159 return "Date.dayNames[this.getDay()] + ";
1161 return "this.getSuffix() + ";
1163 return "this.getDay() + ";
1165 return "this.getDayOfYear() + ";
1167 return "this.getWeekOfYear() + ";
1169 return "Date.monthNames[this.getMonth()] + ";
1171 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1173 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1175 return "(this.getMonth() + 1) + ";
1177 return "this.getDaysInMonth() + ";
1179 return "(this.isLeapYear() ? 1 : 0) + ";
1181 return "this.getFullYear() + ";
1183 return "('' + this.getFullYear()).substring(2, 4) + ";
1185 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1187 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1189 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1191 return "this.getHours() + ";
1193 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1195 return "String.leftPad(this.getHours(), 2, '0') + ";
1197 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1199 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1201 return "this.getGMTOffset() + ";
1203 return "this.getGMTColonOffset() + ";
1205 return "this.getTimezone() + ";
1207 return "(this.getTimezoneOffset() * -60) + ";
1209 return "'" + String.escape(character) + "' + ";
1214 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1215 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1216 * the date format that is not specified will default to the current date value for that part. Time parts can also
1217 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1218 * string or the parse operation will fail.
1221 //dt = Fri May 25 2007 (current date)
1222 var dt = new Date();
1224 //dt = Thu May 25 2006 (today's month/day in 2006)
1225 dt = Date.parseDate("2006", "Y");
1227 //dt = Sun Jan 15 2006 (all date parts specified)
1228 dt = Date.parseDate("2006-1-15", "Y-m-d");
1230 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1231 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1233 * @param {String} input The unparsed date as a string
1234 * @param {String} format The format the date is in
1235 * @return {Date} The parsed date
1238 Date.parseDate = function(input, format) {
1239 if (Date.parseFunctions[format] == null) {
1240 Date.createParser(format);
1242 var func = Date.parseFunctions[format];
1243 return Date[func](input);
1249 Date.createParser = function(format) {
1250 var funcName = "parse" + Date.parseFunctions.count++;
1251 var regexNum = Date.parseRegexes.length;
1252 var currentGroup = 1;
1253 Date.parseFunctions[format] = funcName;
1255 var code = "Date." + funcName + " = function(input){\n"
1256 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1257 + "var d = new Date();\n"
1258 + "y = d.getFullYear();\n"
1259 + "m = d.getMonth();\n"
1260 + "d = d.getDate();\n"
1261 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1262 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1263 + "if (results && results.length > 0) {";
1266 var special = false;
1268 for (var i = 0; i < format.length; ++i) {
1269 ch = format.charAt(i);
1270 if (!special && ch == "\\") {
1275 regex += String.escape(ch);
1278 var obj = Date.formatCodeToRegex(ch, currentGroup);
1279 currentGroup += obj.g;
1281 if (obj.g && obj.c) {
1287 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1288 + "{v = new Date(y, m, d, h, i, s);}\n"
1289 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1290 + "{v = new Date(y, m, d, h, i);}\n"
1291 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1292 + "{v = new Date(y, m, d, h);}\n"
1293 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1294 + "{v = new Date(y, m, d);}\n"
1295 + "else if (y >= 0 && m >= 0)\n"
1296 + "{v = new Date(y, m);}\n"
1297 + "else if (y >= 0)\n"
1298 + "{v = new Date(y);}\n"
1299 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1300 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1301 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1304 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1305 /** eval:var:zzzzzzzzzzzzz */
1310 Date.formatCodeToRegex = function(character, currentGroup) {
1311 switch (character) {
1315 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1318 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1319 s:"(\\d{1,2})"}; // day of month without leading zeroes
1322 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1323 s:"(\\d{2})"}; // day of month with leading zeroes
1327 s:"(?:" + Date.dayNames.join("|") + ")"};
1331 s:"(?:st|nd|rd|th)"};
1346 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1347 s:"(" + Date.monthNames.join("|") + ")"};
1350 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1351 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1354 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1355 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1358 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1359 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1370 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1374 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1375 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1379 c:"if (results[" + currentGroup + "] == 'am') {\n"
1380 + "if (h == 12) { h = 0; }\n"
1381 + "} else { if (h < 12) { h += 12; }}",
1385 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1386 + "if (h == 12) { h = 0; }\n"
1387 + "} else { if (h < 12) { h += 12; }}",
1392 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1393 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1397 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1398 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1401 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1405 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1410 "o = results[", currentGroup, "];\n",
1411 "var sn = o.substring(0,1);\n", // get + / - sign
1412 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1413 "var mn = o.substring(3,5) % 60;\n", // get minutes
1414 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1415 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1417 s:"([+\-]\\d{2,4})"};
1423 "o = results[", currentGroup, "];\n",
1424 "var sn = o.substring(0,1);\n",
1425 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1426 "var mn = o.substring(4,6) % 60;\n",
1427 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1428 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1434 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1437 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1438 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1439 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1443 s:String.escape(character)};
1448 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1449 * @return {String} The abbreviated timezone name (e.g. 'CST')
1451 Date.prototype.getTimezone = function() {
1452 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1456 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1457 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1459 Date.prototype.getGMTOffset = function() {
1460 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1461 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1462 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1466 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1467 * @return {String} 2-characters representing hours and 2-characters representing minutes
1468 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1470 Date.prototype.getGMTColonOffset = function() {
1471 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1472 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1474 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1478 * Get the numeric day number of the year, adjusted for leap year.
1479 * @return {Number} 0 through 364 (365 in leap years)
1481 Date.prototype.getDayOfYear = function() {
1483 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1484 for (var i = 0; i < this.getMonth(); ++i) {
1485 num += Date.daysInMonth[i];
1487 return num + this.getDate() - 1;
1491 * Get the string representation of the numeric week number of the year
1492 * (equivalent to the format specifier 'W').
1493 * @return {String} '00' through '52'
1495 Date.prototype.getWeekOfYear = function() {
1496 // Skip to Thursday of this week
1497 var now = this.getDayOfYear() + (4 - this.getDay());
1498 // Find the first Thursday of the year
1499 var jan1 = new Date(this.getFullYear(), 0, 1);
1500 var then = (7 - jan1.getDay() + 4);
1501 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1505 * Whether or not the current date is in a leap year.
1506 * @return {Boolean} True if the current date is in a leap year, else false
1508 Date.prototype.isLeapYear = function() {
1509 var year = this.getFullYear();
1510 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1514 * Get the first day of the current month, adjusted for leap year. The returned value
1515 * is the numeric day index within the week (0-6) which can be used in conjunction with
1516 * the {@link #monthNames} array to retrieve the textual day name.
1519 var dt = new Date('1/10/2007');
1520 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1522 * @return {Number} The day number (0-6)
1524 Date.prototype.getFirstDayOfMonth = function() {
1525 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1526 return (day < 0) ? (day + 7) : day;
1530 * Get the last day of the current month, adjusted for leap year. The returned value
1531 * is the numeric day index within the week (0-6) which can be used in conjunction with
1532 * the {@link #monthNames} array to retrieve the textual day name.
1535 var dt = new Date('1/10/2007');
1536 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1538 * @return {Number} The day number (0-6)
1540 Date.prototype.getLastDayOfMonth = function() {
1541 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1542 return (day < 0) ? (day + 7) : day;
1547 * Get the first date of this date's month
1550 Date.prototype.getFirstDateOfMonth = function() {
1551 return new Date(this.getFullYear(), this.getMonth(), 1);
1555 * Get the last date of this date's month
1558 Date.prototype.getLastDateOfMonth = function() {
1559 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1562 * Get the number of days in the current month, adjusted for leap year.
1563 * @return {Number} The number of days in the month
1565 Date.prototype.getDaysInMonth = function() {
1566 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1567 return Date.daysInMonth[this.getMonth()];
1571 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1572 * @return {String} 'st, 'nd', 'rd' or 'th'
1574 Date.prototype.getSuffix = function() {
1575 switch (this.getDate()) {
1592 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1595 * An array of textual month names.
1596 * Override these values for international dates, for example...
1597 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1616 * An array of textual day names.
1617 * Override these values for international dates, for example...
1618 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1634 Date.monthNumbers = {
1649 * Creates and returns a new Date instance with the exact same date value as the called instance.
1650 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1651 * variable will also be changed. When the intention is to create a new variable that will not
1652 * modify the original instance, you should create a clone.
1654 * Example of correctly cloning a date:
1657 var orig = new Date('10/1/2006');
1660 document.write(orig); //returns 'Thu Oct 05 2006'!
1663 var orig = new Date('10/1/2006');
1664 var copy = orig.clone();
1666 document.write(orig); //returns 'Thu Oct 01 2006'
1668 * @return {Date} The new Date instance
1670 Date.prototype.clone = function() {
1671 return new Date(this.getTime());
1675 * Clears any time information from this date
1676 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1677 @return {Date} this or the clone
1679 Date.prototype.clearTime = function(clone){
1681 return this.clone().clearTime();
1686 this.setMilliseconds(0);
1691 // safari setMonth is broken -- check that this is only donw once...
1692 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1693 Date.brokenSetMonth = Date.prototype.setMonth;
1694 Date.prototype.setMonth = function(num){
1696 var n = Math.ceil(-num);
1697 var back_year = Math.ceil(n/12);
1698 var month = (n % 12) ? 12 - n % 12 : 0 ;
1699 this.setFullYear(this.getFullYear() - back_year);
1700 return Date.brokenSetMonth.call(this, month);
1702 return Date.brokenSetMonth.apply(this, arguments);
1707 /** Date interval constant
1711 /** Date interval constant
1715 /** Date interval constant
1719 /** Date interval constant
1723 /** Date interval constant
1727 /** Date interval constant
1731 /** Date interval constant
1737 * Provides a convenient method of performing basic date arithmetic. This method
1738 * does not modify the Date instance being called - it creates and returns
1739 * a new Date instance containing the resulting date value.
1744 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1745 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1747 //Negative values will subtract correctly:
1748 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1749 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1751 //You can even chain several calls together in one line!
1752 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1753 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1756 * @param {String} interval A valid date interval enum value
1757 * @param {Number} value The amount to add to the current date
1758 * @return {Date} The new Date instance
1760 Date.prototype.add = function(interval, value){
1761 var d = this.clone();
1762 if (!interval || value === 0) { return d; }
1763 switch(interval.toLowerCase()){
1765 d.setMilliseconds(this.getMilliseconds() + value);
1768 d.setSeconds(this.getSeconds() + value);
1771 d.setMinutes(this.getMinutes() + value);
1774 d.setHours(this.getHours() + value);
1777 d.setDate(this.getDate() + value);
1780 var day = this.getDate();
1782 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1785 d.setMonth(this.getMonth() + value);
1788 d.setFullYear(this.getFullYear() + value);
1795 * Ext JS Library 1.1.1
1796 * Copyright(c) 2006-2007, Ext JS, LLC.
1798 * Originally Released Under LGPL - original licence link has changed is not relivant.
1801 * <script type="text/javascript">
1805 * @class Roo.lib.Dom
1808 * Dom utils (from YIU afaik)
1813 * Get the view width
1814 * @param {Boolean} full True will get the full document, otherwise it's the view width
1815 * @return {Number} The width
1818 getViewWidth : function(full) {
1819 return full ? this.getDocumentWidth() : this.getViewportWidth();
1822 * Get the view height
1823 * @param {Boolean} full True will get the full document, otherwise it's the view height
1824 * @return {Number} The height
1826 getViewHeight : function(full) {
1827 return full ? this.getDocumentHeight() : this.getViewportHeight();
1830 getDocumentHeight: function() {
1831 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1832 return Math.max(scrollHeight, this.getViewportHeight());
1835 getDocumentWidth: function() {
1836 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1837 return Math.max(scrollWidth, this.getViewportWidth());
1840 getViewportHeight: function() {
1841 var height = self.innerHeight;
1842 var mode = document.compatMode;
1844 if ((mode || Roo.isIE) && !Roo.isOpera) {
1845 height = (mode == "CSS1Compat") ?
1846 document.documentElement.clientHeight :
1847 document.body.clientHeight;
1853 getViewportWidth: function() {
1854 var width = self.innerWidth;
1855 var mode = document.compatMode;
1857 if (mode || Roo.isIE) {
1858 width = (mode == "CSS1Compat") ?
1859 document.documentElement.clientWidth :
1860 document.body.clientWidth;
1865 isAncestor : function(p, c) {
1872 if (p.contains && !Roo.isSafari) {
1873 return p.contains(c);
1874 } else if (p.compareDocumentPosition) {
1875 return !!(p.compareDocumentPosition(c) & 16);
1877 var parent = c.parentNode;
1882 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1885 parent = parent.parentNode;
1891 getRegion : function(el) {
1892 return Roo.lib.Region.getRegion(el);
1895 getY : function(el) {
1896 return this.getXY(el)[1];
1899 getX : function(el) {
1900 return this.getXY(el)[0];
1903 getXY : function(el) {
1904 var p, pe, b, scroll, bd = document.body;
1905 el = Roo.getDom(el);
1906 var fly = Roo.lib.AnimBase.fly;
1907 if (el.getBoundingClientRect) {
1908 b = el.getBoundingClientRect();
1909 scroll = fly(document).getScroll();
1910 return [b.left + scroll.left, b.top + scroll.top];
1916 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1923 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1930 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1931 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1938 if (p != el && pe.getStyle('overflow') != 'visible') {
1946 if (Roo.isSafari && hasAbsolute) {
1951 if (Roo.isGecko && !hasAbsolute) {
1953 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1954 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1958 while (p && p != bd) {
1959 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1971 setXY : function(el, xy) {
1972 el = Roo.fly(el, '_setXY');
1974 var pts = el.translatePoints(xy);
1975 if (xy[0] !== false) {
1976 el.dom.style.left = pts.left + "px";
1978 if (xy[1] !== false) {
1979 el.dom.style.top = pts.top + "px";
1983 setX : function(el, x) {
1984 this.setXY(el, [x, false]);
1987 setY : function(el, y) {
1988 this.setXY(el, [false, y]);
1992 * Portions of this file are based on pieces of Yahoo User Interface Library
1993 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1994 * YUI licensed under the BSD License:
1995 * http://developer.yahoo.net/yui/license.txt
1996 * <script type="text/javascript">
2000 Roo.lib.Event = function() {
2001 var loadComplete = false;
2003 var unloadListeners = [];
2005 var onAvailStack = [];
2007 var lastError = null;
2020 startInterval: function() {
2021 if (!this._interval) {
2023 var callback = function() {
2024 self._tryPreloadAttach();
2026 this._interval = setInterval(callback, this.POLL_INTERVAL);
2031 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2032 onAvailStack.push({ id: p_id,
2035 override: p_override,
2036 checkReady: false });
2038 retryCount = this.POLL_RETRYS;
2039 this.startInterval();
2043 addListener: function(el, eventName, fn) {
2044 el = Roo.getDom(el);
2049 if ("unload" == eventName) {
2050 unloadListeners[unloadListeners.length] =
2051 [el, eventName, fn];
2055 var wrappedFn = function(e) {
2056 return fn(Roo.lib.Event.getEvent(e));
2059 var li = [el, eventName, fn, wrappedFn];
2061 var index = listeners.length;
2062 listeners[index] = li;
2064 this.doAdd(el, eventName, wrappedFn, false);
2070 removeListener: function(el, eventName, fn) {
2073 el = Roo.getDom(el);
2076 return this.purgeElement(el, false, eventName);
2080 if ("unload" == eventName) {
2082 for (i = 0,len = unloadListeners.length; i < len; i++) {
2083 var li = unloadListeners[i];
2086 li[1] == eventName &&
2088 unloadListeners.splice(i, 1);
2096 var cacheItem = null;
2099 var index = arguments[3];
2101 if ("undefined" == typeof index) {
2102 index = this._getCacheIndex(el, eventName, fn);
2106 cacheItem = listeners[index];
2109 if (!el || !cacheItem) {
2113 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2115 delete listeners[index][this.WFN];
2116 delete listeners[index][this.FN];
2117 listeners.splice(index, 1);
2124 getTarget: function(ev, resolveTextNode) {
2125 ev = ev.browserEvent || ev;
2126 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2127 var t = ev.target || ev.srcElement;
2128 return this.resolveTextNode(t);
2132 resolveTextNode: function(node) {
2133 if (Roo.isSafari && node && 3 == node.nodeType) {
2134 return node.parentNode;
2141 getPageX: function(ev) {
2142 ev = ev.browserEvent || ev;
2143 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2145 if (!x && 0 !== x) {
2146 x = ev.clientX || 0;
2149 x += this.getScroll()[1];
2157 getPageY: function(ev) {
2158 ev = ev.browserEvent || ev;
2159 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2161 if (!y && 0 !== y) {
2162 y = ev.clientY || 0;
2165 y += this.getScroll()[0];
2174 getXY: function(ev) {
2175 ev = ev.browserEvent || ev;
2176 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2177 return [this.getPageX(ev), this.getPageY(ev)];
2181 getRelatedTarget: function(ev) {
2182 ev = ev.browserEvent || ev;
2183 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2184 var t = ev.relatedTarget;
2186 if (ev.type == "mouseout") {
2188 } else if (ev.type == "mouseover") {
2193 return this.resolveTextNode(t);
2197 getTime: function(ev) {
2198 ev = ev.browserEvent || ev;
2199 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2201 var t = new Date().getTime();
2205 this.lastError = ex;
2214 stopEvent: function(ev) {
2215 this.stopPropagation(ev);
2216 this.preventDefault(ev);
2220 stopPropagation: function(ev) {
2221 ev = ev.browserEvent || ev;
2222 if (ev.stopPropagation) {
2223 ev.stopPropagation();
2225 ev.cancelBubble = true;
2230 preventDefault: function(ev) {
2231 ev = ev.browserEvent || ev;
2232 if(ev.preventDefault) {
2233 ev.preventDefault();
2235 ev.returnValue = false;
2240 getEvent: function(e) {
2241 var ev = e || window.event;
2243 var c = this.getEvent.caller;
2245 ev = c.arguments[0];
2246 if (ev && Event == ev.constructor) {
2256 getCharCode: function(ev) {
2257 ev = ev.browserEvent || ev;
2258 return ev.charCode || ev.keyCode || 0;
2262 _getCacheIndex: function(el, eventName, fn) {
2263 for (var i = 0,len = listeners.length; i < len; ++i) {
2264 var li = listeners[i];
2266 li[this.FN] == fn &&
2267 li[this.EL] == el &&
2268 li[this.TYPE] == eventName) {
2280 getEl: function(id) {
2281 return document.getElementById(id);
2285 clearCache: function() {
2289 _load: function(e) {
2290 loadComplete = true;
2291 var EU = Roo.lib.Event;
2295 EU.doRemove(window, "load", EU._load);
2300 _tryPreloadAttach: function() {
2309 var tryAgain = !loadComplete;
2311 tryAgain = (retryCount > 0);
2316 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2317 var item = onAvailStack[i];
2319 var el = this.getEl(item.id);
2322 if (!item.checkReady ||
2325 (document && document.body)) {
2328 if (item.override) {
2329 if (item.override === true) {
2332 scope = item.override;
2335 item.fn.call(scope, item.obj);
2336 onAvailStack[i] = null;
2339 notAvail.push(item);
2344 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2348 this.startInterval();
2350 clearInterval(this._interval);
2351 this._interval = null;
2354 this.locked = false;
2361 purgeElement: function(el, recurse, eventName) {
2362 var elListeners = this.getListeners(el, eventName);
2364 for (var i = 0,len = elListeners.length; i < len; ++i) {
2365 var l = elListeners[i];
2366 this.removeListener(el, l.type, l.fn);
2370 if (recurse && el && el.childNodes) {
2371 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2372 this.purgeElement(el.childNodes[i], recurse, eventName);
2378 getListeners: function(el, eventName) {
2379 var results = [], searchLists;
2381 searchLists = [listeners, unloadListeners];
2382 } else if (eventName == "unload") {
2383 searchLists = [unloadListeners];
2385 searchLists = [listeners];
2388 for (var j = 0; j < searchLists.length; ++j) {
2389 var searchList = searchLists[j];
2390 if (searchList && searchList.length > 0) {
2391 for (var i = 0,len = searchList.length; i < len; ++i) {
2392 var l = searchList[i];
2393 if (l && l[this.EL] === el &&
2394 (!eventName || eventName === l[this.TYPE])) {
2399 adjust: l[this.ADJ_SCOPE],
2407 return (results.length) ? results : null;
2411 _unload: function(e) {
2413 var EU = Roo.lib.Event, i, j, l, len, index;
2415 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2416 l = unloadListeners[i];
2419 if (l[EU.ADJ_SCOPE]) {
2420 if (l[EU.ADJ_SCOPE] === true) {
2423 scope = l[EU.ADJ_SCOPE];
2426 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2427 unloadListeners[i] = null;
2433 unloadListeners = null;
2435 if (listeners && listeners.length > 0) {
2436 j = listeners.length;
2439 l = listeners[index];
2441 EU.removeListener(l[EU.EL], l[EU.TYPE],
2451 EU.doRemove(window, "unload", EU._unload);
2456 getScroll: function() {
2457 var dd = document.documentElement, db = document.body;
2458 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2459 return [dd.scrollTop, dd.scrollLeft];
2461 return [db.scrollTop, db.scrollLeft];
2468 doAdd: function () {
2469 if (window.addEventListener) {
2470 return function(el, eventName, fn, capture) {
2471 el.addEventListener(eventName, fn, (capture));
2473 } else if (window.attachEvent) {
2474 return function(el, eventName, fn, capture) {
2475 el.attachEvent("on" + eventName, fn);
2484 doRemove: function() {
2485 if (window.removeEventListener) {
2486 return function (el, eventName, fn, capture) {
2487 el.removeEventListener(eventName, fn, (capture));
2489 } else if (window.detachEvent) {
2490 return function (el, eventName, fn) {
2491 el.detachEvent("on" + eventName, fn);
2503 var E = Roo.lib.Event;
2504 E.on = E.addListener;
2505 E.un = E.removeListener;
2507 if (document && document.body) {
2510 E.doAdd(window, "load", E._load);
2512 E.doAdd(window, "unload", E._unload);
2513 E._tryPreloadAttach();
2517 * Portions of this file are based on pieces of Yahoo User Interface Library
2518 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2519 * YUI licensed under the BSD License:
2520 * http://developer.yahoo.net/yui/license.txt
2521 * <script type="text/javascript">
2527 * @class Roo.lib.Ajax
2534 request : function(method, uri, cb, data, options) {
2536 var hs = options.headers;
2539 if(hs.hasOwnProperty(h)){
2540 this.initHeader(h, hs[h], false);
2544 if(options.xmlData){
2545 this.initHeader('Content-Type', 'text/xml', false);
2547 data = options.xmlData;
2551 return this.asyncRequest(method, uri, cb, data);
2554 serializeForm : function(form) {
2555 if(typeof form == 'string') {
2556 form = (document.getElementById(form) || document.forms[form]);
2559 var el, name, val, disabled, data = '', hasSubmit = false;
2560 for (var i = 0; i < form.elements.length; i++) {
2561 el = form.elements[i];
2562 disabled = form.elements[i].disabled;
2563 name = form.elements[i].name;
2564 val = form.elements[i].value;
2566 if (!disabled && name){
2570 case 'select-multiple':
2571 for (var j = 0; j < el.options.length; j++) {
2572 if (el.options[j].selected) {
2574 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2577 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2585 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2598 if(hasSubmit == false) {
2599 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2604 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2609 data = data.substr(0, data.length - 1);
2617 useDefaultHeader:true,
2619 defaultPostHeader:'application/x-www-form-urlencoded',
2621 useDefaultXhrHeader:true,
2623 defaultXhrHeader:'XMLHttpRequest',
2625 hasDefaultHeaders:true,
2637 setProgId:function(id)
2639 this.activeX.unshift(id);
2642 setDefaultPostHeader:function(b)
2644 this.useDefaultHeader = b;
2647 setDefaultXhrHeader:function(b)
2649 this.useDefaultXhrHeader = b;
2652 setPollingInterval:function(i)
2654 if (typeof i == 'number' && isFinite(i)) {
2655 this.pollInterval = i;
2659 createXhrObject:function(transactionId)
2665 http = new XMLHttpRequest();
2667 obj = { conn:http, tId:transactionId };
2671 for (var i = 0; i < this.activeX.length; ++i) {
2675 http = new ActiveXObject(this.activeX[i]);
2677 obj = { conn:http, tId:transactionId };
2690 getConnectionObject:function()
2693 var tId = this.transactionId;
2697 o = this.createXhrObject(tId);
2699 this.transactionId++;
2710 asyncRequest:function(method, uri, callback, postData)
2712 var o = this.getConnectionObject();
2718 o.conn.open(method, uri, true);
2720 if (this.useDefaultXhrHeader) {
2721 if (!this.defaultHeaders['X-Requested-With']) {
2722 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2726 if(postData && this.useDefaultHeader){
2727 this.initHeader('Content-Type', this.defaultPostHeader);
2730 if (this.hasDefaultHeaders || this.hasHeaders) {
2734 this.handleReadyState(o, callback);
2735 o.conn.send(postData || null);
2741 handleReadyState:function(o, callback)
2745 if (callback && callback.timeout) {
2747 this.timeout[o.tId] = window.setTimeout(function() {
2748 oConn.abort(o, callback, true);
2749 }, callback.timeout);
2752 this.poll[o.tId] = window.setInterval(
2754 if (o.conn && o.conn.readyState == 4) {
2755 window.clearInterval(oConn.poll[o.tId]);
2756 delete oConn.poll[o.tId];
2758 if(callback && callback.timeout) {
2759 window.clearTimeout(oConn.timeout[o.tId]);
2760 delete oConn.timeout[o.tId];
2763 oConn.handleTransactionResponse(o, callback);
2766 , this.pollInterval);
2769 handleTransactionResponse:function(o, callback, isAbort)
2773 this.releaseObject(o);
2777 var httpStatus, responseObject;
2781 if (o.conn.status !== undefined && o.conn.status != 0) {
2782 httpStatus = o.conn.status;
2794 if (httpStatus >= 200 && httpStatus < 300) {
2795 responseObject = this.createResponseObject(o, callback.argument);
2796 if (callback.success) {
2797 if (!callback.scope) {
2798 callback.success(responseObject);
2803 callback.success.apply(callback.scope, [responseObject]);
2808 switch (httpStatus) {
2816 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2817 if (callback.failure) {
2818 if (!callback.scope) {
2819 callback.failure(responseObject);
2822 callback.failure.apply(callback.scope, [responseObject]);
2827 responseObject = this.createResponseObject(o, callback.argument);
2828 if (callback.failure) {
2829 if (!callback.scope) {
2830 callback.failure(responseObject);
2833 callback.failure.apply(callback.scope, [responseObject]);
2839 this.releaseObject(o);
2840 responseObject = null;
2843 createResponseObject:function(o, callbackArg)
2850 var headerStr = o.conn.getAllResponseHeaders();
2851 var header = headerStr.split('\n');
2852 for (var i = 0; i < header.length; i++) {
2853 var delimitPos = header[i].indexOf(':');
2854 if (delimitPos != -1) {
2855 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2863 obj.status = o.conn.status;
2864 obj.statusText = o.conn.statusText;
2865 obj.getResponseHeader = headerObj;
2866 obj.getAllResponseHeaders = headerStr;
2867 obj.responseText = o.conn.responseText;
2868 obj.responseXML = o.conn.responseXML;
2870 if (typeof callbackArg !== undefined) {
2871 obj.argument = callbackArg;
2877 createExceptionObject:function(tId, callbackArg, isAbort)
2880 var COMM_ERROR = 'communication failure';
2881 var ABORT_CODE = -1;
2882 var ABORT_ERROR = 'transaction aborted';
2888 obj.status = ABORT_CODE;
2889 obj.statusText = ABORT_ERROR;
2892 obj.status = COMM_CODE;
2893 obj.statusText = COMM_ERROR;
2897 obj.argument = callbackArg;
2903 initHeader:function(label, value, isDefault)
2905 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2907 if (headerObj[label] === undefined) {
2908 headerObj[label] = value;
2913 headerObj[label] = value + "," + headerObj[label];
2917 this.hasDefaultHeaders = true;
2920 this.hasHeaders = true;
2925 setHeader:function(o)
2927 if (this.hasDefaultHeaders) {
2928 for (var prop in this.defaultHeaders) {
2929 if (this.defaultHeaders.hasOwnProperty(prop)) {
2930 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2935 if (this.hasHeaders) {
2936 for (var prop in this.headers) {
2937 if (this.headers.hasOwnProperty(prop)) {
2938 o.conn.setRequestHeader(prop, this.headers[prop]);
2942 this.hasHeaders = false;
2946 resetDefaultHeaders:function() {
2947 delete this.defaultHeaders;
2948 this.defaultHeaders = {};
2949 this.hasDefaultHeaders = false;
2952 abort:function(o, callback, isTimeout)
2954 if(this.isCallInProgress(o)) {
2956 window.clearInterval(this.poll[o.tId]);
2957 delete this.poll[o.tId];
2959 delete this.timeout[o.tId];
2962 this.handleTransactionResponse(o, callback, true);
2972 isCallInProgress:function(o)
2975 return o.conn.readyState != 4 && o.conn.readyState != 0;
2984 releaseObject:function(o)
2993 'MSXML2.XMLHTTP.3.0',
3001 * Portions of this file are based on pieces of Yahoo User Interface Library
3002 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3003 * YUI licensed under the BSD License:
3004 * http://developer.yahoo.net/yui/license.txt
3005 * <script type="text/javascript">
3009 Roo.lib.Region = function(t, r, b, l) {
3019 Roo.lib.Region.prototype = {
3020 contains : function(region) {
3021 return ( region.left >= this.left &&
3022 region.right <= this.right &&
3023 region.top >= this.top &&
3024 region.bottom <= this.bottom );
3028 getArea : function() {
3029 return ( (this.bottom - this.top) * (this.right - this.left) );
3032 intersect : function(region) {
3033 var t = Math.max(this.top, region.top);
3034 var r = Math.min(this.right, region.right);
3035 var b = Math.min(this.bottom, region.bottom);
3036 var l = Math.max(this.left, region.left);
3038 if (b >= t && r >= l) {
3039 return new Roo.lib.Region(t, r, b, l);
3044 union : function(region) {
3045 var t = Math.min(this.top, region.top);
3046 var r = Math.max(this.right, region.right);
3047 var b = Math.max(this.bottom, region.bottom);
3048 var l = Math.min(this.left, region.left);
3050 return new Roo.lib.Region(t, r, b, l);
3053 adjust : function(t, l, b, r) {
3062 Roo.lib.Region.getRegion = function(el) {
3063 var p = Roo.lib.Dom.getXY(el);
3066 var r = p[0] + el.offsetWidth;
3067 var b = p[1] + el.offsetHeight;
3070 return new Roo.lib.Region(t, r, b, l);
3073 * Portions of this file are based on pieces of Yahoo User Interface Library
3074 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3075 * YUI licensed under the BSD License:
3076 * http://developer.yahoo.net/yui/license.txt
3077 * <script type="text/javascript">
3080 //@@dep Roo.lib.Region
3083 Roo.lib.Point = function(x, y) {
3084 if (x instanceof Array) {
3088 this.x = this.right = this.left = this[0] = x;
3089 this.y = this.top = this.bottom = this[1] = y;
3092 Roo.lib.Point.prototype = new Roo.lib.Region();
3094 * Portions of this file are based on pieces of Yahoo User Interface Library
3095 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3096 * YUI licensed under the BSD License:
3097 * http://developer.yahoo.net/yui/license.txt
3098 * <script type="text/javascript">
3105 scroll : function(el, args, duration, easing, cb, scope) {
3106 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3109 motion : function(el, args, duration, easing, cb, scope) {
3110 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3113 color : function(el, args, duration, easing, cb, scope) {
3114 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3117 run : function(el, args, duration, easing, cb, scope, type) {
3118 type = type || Roo.lib.AnimBase;
3119 if (typeof easing == "string") {
3120 easing = Roo.lib.Easing[easing];
3122 var anim = new type(el, args, duration, easing);
3123 anim.animateX(function() {
3124 Roo.callback(cb, scope);
3130 * Portions of this file are based on pieces of Yahoo User Interface Library
3131 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3132 * YUI licensed under the BSD License:
3133 * http://developer.yahoo.net/yui/license.txt
3134 * <script type="text/javascript">
3142 if (!libFlyweight) {
3143 libFlyweight = new Roo.Element.Flyweight();
3145 libFlyweight.dom = el;
3146 return libFlyweight;
3149 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3153 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3155 this.init(el, attributes, duration, method);
3159 Roo.lib.AnimBase.fly = fly;
3163 Roo.lib.AnimBase.prototype = {
3165 toString: function() {
3166 var el = this.getEl();
3167 var id = el.id || el.tagName;
3168 return ("Anim " + id);
3172 noNegatives: /width|height|opacity|padding/i,
3173 offsetAttribute: /^((width|height)|(top|left))$/,
3174 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3175 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3179 doMethod: function(attr, start, end) {
3180 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3184 setAttribute: function(attr, val, unit) {
3185 if (this.patterns.noNegatives.test(attr)) {
3186 val = (val > 0) ? val : 0;
3189 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3193 getAttribute: function(attr) {
3194 var el = this.getEl();
3195 var val = fly(el).getStyle(attr);
3197 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3198 return parseFloat(val);
3201 var a = this.patterns.offsetAttribute.exec(attr) || [];
3202 var pos = !!( a[3] );
3203 var box = !!( a[2] );
3206 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3207 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3216 getDefaultUnit: function(attr) {
3217 if (this.patterns.defaultUnit.test(attr)) {
3224 animateX : function(callback, scope) {
3225 var f = function() {
3226 this.onComplete.removeListener(f);
3227 if (typeof callback == "function") {
3228 callback.call(scope || this, this);
3231 this.onComplete.addListener(f, this);
3236 setRuntimeAttribute: function(attr) {
3239 var attributes = this.attributes;
3241 this.runtimeAttributes[attr] = {};
3243 var isset = function(prop) {
3244 return (typeof prop !== 'undefined');
3247 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3251 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3254 if (isset(attributes[attr]['to'])) {
3255 end = attributes[attr]['to'];
3256 } else if (isset(attributes[attr]['by'])) {
3257 if (start.constructor == Array) {
3259 for (var i = 0, len = start.length; i < len; ++i) {
3260 end[i] = start[i] + attributes[attr]['by'][i];
3263 end = start + attributes[attr]['by'];
3267 this.runtimeAttributes[attr].start = start;
3268 this.runtimeAttributes[attr].end = end;
3271 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3275 init: function(el, attributes, duration, method) {
3277 var isAnimated = false;
3280 var startTime = null;
3283 var actualFrames = 0;
3286 el = Roo.getDom(el);
3289 this.attributes = attributes || {};
3292 this.duration = duration || 1;
3295 this.method = method || Roo.lib.Easing.easeNone;
3298 this.useSeconds = true;
3301 this.currentFrame = 0;
3304 this.totalFrames = Roo.lib.AnimMgr.fps;
3307 this.getEl = function() {
3312 this.isAnimated = function() {
3317 this.getStartTime = function() {
3321 this.runtimeAttributes = {};
3324 this.animate = function() {
3325 if (this.isAnimated()) {
3329 this.currentFrame = 0;
3331 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3333 Roo.lib.AnimMgr.registerElement(this);
3337 this.stop = function(finish) {
3339 this.currentFrame = this.totalFrames;
3340 this._onTween.fire();
3342 Roo.lib.AnimMgr.stop(this);
3345 var onStart = function() {
3346 this.onStart.fire();
3348 this.runtimeAttributes = {};
3349 for (var attr in this.attributes) {
3350 this.setRuntimeAttribute(attr);
3355 startTime = new Date();
3359 var onTween = function() {
3361 duration: new Date() - this.getStartTime(),
3362 currentFrame: this.currentFrame
3365 data.toString = function() {
3367 'duration: ' + data.duration +
3368 ', currentFrame: ' + data.currentFrame
3372 this.onTween.fire(data);
3374 var runtimeAttributes = this.runtimeAttributes;
3376 for (var attr in runtimeAttributes) {
3377 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3383 var onComplete = function() {
3384 var actual_duration = (new Date() - startTime) / 1000 ;
3387 duration: actual_duration,
3388 frames: actualFrames,
3389 fps: actualFrames / actual_duration
3392 data.toString = function() {
3394 'duration: ' + data.duration +
3395 ', frames: ' + data.frames +
3396 ', fps: ' + data.fps
3402 this.onComplete.fire(data);
3406 this._onStart = new Roo.util.Event(this);
3407 this.onStart = new Roo.util.Event(this);
3408 this.onTween = new Roo.util.Event(this);
3409 this._onTween = new Roo.util.Event(this);
3410 this.onComplete = new Roo.util.Event(this);
3411 this._onComplete = new Roo.util.Event(this);
3412 this._onStart.addListener(onStart);
3413 this._onTween.addListener(onTween);
3414 this._onComplete.addListener(onComplete);
3419 * Portions of this file are based on pieces of Yahoo User Interface Library
3420 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3421 * YUI licensed under the BSD License:
3422 * http://developer.yahoo.net/yui/license.txt
3423 * <script type="text/javascript">
3427 Roo.lib.AnimMgr = new function() {
3444 this.registerElement = function(tween) {
3445 queue[queue.length] = tween;
3447 tween._onStart.fire();
3452 this.unRegister = function(tween, index) {
3453 tween._onComplete.fire();
3454 index = index || getIndex(tween);
3456 queue.splice(index, 1);
3460 if (tweenCount <= 0) {
3466 this.start = function() {
3467 if (thread === null) {
3468 thread = setInterval(this.run, this.delay);
3473 this.stop = function(tween) {
3475 clearInterval(thread);
3477 for (var i = 0, len = queue.length; i < len; ++i) {
3478 if (queue[0].isAnimated()) {
3479 this.unRegister(queue[0], 0);
3488 this.unRegister(tween);
3493 this.run = function() {
3494 for (var i = 0, len = queue.length; i < len; ++i) {
3495 var tween = queue[i];
3496 if (!tween || !tween.isAnimated()) {
3500 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3502 tween.currentFrame += 1;
3504 if (tween.useSeconds) {
3505 correctFrame(tween);
3507 tween._onTween.fire();
3510 Roo.lib.AnimMgr.stop(tween, i);
3515 var getIndex = function(anim) {
3516 for (var i = 0, len = queue.length; i < len; ++i) {
3517 if (queue[i] == anim) {
3525 var correctFrame = function(tween) {
3526 var frames = tween.totalFrames;
3527 var frame = tween.currentFrame;
3528 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3529 var elapsed = (new Date() - tween.getStartTime());
3532 if (elapsed < tween.duration * 1000) {
3533 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3535 tweak = frames - (frame + 1);
3537 if (tweak > 0 && isFinite(tweak)) {
3538 if (tween.currentFrame + tweak >= frames) {
3539 tweak = frames - (frame + 1);
3542 tween.currentFrame += tweak;
3548 * Portions of this file are based on pieces of Yahoo User Interface Library
3549 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3550 * YUI licensed under the BSD License:
3551 * http://developer.yahoo.net/yui/license.txt
3552 * <script type="text/javascript">
3555 Roo.lib.Bezier = new function() {
3557 this.getPosition = function(points, t) {
3558 var n = points.length;
3561 for (var i = 0; i < n; ++i) {
3562 tmp[i] = [points[i][0], points[i][1]];
3565 for (var j = 1; j < n; ++j) {
3566 for (i = 0; i < n - j; ++i) {
3567 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3568 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3572 return [ tmp[0][0], tmp[0][1] ];
3576 * Portions of this file are based on pieces of Yahoo User Interface Library
3577 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3578 * YUI licensed under the BSD License:
3579 * http://developer.yahoo.net/yui/license.txt
3580 * <script type="text/javascript">
3585 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3586 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3589 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3591 var fly = Roo.lib.AnimBase.fly;
3593 var superclass = Y.ColorAnim.superclass;
3594 var proto = Y.ColorAnim.prototype;
3596 proto.toString = function() {
3597 var el = this.getEl();
3598 var id = el.id || el.tagName;
3599 return ("ColorAnim " + id);
3602 proto.patterns.color = /color$/i;
3603 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3604 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3605 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3606 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3609 proto.parseColor = function(s) {
3610 if (s.length == 3) {
3614 var c = this.patterns.hex.exec(s);
3615 if (c && c.length == 4) {
3616 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3619 c = this.patterns.rgb.exec(s);
3620 if (c && c.length == 4) {
3621 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3624 c = this.patterns.hex3.exec(s);
3625 if (c && c.length == 4) {
3626 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3631 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3632 proto.getAttribute = function(attr) {
3633 var el = this.getEl();
3634 if (this.patterns.color.test(attr)) {
3635 var val = fly(el).getStyle(attr);
3637 if (this.patterns.transparent.test(val)) {
3638 var parent = el.parentNode;
3639 val = fly(parent).getStyle(attr);
3641 while (parent && this.patterns.transparent.test(val)) {
3642 parent = parent.parentNode;
3643 val = fly(parent).getStyle(attr);
3644 if (parent.tagName.toUpperCase() == 'HTML') {
3650 val = superclass.getAttribute.call(this, attr);
3655 proto.getAttribute = function(attr) {
3656 var el = this.getEl();
3657 if (this.patterns.color.test(attr)) {
3658 var val = fly(el).getStyle(attr);
3660 if (this.patterns.transparent.test(val)) {
3661 var parent = el.parentNode;
3662 val = fly(parent).getStyle(attr);
3664 while (parent && this.patterns.transparent.test(val)) {
3665 parent = parent.parentNode;
3666 val = fly(parent).getStyle(attr);
3667 if (parent.tagName.toUpperCase() == 'HTML') {
3673 val = superclass.getAttribute.call(this, attr);
3679 proto.doMethod = function(attr, start, end) {
3682 if (this.patterns.color.test(attr)) {
3684 for (var i = 0, len = start.length; i < len; ++i) {
3685 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3688 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3691 val = superclass.doMethod.call(this, attr, start, end);
3697 proto.setRuntimeAttribute = function(attr) {
3698 superclass.setRuntimeAttribute.call(this, attr);
3700 if (this.patterns.color.test(attr)) {
3701 var attributes = this.attributes;
3702 var start = this.parseColor(this.runtimeAttributes[attr].start);
3703 var end = this.parseColor(this.runtimeAttributes[attr].end);
3705 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3706 end = this.parseColor(attributes[attr].by);
3708 for (var i = 0, len = start.length; i < len; ++i) {
3709 end[i] = start[i] + end[i];
3713 this.runtimeAttributes[attr].start = start;
3714 this.runtimeAttributes[attr].end = end;
3720 * Portions of this file are based on pieces of Yahoo User Interface Library
3721 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3722 * YUI licensed under the BSD License:
3723 * http://developer.yahoo.net/yui/license.txt
3724 * <script type="text/javascript">
3730 easeNone: function (t, b, c, d) {
3731 return c * t / d + b;
3735 easeIn: function (t, b, c, d) {
3736 return c * (t /= d) * t + b;
3740 easeOut: function (t, b, c, d) {
3741 return -c * (t /= d) * (t - 2) + b;
3745 easeBoth: function (t, b, c, d) {
3746 if ((t /= d / 2) < 1) {
3747 return c / 2 * t * t + b;
3750 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3754 easeInStrong: function (t, b, c, d) {
3755 return c * (t /= d) * t * t * t + b;
3759 easeOutStrong: function (t, b, c, d) {
3760 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3764 easeBothStrong: function (t, b, c, d) {
3765 if ((t /= d / 2) < 1) {
3766 return c / 2 * t * t * t * t + b;
3769 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3774 elasticIn: function (t, b, c, d, a, p) {
3778 if ((t /= d) == 1) {
3785 if (!a || a < Math.abs(c)) {
3790 var s = p / (2 * Math.PI) * Math.asin(c / a);
3793 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3797 elasticOut: function (t, b, c, d, a, p) {
3801 if ((t /= d) == 1) {
3808 if (!a || a < Math.abs(c)) {
3813 var s = p / (2 * Math.PI) * Math.asin(c / a);
3816 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3820 elasticBoth: function (t, b, c, d, a, p) {
3825 if ((t /= d / 2) == 2) {
3833 if (!a || a < Math.abs(c)) {
3838 var s = p / (2 * Math.PI) * Math.asin(c / a);
3842 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3843 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3845 return a * Math.pow(2, -10 * (t -= 1)) *
3846 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3851 backIn: function (t, b, c, d, s) {
3852 if (typeof s == 'undefined') {
3855 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3859 backOut: function (t, b, c, d, s) {
3860 if (typeof s == 'undefined') {
3863 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3867 backBoth: function (t, b, c, d, s) {
3868 if (typeof s == 'undefined') {
3872 if ((t /= d / 2 ) < 1) {
3873 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3875 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3879 bounceIn: function (t, b, c, d) {
3880 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3884 bounceOut: function (t, b, c, d) {
3885 if ((t /= d) < (1 / 2.75)) {
3886 return c * (7.5625 * t * t) + b;
3887 } else if (t < (2 / 2.75)) {
3888 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3889 } else if (t < (2.5 / 2.75)) {
3890 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3892 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3896 bounceBoth: function (t, b, c, d) {
3898 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3900 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3903 * Portions of this file are based on pieces of Yahoo User Interface Library
3904 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3905 * YUI licensed under the BSD License:
3906 * http://developer.yahoo.net/yui/license.txt
3907 * <script type="text/javascript">
3911 Roo.lib.Motion = function(el, attributes, duration, method) {
3913 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3917 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3921 var superclass = Y.Motion.superclass;
3922 var proto = Y.Motion.prototype;
3924 proto.toString = function() {
3925 var el = this.getEl();
3926 var id = el.id || el.tagName;
3927 return ("Motion " + id);
3930 proto.patterns.points = /^points$/i;
3932 proto.setAttribute = function(attr, val, unit) {
3933 if (this.patterns.points.test(attr)) {
3934 unit = unit || 'px';
3935 superclass.setAttribute.call(this, 'left', val[0], unit);
3936 superclass.setAttribute.call(this, 'top', val[1], unit);
3938 superclass.setAttribute.call(this, attr, val, unit);
3942 proto.getAttribute = function(attr) {
3943 if (this.patterns.points.test(attr)) {
3945 superclass.getAttribute.call(this, 'left'),
3946 superclass.getAttribute.call(this, 'top')
3949 val = superclass.getAttribute.call(this, attr);
3955 proto.doMethod = function(attr, start, end) {
3958 if (this.patterns.points.test(attr)) {
3959 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3960 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3962 val = superclass.doMethod.call(this, attr, start, end);
3967 proto.setRuntimeAttribute = function(attr) {
3968 if (this.patterns.points.test(attr)) {
3969 var el = this.getEl();
3970 var attributes = this.attributes;
3972 var control = attributes['points']['control'] || [];
3976 if (control.length > 0 && !(control[0] instanceof Array)) {
3977 control = [control];
3980 for (i = 0,len = control.length; i < len; ++i) {
3981 tmp[i] = control[i];
3986 Roo.fly(el).position();
3988 if (isset(attributes['points']['from'])) {
3989 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3992 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3995 start = this.getAttribute('points');
3998 if (isset(attributes['points']['to'])) {
3999 end = translateValues.call(this, attributes['points']['to'], start);
4001 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4002 for (i = 0,len = control.length; i < len; ++i) {
4003 control[i] = translateValues.call(this, control[i], start);
4007 } else if (isset(attributes['points']['by'])) {
4008 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4010 for (i = 0,len = control.length; i < len; ++i) {
4011 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4015 this.runtimeAttributes[attr] = [start];
4017 if (control.length > 0) {
4018 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4021 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4024 superclass.setRuntimeAttribute.call(this, attr);
4028 var translateValues = function(val, start) {
4029 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4030 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4035 var isset = function(prop) {
4036 return (typeof prop !== 'undefined');
4040 * Portions of this file are based on pieces of Yahoo User Interface Library
4041 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4042 * YUI licensed under the BSD License:
4043 * http://developer.yahoo.net/yui/license.txt
4044 * <script type="text/javascript">
4048 Roo.lib.Scroll = function(el, attributes, duration, method) {
4050 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4054 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4058 var superclass = Y.Scroll.superclass;
4059 var proto = Y.Scroll.prototype;
4061 proto.toString = function() {
4062 var el = this.getEl();
4063 var id = el.id || el.tagName;
4064 return ("Scroll " + id);
4067 proto.doMethod = function(attr, start, end) {
4070 if (attr == 'scroll') {
4072 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4073 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4077 val = superclass.doMethod.call(this, attr, start, end);
4082 proto.getAttribute = function(attr) {
4084 var el = this.getEl();
4086 if (attr == 'scroll') {
4087 val = [ el.scrollLeft, el.scrollTop ];
4089 val = superclass.getAttribute.call(this, attr);
4095 proto.setAttribute = function(attr, val, unit) {
4096 var el = this.getEl();
4098 if (attr == 'scroll') {
4099 el.scrollLeft = val[0];
4100 el.scrollTop = val[1];
4102 superclass.setAttribute.call(this, attr, val, unit);
4108 * Ext JS Library 1.1.1
4109 * Copyright(c) 2006-2007, Ext JS, LLC.
4111 * Originally Released Under LGPL - original licence link has changed is not relivant.
4114 * <script type="text/javascript">
4118 // nasty IE9 hack - what a pile of crap that is..
4120 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4121 Range.prototype.createContextualFragment = function (html) {
4122 var doc = window.document;
4123 var container = doc.createElement("div");
4124 container.innerHTML = html;
4125 var frag = doc.createDocumentFragment(), n;
4126 while ((n = container.firstChild)) {
4127 frag.appendChild(n);
4134 * @class Roo.DomHelper
4135 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4136 * 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>.
4139 Roo.DomHelper = function(){
4140 var tempTableEl = null;
4141 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4142 var tableRe = /^table|tbody|tr|td$/i;
4144 // build as innerHTML where available
4146 var createHtml = function(o){
4147 if(typeof o == 'string'){
4156 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4157 if(attr == "style"){
4159 if(typeof s == "function"){
4162 if(typeof s == "string"){
4163 b += ' style="' + s + '"';
4164 }else if(typeof s == "object"){
4167 if(typeof s[key] != "function"){
4168 b += key + ":" + s[key] + ";";
4175 b += ' class="' + o["cls"] + '"';
4176 }else if(attr == "htmlFor"){
4177 b += ' for="' + o["htmlFor"] + '"';
4179 b += " " + attr + '="' + o[attr] + '"';
4183 if(emptyTags.test(o.tag)){
4187 var cn = o.children || o.cn;
4189 //http://bugs.kde.org/show_bug.cgi?id=71506
4190 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4191 for(var i = 0, len = cn.length; i < len; i++) {
4192 b += createHtml(cn[i], b);
4195 b += createHtml(cn, b);
4201 b += "</" + o.tag + ">";
4208 var createDom = function(o, parentNode){
4210 // defininition craeted..
4212 if (o.ns && o.ns != 'html') {
4214 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4215 xmlns[o.ns] = o.xmlns;
4218 if (typeof(xmlns[o.ns]) == 'undefined') {
4219 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4225 if (typeof(o) == 'string') {
4226 return parentNode.appendChild(document.createTextNode(o));
4228 o.tag = o.tag || div;
4229 if (o.ns && Roo.isIE) {
4231 o.tag = o.ns + ':' + o.tag;
4234 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4235 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4238 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4239 attr == "style" || typeof o[attr] == "function") { continue; }
4241 if(attr=="cls" && Roo.isIE){
4242 el.className = o["cls"];
4244 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4250 Roo.DomHelper.applyStyles(el, o.style);
4251 var cn = o.children || o.cn;
4253 //http://bugs.kde.org/show_bug.cgi?id=71506
4254 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4255 for(var i = 0, len = cn.length; i < len; i++) {
4256 createDom(cn[i], el);
4263 el.innerHTML = o.html;
4266 parentNode.appendChild(el);
4271 var ieTable = function(depth, s, h, e){
4272 tempTableEl.innerHTML = [s, h, e].join('');
4273 var i = -1, el = tempTableEl;
4280 // kill repeat to save bytes
4284 tbe = '</tbody>'+te,
4290 * Nasty code for IE's broken table implementation
4292 var insertIntoTable = function(tag, where, el, html){
4294 tempTableEl = document.createElement('div');
4299 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4302 if(where == 'beforebegin'){
4306 before = el.nextSibling;
4309 node = ieTable(4, trs, html, tre);
4311 else if(tag == 'tr'){
4312 if(where == 'beforebegin'){
4315 node = ieTable(3, tbs, html, tbe);
4316 } else if(where == 'afterend'){
4317 before = el.nextSibling;
4319 node = ieTable(3, tbs, html, tbe);
4320 } else{ // INTO a TR
4321 if(where == 'afterbegin'){
4322 before = el.firstChild;
4324 node = ieTable(4, trs, html, tre);
4326 } else if(tag == 'tbody'){
4327 if(where == 'beforebegin'){
4330 node = ieTable(2, ts, html, te);
4331 } else if(where == 'afterend'){
4332 before = el.nextSibling;
4334 node = ieTable(2, ts, html, te);
4336 if(where == 'afterbegin'){
4337 before = el.firstChild;
4339 node = ieTable(3, tbs, html, tbe);
4342 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4345 if(where == 'afterbegin'){
4346 before = el.firstChild;
4348 node = ieTable(2, ts, html, te);
4350 el.insertBefore(node, before);
4355 /** True to force the use of DOM instead of html fragments @type Boolean */
4359 * Returns the markup for the passed Element(s) config
4360 * @param {Object} o The Dom object spec (and children)
4363 markup : function(o){
4364 return createHtml(o);
4368 * Applies a style specification to an element
4369 * @param {String/HTMLElement} el The element to apply styles to
4370 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4371 * a function which returns such a specification.
4373 applyStyles : function(el, styles){
4376 if(typeof styles == "string"){
4377 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4379 while ((matches = re.exec(styles)) != null){
4380 el.setStyle(matches[1], matches[2]);
4382 }else if (typeof styles == "object"){
4383 for (var style in styles){
4384 el.setStyle(style, styles[style]);
4386 }else if (typeof styles == "function"){
4387 Roo.DomHelper.applyStyles(el, styles.call());
4393 * Inserts an HTML fragment into the Dom
4394 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4395 * @param {HTMLElement} el The context element
4396 * @param {String} html The HTML fragmenet
4397 * @return {HTMLElement} The new node
4399 insertHtml : function(where, el, html){
4400 where = where.toLowerCase();
4401 if(el.insertAdjacentHTML){
4402 if(tableRe.test(el.tagName)){
4404 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4410 el.insertAdjacentHTML('BeforeBegin', html);
4411 return el.previousSibling;
4413 el.insertAdjacentHTML('AfterBegin', html);
4414 return el.firstChild;
4416 el.insertAdjacentHTML('BeforeEnd', html);
4417 return el.lastChild;
4419 el.insertAdjacentHTML('AfterEnd', html);
4420 return el.nextSibling;
4422 throw 'Illegal insertion point -> "' + where + '"';
4424 var range = el.ownerDocument.createRange();
4428 range.setStartBefore(el);
4429 frag = range.createContextualFragment(html);
4430 el.parentNode.insertBefore(frag, el);
4431 return el.previousSibling;
4434 range.setStartBefore(el.firstChild);
4435 frag = range.createContextualFragment(html);
4436 el.insertBefore(frag, el.firstChild);
4437 return el.firstChild;
4439 el.innerHTML = html;
4440 return el.firstChild;
4444 range.setStartAfter(el.lastChild);
4445 frag = range.createContextualFragment(html);
4446 el.appendChild(frag);
4447 return el.lastChild;
4449 el.innerHTML = html;
4450 return el.lastChild;
4453 range.setStartAfter(el);
4454 frag = range.createContextualFragment(html);
4455 el.parentNode.insertBefore(frag, el.nextSibling);
4456 return el.nextSibling;
4458 throw 'Illegal insertion point -> "' + where + '"';
4462 * Creates new Dom element(s) and inserts them before el
4463 * @param {String/HTMLElement/Element} el The context element
4464 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4465 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4466 * @return {HTMLElement/Roo.Element} The new node
4468 insertBefore : function(el, o, returnElement){
4469 return this.doInsert(el, o, returnElement, "beforeBegin");
4473 * Creates new Dom element(s) and inserts them after el
4474 * @param {String/HTMLElement/Element} el The context element
4475 * @param {Object} o The Dom object spec (and children)
4476 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4477 * @return {HTMLElement/Roo.Element} The new node
4479 insertAfter : function(el, o, returnElement){
4480 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4484 * Creates new Dom element(s) and inserts them as the first child of el
4485 * @param {String/HTMLElement/Element} el The context element
4486 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4487 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4488 * @return {HTMLElement/Roo.Element} The new node
4490 insertFirst : function(el, o, returnElement){
4491 return this.doInsert(el, o, returnElement, "afterBegin");
4495 doInsert : function(el, o, returnElement, pos, sibling){
4496 el = Roo.getDom(el);
4498 if(this.useDom || o.ns){
4499 newNode = createDom(o, null);
4500 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4502 var html = createHtml(o);
4503 newNode = this.insertHtml(pos, el, html);
4505 return returnElement ? Roo.get(newNode, true) : newNode;
4509 * Creates new Dom element(s) and appends them to el
4510 * @param {String/HTMLElement/Element} el The context element
4511 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4512 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4513 * @return {HTMLElement/Roo.Element} The new node
4515 append : function(el, o, returnElement){
4516 el = Roo.getDom(el);
4518 if(this.useDom || o.ns){
4519 newNode = createDom(o, null);
4520 el.appendChild(newNode);
4522 var html = createHtml(o);
4523 newNode = this.insertHtml("beforeEnd", el, html);
4525 return returnElement ? Roo.get(newNode, true) : newNode;
4529 * Creates new Dom element(s) and overwrites the contents of el with them
4530 * @param {String/HTMLElement/Element} el The context element
4531 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4532 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4533 * @return {HTMLElement/Roo.Element} The new node
4535 overwrite : function(el, o, returnElement){
4536 el = Roo.getDom(el);
4539 while (el.childNodes.length) {
4540 el.removeChild(el.firstChild);
4544 el.innerHTML = createHtml(o);
4547 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4551 * Creates a new Roo.DomHelper.Template from the Dom object spec
4552 * @param {Object} o The Dom object spec (and children)
4553 * @return {Roo.DomHelper.Template} The new template
4555 createTemplate : function(o){
4556 var html = createHtml(o);
4557 return new Roo.Template(html);
4563 * Ext JS Library 1.1.1
4564 * Copyright(c) 2006-2007, Ext JS, LLC.
4566 * Originally Released Under LGPL - original licence link has changed is not relivant.
4569 * <script type="text/javascript">
4573 * @class Roo.Template
4574 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4575 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4578 var t = new Roo.Template({
4579 html : '<div name="{id}">' +
4580 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4582 myformat: function (value, allValues) {
4583 return 'XX' + value;
4586 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4588 * For more information see this blog post with examples:
4589 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4590 - Create Elements using DOM, HTML fragments and Templates</a>.
4592 * @param {Object} cfg - Configuration object.
4594 Roo.Template = function(cfg){
4596 if(cfg instanceof Array){
4598 }else if(arguments.length > 1){
4599 cfg = Array.prototype.join.call(arguments, "");
4603 if (typeof(cfg) == 'object') {
4614 Roo.Template.prototype = {
4617 * @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..
4618 * it should be fixed so that template is observable...
4622 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4626 * Returns an HTML fragment of this template with the specified values applied.
4627 * @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'})
4628 * @return {String} The HTML fragment
4630 applyTemplate : function(values){
4634 return this.compiled(values);
4636 var useF = this.disableFormats !== true;
4637 var fm = Roo.util.Format, tpl = this;
4638 var fn = function(m, name, format, args){
4640 if(format.substr(0, 5) == "this."){
4641 return tpl.call(format.substr(5), values[name], values);
4644 // quoted values are required for strings in compiled templates,
4645 // but for non compiled we need to strip them
4646 // quoted reversed for jsmin
4647 var re = /^\s*['"](.*)["']\s*$/;
4648 args = args.split(',');
4649 for(var i = 0, len = args.length; i < len; i++){
4650 args[i] = args[i].replace(re, "$1");
4652 args = [values[name]].concat(args);
4654 args = [values[name]];
4656 return fm[format].apply(fm, args);
4659 return values[name] !== undefined ? values[name] : "";
4662 return this.html.replace(this.re, fn);
4680 this.loading = true;
4681 this.compiled = false;
4683 var cx = new Roo.data.Connection();
4687 success : function (response) {
4689 _t.html = response.responseText;
4693 failure : function(response) {
4694 Roo.log("Template failed to load from " + _t.url);
4701 * Sets the HTML used as the template and optionally compiles it.
4702 * @param {String} html
4703 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4704 * @return {Roo.Template} this
4706 set : function(html, compile){
4708 this.compiled = null;
4716 * True to disable format functions (defaults to false)
4719 disableFormats : false,
4722 * The regular expression used to match template variables
4726 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4729 * Compiles the template into an internal function, eliminating the RegEx overhead.
4730 * @return {Roo.Template} this
4732 compile : function(){
4733 var fm = Roo.util.Format;
4734 var useF = this.disableFormats !== true;
4735 var sep = Roo.isGecko ? "+" : ",";
4736 var fn = function(m, name, format, args){
4738 args = args ? ',' + args : "";
4739 if(format.substr(0, 5) != "this."){
4740 format = "fm." + format + '(';
4742 format = 'this.call("'+ format.substr(5) + '", ';
4746 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4748 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4751 // branched to use + in gecko and [].join() in others
4753 body = "this.compiled = function(values){ return '" +
4754 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4757 body = ["this.compiled = function(values){ return ['"];
4758 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4759 body.push("'].join('');};");
4760 body = body.join('');
4770 // private function used to call members
4771 call : function(fnName, value, allValues){
4772 return this[fnName](value, allValues);
4776 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4777 * @param {String/HTMLElement/Roo.Element} el The context element
4778 * @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'})
4779 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4780 * @return {HTMLElement/Roo.Element} The new node or Element
4782 insertFirst: function(el, values, returnElement){
4783 return this.doInsert('afterBegin', el, values, returnElement);
4787 * Applies the supplied values to the template and inserts the new node(s) before el.
4788 * @param {String/HTMLElement/Roo.Element} el The context element
4789 * @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'})
4790 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4791 * @return {HTMLElement/Roo.Element} The new node or Element
4793 insertBefore: function(el, values, returnElement){
4794 return this.doInsert('beforeBegin', el, values, returnElement);
4798 * Applies the supplied values to the template and inserts the new node(s) after el.
4799 * @param {String/HTMLElement/Roo.Element} el The context element
4800 * @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'})
4801 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4802 * @return {HTMLElement/Roo.Element} The new node or Element
4804 insertAfter : function(el, values, returnElement){
4805 return this.doInsert('afterEnd', el, values, returnElement);
4809 * Applies the supplied values to the template and appends the new node(s) to el.
4810 * @param {String/HTMLElement/Roo.Element} el The context element
4811 * @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'})
4812 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4813 * @return {HTMLElement/Roo.Element} The new node or Element
4815 append : function(el, values, returnElement){
4816 return this.doInsert('beforeEnd', el, values, returnElement);
4819 doInsert : function(where, el, values, returnEl){
4820 el = Roo.getDom(el);
4821 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4822 return returnEl ? Roo.get(newNode, true) : newNode;
4826 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4827 * @param {String/HTMLElement/Roo.Element} el The context element
4828 * @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'})
4829 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4830 * @return {HTMLElement/Roo.Element} The new node or Element
4832 overwrite : function(el, values, returnElement){
4833 el = Roo.getDom(el);
4834 el.innerHTML = this.applyTemplate(values);
4835 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4839 * Alias for {@link #applyTemplate}
4842 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4845 Roo.DomHelper.Template = Roo.Template;
4848 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4849 * @param {String/HTMLElement} el A DOM element or its id
4850 * @returns {Roo.Template} The created template
4853 Roo.Template.from = function(el){
4854 el = Roo.getDom(el);
4855 return new Roo.Template(el.value || el.innerHTML);
4858 * Ext JS Library 1.1.1
4859 * Copyright(c) 2006-2007, Ext JS, LLC.
4861 * Originally Released Under LGPL - original licence link has changed is not relivant.
4864 * <script type="text/javascript">
4869 * This is code is also distributed under MIT license for use
4870 * with jQuery and prototype JavaScript libraries.
4873 * @class Roo.DomQuery
4874 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).
4876 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>
4879 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.
4881 <h4>Element Selectors:</h4>
4883 <li> <b>*</b> any element</li>
4884 <li> <b>E</b> an element with the tag E</li>
4885 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4886 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4887 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4888 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4890 <h4>Attribute Selectors:</h4>
4891 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4893 <li> <b>E[foo]</b> has an attribute "foo"</li>
4894 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4895 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4896 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4897 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4898 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4899 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4901 <h4>Pseudo Classes:</h4>
4903 <li> <b>E:first-child</b> E is the first child of its parent</li>
4904 <li> <b>E:last-child</b> E is the last child of its parent</li>
4905 <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>
4906 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4907 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4908 <li> <b>E:only-child</b> E is the only child of its parent</li>
4909 <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>
4910 <li> <b>E:first</b> the first E in the resultset</li>
4911 <li> <b>E:last</b> the last E in the resultset</li>
4912 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4913 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4914 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4915 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4916 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4917 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4918 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4919 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4920 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4922 <h4>CSS Value Selectors:</h4>
4924 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4925 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4926 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4927 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4928 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4929 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4933 Roo.DomQuery = function(){
4934 var cache = {}, simpleCache = {}, valueCache = {};
4935 var nonSpace = /\S/;
4936 var trimRe = /^\s+|\s+$/g;
4937 var tplRe = /\{(\d+)\}/g;
4938 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4939 var tagTokenRe = /^(#)?([\w-\*]+)/;
4940 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4942 function child(p, index){
4944 var n = p.firstChild;
4946 if(n.nodeType == 1){
4957 while((n = n.nextSibling) && n.nodeType != 1);
4962 while((n = n.previousSibling) && n.nodeType != 1);
4966 function children(d){
4967 var n = d.firstChild, ni = -1;
4969 var nx = n.nextSibling;
4970 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4980 function byClassName(c, a, v){
4984 var r = [], ri = -1, cn;
4985 for(var i = 0, ci; ci = c[i]; i++){
4986 if((' '+ci.className+' ').indexOf(v) != -1){
4993 function attrValue(n, attr){
4994 if(!n.tagName && typeof n.length != "undefined"){
5003 if(attr == "class" || attr == "className"){
5006 return n.getAttribute(attr) || n[attr];
5010 function getNodes(ns, mode, tagName){
5011 var result = [], ri = -1, cs;
5015 tagName = tagName || "*";
5016 if(typeof ns.getElementsByTagName != "undefined"){
5020 for(var i = 0, ni; ni = ns[i]; i++){
5021 cs = ni.getElementsByTagName(tagName);
5022 for(var j = 0, ci; ci = cs[j]; j++){
5026 }else if(mode == "/" || mode == ">"){
5027 var utag = tagName.toUpperCase();
5028 for(var i = 0, ni, cn; ni = ns[i]; i++){
5029 cn = ni.children || ni.childNodes;
5030 for(var j = 0, cj; cj = cn[j]; j++){
5031 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5036 }else if(mode == "+"){
5037 var utag = tagName.toUpperCase();
5038 for(var i = 0, n; n = ns[i]; i++){
5039 while((n = n.nextSibling) && n.nodeType != 1);
5040 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5044 }else if(mode == "~"){
5045 for(var i = 0, n; n = ns[i]; i++){
5046 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5055 function concat(a, b){
5059 for(var i = 0, l = b.length; i < l; i++){
5065 function byTag(cs, tagName){
5066 if(cs.tagName || cs == document){
5072 var r = [], ri = -1;
5073 tagName = tagName.toLowerCase();
5074 for(var i = 0, ci; ci = cs[i]; i++){
5075 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5082 function byId(cs, attr, id){
5083 if(cs.tagName || cs == document){
5089 var r = [], ri = -1;
5090 for(var i = 0,ci; ci = cs[i]; i++){
5091 if(ci && ci.id == id){
5099 function byAttribute(cs, attr, value, op, custom){
5100 var r = [], ri = -1, st = custom=="{";
5101 var f = Roo.DomQuery.operators[op];
5102 for(var i = 0, ci; ci = cs[i]; i++){
5105 a = Roo.DomQuery.getStyle(ci, attr);
5107 else if(attr == "class" || attr == "className"){
5109 }else if(attr == "for"){
5111 }else if(attr == "href"){
5112 a = ci.getAttribute("href", 2);
5114 a = ci.getAttribute(attr);
5116 if((f && f(a, value)) || (!f && a)){
5123 function byPseudo(cs, name, value){
5124 return Roo.DomQuery.pseudos[name](cs, value);
5127 // This is for IE MSXML which does not support expandos.
5128 // IE runs the same speed using setAttribute, however FF slows way down
5129 // and Safari completely fails so they need to continue to use expandos.
5130 var isIE = window.ActiveXObject ? true : false;
5132 // this eval is stop the compressor from
5133 // renaming the variable to something shorter
5135 /** eval:var:batch */
5140 function nodupIEXml(cs){
5142 cs[0].setAttribute("_nodup", d);
5144 for(var i = 1, len = cs.length; i < len; i++){
5146 if(!c.getAttribute("_nodup") != d){
5147 c.setAttribute("_nodup", d);
5151 for(var i = 0, len = cs.length; i < len; i++){
5152 cs[i].removeAttribute("_nodup");
5161 var len = cs.length, c, i, r = cs, cj, ri = -1;
5162 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5165 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5166 return nodupIEXml(cs);
5170 for(i = 1; c = cs[i]; i++){
5175 for(var j = 0; j < i; j++){
5178 for(j = i+1; cj = cs[j]; j++){
5190 function quickDiffIEXml(c1, c2){
5192 for(var i = 0, len = c1.length; i < len; i++){
5193 c1[i].setAttribute("_qdiff", d);
5196 for(var i = 0, len = c2.length; i < len; i++){
5197 if(c2[i].getAttribute("_qdiff") != d){
5198 r[r.length] = c2[i];
5201 for(var i = 0, len = c1.length; i < len; i++){
5202 c1[i].removeAttribute("_qdiff");
5207 function quickDiff(c1, c2){
5208 var len1 = c1.length;
5212 if(isIE && c1[0].selectSingleNode){
5213 return quickDiffIEXml(c1, c2);
5216 for(var i = 0; i < len1; i++){
5220 for(var i = 0, len = c2.length; i < len; i++){
5221 if(c2[i]._qdiff != d){
5222 r[r.length] = c2[i];
5228 function quickId(ns, mode, root, id){
5230 var d = root.ownerDocument || root;
5231 return d.getElementById(id);
5233 ns = getNodes(ns, mode, "*");
5234 return byId(ns, null, id);
5238 getStyle : function(el, name){
5239 return Roo.fly(el).getStyle(name);
5242 * Compiles a selector/xpath query into a reusable function. The returned function
5243 * takes one parameter "root" (optional), which is the context node from where the query should start.
5244 * @param {String} selector The selector/xpath query
5245 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5246 * @return {Function}
5248 compile : function(path, type){
5249 type = type || "select";
5251 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5252 var q = path, mode, lq;
5253 var tk = Roo.DomQuery.matchers;
5254 var tklen = tk.length;
5257 // accept leading mode switch
5258 var lmode = q.match(modeRe);
5259 if(lmode && lmode[1]){
5260 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5261 q = q.replace(lmode[1], "");
5263 // strip leading slashes
5264 while(path.substr(0, 1)=="/"){
5265 path = path.substr(1);
5268 while(q && lq != q){
5270 var tm = q.match(tagTokenRe);
5271 if(type == "select"){
5274 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5276 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5278 q = q.replace(tm[0], "");
5279 }else if(q.substr(0, 1) != '@'){
5280 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5285 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5287 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5289 q = q.replace(tm[0], "");
5292 while(!(mm = q.match(modeRe))){
5293 var matched = false;
5294 for(var j = 0; j < tklen; j++){
5296 var m = q.match(t.re);
5298 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5301 q = q.replace(m[0], "");
5306 // prevent infinite loop on bad selector
5308 throw 'Error parsing selector, parsing failed at "' + q + '"';
5312 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5313 q = q.replace(mm[1], "");
5316 fn[fn.length] = "return nodup(n);\n}";
5319 * list of variables that need from compression as they are used by eval.
5329 * eval:var:byClassName
5331 * eval:var:byAttribute
5332 * eval:var:attrValue
5340 * Selects a group of elements.
5341 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5342 * @param {Node} root (optional) The start of the query (defaults to document).
5345 select : function(path, root, type){
5346 if(!root || root == document){
5349 if(typeof root == "string"){
5350 root = document.getElementById(root);
5352 var paths = path.split(",");
5354 for(var i = 0, len = paths.length; i < len; i++){
5355 var p = paths[i].replace(trimRe, "");
5357 cache[p] = Roo.DomQuery.compile(p);
5359 throw p + " is not a valid selector";
5362 var result = cache[p](root);
5363 if(result && result != document){
5364 results = results.concat(result);
5367 if(paths.length > 1){
5368 return nodup(results);
5374 * Selects a single element.
5375 * @param {String} selector The selector/xpath query
5376 * @param {Node} root (optional) The start of the query (defaults to document).
5379 selectNode : function(path, root){
5380 return Roo.DomQuery.select(path, root)[0];
5384 * Selects the value of a node, optionally replacing null with the defaultValue.
5385 * @param {String} selector The selector/xpath query
5386 * @param {Node} root (optional) The start of the query (defaults to document).
5387 * @param {String} defaultValue
5389 selectValue : function(path, root, defaultValue){
5390 path = path.replace(trimRe, "");
5391 if(!valueCache[path]){
5392 valueCache[path] = Roo.DomQuery.compile(path, "select");
5394 var n = valueCache[path](root);
5395 n = n[0] ? n[0] : n;
5396 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5397 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5401 * Selects the value of a node, parsing integers and floats.
5402 * @param {String} selector The selector/xpath query
5403 * @param {Node} root (optional) The start of the query (defaults to document).
5404 * @param {Number} defaultValue
5407 selectNumber : function(path, root, defaultValue){
5408 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5409 return parseFloat(v);
5413 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5414 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5415 * @param {String} selector The simple selector to test
5418 is : function(el, ss){
5419 if(typeof el == "string"){
5420 el = document.getElementById(el);
5422 var isArray = (el instanceof Array);
5423 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5424 return isArray ? (result.length == el.length) : (result.length > 0);
5428 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5429 * @param {Array} el An array of elements to filter
5430 * @param {String} selector The simple selector to test
5431 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5432 * the selector instead of the ones that match
5435 filter : function(els, ss, nonMatches){
5436 ss = ss.replace(trimRe, "");
5437 if(!simpleCache[ss]){
5438 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5440 var result = simpleCache[ss](els);
5441 return nonMatches ? quickDiff(result, els) : result;
5445 * Collection of matching regular expressions and code snippets.
5449 select: 'n = byClassName(n, null, " {1} ");'
5451 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5452 select: 'n = byPseudo(n, "{1}", "{2}");'
5454 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5455 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5458 select: 'n = byId(n, null, "{1}");'
5461 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5466 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5467 * 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, > <.
5470 "=" : function(a, v){
5473 "!=" : function(a, v){
5476 "^=" : function(a, v){
5477 return a && a.substr(0, v.length) == v;
5479 "$=" : function(a, v){
5480 return a && a.substr(a.length-v.length) == v;
5482 "*=" : function(a, v){
5483 return a && a.indexOf(v) !== -1;
5485 "%=" : function(a, v){
5486 return (a % v) == 0;
5488 "|=" : function(a, v){
5489 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5491 "~=" : function(a, v){
5492 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5497 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5498 * and the argument (if any) supplied in the selector.
5501 "first-child" : function(c){
5502 var r = [], ri = -1, n;
5503 for(var i = 0, ci; ci = n = c[i]; i++){
5504 while((n = n.previousSibling) && n.nodeType != 1);
5512 "last-child" : function(c){
5513 var r = [], ri = -1, n;
5514 for(var i = 0, ci; ci = n = c[i]; i++){
5515 while((n = n.nextSibling) && n.nodeType != 1);
5523 "nth-child" : function(c, a) {
5524 var r = [], ri = -1;
5525 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5526 var f = (m[1] || 1) - 0, l = m[2] - 0;
5527 for(var i = 0, n; n = c[i]; i++){
5528 var pn = n.parentNode;
5529 if (batch != pn._batch) {
5531 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5532 if(cn.nodeType == 1){
5539 if (l == 0 || n.nodeIndex == l){
5542 } else if ((n.nodeIndex + l) % f == 0){
5550 "only-child" : function(c){
5551 var r = [], ri = -1;;
5552 for(var i = 0, ci; ci = c[i]; i++){
5553 if(!prev(ci) && !next(ci)){
5560 "empty" : function(c){
5561 var r = [], ri = -1;
5562 for(var i = 0, ci; ci = c[i]; i++){
5563 var cns = ci.childNodes, j = 0, cn, empty = true;
5566 if(cn.nodeType == 1 || cn.nodeType == 3){
5578 "contains" : function(c, v){
5579 var r = [], ri = -1;
5580 for(var i = 0, ci; ci = c[i]; i++){
5581 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5588 "nodeValue" : function(c, v){
5589 var r = [], ri = -1;
5590 for(var i = 0, ci; ci = c[i]; i++){
5591 if(ci.firstChild && ci.firstChild.nodeValue == v){
5598 "checked" : function(c){
5599 var r = [], ri = -1;
5600 for(var i = 0, ci; ci = c[i]; i++){
5601 if(ci.checked == true){
5608 "not" : function(c, ss){
5609 return Roo.DomQuery.filter(c, ss, true);
5612 "odd" : function(c){
5613 return this["nth-child"](c, "odd");
5616 "even" : function(c){
5617 return this["nth-child"](c, "even");
5620 "nth" : function(c, a){
5621 return c[a-1] || [];
5624 "first" : function(c){
5628 "last" : function(c){
5629 return c[c.length-1] || [];
5632 "has" : function(c, ss){
5633 var s = Roo.DomQuery.select;
5634 var r = [], ri = -1;
5635 for(var i = 0, ci; ci = c[i]; i++){
5636 if(s(ss, ci).length > 0){
5643 "next" : function(c, ss){
5644 var is = Roo.DomQuery.is;
5645 var r = [], ri = -1;
5646 for(var i = 0, ci; ci = c[i]; i++){
5655 "prev" : function(c, ss){
5656 var is = Roo.DomQuery.is;
5657 var r = [], ri = -1;
5658 for(var i = 0, ci; ci = c[i]; i++){
5671 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5672 * @param {String} path The selector/xpath query
5673 * @param {Node} root (optional) The start of the query (defaults to document).
5678 Roo.query = Roo.DomQuery.select;
5681 * Ext JS Library 1.1.1
5682 * Copyright(c) 2006-2007, Ext JS, LLC.
5684 * Originally Released Under LGPL - original licence link has changed is not relivant.
5687 * <script type="text/javascript">
5691 * @class Roo.util.Observable
5692 * Base class that provides a common interface for publishing events. Subclasses are expected to
5693 * to have a property "events" with all the events defined.<br>
5696 Employee = function(name){
5703 Roo.extend(Employee, Roo.util.Observable);
5705 * @param {Object} config properties to use (incuding events / listeners)
5708 Roo.util.Observable = function(cfg){
5711 this.addEvents(cfg.events || {});
5713 delete cfg.events; // make sure
5716 Roo.apply(this, cfg);
5719 this.on(this.listeners);
5720 delete this.listeners;
5723 Roo.util.Observable.prototype = {
5725 * @cfg {Object} listeners list of events and functions to call for this object,
5729 'click' : function(e) {
5739 * Fires the specified event with the passed parameters (minus the event name).
5740 * @param {String} eventName
5741 * @param {Object...} args Variable number of parameters are passed to handlers
5742 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5744 fireEvent : function(){
5745 var ce = this.events[arguments[0].toLowerCase()];
5746 if(typeof ce == "object"){
5747 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5754 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5757 * Appends an event handler to this component
5758 * @param {String} eventName The type of event to listen for
5759 * @param {Function} handler The method the event invokes
5760 * @param {Object} scope (optional) The scope in which to execute the handler
5761 * function. The handler function's "this" context.
5762 * @param {Object} options (optional) An object containing handler configuration
5763 * properties. This may contain any of the following properties:<ul>
5764 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5765 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5766 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5767 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5768 * by the specified number of milliseconds. If the event fires again within that time, the original
5769 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5772 * <b>Combining Options</b><br>
5773 * Using the options argument, it is possible to combine different types of listeners:<br>
5775 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5777 el.on('click', this.onClick, this, {
5784 * <b>Attaching multiple handlers in 1 call</b><br>
5785 * The method also allows for a single argument to be passed which is a config object containing properties
5786 * which specify multiple handlers.
5795 fn: this.onMouseOver,
5799 fn: this.onMouseOut,
5805 * Or a shorthand syntax which passes the same scope object to all handlers:
5808 'click': this.onClick,
5809 'mouseover': this.onMouseOver,
5810 'mouseout': this.onMouseOut,
5815 addListener : function(eventName, fn, scope, o){
5816 if(typeof eventName == "object"){
5819 if(this.filterOptRe.test(e)){
5822 if(typeof o[e] == "function"){
5824 this.addListener(e, o[e], o.scope, o);
5826 // individual options
5827 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5832 o = (!o || typeof o == "boolean") ? {} : o;
5833 eventName = eventName.toLowerCase();
5834 var ce = this.events[eventName] || true;
5835 if(typeof ce == "boolean"){
5836 ce = new Roo.util.Event(this, eventName);
5837 this.events[eventName] = ce;
5839 ce.addListener(fn, scope, o);
5843 * Removes a listener
5844 * @param {String} eventName The type of event to listen for
5845 * @param {Function} handler The handler to remove
5846 * @param {Object} scope (optional) The scope (this object) for the handler
5848 removeListener : function(eventName, fn, scope){
5849 var ce = this.events[eventName.toLowerCase()];
5850 if(typeof ce == "object"){
5851 ce.removeListener(fn, scope);
5856 * Removes all listeners for this object
5858 purgeListeners : function(){
5859 for(var evt in this.events){
5860 if(typeof this.events[evt] == "object"){
5861 this.events[evt].clearListeners();
5866 relayEvents : function(o, events){
5867 var createHandler = function(ename){
5869 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5872 for(var i = 0, len = events.length; i < len; i++){
5873 var ename = events[i];
5874 if(!this.events[ename]){ this.events[ename] = true; };
5875 o.on(ename, createHandler(ename), this);
5880 * Used to define events on this Observable
5881 * @param {Object} object The object with the events defined
5883 addEvents : function(o){
5887 Roo.applyIf(this.events, o);
5891 * Checks to see if this object has any listeners for a specified event
5892 * @param {String} eventName The name of the event to check for
5893 * @return {Boolean} True if the event is being listened for, else false
5895 hasListener : function(eventName){
5896 var e = this.events[eventName];
5897 return typeof e == "object" && e.listeners.length > 0;
5901 * Appends an event handler to this element (shorthand for addListener)
5902 * @param {String} eventName The type of event to listen for
5903 * @param {Function} handler The method the event invokes
5904 * @param {Object} scope (optional) The scope in which to execute the handler
5905 * function. The handler function's "this" context.
5906 * @param {Object} options (optional)
5909 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5911 * Removes a listener (shorthand for removeListener)
5912 * @param {String} eventName The type of event to listen for
5913 * @param {Function} handler The handler to remove
5914 * @param {Object} scope (optional) The scope (this object) for the handler
5917 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5920 * Starts capture on the specified Observable. All events will be passed
5921 * to the supplied function with the event name + standard signature of the event
5922 * <b>before</b> the event is fired. If the supplied function returns false,
5923 * the event will not fire.
5924 * @param {Observable} o The Observable to capture
5925 * @param {Function} fn The function to call
5926 * @param {Object} scope (optional) The scope (this object) for the fn
5929 Roo.util.Observable.capture = function(o, fn, scope){
5930 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5934 * Removes <b>all</b> added captures from the Observable.
5935 * @param {Observable} o The Observable to release
5938 Roo.util.Observable.releaseCapture = function(o){
5939 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5944 var createBuffered = function(h, o, scope){
5945 var task = new Roo.util.DelayedTask();
5947 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5951 var createSingle = function(h, e, fn, scope){
5953 e.removeListener(fn, scope);
5954 return h.apply(scope, arguments);
5958 var createDelayed = function(h, o, scope){
5960 var args = Array.prototype.slice.call(arguments, 0);
5961 setTimeout(function(){
5962 h.apply(scope, args);
5967 Roo.util.Event = function(obj, name){
5970 this.listeners = [];
5973 Roo.util.Event.prototype = {
5974 addListener : function(fn, scope, options){
5975 var o = options || {};
5976 scope = scope || this.obj;
5977 if(!this.isListening(fn, scope)){
5978 var l = {fn: fn, scope: scope, options: o};
5981 h = createDelayed(h, o, scope);
5984 h = createSingle(h, this, fn, scope);
5987 h = createBuffered(h, o, scope);
5990 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5991 this.listeners.push(l);
5993 this.listeners = this.listeners.slice(0);
5994 this.listeners.push(l);
5999 findListener : function(fn, scope){
6000 scope = scope || this.obj;
6001 var ls = this.listeners;
6002 for(var i = 0, len = ls.length; i < len; i++){
6004 if(l.fn == fn && l.scope == scope){
6011 isListening : function(fn, scope){
6012 return this.findListener(fn, scope) != -1;
6015 removeListener : function(fn, scope){
6017 if((index = this.findListener(fn, scope)) != -1){
6019 this.listeners.splice(index, 1);
6021 this.listeners = this.listeners.slice(0);
6022 this.listeners.splice(index, 1);
6029 clearListeners : function(){
6030 this.listeners = [];
6034 var ls = this.listeners, scope, len = ls.length;
6037 var args = Array.prototype.slice.call(arguments, 0);
6038 for(var i = 0; i < len; i++){
6040 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6041 this.firing = false;
6045 this.firing = false;
6052 * Ext JS Library 1.1.1
6053 * Copyright(c) 2006-2007, Ext JS, LLC.
6055 * Originally Released Under LGPL - original licence link has changed is not relivant.
6058 * <script type="text/javascript">
6062 * @class Roo.EventManager
6063 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6064 * several useful events directly.
6065 * See {@link Roo.EventObject} for more details on normalized event objects.
6068 Roo.EventManager = function(){
6069 var docReadyEvent, docReadyProcId, docReadyState = false;
6070 var resizeEvent, resizeTask, textEvent, textSize;
6071 var E = Roo.lib.Event;
6072 var D = Roo.lib.Dom;
6077 var fireDocReady = function(){
6079 docReadyState = true;
6082 clearInterval(docReadyProcId);
6084 if(Roo.isGecko || Roo.isOpera) {
6085 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6088 var defer = document.getElementById("ie-deferred-loader");
6090 defer.onreadystatechange = null;
6091 defer.parentNode.removeChild(defer);
6095 docReadyEvent.fire();
6096 docReadyEvent.clearListeners();
6101 var initDocReady = function(){
6102 docReadyEvent = new Roo.util.Event();
6103 if(Roo.isGecko || Roo.isOpera) {
6104 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6106 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6107 var defer = document.getElementById("ie-deferred-loader");
6108 defer.onreadystatechange = function(){
6109 if(this.readyState == "complete"){
6113 }else if(Roo.isSafari){
6114 docReadyProcId = setInterval(function(){
6115 var rs = document.readyState;
6116 if(rs == "complete") {
6121 // no matter what, make sure it fires on load
6122 E.on(window, "load", fireDocReady);
6125 var createBuffered = function(h, o){
6126 var task = new Roo.util.DelayedTask(h);
6128 // create new event object impl so new events don't wipe out properties
6129 e = new Roo.EventObjectImpl(e);
6130 task.delay(o.buffer, h, null, [e]);
6134 var createSingle = function(h, el, ename, fn){
6136 Roo.EventManager.removeListener(el, ename, fn);
6141 var createDelayed = function(h, o){
6143 // create new event object impl so new events don't wipe out properties
6144 e = new Roo.EventObjectImpl(e);
6145 setTimeout(function(){
6150 var transitionEndVal = false;
6152 var transitionEnd = function()
6154 if (transitionEndVal) {
6155 return transitionEndVal;
6157 var el = document.createElement('div');
6159 var transEndEventNames = {
6160 WebkitTransition : 'webkitTransitionEnd',
6161 MozTransition : 'transitionend',
6162 OTransition : 'oTransitionEnd otransitionend',
6163 transition : 'transitionend'
6166 for (var name in transEndEventNames) {
6167 if (el.style[name] !== undefined) {
6168 transitionEndVal = transEndEventNames[name];
6169 return transitionEndVal ;
6175 var listen = function(element, ename, opt, fn, scope){
6176 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6177 fn = fn || o.fn; scope = scope || o.scope;
6178 var el = Roo.getDom(element);
6182 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6185 if (ename == 'transitionend') {
6186 ename = transitionEnd();
6188 var h = function(e){
6189 e = Roo.EventObject.setEvent(e);
6192 t = e.getTarget(o.delegate, el);
6199 if(o.stopEvent === true){
6202 if(o.preventDefault === true){
6205 if(o.stopPropagation === true){
6206 e.stopPropagation();
6209 if(o.normalized === false){
6213 fn.call(scope || el, e, t, o);
6216 h = createDelayed(h, o);
6219 h = createSingle(h, el, ename, fn);
6222 h = createBuffered(h, o);
6224 fn._handlers = fn._handlers || [];
6227 fn._handlers.push([Roo.id(el), ename, h]);
6232 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6233 el.addEventListener("DOMMouseScroll", h, false);
6234 E.on(window, 'unload', function(){
6235 el.removeEventListener("DOMMouseScroll", h, false);
6238 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6239 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6244 var stopListening = function(el, ename, fn){
6245 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6247 for(var i = 0, len = hds.length; i < len; i++){
6249 if(h[0] == id && h[1] == ename){
6256 E.un(el, ename, hd);
6257 el = Roo.getDom(el);
6258 if(ename == "mousewheel" && el.addEventListener){
6259 el.removeEventListener("DOMMouseScroll", hd, false);
6261 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6262 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6266 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6273 * @scope Roo.EventManager
6278 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6279 * object with a Roo.EventObject
6280 * @param {Function} fn The method the event invokes
6281 * @param {Object} scope An object that becomes the scope of the handler
6282 * @param {boolean} override If true, the obj passed in becomes
6283 * the execution scope of the listener
6284 * @return {Function} The wrapped function
6287 wrap : function(fn, scope, override){
6289 Roo.EventObject.setEvent(e);
6290 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6295 * Appends an event handler to an element (shorthand for addListener)
6296 * @param {String/HTMLElement} element The html element or id to assign the
6297 * @param {String} eventName The type of event to listen for
6298 * @param {Function} handler The method the event invokes
6299 * @param {Object} scope (optional) The scope in which to execute the handler
6300 * function. The handler function's "this" context.
6301 * @param {Object} options (optional) An object containing handler configuration
6302 * properties. This may contain any of the following properties:<ul>
6303 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6304 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6305 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6306 * <li>preventDefault {Boolean} True to prevent the default action</li>
6307 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6308 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6309 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6310 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6311 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6312 * by the specified number of milliseconds. If the event fires again within that time, the original
6313 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6316 * <b>Combining Options</b><br>
6317 * Using the options argument, it is possible to combine different types of listeners:<br>
6319 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6321 el.on('click', this.onClick, this, {
6328 * <b>Attaching multiple handlers in 1 call</b><br>
6329 * The method also allows for a single argument to be passed which is a config object containing properties
6330 * which specify multiple handlers.
6340 fn: this.onMouseOver
6349 * Or a shorthand syntax:<br>
6352 'click' : this.onClick,
6353 'mouseover' : this.onMouseOver,
6354 'mouseout' : this.onMouseOut
6358 addListener : function(element, eventName, fn, scope, options){
6359 if(typeof eventName == "object"){
6365 if(typeof o[e] == "function"){
6367 listen(element, e, o, o[e], o.scope);
6369 // individual options
6370 listen(element, e, o[e]);
6375 return listen(element, eventName, options, fn, scope);
6379 * Removes an event handler
6381 * @param {String/HTMLElement} element The id or html element to remove the
6383 * @param {String} eventName The type of event
6384 * @param {Function} fn
6385 * @return {Boolean} True if a listener was actually removed
6387 removeListener : function(element, eventName, fn){
6388 return stopListening(element, eventName, fn);
6392 * Fires when the document is ready (before onload and before images are loaded). Can be
6393 * accessed shorthanded Roo.onReady().
6394 * @param {Function} fn The method the event invokes
6395 * @param {Object} scope An object that becomes the scope of the handler
6396 * @param {boolean} options
6398 onDocumentReady : function(fn, scope, options){
6399 if(docReadyState){ // if it already fired
6400 docReadyEvent.addListener(fn, scope, options);
6401 docReadyEvent.fire();
6402 docReadyEvent.clearListeners();
6408 docReadyEvent.addListener(fn, scope, options);
6412 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6413 * @param {Function} fn The method the event invokes
6414 * @param {Object} scope An object that becomes the scope of the handler
6415 * @param {boolean} options
6417 onWindowResize : function(fn, scope, options){
6419 resizeEvent = new Roo.util.Event();
6420 resizeTask = new Roo.util.DelayedTask(function(){
6421 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6423 E.on(window, "resize", function(){
6425 resizeTask.delay(50);
6427 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6431 resizeEvent.addListener(fn, scope, options);
6435 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6436 * @param {Function} fn The method the event invokes
6437 * @param {Object} scope An object that becomes the scope of the handler
6438 * @param {boolean} options
6440 onTextResize : function(fn, scope, options){
6442 textEvent = new Roo.util.Event();
6443 var textEl = new Roo.Element(document.createElement('div'));
6444 textEl.dom.className = 'x-text-resize';
6445 textEl.dom.innerHTML = 'X';
6446 textEl.appendTo(document.body);
6447 textSize = textEl.dom.offsetHeight;
6448 setInterval(function(){
6449 if(textEl.dom.offsetHeight != textSize){
6450 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6452 }, this.textResizeInterval);
6454 textEvent.addListener(fn, scope, options);
6458 * Removes the passed window resize listener.
6459 * @param {Function} fn The method the event invokes
6460 * @param {Object} scope The scope of handler
6462 removeResizeListener : function(fn, scope){
6464 resizeEvent.removeListener(fn, scope);
6469 fireResize : function(){
6471 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6475 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6479 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6481 textResizeInterval : 50
6486 * @scopeAlias pub=Roo.EventManager
6490 * Appends an event handler to an element (shorthand for addListener)
6491 * @param {String/HTMLElement} element The html element or id to assign the
6492 * @param {String} eventName The type of event to listen for
6493 * @param {Function} handler The method the event invokes
6494 * @param {Object} scope (optional) The scope in which to execute the handler
6495 * function. The handler function's "this" context.
6496 * @param {Object} options (optional) An object containing handler configuration
6497 * properties. This may contain any of the following properties:<ul>
6498 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6499 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6500 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6501 * <li>preventDefault {Boolean} True to prevent the default action</li>
6502 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6503 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6504 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6505 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6506 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6507 * by the specified number of milliseconds. If the event fires again within that time, the original
6508 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6511 * <b>Combining Options</b><br>
6512 * Using the options argument, it is possible to combine different types of listeners:<br>
6514 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6516 el.on('click', this.onClick, this, {
6523 * <b>Attaching multiple handlers in 1 call</b><br>
6524 * The method also allows for a single argument to be passed which is a config object containing properties
6525 * which specify multiple handlers.
6535 fn: this.onMouseOver
6544 * Or a shorthand syntax:<br>
6547 'click' : this.onClick,
6548 'mouseover' : this.onMouseOver,
6549 'mouseout' : this.onMouseOut
6553 pub.on = pub.addListener;
6554 pub.un = pub.removeListener;
6556 pub.stoppedMouseDownEvent = new Roo.util.Event();
6560 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6561 * @param {Function} fn The method the event invokes
6562 * @param {Object} scope An object that becomes the scope of the handler
6563 * @param {boolean} override If true, the obj passed in becomes
6564 * the execution scope of the listener
6568 Roo.onReady = Roo.EventManager.onDocumentReady;
6570 Roo.onReady(function(){
6571 var bd = Roo.get(document.body);
6576 : Roo.isGecko ? "roo-gecko"
6577 : Roo.isOpera ? "roo-opera"
6578 : Roo.isSafari ? "roo-safari" : ""];
6581 cls.push("roo-mac");
6584 cls.push("roo-linux");
6587 cls.push("roo-ios");
6590 cls.push("roo-touch");
6592 if(Roo.isBorderBox){
6593 cls.push('roo-border-box');
6595 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6596 var p = bd.dom.parentNode;
6598 p.className += ' roo-strict';
6601 bd.addClass(cls.join(' '));
6605 * @class Roo.EventObject
6606 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6607 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6610 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6612 var target = e.getTarget();
6615 var myDiv = Roo.get("myDiv");
6616 myDiv.on("click", handleClick);
6618 Roo.EventManager.on("myDiv", 'click', handleClick);
6619 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6623 Roo.EventObject = function(){
6625 var E = Roo.lib.Event;
6627 // safari keypress events for special keys return bad keycodes
6630 63235 : 39, // right
6633 63276 : 33, // page up
6634 63277 : 34, // page down
6635 63272 : 46, // delete
6640 // normalize button clicks
6641 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6642 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6644 Roo.EventObjectImpl = function(e){
6646 this.setEvent(e.browserEvent || e);
6649 Roo.EventObjectImpl.prototype = {
6651 * Used to fix doc tools.
6652 * @scope Roo.EventObject.prototype
6658 /** The normal browser event */
6659 browserEvent : null,
6660 /** The button pressed in a mouse event */
6662 /** True if the shift key was down during the event */
6664 /** True if the control key was down during the event */
6666 /** True if the alt key was down during the event */
6725 setEvent : function(e){
6726 if(e == this || (e && e.browserEvent)){ // already wrapped
6729 this.browserEvent = e;
6731 // normalize buttons
6732 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6733 if(e.type == 'click' && this.button == -1){
6737 this.shiftKey = e.shiftKey;
6738 // mac metaKey behaves like ctrlKey
6739 this.ctrlKey = e.ctrlKey || e.metaKey;
6740 this.altKey = e.altKey;
6741 // in getKey these will be normalized for the mac
6742 this.keyCode = e.keyCode;
6743 // keyup warnings on firefox.
6744 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6745 // cache the target for the delayed and or buffered events
6746 this.target = E.getTarget(e);
6748 this.xy = E.getXY(e);
6751 this.shiftKey = false;
6752 this.ctrlKey = false;
6753 this.altKey = false;
6763 * Stop the event (preventDefault and stopPropagation)
6765 stopEvent : function(){
6766 if(this.browserEvent){
6767 if(this.browserEvent.type == 'mousedown'){
6768 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6770 E.stopEvent(this.browserEvent);
6775 * Prevents the browsers default handling of the event.
6777 preventDefault : function(){
6778 if(this.browserEvent){
6779 E.preventDefault(this.browserEvent);
6784 isNavKeyPress : function(){
6785 var k = this.keyCode;
6786 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6787 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6790 isSpecialKey : function(){
6791 var k = this.keyCode;
6792 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6793 (k == 16) || (k == 17) ||
6794 (k >= 18 && k <= 20) ||
6795 (k >= 33 && k <= 35) ||
6796 (k >= 36 && k <= 39) ||
6797 (k >= 44 && k <= 45);
6800 * Cancels bubbling of the event.
6802 stopPropagation : function(){
6803 if(this.browserEvent){
6804 if(this.type == 'mousedown'){
6805 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6807 E.stopPropagation(this.browserEvent);
6812 * Gets the key code for the event.
6815 getCharCode : function(){
6816 return this.charCode || this.keyCode;
6820 * Returns a normalized keyCode for the event.
6821 * @return {Number} The key code
6823 getKey : function(){
6824 var k = this.keyCode || this.charCode;
6825 return Roo.isSafari ? (safariKeys[k] || k) : k;
6829 * Gets the x coordinate of the event.
6832 getPageX : function(){
6837 * Gets the y coordinate of the event.
6840 getPageY : function(){
6845 * Gets the time of the event.
6848 getTime : function(){
6849 if(this.browserEvent){
6850 return E.getTime(this.browserEvent);
6856 * Gets the page coordinates of the event.
6857 * @return {Array} The xy values like [x, y]
6864 * Gets the target for the event.
6865 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6866 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6867 search as a number or element (defaults to 10 || document.body)
6868 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6869 * @return {HTMLelement}
6871 getTarget : function(selector, maxDepth, returnEl){
6872 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6875 * Gets the related target.
6876 * @return {HTMLElement}
6878 getRelatedTarget : function(){
6879 if(this.browserEvent){
6880 return E.getRelatedTarget(this.browserEvent);
6886 * Normalizes mouse wheel delta across browsers
6887 * @return {Number} The delta
6889 getWheelDelta : function(){
6890 var e = this.browserEvent;
6892 if(e.wheelDelta){ /* IE/Opera. */
6893 delta = e.wheelDelta/120;
6894 }else if(e.detail){ /* Mozilla case. */
6895 delta = -e.detail/3;
6901 * Returns true if the control, meta, shift or alt key was pressed during this event.
6904 hasModifier : function(){
6905 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6909 * Returns true if the target of this event equals el or is a child of el
6910 * @param {String/HTMLElement/Element} el
6911 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6914 within : function(el, related){
6915 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6916 return t && Roo.fly(el).contains(t);
6919 getPoint : function(){
6920 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6924 return new Roo.EventObjectImpl();
6929 * Ext JS Library 1.1.1
6930 * Copyright(c) 2006-2007, Ext JS, LLC.
6932 * Originally Released Under LGPL - original licence link has changed is not relivant.
6935 * <script type="text/javascript">
6939 // was in Composite Element!??!?!
6942 var D = Roo.lib.Dom;
6943 var E = Roo.lib.Event;
6944 var A = Roo.lib.Anim;
6946 // local style camelizing for speed
6948 var camelRe = /(-[a-z])/gi;
6949 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6950 var view = document.defaultView;
6953 * @class Roo.Element
6954 * Represents an Element in the DOM.<br><br>
6957 var el = Roo.get("my-div");
6960 var el = getEl("my-div");
6962 // or with a DOM element
6963 var el = Roo.get(myDivElement);
6965 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6966 * each call instead of constructing a new one.<br><br>
6967 * <b>Animations</b><br />
6968 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6969 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6971 Option Default Description
6972 --------- -------- ---------------------------------------------
6973 duration .35 The duration of the animation in seconds
6974 easing easeOut The YUI easing method
6975 callback none A function to execute when the anim completes
6976 scope this The scope (this) of the callback function
6978 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6979 * manipulate the animation. Here's an example:
6981 var el = Roo.get("my-div");
6986 // default animation
6987 el.setWidth(100, true);
6989 // animation with some options set
6996 // using the "anim" property to get the Anim object
7002 el.setWidth(100, opt);
7004 if(opt.anim.isAnimated()){
7008 * <b> Composite (Collections of) Elements</b><br />
7009 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7010 * @constructor Create a new Element directly.
7011 * @param {String/HTMLElement} element
7012 * @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).
7014 Roo.Element = function(element, forceNew){
7015 var dom = typeof element == "string" ?
7016 document.getElementById(element) : element;
7017 if(!dom){ // invalid id/element
7021 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7022 return Roo.Element.cache[id];
7032 * The DOM element ID
7035 this.id = id || Roo.id(dom);
7038 var El = Roo.Element;
7042 * The element's default display mode (defaults to "")
7045 originalDisplay : "",
7049 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7055 * Sets the element's visibility mode. When setVisible() is called it
7056 * will use this to determine whether to set the visibility or the display property.
7057 * @param visMode Element.VISIBILITY or Element.DISPLAY
7058 * @return {Roo.Element} this
7060 setVisibilityMode : function(visMode){
7061 this.visibilityMode = visMode;
7065 * Convenience method for setVisibilityMode(Element.DISPLAY)
7066 * @param {String} display (optional) What to set display to when visible
7067 * @return {Roo.Element} this
7069 enableDisplayMode : function(display){
7070 this.setVisibilityMode(El.DISPLAY);
7071 if(typeof display != "undefined") { this.originalDisplay = display; }
7076 * 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)
7077 * @param {String} selector The simple selector to test
7078 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7079 search as a number or element (defaults to 10 || document.body)
7080 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7081 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7083 findParent : function(simpleSelector, maxDepth, returnEl){
7084 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7085 maxDepth = maxDepth || 50;
7086 if(typeof maxDepth != "number"){
7087 stopEl = Roo.getDom(maxDepth);
7090 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7091 if(dq.is(p, simpleSelector)){
7092 return returnEl ? Roo.get(p) : p;
7102 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7103 * @param {String} selector The simple selector to test
7104 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7105 search as a number or element (defaults to 10 || document.body)
7106 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7107 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7109 findParentNode : function(simpleSelector, maxDepth, returnEl){
7110 var p = Roo.fly(this.dom.parentNode, '_internal');
7111 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7115 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7116 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7117 * @param {String} selector The simple selector to test
7118 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7119 search as a number or element (defaults to 10 || document.body)
7120 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7122 up : function(simpleSelector, maxDepth){
7123 return this.findParentNode(simpleSelector, maxDepth, true);
7129 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7130 * @param {String} selector The simple selector to test
7131 * @return {Boolean} True if this element matches the selector, else false
7133 is : function(simpleSelector){
7134 return Roo.DomQuery.is(this.dom, simpleSelector);
7138 * Perform animation on this element.
7139 * @param {Object} args The YUI animation control args
7140 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7141 * @param {Function} onComplete (optional) Function to call when animation completes
7142 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7143 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7144 * @return {Roo.Element} this
7146 animate : function(args, duration, onComplete, easing, animType){
7147 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7152 * @private Internal animation call
7154 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7155 animType = animType || 'run';
7157 var anim = Roo.lib.Anim[animType](
7159 (opt.duration || defaultDur) || .35,
7160 (opt.easing || defaultEase) || 'easeOut',
7162 Roo.callback(cb, this);
7163 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7171 // private legacy anim prep
7172 preanim : function(a, i){
7173 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7177 * Removes worthless text nodes
7178 * @param {Boolean} forceReclean (optional) By default the element
7179 * keeps track if it has been cleaned already so
7180 * you can call this over and over. However, if you update the element and
7181 * need to force a reclean, you can pass true.
7183 clean : function(forceReclean){
7184 if(this.isCleaned && forceReclean !== true){
7188 var d = this.dom, n = d.firstChild, ni = -1;
7190 var nx = n.nextSibling;
7191 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7198 this.isCleaned = true;
7203 calcOffsetsTo : function(el){
7206 var restorePos = false;
7207 if(el.getStyle('position') == 'static'){
7208 el.position('relative');
7213 while(op && op != d && op.tagName != 'HTML'){
7216 op = op.offsetParent;
7219 el.position('static');
7225 * Scrolls this element into view within the passed container.
7226 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7227 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7228 * @return {Roo.Element} this
7230 scrollIntoView : function(container, hscroll){
7231 var c = Roo.getDom(container) || document.body;
7234 var o = this.calcOffsetsTo(c),
7237 b = t+el.offsetHeight,
7238 r = l+el.offsetWidth;
7240 var ch = c.clientHeight;
7241 var ct = parseInt(c.scrollTop, 10);
7242 var cl = parseInt(c.scrollLeft, 10);
7244 var cr = cl + c.clientWidth;
7252 if(hscroll !== false){
7256 c.scrollLeft = r-c.clientWidth;
7263 scrollChildIntoView : function(child, hscroll){
7264 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7268 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7269 * the new height may not be available immediately.
7270 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7271 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7272 * @param {Function} onComplete (optional) Function to call when animation completes
7273 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7274 * @return {Roo.Element} this
7276 autoHeight : function(animate, duration, onComplete, easing){
7277 var oldHeight = this.getHeight();
7279 this.setHeight(1); // force clipping
7280 setTimeout(function(){
7281 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7283 this.setHeight(height);
7285 if(typeof onComplete == "function"){
7289 this.setHeight(oldHeight); // restore original height
7290 this.setHeight(height, animate, duration, function(){
7292 if(typeof onComplete == "function") { onComplete(); }
7293 }.createDelegate(this), easing);
7295 }.createDelegate(this), 0);
7300 * Returns true if this element is an ancestor of the passed element
7301 * @param {HTMLElement/String} el The element to check
7302 * @return {Boolean} True if this element is an ancestor of el, else false
7304 contains : function(el){
7305 if(!el){return false;}
7306 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7310 * Checks whether the element is currently visible using both visibility and display properties.
7311 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7312 * @return {Boolean} True if the element is currently visible, else false
7314 isVisible : function(deep) {
7315 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7316 if(deep !== true || !vis){
7319 var p = this.dom.parentNode;
7320 while(p && p.tagName.toLowerCase() != "body"){
7321 if(!Roo.fly(p, '_isVisible').isVisible()){
7330 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7331 * @param {String} selector The CSS selector
7332 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7333 * @return {CompositeElement/CompositeElementLite} The composite element
7335 select : function(selector, unique){
7336 return El.select(selector, unique, this.dom);
7340 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7341 * @param {String} selector The CSS selector
7342 * @return {Array} An array of the matched nodes
7344 query : function(selector, unique){
7345 return Roo.DomQuery.select(selector, this.dom);
7349 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7350 * @param {String} selector The CSS selector
7351 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7352 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7354 child : function(selector, returnDom){
7355 var n = Roo.DomQuery.selectNode(selector, this.dom);
7356 return returnDom ? n : Roo.get(n);
7360 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7361 * @param {String} selector The CSS selector
7362 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7363 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7365 down : function(selector, returnDom){
7366 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7367 return returnDom ? n : Roo.get(n);
7371 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7372 * @param {String} group The group the DD object is member of
7373 * @param {Object} config The DD config object
7374 * @param {Object} overrides An object containing methods to override/implement on the DD object
7375 * @return {Roo.dd.DD} The DD object
7377 initDD : function(group, config, overrides){
7378 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7379 return Roo.apply(dd, overrides);
7383 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7384 * @param {String} group The group the DDProxy object is member of
7385 * @param {Object} config The DDProxy config object
7386 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7387 * @return {Roo.dd.DDProxy} The DDProxy object
7389 initDDProxy : function(group, config, overrides){
7390 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7391 return Roo.apply(dd, overrides);
7395 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7396 * @param {String} group The group the DDTarget object is member of
7397 * @param {Object} config The DDTarget config object
7398 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7399 * @return {Roo.dd.DDTarget} The DDTarget object
7401 initDDTarget : function(group, config, overrides){
7402 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7403 return Roo.apply(dd, overrides);
7407 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7408 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7409 * @param {Boolean} visible Whether the element is visible
7410 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7411 * @return {Roo.Element} this
7413 setVisible : function(visible, animate){
7415 if(this.visibilityMode == El.DISPLAY){
7416 this.setDisplayed(visible);
7419 this.dom.style.visibility = visible ? "visible" : "hidden";
7422 // closure for composites
7424 var visMode = this.visibilityMode;
7426 this.setOpacity(.01);
7427 this.setVisible(true);
7429 this.anim({opacity: { to: (visible?1:0) }},
7430 this.preanim(arguments, 1),
7431 null, .35, 'easeIn', function(){
7433 if(visMode == El.DISPLAY){
7434 dom.style.display = "none";
7436 dom.style.visibility = "hidden";
7438 Roo.get(dom).setOpacity(1);
7446 * Returns true if display is not "none"
7449 isDisplayed : function() {
7450 return this.getStyle("display") != "none";
7454 * Toggles the element's visibility or display, depending on visibility mode.
7455 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7456 * @return {Roo.Element} this
7458 toggle : function(animate){
7459 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7464 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7465 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7466 * @return {Roo.Element} this
7468 setDisplayed : function(value) {
7469 if(typeof value == "boolean"){
7470 value = value ? this.originalDisplay : "none";
7472 this.setStyle("display", value);
7477 * Tries to focus the element. Any exceptions are caught and ignored.
7478 * @return {Roo.Element} this
7480 focus : function() {
7488 * Tries to blur the element. Any exceptions are caught and ignored.
7489 * @return {Roo.Element} this
7499 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7500 * @param {String/Array} className The CSS class to add, or an array of classes
7501 * @return {Roo.Element} this
7503 addClass : function(className){
7504 if(className instanceof Array){
7505 for(var i = 0, len = className.length; i < len; i++) {
7506 this.addClass(className[i]);
7509 if(className && !this.hasClass(className)){
7510 this.dom.className = this.dom.className + " " + className;
7517 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7518 * @param {String/Array} className The CSS class to add, or an array of classes
7519 * @return {Roo.Element} this
7521 radioClass : function(className){
7522 var siblings = this.dom.parentNode.childNodes;
7523 for(var i = 0; i < siblings.length; i++) {
7524 var s = siblings[i];
7525 if(s.nodeType == 1){
7526 Roo.get(s).removeClass(className);
7529 this.addClass(className);
7534 * Removes one or more CSS classes from the element.
7535 * @param {String/Array} className The CSS class to remove, or an array of classes
7536 * @return {Roo.Element} this
7538 removeClass : function(className){
7539 if(!className || !this.dom.className){
7542 if(className instanceof Array){
7543 for(var i = 0, len = className.length; i < len; i++) {
7544 this.removeClass(className[i]);
7547 if(this.hasClass(className)){
7548 var re = this.classReCache[className];
7550 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7551 this.classReCache[className] = re;
7553 this.dom.className =
7554 this.dom.className.replace(re, " ");
7564 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7565 * @param {String} className The CSS class to toggle
7566 * @return {Roo.Element} this
7568 toggleClass : function(className){
7569 if(this.hasClass(className)){
7570 this.removeClass(className);
7572 this.addClass(className);
7578 * Checks if the specified CSS class exists on this element's DOM node.
7579 * @param {String} className The CSS class to check for
7580 * @return {Boolean} True if the class exists, else false
7582 hasClass : function(className){
7583 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7587 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7588 * @param {String} oldClassName The CSS class to replace
7589 * @param {String} newClassName The replacement CSS class
7590 * @return {Roo.Element} this
7592 replaceClass : function(oldClassName, newClassName){
7593 this.removeClass(oldClassName);
7594 this.addClass(newClassName);
7599 * Returns an object with properties matching the styles requested.
7600 * For example, el.getStyles('color', 'font-size', 'width') might return
7601 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7602 * @param {String} style1 A style name
7603 * @param {String} style2 A style name
7604 * @param {String} etc.
7605 * @return {Object} The style object
7607 getStyles : function(){
7608 var a = arguments, len = a.length, r = {};
7609 for(var i = 0; i < len; i++){
7610 r[a[i]] = this.getStyle(a[i]);
7616 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7617 * @param {String} property The style property whose value is returned.
7618 * @return {String} The current value of the style property for this element.
7620 getStyle : function(){
7621 return view && view.getComputedStyle ?
7623 var el = this.dom, v, cs, camel;
7624 if(prop == 'float'){
7627 if(el.style && (v = el.style[prop])){
7630 if(cs = view.getComputedStyle(el, "")){
7631 if(!(camel = propCache[prop])){
7632 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7639 var el = this.dom, v, cs, camel;
7640 if(prop == 'opacity'){
7641 if(typeof el.style.filter == 'string'){
7642 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7644 var fv = parseFloat(m[1]);
7646 return fv ? fv / 100 : 0;
7651 }else if(prop == 'float'){
7652 prop = "styleFloat";
7654 if(!(camel = propCache[prop])){
7655 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7657 if(v = el.style[camel]){
7660 if(cs = el.currentStyle){
7668 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7669 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7670 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7671 * @return {Roo.Element} this
7673 setStyle : function(prop, value){
7674 if(typeof prop == "string"){
7676 if (prop == 'float') {
7677 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7682 if(!(camel = propCache[prop])){
7683 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7686 if(camel == 'opacity') {
7687 this.setOpacity(value);
7689 this.dom.style[camel] = value;
7692 for(var style in prop){
7693 if(typeof prop[style] != "function"){
7694 this.setStyle(style, prop[style]);
7702 * More flexible version of {@link #setStyle} for setting style properties.
7703 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7704 * a function which returns such a specification.
7705 * @return {Roo.Element} this
7707 applyStyles : function(style){
7708 Roo.DomHelper.applyStyles(this.dom, style);
7713 * 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).
7714 * @return {Number} The X position of the element
7717 return D.getX(this.dom);
7721 * 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).
7722 * @return {Number} The Y position of the element
7725 return D.getY(this.dom);
7729 * 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).
7730 * @return {Array} The XY position of the element
7733 return D.getXY(this.dom);
7737 * 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).
7738 * @param {Number} The X position of the element
7739 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7740 * @return {Roo.Element} this
7742 setX : function(x, animate){
7744 D.setX(this.dom, x);
7746 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7752 * 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).
7753 * @param {Number} The Y position of the element
7754 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7755 * @return {Roo.Element} this
7757 setY : function(y, animate){
7759 D.setY(this.dom, y);
7761 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7767 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7768 * @param {String} left The left CSS property value
7769 * @return {Roo.Element} this
7771 setLeft : function(left){
7772 this.setStyle("left", this.addUnits(left));
7777 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7778 * @param {String} top The top CSS property value
7779 * @return {Roo.Element} this
7781 setTop : function(top){
7782 this.setStyle("top", this.addUnits(top));
7787 * Sets the element's CSS right style.
7788 * @param {String} right The right CSS property value
7789 * @return {Roo.Element} this
7791 setRight : function(right){
7792 this.setStyle("right", this.addUnits(right));
7797 * Sets the element's CSS bottom style.
7798 * @param {String} bottom The bottom CSS property value
7799 * @return {Roo.Element} this
7801 setBottom : function(bottom){
7802 this.setStyle("bottom", this.addUnits(bottom));
7807 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7808 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7809 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7810 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7811 * @return {Roo.Element} this
7813 setXY : function(pos, animate){
7815 D.setXY(this.dom, pos);
7817 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7823 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7824 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7825 * @param {Number} x X value for new position (coordinates are page-based)
7826 * @param {Number} y Y value for new position (coordinates are page-based)
7827 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7828 * @return {Roo.Element} this
7830 setLocation : function(x, y, animate){
7831 this.setXY([x, y], this.preanim(arguments, 2));
7836 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7837 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7838 * @param {Number} x X value for new position (coordinates are page-based)
7839 * @param {Number} y Y value for new position (coordinates are page-based)
7840 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7841 * @return {Roo.Element} this
7843 moveTo : function(x, y, animate){
7844 this.setXY([x, y], this.preanim(arguments, 2));
7849 * Returns the region of the given element.
7850 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7851 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7853 getRegion : function(){
7854 return D.getRegion(this.dom);
7858 * Returns the offset height of the element
7859 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7860 * @return {Number} The element's height
7862 getHeight : function(contentHeight){
7863 var h = this.dom.offsetHeight || 0;
7864 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7868 * Returns the offset width of the element
7869 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7870 * @return {Number} The element's width
7872 getWidth : function(contentWidth){
7873 var w = this.dom.offsetWidth || 0;
7874 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7878 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7879 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7880 * if a height has not been set using CSS.
7883 getComputedHeight : function(){
7884 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7886 h = parseInt(this.getStyle('height'), 10) || 0;
7887 if(!this.isBorderBox()){
7888 h += this.getFrameWidth('tb');
7895 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7896 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7897 * if a width has not been set using CSS.
7900 getComputedWidth : function(){
7901 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7903 w = parseInt(this.getStyle('width'), 10) || 0;
7904 if(!this.isBorderBox()){
7905 w += this.getFrameWidth('lr');
7912 * Returns the size of the element.
7913 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7914 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7916 getSize : function(contentSize){
7917 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7921 * Returns the width and height of the viewport.
7922 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7924 getViewSize : function(){
7925 var d = this.dom, doc = document, aw = 0, ah = 0;
7926 if(d == doc || d == doc.body){
7927 return {width : D.getViewWidth(), height: D.getViewHeight()};
7930 width : d.clientWidth,
7931 height: d.clientHeight
7937 * Returns the value of the "value" attribute
7938 * @param {Boolean} asNumber true to parse the value as a number
7939 * @return {String/Number}
7941 getValue : function(asNumber){
7942 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7946 adjustWidth : function(width){
7947 if(typeof width == "number"){
7948 if(this.autoBoxAdjust && !this.isBorderBox()){
7949 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7959 adjustHeight : function(height){
7960 if(typeof height == "number"){
7961 if(this.autoBoxAdjust && !this.isBorderBox()){
7962 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7972 * Set the width of the element
7973 * @param {Number} width The new width
7974 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7975 * @return {Roo.Element} this
7977 setWidth : function(width, animate){
7978 width = this.adjustWidth(width);
7980 this.dom.style.width = this.addUnits(width);
7982 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7988 * Set the height of the element
7989 * @param {Number} height The new height
7990 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7991 * @return {Roo.Element} this
7993 setHeight : function(height, animate){
7994 height = this.adjustHeight(height);
7996 this.dom.style.height = this.addUnits(height);
7998 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8004 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8005 * @param {Number} width The new width
8006 * @param {Number} height The new height
8007 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8008 * @return {Roo.Element} this
8010 setSize : function(width, height, animate){
8011 if(typeof width == "object"){ // in case of object from getSize()
8012 height = width.height; width = width.width;
8014 width = this.adjustWidth(width); height = this.adjustHeight(height);
8016 this.dom.style.width = this.addUnits(width);
8017 this.dom.style.height = this.addUnits(height);
8019 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8025 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8026 * @param {Number} x X value for new position (coordinates are page-based)
8027 * @param {Number} y Y value for new position (coordinates are page-based)
8028 * @param {Number} width The new width
8029 * @param {Number} height The new height
8030 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8031 * @return {Roo.Element} this
8033 setBounds : function(x, y, width, height, animate){
8035 this.setSize(width, height);
8036 this.setLocation(x, y);
8038 width = this.adjustWidth(width); height = this.adjustHeight(height);
8039 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8040 this.preanim(arguments, 4), 'motion');
8046 * 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.
8047 * @param {Roo.lib.Region} region The region to fill
8048 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8049 * @return {Roo.Element} this
8051 setRegion : function(region, animate){
8052 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8057 * Appends an event handler
8059 * @param {String} eventName The type of event to append
8060 * @param {Function} fn The method the event invokes
8061 * @param {Object} scope (optional) The scope (this object) of the fn
8062 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8064 addListener : function(eventName, fn, scope, options){
8066 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8071 * Removes an event handler from this element
8072 * @param {String} eventName the type of event to remove
8073 * @param {Function} fn the method the event invokes
8074 * @return {Roo.Element} this
8076 removeListener : function(eventName, fn){
8077 Roo.EventManager.removeListener(this.dom, eventName, fn);
8082 * Removes all previous added listeners from this element
8083 * @return {Roo.Element} this
8085 removeAllListeners : function(){
8086 E.purgeElement(this.dom);
8090 relayEvent : function(eventName, observable){
8091 this.on(eventName, function(e){
8092 observable.fireEvent(eventName, e);
8097 * Set the opacity of the element
8098 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8099 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8100 * @return {Roo.Element} this
8102 setOpacity : function(opacity, animate){
8104 var s = this.dom.style;
8107 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8108 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8110 s.opacity = opacity;
8113 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8119 * Gets the left X coordinate
8120 * @param {Boolean} local True to get the local css position instead of page coordinate
8123 getLeft : function(local){
8127 return parseInt(this.getStyle("left"), 10) || 0;
8132 * Gets the right X coordinate of the element (element X position + element width)
8133 * @param {Boolean} local True to get the local css position instead of page coordinate
8136 getRight : function(local){
8138 return this.getX() + this.getWidth();
8140 return (this.getLeft(true) + this.getWidth()) || 0;
8145 * Gets the top Y coordinate
8146 * @param {Boolean} local True to get the local css position instead of page coordinate
8149 getTop : function(local) {
8153 return parseInt(this.getStyle("top"), 10) || 0;
8158 * Gets the bottom Y coordinate of the element (element Y position + element height)
8159 * @param {Boolean} local True to get the local css position instead of page coordinate
8162 getBottom : function(local){
8164 return this.getY() + this.getHeight();
8166 return (this.getTop(true) + this.getHeight()) || 0;
8171 * Initializes positioning on this element. If a desired position is not passed, it will make the
8172 * the element positioned relative IF it is not already positioned.
8173 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8174 * @param {Number} zIndex (optional) The zIndex to apply
8175 * @param {Number} x (optional) Set the page X position
8176 * @param {Number} y (optional) Set the page Y position
8178 position : function(pos, zIndex, x, y){
8180 if(this.getStyle('position') == 'static'){
8181 this.setStyle('position', 'relative');
8184 this.setStyle("position", pos);
8187 this.setStyle("z-index", zIndex);
8189 if(x !== undefined && y !== undefined){
8191 }else if(x !== undefined){
8193 }else if(y !== undefined){
8199 * Clear positioning back to the default when the document was loaded
8200 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8201 * @return {Roo.Element} this
8203 clearPositioning : function(value){
8211 "position" : "static"
8217 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8218 * snapshot before performing an update and then restoring the element.
8221 getPositioning : function(){
8222 var l = this.getStyle("left");
8223 var t = this.getStyle("top");
8225 "position" : this.getStyle("position"),
8227 "right" : l ? "" : this.getStyle("right"),
8229 "bottom" : t ? "" : this.getStyle("bottom"),
8230 "z-index" : this.getStyle("z-index")
8235 * Gets the width of the border(s) for the specified side(s)
8236 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8237 * passing lr would get the border (l)eft width + the border (r)ight width.
8238 * @return {Number} The width of the sides passed added together
8240 getBorderWidth : function(side){
8241 return this.addStyles(side, El.borders);
8245 * Gets the width of the padding(s) for the specified side(s)
8246 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8247 * passing lr would get the padding (l)eft + the padding (r)ight.
8248 * @return {Number} The padding of the sides passed added together
8250 getPadding : function(side){
8251 return this.addStyles(side, El.paddings);
8255 * Set positioning with an object returned by getPositioning().
8256 * @param {Object} posCfg
8257 * @return {Roo.Element} this
8259 setPositioning : function(pc){
8260 this.applyStyles(pc);
8261 if(pc.right == "auto"){
8262 this.dom.style.right = "";
8264 if(pc.bottom == "auto"){
8265 this.dom.style.bottom = "";
8271 fixDisplay : function(){
8272 if(this.getStyle("display") == "none"){
8273 this.setStyle("visibility", "hidden");
8274 this.setStyle("display", this.originalDisplay); // first try reverting to default
8275 if(this.getStyle("display") == "none"){ // if that fails, default to block
8276 this.setStyle("display", "block");
8282 * Quick set left and top adding default units
8283 * @param {String} left The left CSS property value
8284 * @param {String} top The top CSS property value
8285 * @return {Roo.Element} this
8287 setLeftTop : function(left, top){
8288 this.dom.style.left = this.addUnits(left);
8289 this.dom.style.top = this.addUnits(top);
8294 * Move this element relative to its current position.
8295 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8296 * @param {Number} distance How far to move the element in pixels
8297 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8298 * @return {Roo.Element} this
8300 move : function(direction, distance, animate){
8301 var xy = this.getXY();
8302 direction = direction.toLowerCase();
8306 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8310 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8315 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8320 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8327 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8328 * @return {Roo.Element} this
8331 if(!this.isClipped){
8332 this.isClipped = true;
8333 this.originalClip = {
8334 "o": this.getStyle("overflow"),
8335 "x": this.getStyle("overflow-x"),
8336 "y": this.getStyle("overflow-y")
8338 this.setStyle("overflow", "hidden");
8339 this.setStyle("overflow-x", "hidden");
8340 this.setStyle("overflow-y", "hidden");
8346 * Return clipping (overflow) to original clipping before clip() was called
8347 * @return {Roo.Element} this
8349 unclip : function(){
8351 this.isClipped = false;
8352 var o = this.originalClip;
8353 if(o.o){this.setStyle("overflow", o.o);}
8354 if(o.x){this.setStyle("overflow-x", o.x);}
8355 if(o.y){this.setStyle("overflow-y", o.y);}
8362 * Gets the x,y coordinates specified by the anchor position on the element.
8363 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8364 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8365 * {width: (target width), height: (target height)} (defaults to the element's current size)
8366 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8367 * @return {Array} [x, y] An array containing the element's x and y coordinates
8369 getAnchorXY : function(anchor, local, s){
8370 //Passing a different size is useful for pre-calculating anchors,
8371 //especially for anchored animations that change the el size.
8373 var w, h, vp = false;
8376 if(d == document.body || d == document){
8378 w = D.getViewWidth(); h = D.getViewHeight();
8380 w = this.getWidth(); h = this.getHeight();
8383 w = s.width; h = s.height;
8385 var x = 0, y = 0, r = Math.round;
8386 switch((anchor || "tl").toLowerCase()){
8428 var sc = this.getScroll();
8429 return [x + sc.left, y + sc.top];
8431 //Add the element's offset xy
8432 var o = this.getXY();
8433 return [x+o[0], y+o[1]];
8437 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8438 * supported position values.
8439 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8440 * @param {String} position The position to align to.
8441 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8442 * @return {Array} [x, y]
8444 getAlignToXY : function(el, p, o){
8448 throw "Element.alignTo with an element that doesn't exist";
8450 var c = false; //constrain to viewport
8451 var p1 = "", p2 = "";
8458 }else if(p.indexOf("-") == -1){
8461 p = p.toLowerCase();
8462 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8464 throw "Element.alignTo with an invalid alignment " + p;
8466 p1 = m[1]; p2 = m[2]; c = !!m[3];
8468 //Subtract the aligned el's internal xy from the target's offset xy
8469 //plus custom offset to get the aligned el's new offset xy
8470 var a1 = this.getAnchorXY(p1, true);
8471 var a2 = el.getAnchorXY(p2, false);
8472 var x = a2[0] - a1[0] + o[0];
8473 var y = a2[1] - a1[1] + o[1];
8475 //constrain the aligned el to viewport if necessary
8476 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8477 // 5px of margin for ie
8478 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8480 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8481 //perpendicular to the vp border, allow the aligned el to slide on that border,
8482 //otherwise swap the aligned el to the opposite border of the target.
8483 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8484 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8485 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8486 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8489 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8490 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8492 if((x+w) > dw + scrollX){
8493 x = swapX ? r.left-w : dw+scrollX-w;
8496 x = swapX ? r.right : scrollX;
8498 if((y+h) > dh + scrollY){
8499 y = swapY ? r.top-h : dh+scrollY-h;
8502 y = swapY ? r.bottom : scrollY;
8509 getConstrainToXY : function(){
8510 var os = {top:0, left:0, bottom:0, right: 0};
8512 return function(el, local, offsets, proposedXY){
8514 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8516 var vw, vh, vx = 0, vy = 0;
8517 if(el.dom == document.body || el.dom == document){
8518 vw = Roo.lib.Dom.getViewWidth();
8519 vh = Roo.lib.Dom.getViewHeight();
8521 vw = el.dom.clientWidth;
8522 vh = el.dom.clientHeight;
8524 var vxy = el.getXY();
8530 var s = el.getScroll();
8532 vx += offsets.left + s.left;
8533 vy += offsets.top + s.top;
8535 vw -= offsets.right;
8536 vh -= offsets.bottom;
8541 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8542 var x = xy[0], y = xy[1];
8543 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8545 // only move it if it needs it
8548 // first validate right/bottom
8557 // then make sure top/left isn't negative
8566 return moved ? [x, y] : false;
8571 adjustForConstraints : function(xy, parent, offsets){
8572 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8576 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8577 * document it aligns it to the viewport.
8578 * The position parameter is optional, and can be specified in any one of the following formats:
8580 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8581 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8582 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8583 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8584 * <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
8585 * element's anchor point, and the second value is used as the target's anchor point.</li>
8587 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8588 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8589 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8590 * that specified in order to enforce the viewport constraints.
8591 * Following are all of the supported anchor positions:
8594 ----- -----------------------------
8595 tl The top left corner (default)
8596 t The center of the top edge
8597 tr The top right corner
8598 l The center of the left edge
8599 c In the center of the element
8600 r The center of the right edge
8601 bl The bottom left corner
8602 b The center of the bottom edge
8603 br The bottom right corner
8607 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8608 el.alignTo("other-el");
8610 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8611 el.alignTo("other-el", "tr?");
8613 // align the bottom right corner of el with the center left edge of other-el
8614 el.alignTo("other-el", "br-l?");
8616 // align the center of el with the bottom left corner of other-el and
8617 // adjust the x position by -6 pixels (and the y position by 0)
8618 el.alignTo("other-el", "c-bl", [-6, 0]);
8620 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8621 * @param {String} position The position to align to.
8622 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8623 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8624 * @return {Roo.Element} this
8626 alignTo : function(element, position, offsets, animate){
8627 var xy = this.getAlignToXY(element, position, offsets);
8628 this.setXY(xy, this.preanim(arguments, 3));
8633 * Anchors an element to another element and realigns it when the window is resized.
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 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8639 * is a number, it is used as the buffer delay (defaults to 50ms).
8640 * @param {Function} callback The function to call after the animation finishes
8641 * @return {Roo.Element} this
8643 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8644 var action = function(){
8645 this.alignTo(el, alignment, offsets, animate);
8646 Roo.callback(callback, this);
8648 Roo.EventManager.onWindowResize(action, this);
8649 var tm = typeof monitorScroll;
8650 if(tm != 'undefined'){
8651 Roo.EventManager.on(window, 'scroll', action, this,
8652 {buffer: tm == 'number' ? monitorScroll : 50});
8654 action.call(this); // align immediately
8658 * Clears any opacity settings from this element. Required in some cases for IE.
8659 * @return {Roo.Element} this
8661 clearOpacity : function(){
8662 if (window.ActiveXObject) {
8663 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8664 this.dom.style.filter = "";
8667 this.dom.style.opacity = "";
8668 this.dom.style["-moz-opacity"] = "";
8669 this.dom.style["-khtml-opacity"] = "";
8675 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8676 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8677 * @return {Roo.Element} this
8679 hide : function(animate){
8680 this.setVisible(false, this.preanim(arguments, 0));
8685 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8686 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8687 * @return {Roo.Element} this
8689 show : function(animate){
8690 this.setVisible(true, this.preanim(arguments, 0));
8695 * @private Test if size has a unit, otherwise appends the default
8697 addUnits : function(size){
8698 return Roo.Element.addUnits(size, this.defaultUnit);
8702 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8703 * @return {Roo.Element} this
8705 beginMeasure : function(){
8707 if(el.offsetWidth || el.offsetHeight){
8708 return this; // offsets work already
8711 var p = this.dom, b = document.body; // start with this element
8712 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8713 var pe = Roo.get(p);
8714 if(pe.getStyle('display') == 'none'){
8715 changed.push({el: p, visibility: pe.getStyle("visibility")});
8716 p.style.visibility = "hidden";
8717 p.style.display = "block";
8721 this._measureChanged = changed;
8727 * Restores displays to before beginMeasure was called
8728 * @return {Roo.Element} this
8730 endMeasure : function(){
8731 var changed = this._measureChanged;
8733 for(var i = 0, len = changed.length; i < len; i++) {
8735 r.el.style.visibility = r.visibility;
8736 r.el.style.display = "none";
8738 this._measureChanged = null;
8744 * Update the innerHTML of this element, optionally searching for and processing scripts
8745 * @param {String} html The new HTML
8746 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8747 * @param {Function} callback For async script loading you can be noticed when the update completes
8748 * @return {Roo.Element} this
8750 update : function(html, loadScripts, callback){
8751 if(typeof html == "undefined"){
8754 if(loadScripts !== true){
8755 this.dom.innerHTML = html;
8756 if(typeof callback == "function"){
8764 html += '<span id="' + id + '"></span>';
8766 E.onAvailable(id, function(){
8767 var hd = document.getElementsByTagName("head")[0];
8768 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8769 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8770 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8773 while(match = re.exec(html)){
8774 var attrs = match[1];
8775 var srcMatch = attrs ? attrs.match(srcRe) : false;
8776 if(srcMatch && srcMatch[2]){
8777 var s = document.createElement("script");
8778 s.src = srcMatch[2];
8779 var typeMatch = attrs.match(typeRe);
8780 if(typeMatch && typeMatch[2]){
8781 s.type = typeMatch[2];
8784 }else if(match[2] && match[2].length > 0){
8785 if(window.execScript) {
8786 window.execScript(match[2]);
8794 window.eval(match[2]);
8798 var el = document.getElementById(id);
8799 if(el){el.parentNode.removeChild(el);}
8800 if(typeof callback == "function"){
8804 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8809 * Direct access to the UpdateManager update() method (takes the same parameters).
8810 * @param {String/Function} url The url for this request or a function to call to get the url
8811 * @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}
8812 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8813 * @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.
8814 * @return {Roo.Element} this
8817 var um = this.getUpdateManager();
8818 um.update.apply(um, arguments);
8823 * Gets this element's UpdateManager
8824 * @return {Roo.UpdateManager} The UpdateManager
8826 getUpdateManager : function(){
8827 if(!this.updateManager){
8828 this.updateManager = new Roo.UpdateManager(this);
8830 return this.updateManager;
8834 * Disables text selection for this element (normalized across browsers)
8835 * @return {Roo.Element} this
8837 unselectable : function(){
8838 this.dom.unselectable = "on";
8839 this.swallowEvent("selectstart", true);
8840 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8841 this.addClass("x-unselectable");
8846 * Calculates the x, y to center this element on the screen
8847 * @return {Array} The x, y values [x, y]
8849 getCenterXY : function(){
8850 return this.getAlignToXY(document, 'c-c');
8854 * Centers the Element in either the viewport, or another Element.
8855 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8857 center : function(centerIn){
8858 this.alignTo(centerIn || document, 'c-c');
8863 * Tests various css rules/browsers to determine if this element uses a border box
8866 isBorderBox : function(){
8867 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8871 * Return a box {x, y, width, height} that can be used to set another elements
8872 * size/location to match this element.
8873 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8874 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8875 * @return {Object} box An object in the format {x, y, width, height}
8877 getBox : function(contentBox, local){
8882 var left = parseInt(this.getStyle("left"), 10) || 0;
8883 var top = parseInt(this.getStyle("top"), 10) || 0;
8886 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8888 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8890 var l = this.getBorderWidth("l")+this.getPadding("l");
8891 var r = this.getBorderWidth("r")+this.getPadding("r");
8892 var t = this.getBorderWidth("t")+this.getPadding("t");
8893 var b = this.getBorderWidth("b")+this.getPadding("b");
8894 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)};
8896 bx.right = bx.x + bx.width;
8897 bx.bottom = bx.y + bx.height;
8902 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8903 for more information about the sides.
8904 * @param {String} sides
8907 getFrameWidth : function(sides, onlyContentBox){
8908 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8912 * 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.
8913 * @param {Object} box The box to fill {x, y, width, height}
8914 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8915 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8916 * @return {Roo.Element} this
8918 setBox : function(box, adjust, animate){
8919 var w = box.width, h = box.height;
8920 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8921 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8922 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8924 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8929 * Forces the browser to repaint this element
8930 * @return {Roo.Element} this
8932 repaint : function(){
8934 this.addClass("x-repaint");
8935 setTimeout(function(){
8936 Roo.get(dom).removeClass("x-repaint");
8942 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8943 * then it returns the calculated width of the sides (see getPadding)
8944 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8945 * @return {Object/Number}
8947 getMargins : function(side){
8950 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8951 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8952 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8953 right: parseInt(this.getStyle("margin-right"), 10) || 0
8956 return this.addStyles(side, El.margins);
8961 addStyles : function(sides, styles){
8963 for(var i = 0, len = sides.length; i < len; i++){
8964 v = this.getStyle(styles[sides.charAt(i)]);
8966 w = parseInt(v, 10);
8974 * Creates a proxy element of this element
8975 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8976 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8977 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8978 * @return {Roo.Element} The new proxy element
8980 createProxy : function(config, renderTo, matchBox){
8982 renderTo = Roo.getDom(renderTo);
8984 renderTo = document.body;
8986 config = typeof config == "object" ?
8987 config : {tag : "div", cls: config};
8988 var proxy = Roo.DomHelper.append(renderTo, config, true);
8990 proxy.setBox(this.getBox());
8996 * Puts a mask over this element to disable user interaction. Requires core.css.
8997 * This method can only be applied to elements which accept child nodes.
8998 * @param {String} msg (optional) A message to display in the mask
8999 * @param {String} msgCls (optional) A css class to apply to the msg element
9000 * @return {Element} The mask element
9002 mask : function(msg, msgCls)
9004 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9005 this.setStyle("position", "relative");
9008 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9010 this.addClass("x-masked");
9011 this._mask.setDisplayed(true);
9016 while (dom && dom.style) {
9017 if (!isNaN(parseInt(dom.style.zIndex))) {
9018 z = Math.max(z, parseInt(dom.style.zIndex));
9020 dom = dom.parentNode;
9022 // if we are masking the body - then it hides everything..
9023 if (this.dom == document.body) {
9025 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9026 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9029 if(typeof msg == 'string'){
9031 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9033 var mm = this._maskMsg;
9034 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9035 if (mm.dom.firstChild) { // weird IE issue?
9036 mm.dom.firstChild.innerHTML = msg;
9038 mm.setDisplayed(true);
9040 mm.setStyle('z-index', z + 102);
9042 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9043 this._mask.setHeight(this.getHeight());
9045 this._mask.setStyle('z-index', z + 100);
9051 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9052 * it is cached for reuse.
9054 unmask : function(removeEl){
9056 if(removeEl === true){
9057 this._mask.remove();
9060 this._maskMsg.remove();
9061 delete this._maskMsg;
9064 this._mask.setDisplayed(false);
9066 this._maskMsg.setDisplayed(false);
9070 this.removeClass("x-masked");
9074 * Returns true if this element is masked
9077 isMasked : function(){
9078 return this._mask && this._mask.isVisible();
9082 * Creates an iframe shim for this element to keep selects and other windowed objects from
9084 * @return {Roo.Element} The new shim element
9086 createShim : function(){
9087 var el = document.createElement('iframe');
9088 el.frameBorder = 'no';
9089 el.className = 'roo-shim';
9090 if(Roo.isIE && Roo.isSecure){
9091 el.src = Roo.SSL_SECURE_URL;
9093 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9094 shim.autoBoxAdjust = false;
9099 * Removes this element from the DOM and deletes it from the cache
9101 remove : function(){
9102 if(this.dom.parentNode){
9103 this.dom.parentNode.removeChild(this.dom);
9105 delete El.cache[this.dom.id];
9109 * Sets up event handlers to add and remove a css class when the mouse is over this element
9110 * @param {String} className
9111 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9112 * mouseout events for children elements
9113 * @return {Roo.Element} this
9115 addClassOnOver : function(className, preventFlicker){
9116 this.on("mouseover", function(){
9117 Roo.fly(this, '_internal').addClass(className);
9119 var removeFn = function(e){
9120 if(preventFlicker !== true || !e.within(this, true)){
9121 Roo.fly(this, '_internal').removeClass(className);
9124 this.on("mouseout", removeFn, this.dom);
9129 * Sets up event handlers to add and remove a css class when this element has the focus
9130 * @param {String} className
9131 * @return {Roo.Element} this
9133 addClassOnFocus : function(className){
9134 this.on("focus", function(){
9135 Roo.fly(this, '_internal').addClass(className);
9137 this.on("blur", function(){
9138 Roo.fly(this, '_internal').removeClass(className);
9143 * 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)
9144 * @param {String} className
9145 * @return {Roo.Element} this
9147 addClassOnClick : function(className){
9149 this.on("mousedown", function(){
9150 Roo.fly(dom, '_internal').addClass(className);
9151 var d = Roo.get(document);
9152 var fn = function(){
9153 Roo.fly(dom, '_internal').removeClass(className);
9154 d.removeListener("mouseup", fn);
9156 d.on("mouseup", fn);
9162 * Stops the specified event from bubbling and optionally prevents the default action
9163 * @param {String} eventName
9164 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9165 * @return {Roo.Element} this
9167 swallowEvent : function(eventName, preventDefault){
9168 var fn = function(e){
9169 e.stopPropagation();
9174 if(eventName instanceof Array){
9175 for(var i = 0, len = eventName.length; i < len; i++){
9176 this.on(eventName[i], fn);
9180 this.on(eventName, fn);
9187 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9190 * Sizes this element to its parent element's dimensions performing
9191 * neccessary box adjustments.
9192 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9193 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9194 * @return {Roo.Element} this
9196 fitToParent : function(monitorResize, targetParent) {
9197 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9198 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9199 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9202 var p = Roo.get(targetParent || this.dom.parentNode);
9203 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9204 if (monitorResize === true) {
9205 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9206 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9212 * Gets the next sibling, skipping text nodes
9213 * @return {HTMLElement} The next sibling or null
9215 getNextSibling : function(){
9216 var n = this.dom.nextSibling;
9217 while(n && n.nodeType != 1){
9224 * Gets the previous sibling, skipping text nodes
9225 * @return {HTMLElement} The previous sibling or null
9227 getPrevSibling : function(){
9228 var n = this.dom.previousSibling;
9229 while(n && n.nodeType != 1){
9230 n = n.previousSibling;
9237 * Appends the passed element(s) to this element
9238 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9239 * @return {Roo.Element} this
9241 appendChild: function(el){
9248 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9249 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9250 * automatically generated with the specified attributes.
9251 * @param {HTMLElement} insertBefore (optional) a child element of this element
9252 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9253 * @return {Roo.Element} The new child element
9255 createChild: function(config, insertBefore, returnDom){
9256 config = config || {tag:'div'};
9258 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9260 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9264 * Appends this element to the passed element
9265 * @param {String/HTMLElement/Element} el The new parent element
9266 * @return {Roo.Element} this
9268 appendTo: function(el){
9269 el = Roo.getDom(el);
9270 el.appendChild(this.dom);
9275 * Inserts this element before the passed element in the DOM
9276 * @param {String/HTMLElement/Element} el The element to insert before
9277 * @return {Roo.Element} this
9279 insertBefore: function(el){
9280 el = Roo.getDom(el);
9281 el.parentNode.insertBefore(this.dom, el);
9286 * Inserts this element after the passed element in the DOM
9287 * @param {String/HTMLElement/Element} el The element to insert after
9288 * @return {Roo.Element} this
9290 insertAfter: function(el){
9291 el = Roo.getDom(el);
9292 el.parentNode.insertBefore(this.dom, el.nextSibling);
9297 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9298 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9299 * @return {Roo.Element} The new child
9301 insertFirst: function(el, returnDom){
9303 if(typeof el == 'object' && !el.nodeType){ // dh config
9304 return this.createChild(el, this.dom.firstChild, returnDom);
9306 el = Roo.getDom(el);
9307 this.dom.insertBefore(el, this.dom.firstChild);
9308 return !returnDom ? Roo.get(el) : el;
9313 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9314 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9315 * @param {String} where (optional) 'before' or 'after' defaults to before
9316 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9317 * @return {Roo.Element} the inserted Element
9319 insertSibling: function(el, where, returnDom){
9320 where = where ? where.toLowerCase() : 'before';
9322 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9324 if(typeof el == 'object' && !el.nodeType){ // dh config
9325 if(where == 'after' && !this.dom.nextSibling){
9326 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9328 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9332 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9333 where == 'before' ? this.dom : this.dom.nextSibling);
9342 * Creates and wraps this element with another element
9343 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9344 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9345 * @return {HTMLElement/Element} The newly created wrapper element
9347 wrap: function(config, returnDom){
9349 config = {tag: "div"};
9351 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9352 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9357 * Replaces the passed element with this element
9358 * @param {String/HTMLElement/Element} el The element to replace
9359 * @return {Roo.Element} this
9361 replace: function(el){
9363 this.insertBefore(el);
9369 * Inserts an html fragment into this element
9370 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9371 * @param {String} html The HTML fragment
9372 * @param {Boolean} returnEl True to return an Roo.Element
9373 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9375 insertHtml : function(where, html, returnEl){
9376 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9377 return returnEl ? Roo.get(el) : el;
9381 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9382 * @param {Object} o The object with the attributes
9383 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9384 * @return {Roo.Element} this
9386 set : function(o, useSet){
9388 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9390 if(attr == "style" || typeof o[attr] == "function") { continue; }
9392 el.className = o["cls"];
9395 el.setAttribute(attr, o[attr]);
9402 Roo.DomHelper.applyStyles(el, o.style);
9408 * Convenience method for constructing a KeyMap
9409 * @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:
9410 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9411 * @param {Function} fn The function to call
9412 * @param {Object} scope (optional) The scope of the function
9413 * @return {Roo.KeyMap} The KeyMap created
9415 addKeyListener : function(key, fn, scope){
9417 if(typeof key != "object" || key instanceof Array){
9433 return new Roo.KeyMap(this, config);
9437 * Creates a KeyMap for this element
9438 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9439 * @return {Roo.KeyMap} The KeyMap created
9441 addKeyMap : function(config){
9442 return new Roo.KeyMap(this, config);
9446 * Returns true if this element is scrollable.
9449 isScrollable : function(){
9451 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9455 * 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().
9456 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9457 * @param {Number} value The new scroll value
9458 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9459 * @return {Element} this
9462 scrollTo : function(side, value, animate){
9463 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9465 this.dom[prop] = value;
9467 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9468 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9474 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9475 * within this element's scrollable range.
9476 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9477 * @param {Number} distance How far to scroll the element in pixels
9478 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9479 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9480 * was scrolled as far as it could go.
9482 scroll : function(direction, distance, animate){
9483 if(!this.isScrollable()){
9487 var l = el.scrollLeft, t = el.scrollTop;
9488 var w = el.scrollWidth, h = el.scrollHeight;
9489 var cw = el.clientWidth, ch = el.clientHeight;
9490 direction = direction.toLowerCase();
9491 var scrolled = false;
9492 var a = this.preanim(arguments, 2);
9497 var v = Math.min(l + distance, w-cw);
9498 this.scrollTo("left", v, a);
9505 var v = Math.max(l - distance, 0);
9506 this.scrollTo("left", v, a);
9514 var v = Math.max(t - distance, 0);
9515 this.scrollTo("top", v, a);
9523 var v = Math.min(t + distance, h-ch);
9524 this.scrollTo("top", v, a);
9533 * Translates the passed page coordinates into left/top css values for this element
9534 * @param {Number/Array} x The page x or an array containing [x, y]
9535 * @param {Number} y The page y
9536 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9538 translatePoints : function(x, y){
9539 if(typeof x == 'object' || x instanceof Array){
9542 var p = this.getStyle('position');
9543 var o = this.getXY();
9545 var l = parseInt(this.getStyle('left'), 10);
9546 var t = parseInt(this.getStyle('top'), 10);
9549 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9552 t = (p == "relative") ? 0 : this.dom.offsetTop;
9555 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9559 * Returns the current scroll position of the element.
9560 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9562 getScroll : function(){
9563 var d = this.dom, doc = document;
9564 if(d == doc || d == doc.body){
9565 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9566 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9567 return {left: l, top: t};
9569 return {left: d.scrollLeft, top: d.scrollTop};
9574 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9575 * are convert to standard 6 digit hex color.
9576 * @param {String} attr The css attribute
9577 * @param {String} defaultValue The default value to use when a valid color isn't found
9578 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9581 getColor : function(attr, defaultValue, prefix){
9582 var v = this.getStyle(attr);
9583 if(!v || v == "transparent" || v == "inherit") {
9584 return defaultValue;
9586 var color = typeof prefix == "undefined" ? "#" : prefix;
9587 if(v.substr(0, 4) == "rgb("){
9588 var rvs = v.slice(4, v.length -1).split(",");
9589 for(var i = 0; i < 3; i++){
9590 var h = parseInt(rvs[i]).toString(16);
9597 if(v.substr(0, 1) == "#"){
9599 for(var i = 1; i < 4; i++){
9600 var c = v.charAt(i);
9603 }else if(v.length == 7){
9604 color += v.substr(1);
9608 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9612 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9613 * gradient background, rounded corners and a 4-way shadow.
9614 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9615 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9616 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9617 * @return {Roo.Element} this
9619 boxWrap : function(cls){
9620 cls = cls || 'x-box';
9621 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9622 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9627 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9628 * @param {String} namespace The namespace in which to look for the attribute
9629 * @param {String} name The attribute name
9630 * @return {String} The attribute value
9632 getAttributeNS : Roo.isIE ? function(ns, name){
9634 var type = typeof d[ns+":"+name];
9635 if(type != 'undefined' && type != 'unknown'){
9636 return d[ns+":"+name];
9639 } : function(ns, name){
9641 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9646 * Sets or Returns the value the dom attribute value
9647 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9648 * @param {String} value (optional) The value to set the attribute to
9649 * @return {String} The attribute value
9651 attr : function(name){
9652 if (arguments.length > 1) {
9653 this.dom.setAttribute(name, arguments[1]);
9654 return arguments[1];
9656 if (typeof(name) == 'object') {
9657 for(var i in name) {
9658 this.attr(i, name[i]);
9664 if (!this.dom.hasAttribute(name)) {
9667 return this.dom.getAttribute(name);
9674 var ep = El.prototype;
9677 * Appends an event handler (Shorthand for addListener)
9678 * @param {String} eventName The type of event to append
9679 * @param {Function} fn The method the event invokes
9680 * @param {Object} scope (optional) The scope (this object) of the fn
9681 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9684 ep.on = ep.addListener;
9686 ep.mon = ep.addListener;
9689 * Removes an event handler from this element (shorthand for removeListener)
9690 * @param {String} eventName the type of event to remove
9691 * @param {Function} fn the method the event invokes
9692 * @return {Roo.Element} this
9695 ep.un = ep.removeListener;
9698 * true to automatically adjust width and height settings for box-model issues (default to true)
9700 ep.autoBoxAdjust = true;
9703 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9706 El.addUnits = function(v, defaultUnit){
9707 if(v === "" || v == "auto"){
9710 if(v === undefined){
9713 if(typeof v == "number" || !El.unitPattern.test(v)){
9714 return v + (defaultUnit || 'px');
9719 // special markup used throughout Roo when box wrapping elements
9720 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>';
9722 * Visibility mode constant - Use visibility to hide element
9728 * Visibility mode constant - Use display to hide element
9734 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9735 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9736 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9748 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9749 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9750 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9751 * @return {Element} The Element object
9754 El.get = function(el){
9756 if(!el){ return null; }
9757 if(typeof el == "string"){ // element id
9758 if(!(elm = document.getElementById(el))){
9761 if(ex = El.cache[el]){
9764 ex = El.cache[el] = new El(elm);
9767 }else if(el.tagName){ // dom element
9771 if(ex = El.cache[id]){
9774 ex = El.cache[id] = new El(el);
9777 }else if(el instanceof El){
9779 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9780 // catch case where it hasn't been appended
9781 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9784 }else if(el.isComposite){
9786 }else if(el instanceof Array){
9787 return El.select(el);
9788 }else if(el == document){
9789 // create a bogus element object representing the document object
9791 var f = function(){};
9792 f.prototype = El.prototype;
9794 docEl.dom = document;
9802 El.uncache = function(el){
9803 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9805 delete El.cache[a[i].id || a[i]];
9811 // Garbage collection - uncache elements/purge listeners on orphaned elements
9812 // so we don't hold a reference and cause the browser to retain them
9813 El.garbageCollect = function(){
9814 if(!Roo.enableGarbageCollector){
9815 clearInterval(El.collectorThread);
9818 for(var eid in El.cache){
9819 var el = El.cache[eid], d = el.dom;
9820 // -------------------------------------------------------
9821 // Determining what is garbage:
9822 // -------------------------------------------------------
9824 // dom node is null, definitely garbage
9825 // -------------------------------------------------------
9827 // no parentNode == direct orphan, definitely garbage
9828 // -------------------------------------------------------
9829 // !d.offsetParent && !document.getElementById(eid)
9830 // display none elements have no offsetParent so we will
9831 // also try to look it up by it's id. However, check
9832 // offsetParent first so we don't do unneeded lookups.
9833 // This enables collection of elements that are not orphans
9834 // directly, but somewhere up the line they have an orphan
9836 // -------------------------------------------------------
9837 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9838 delete El.cache[eid];
9839 if(d && Roo.enableListenerCollection){
9845 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9849 El.Flyweight = function(dom){
9852 El.Flyweight.prototype = El.prototype;
9854 El._flyweights = {};
9856 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9857 * the dom node can be overwritten by other code.
9858 * @param {String/HTMLElement} el The dom node or id
9859 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9860 * prevent conflicts (e.g. internally Roo uses "_internal")
9862 * @return {Element} The shared Element object
9864 El.fly = function(el, named){
9865 named = named || '_global';
9866 el = Roo.getDom(el);
9870 if(!El._flyweights[named]){
9871 El._flyweights[named] = new El.Flyweight();
9873 El._flyweights[named].dom = el;
9874 return El._flyweights[named];
9878 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9879 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9880 * Shorthand of {@link Roo.Element#get}
9881 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9882 * @return {Element} The Element object
9888 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9889 * the dom node can be overwritten by other code.
9890 * Shorthand of {@link Roo.Element#fly}
9891 * @param {String/HTMLElement} el The dom node or id
9892 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9893 * prevent conflicts (e.g. internally Roo uses "_internal")
9895 * @return {Element} The shared Element object
9901 // speedy lookup for elements never to box adjust
9902 var noBoxAdjust = Roo.isStrict ? {
9905 input:1, select:1, textarea:1
9907 if(Roo.isIE || Roo.isGecko){
9908 noBoxAdjust['button'] = 1;
9912 Roo.EventManager.on(window, 'unload', function(){
9914 delete El._flyweights;
9922 Roo.Element.selectorFunction = Roo.DomQuery.select;
9925 Roo.Element.select = function(selector, unique, root){
9927 if(typeof selector == "string"){
9928 els = Roo.Element.selectorFunction(selector, root);
9929 }else if(selector.length !== undefined){
9932 throw "Invalid selector";
9934 if(unique === true){
9935 return new Roo.CompositeElement(els);
9937 return new Roo.CompositeElementLite(els);
9941 * Selects elements based on the passed CSS selector to enable working on them as 1.
9942 * @param {String/Array} selector The CSS selector or an array of elements
9943 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9944 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9945 * @return {CompositeElementLite/CompositeElement}
9949 Roo.select = Roo.Element.select;
9966 * Ext JS Library 1.1.1
9967 * Copyright(c) 2006-2007, Ext JS, LLC.
9969 * Originally Released Under LGPL - original licence link has changed is not relivant.
9972 * <script type="text/javascript">
9977 //Notifies Element that fx methods are available
9978 Roo.enableFx = true;
9982 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9983 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9984 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9985 * Element effects to work.</p><br/>
9987 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9988 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9989 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9990 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9991 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9992 * expected results and should be done with care.</p><br/>
9994 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9995 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9998 ----- -----------------------------
9999 tl The top left corner
10000 t The center of the top edge
10001 tr The top right corner
10002 l The center of the left edge
10003 r The center of the right edge
10004 bl The bottom left corner
10005 b The center of the bottom edge
10006 br The bottom right corner
10008 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10009 * below are common options that can be passed to any Fx method.</b>
10010 * @cfg {Function} callback A function called when the effect is finished
10011 * @cfg {Object} scope The scope of the effect function
10012 * @cfg {String} easing A valid Easing value for the effect
10013 * @cfg {String} afterCls A css class to apply after the effect
10014 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10015 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10016 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10017 * effects that end with the element being visually hidden, ignored otherwise)
10018 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10019 * a function which returns such a specification that will be applied to the Element after the effect finishes
10020 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10021 * @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
10022 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10026 * Slides the element into view. An anchor point can be optionally passed to set the point of
10027 * origin for the slide effect. This function automatically handles wrapping the element with
10028 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10031 // default: slide the element in from the top
10034 // custom: slide the element in from the right with a 2-second duration
10035 el.slideIn('r', { duration: 2 });
10037 // common config options shown with default values
10043 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10044 * @param {Object} options (optional) Object literal with any of the Fx config options
10045 * @return {Roo.Element} The Element
10047 slideIn : function(anchor, o){
10048 var el = this.getFxEl();
10051 el.queueFx(o, function(){
10053 anchor = anchor || "t";
10055 // fix display to visibility
10058 // restore values after effect
10059 var r = this.getFxRestore();
10060 var b = this.getBox();
10061 // fixed size for slide
10065 var wrap = this.fxWrap(r.pos, o, "hidden");
10067 var st = this.dom.style;
10068 st.visibility = "visible";
10069 st.position = "absolute";
10071 // clear out temp styles after slide and unwrap
10072 var after = function(){
10073 el.fxUnwrap(wrap, r.pos, o);
10074 st.width = r.width;
10075 st.height = r.height;
10078 // time to calc the positions
10079 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10081 switch(anchor.toLowerCase()){
10083 wrap.setSize(b.width, 0);
10084 st.left = st.bottom = "0";
10088 wrap.setSize(0, b.height);
10089 st.right = st.top = "0";
10093 wrap.setSize(0, b.height);
10094 wrap.setX(b.right);
10095 st.left = st.top = "0";
10096 a = {width: bw, points: pt};
10099 wrap.setSize(b.width, 0);
10100 wrap.setY(b.bottom);
10101 st.left = st.top = "0";
10102 a = {height: bh, points: pt};
10105 wrap.setSize(0, 0);
10106 st.right = st.bottom = "0";
10107 a = {width: bw, height: bh};
10110 wrap.setSize(0, 0);
10111 wrap.setY(b.y+b.height);
10112 st.right = st.top = "0";
10113 a = {width: bw, height: bh, points: pt};
10116 wrap.setSize(0, 0);
10117 wrap.setXY([b.right, b.bottom]);
10118 st.left = st.top = "0";
10119 a = {width: bw, height: bh, points: pt};
10122 wrap.setSize(0, 0);
10123 wrap.setX(b.x+b.width);
10124 st.left = st.bottom = "0";
10125 a = {width: bw, height: bh, points: pt};
10128 this.dom.style.visibility = "visible";
10131 arguments.callee.anim = wrap.fxanim(a,
10141 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10142 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10143 * 'hidden') but block elements will still take up space in the document. The element must be removed
10144 * from the DOM using the 'remove' config option if desired. This function automatically handles
10145 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10148 // default: slide the element out to the top
10151 // custom: slide the element out to the right with a 2-second duration
10152 el.slideOut('r', { duration: 2 });
10154 // common config options shown with default values
10162 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10163 * @param {Object} options (optional) Object literal with any of the Fx config options
10164 * @return {Roo.Element} The Element
10166 slideOut : function(anchor, o){
10167 var el = this.getFxEl();
10170 el.queueFx(o, function(){
10172 anchor = anchor || "t";
10174 // restore values after effect
10175 var r = this.getFxRestore();
10177 var b = this.getBox();
10178 // fixed size for slide
10182 var wrap = this.fxWrap(r.pos, o, "visible");
10184 var st = this.dom.style;
10185 st.visibility = "visible";
10186 st.position = "absolute";
10190 var after = function(){
10192 el.setDisplayed(false);
10197 el.fxUnwrap(wrap, r.pos, o);
10199 st.width = r.width;
10200 st.height = r.height;
10205 var a, zero = {to: 0};
10206 switch(anchor.toLowerCase()){
10208 st.left = st.bottom = "0";
10209 a = {height: zero};
10212 st.right = st.top = "0";
10216 st.left = st.top = "0";
10217 a = {width: zero, points: {to:[b.right, b.y]}};
10220 st.left = st.top = "0";
10221 a = {height: zero, points: {to:[b.x, b.bottom]}};
10224 st.right = st.bottom = "0";
10225 a = {width: zero, height: zero};
10228 st.right = st.top = "0";
10229 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10232 st.left = st.top = "0";
10233 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10236 st.left = st.bottom = "0";
10237 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10241 arguments.callee.anim = wrap.fxanim(a,
10251 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10252 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10253 * The element must be removed from the DOM using the 'remove' config option if desired.
10259 // common config options shown with default values
10267 * @param {Object} options (optional) Object literal with any of the Fx config options
10268 * @return {Roo.Element} The Element
10270 puff : function(o){
10271 var el = this.getFxEl();
10274 el.queueFx(o, function(){
10275 this.clearOpacity();
10278 // restore values after effect
10279 var r = this.getFxRestore();
10280 var st = this.dom.style;
10282 var after = function(){
10284 el.setDisplayed(false);
10291 el.setPositioning(r.pos);
10292 st.width = r.width;
10293 st.height = r.height;
10298 var width = this.getWidth();
10299 var height = this.getHeight();
10301 arguments.callee.anim = this.fxanim({
10302 width : {to: this.adjustWidth(width * 2)},
10303 height : {to: this.adjustHeight(height * 2)},
10304 points : {by: [-(width * .5), -(height * .5)]},
10306 fontSize: {to:200, unit: "%"}
10317 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10318 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10319 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10325 // all config options shown with default values
10333 * @param {Object} options (optional) Object literal with any of the Fx config options
10334 * @return {Roo.Element} The Element
10336 switchOff : function(o){
10337 var el = this.getFxEl();
10340 el.queueFx(o, function(){
10341 this.clearOpacity();
10344 // restore values after effect
10345 var r = this.getFxRestore();
10346 var st = this.dom.style;
10348 var after = function(){
10350 el.setDisplayed(false);
10356 el.setPositioning(r.pos);
10357 st.width = r.width;
10358 st.height = r.height;
10363 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10364 this.clearOpacity();
10368 points:{by:[0, this.getHeight() * .5]}
10369 }, o, 'motion', 0.3, 'easeIn', after);
10370 }).defer(100, this);
10377 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10378 * changed using the "attr" config option) and then fading back to the original color. If no original
10379 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10382 // default: highlight background to yellow
10385 // custom: highlight foreground text to blue for 2 seconds
10386 el.highlight("0000ff", { attr: 'color', duration: 2 });
10388 // common config options shown with default values
10389 el.highlight("ffff9c", {
10390 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10391 endColor: (current color) or "ffffff",
10396 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10397 * @param {Object} options (optional) Object literal with any of the Fx config options
10398 * @return {Roo.Element} The Element
10400 highlight : function(color, o){
10401 var el = this.getFxEl();
10404 el.queueFx(o, function(){
10405 color = color || "ffff9c";
10406 attr = o.attr || "backgroundColor";
10408 this.clearOpacity();
10411 var origColor = this.getColor(attr);
10412 var restoreColor = this.dom.style[attr];
10413 endColor = (o.endColor || origColor) || "ffffff";
10415 var after = function(){
10416 el.dom.style[attr] = restoreColor;
10421 a[attr] = {from: color, to: endColor};
10422 arguments.callee.anim = this.fxanim(a,
10432 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10435 // default: a single light blue ripple
10438 // custom: 3 red ripples lasting 3 seconds total
10439 el.frame("ff0000", 3, { duration: 3 });
10441 // common config options shown with default values
10442 el.frame("C3DAF9", 1, {
10443 duration: 1 //duration of entire animation (not each individual ripple)
10444 // Note: Easing is not configurable and will be ignored if included
10447 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10448 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10449 * @param {Object} options (optional) Object literal with any of the Fx config options
10450 * @return {Roo.Element} The Element
10452 frame : function(color, count, o){
10453 var el = this.getFxEl();
10456 el.queueFx(o, function(){
10457 color = color || "#C3DAF9";
10458 if(color.length == 6){
10459 color = "#" + color;
10461 count = count || 1;
10462 duration = o.duration || 1;
10465 var b = this.getBox();
10466 var animFn = function(){
10467 var proxy = this.createProxy({
10470 visbility:"hidden",
10471 position:"absolute",
10472 "z-index":"35000", // yee haw
10473 border:"0px solid " + color
10476 var scale = Roo.isBorderBox ? 2 : 1;
10478 top:{from:b.y, to:b.y - 20},
10479 left:{from:b.x, to:b.x - 20},
10480 borderWidth:{from:0, to:10},
10481 opacity:{from:1, to:0},
10482 height:{from:b.height, to:(b.height + (20*scale))},
10483 width:{from:b.width, to:(b.width + (20*scale))}
10484 }, duration, function(){
10488 animFn.defer((duration/2)*1000, this);
10499 * Creates a pause before any subsequent queued effects begin. If there are
10500 * no effects queued after the pause it will have no effect.
10505 * @param {Number} seconds The length of time to pause (in seconds)
10506 * @return {Roo.Element} The Element
10508 pause : function(seconds){
10509 var el = this.getFxEl();
10512 el.queueFx(o, function(){
10513 setTimeout(function(){
10515 }, seconds * 1000);
10521 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10522 * using the "endOpacity" config option.
10525 // default: fade in from opacity 0 to 100%
10528 // custom: fade in from opacity 0 to 75% over 2 seconds
10529 el.fadeIn({ endOpacity: .75, duration: 2});
10531 // common config options shown with default values
10533 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10538 * @param {Object} options (optional) Object literal with any of the Fx config options
10539 * @return {Roo.Element} The Element
10541 fadeIn : function(o){
10542 var el = this.getFxEl();
10544 el.queueFx(o, function(){
10545 this.setOpacity(0);
10547 this.dom.style.visibility = 'visible';
10548 var to = o.endOpacity || 1;
10549 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10550 o, null, .5, "easeOut", function(){
10552 this.clearOpacity();
10561 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10562 * using the "endOpacity" config option.
10565 // default: fade out from the element's current opacity to 0
10568 // custom: fade out from the element's current opacity to 25% over 2 seconds
10569 el.fadeOut({ endOpacity: .25, duration: 2});
10571 // common config options shown with default values
10573 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10580 * @param {Object} options (optional) Object literal with any of the Fx config options
10581 * @return {Roo.Element} The Element
10583 fadeOut : function(o){
10584 var el = this.getFxEl();
10586 el.queueFx(o, function(){
10587 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10588 o, null, .5, "easeOut", function(){
10589 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10590 this.dom.style.display = "none";
10592 this.dom.style.visibility = "hidden";
10594 this.clearOpacity();
10602 * Animates the transition of an element's dimensions from a starting height/width
10603 * to an ending height/width.
10606 // change height and width to 100x100 pixels
10607 el.scale(100, 100);
10609 // common config options shown with default values. The height and width will default to
10610 // the element's existing values if passed as null.
10613 [element's height], {
10618 * @param {Number} width The new width (pass undefined to keep the original width)
10619 * @param {Number} height The new height (pass undefined to keep the original height)
10620 * @param {Object} options (optional) Object literal with any of the Fx config options
10621 * @return {Roo.Element} The Element
10623 scale : function(w, h, o){
10624 this.shift(Roo.apply({}, o, {
10632 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10633 * Any of these properties not specified in the config object will not be changed. This effect
10634 * requires that at least one new dimension, position or opacity setting must be passed in on
10635 * the config object in order for the function to have any effect.
10638 // slide the element horizontally to x position 200 while changing the height and opacity
10639 el.shift({ x: 200, height: 50, opacity: .8 });
10641 // common config options shown with default values.
10643 width: [element's width],
10644 height: [element's height],
10645 x: [element's x position],
10646 y: [element's y position],
10647 opacity: [element's opacity],
10652 * @param {Object} options Object literal with any of the Fx config options
10653 * @return {Roo.Element} The Element
10655 shift : function(o){
10656 var el = this.getFxEl();
10658 el.queueFx(o, function(){
10659 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10660 if(w !== undefined){
10661 a.width = {to: this.adjustWidth(w)};
10663 if(h !== undefined){
10664 a.height = {to: this.adjustHeight(h)};
10666 if(x !== undefined || y !== undefined){
10668 x !== undefined ? x : this.getX(),
10669 y !== undefined ? y : this.getY()
10672 if(op !== undefined){
10673 a.opacity = {to: op};
10675 if(o.xy !== undefined){
10676 a.points = {to: o.xy};
10678 arguments.callee.anim = this.fxanim(a,
10679 o, 'motion', .35, "easeOut", function(){
10687 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10688 * ending point of the effect.
10691 // default: slide the element downward while fading out
10694 // custom: slide the element out to the right with a 2-second duration
10695 el.ghost('r', { duration: 2 });
10697 // common config options shown with default values
10705 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10706 * @param {Object} options (optional) Object literal with any of the Fx config options
10707 * @return {Roo.Element} The Element
10709 ghost : function(anchor, o){
10710 var el = this.getFxEl();
10713 el.queueFx(o, function(){
10714 anchor = anchor || "b";
10716 // restore values after effect
10717 var r = this.getFxRestore();
10718 var w = this.getWidth(),
10719 h = this.getHeight();
10721 var st = this.dom.style;
10723 var after = function(){
10725 el.setDisplayed(false);
10731 el.setPositioning(r.pos);
10732 st.width = r.width;
10733 st.height = r.height;
10738 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10739 switch(anchor.toLowerCase()){
10766 arguments.callee.anim = this.fxanim(a,
10776 * Ensures that all effects queued after syncFx is called on the element are
10777 * run concurrently. This is the opposite of {@link #sequenceFx}.
10778 * @return {Roo.Element} The Element
10780 syncFx : function(){
10781 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10790 * Ensures that all effects queued after sequenceFx is called on the element are
10791 * run in sequence. This is the opposite of {@link #syncFx}.
10792 * @return {Roo.Element} The Element
10794 sequenceFx : function(){
10795 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10797 concurrent : false,
10804 nextFx : function(){
10805 var ef = this.fxQueue[0];
10812 * Returns true if the element has any effects actively running or queued, else returns false.
10813 * @return {Boolean} True if element has active effects, else false
10815 hasActiveFx : function(){
10816 return this.fxQueue && this.fxQueue[0];
10820 * Stops any running effects and clears the element's internal effects queue if it contains
10821 * any additional effects that haven't started yet.
10822 * @return {Roo.Element} The Element
10824 stopFx : function(){
10825 if(this.hasActiveFx()){
10826 var cur = this.fxQueue[0];
10827 if(cur && cur.anim && cur.anim.isAnimated()){
10828 this.fxQueue = [cur]; // clear out others
10829 cur.anim.stop(true);
10836 beforeFx : function(o){
10837 if(this.hasActiveFx() && !o.concurrent){
10848 * Returns true if the element is currently blocking so that no other effect can be queued
10849 * until this effect is finished, else returns false if blocking is not set. This is commonly
10850 * used to ensure that an effect initiated by a user action runs to completion prior to the
10851 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10852 * @return {Boolean} True if blocking, else false
10854 hasFxBlock : function(){
10855 var q = this.fxQueue;
10856 return q && q[0] && q[0].block;
10860 queueFx : function(o, fn){
10864 if(!this.hasFxBlock()){
10865 Roo.applyIf(o, this.fxDefaults);
10867 var run = this.beforeFx(o);
10868 fn.block = o.block;
10869 this.fxQueue.push(fn);
10881 fxWrap : function(pos, o, vis){
10883 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10886 wrapXY = this.getXY();
10888 var div = document.createElement("div");
10889 div.style.visibility = vis;
10890 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10891 wrap.setPositioning(pos);
10892 if(wrap.getStyle("position") == "static"){
10893 wrap.position("relative");
10895 this.clearPositioning('auto');
10897 wrap.dom.appendChild(this.dom);
10899 wrap.setXY(wrapXY);
10906 fxUnwrap : function(wrap, pos, o){
10907 this.clearPositioning();
10908 this.setPositioning(pos);
10910 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10916 getFxRestore : function(){
10917 var st = this.dom.style;
10918 return {pos: this.getPositioning(), width: st.width, height : st.height};
10922 afterFx : function(o){
10924 this.applyStyles(o.afterStyle);
10927 this.addClass(o.afterCls);
10929 if(o.remove === true){
10932 Roo.callback(o.callback, o.scope, [this]);
10934 this.fxQueue.shift();
10940 getFxEl : function(){ // support for composite element fx
10941 return Roo.get(this.dom);
10945 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10946 animType = animType || 'run';
10948 var anim = Roo.lib.Anim[animType](
10950 (opt.duration || defaultDur) || .35,
10951 (opt.easing || defaultEase) || 'easeOut',
10953 Roo.callback(cb, this);
10962 // backwords compat
10963 Roo.Fx.resize = Roo.Fx.scale;
10965 //When included, Roo.Fx is automatically applied to Element so that all basic
10966 //effects are available directly via the Element API
10967 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10969 * Ext JS Library 1.1.1
10970 * Copyright(c) 2006-2007, Ext JS, LLC.
10972 * Originally Released Under LGPL - original licence link has changed is not relivant.
10975 * <script type="text/javascript">
10980 * @class Roo.CompositeElement
10981 * Standard composite class. Creates a Roo.Element for every element in the collection.
10983 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10984 * actions will be performed on all the elements in this collection.</b>
10986 * All methods return <i>this</i> and can be chained.
10988 var els = Roo.select("#some-el div.some-class", true);
10989 // or select directly from an existing element
10990 var el = Roo.get('some-el');
10991 el.select('div.some-class', true);
10993 els.setWidth(100); // all elements become 100 width
10994 els.hide(true); // all elements fade out and hide
10996 els.setWidth(100).hide(true);
10999 Roo.CompositeElement = function(els){
11000 this.elements = [];
11001 this.addElements(els);
11003 Roo.CompositeElement.prototype = {
11005 addElements : function(els){
11009 if(typeof els == "string"){
11010 els = Roo.Element.selectorFunction(els);
11012 var yels = this.elements;
11013 var index = yels.length-1;
11014 for(var i = 0, len = els.length; i < len; i++) {
11015 yels[++index] = Roo.get(els[i]);
11021 * Clears this composite and adds the elements returned by the passed selector.
11022 * @param {String/Array} els A string CSS selector, an array of elements or an element
11023 * @return {CompositeElement} this
11025 fill : function(els){
11026 this.elements = [];
11032 * Filters this composite to only elements that match the passed selector.
11033 * @param {String} selector A string CSS selector
11034 * @param {Boolean} inverse return inverse filter (not matches)
11035 * @return {CompositeElement} this
11037 filter : function(selector, inverse){
11039 inverse = inverse || false;
11040 this.each(function(el){
11041 var match = inverse ? !el.is(selector) : el.is(selector);
11043 els[els.length] = el.dom;
11050 invoke : function(fn, args){
11051 var els = this.elements;
11052 for(var i = 0, len = els.length; i < len; i++) {
11053 Roo.Element.prototype[fn].apply(els[i], args);
11058 * Adds elements to this composite.
11059 * @param {String/Array} els A string CSS selector, an array of elements or an element
11060 * @return {CompositeElement} this
11062 add : function(els){
11063 if(typeof els == "string"){
11064 this.addElements(Roo.Element.selectorFunction(els));
11065 }else if(els.length !== undefined){
11066 this.addElements(els);
11068 this.addElements([els]);
11073 * Calls the passed function passing (el, this, index) for each element in this composite.
11074 * @param {Function} fn The function to call
11075 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11076 * @return {CompositeElement} this
11078 each : function(fn, scope){
11079 var els = this.elements;
11080 for(var i = 0, len = els.length; i < len; i++){
11081 if(fn.call(scope || els[i], els[i], this, i) === false) {
11089 * Returns the Element object at the specified index
11090 * @param {Number} index
11091 * @return {Roo.Element}
11093 item : function(index){
11094 return this.elements[index] || null;
11098 * Returns the first Element
11099 * @return {Roo.Element}
11101 first : function(){
11102 return this.item(0);
11106 * Returns the last Element
11107 * @return {Roo.Element}
11110 return this.item(this.elements.length-1);
11114 * Returns the number of elements in this composite
11117 getCount : function(){
11118 return this.elements.length;
11122 * Returns true if this composite contains the passed element
11125 contains : function(el){
11126 return this.indexOf(el) !== -1;
11130 * Returns true if this composite contains the passed element
11133 indexOf : function(el){
11134 return this.elements.indexOf(Roo.get(el));
11139 * Removes the specified element(s).
11140 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11141 * or an array of any of those.
11142 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11143 * @return {CompositeElement} this
11145 removeElement : function(el, removeDom){
11146 if(el instanceof Array){
11147 for(var i = 0, len = el.length; i < len; i++){
11148 this.removeElement(el[i]);
11152 var index = typeof el == 'number' ? el : this.indexOf(el);
11155 var d = this.elements[index];
11159 d.parentNode.removeChild(d);
11162 this.elements.splice(index, 1);
11168 * Replaces the specified element with the passed element.
11169 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11171 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11172 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11173 * @return {CompositeElement} this
11175 replaceElement : function(el, replacement, domReplace){
11176 var index = typeof el == 'number' ? el : this.indexOf(el);
11179 this.elements[index].replaceWith(replacement);
11181 this.elements.splice(index, 1, Roo.get(replacement))
11188 * Removes all elements.
11190 clear : function(){
11191 this.elements = [];
11195 Roo.CompositeElement.createCall = function(proto, fnName){
11196 if(!proto[fnName]){
11197 proto[fnName] = function(){
11198 return this.invoke(fnName, arguments);
11202 for(var fnName in Roo.Element.prototype){
11203 if(typeof Roo.Element.prototype[fnName] == "function"){
11204 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11210 * Ext JS Library 1.1.1
11211 * Copyright(c) 2006-2007, Ext JS, LLC.
11213 * Originally Released Under LGPL - original licence link has changed is not relivant.
11216 * <script type="text/javascript">
11220 * @class Roo.CompositeElementLite
11221 * @extends Roo.CompositeElement
11222 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11224 var els = Roo.select("#some-el div.some-class");
11225 // or select directly from an existing element
11226 var el = Roo.get('some-el');
11227 el.select('div.some-class');
11229 els.setWidth(100); // all elements become 100 width
11230 els.hide(true); // all elements fade out and hide
11232 els.setWidth(100).hide(true);
11233 </code></pre><br><br>
11234 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11235 * actions will be performed on all the elements in this collection.</b>
11237 Roo.CompositeElementLite = function(els){
11238 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11239 this.el = new Roo.Element.Flyweight();
11241 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11242 addElements : function(els){
11244 if(els instanceof Array){
11245 this.elements = this.elements.concat(els);
11247 var yels = this.elements;
11248 var index = yels.length-1;
11249 for(var i = 0, len = els.length; i < len; i++) {
11250 yels[++index] = els[i];
11256 invoke : function(fn, args){
11257 var els = this.elements;
11259 for(var i = 0, len = els.length; i < len; i++) {
11261 Roo.Element.prototype[fn].apply(el, args);
11266 * Returns a flyweight Element of the dom element object at the specified index
11267 * @param {Number} index
11268 * @return {Roo.Element}
11270 item : function(index){
11271 if(!this.elements[index]){
11274 this.el.dom = this.elements[index];
11278 // fixes scope with flyweight
11279 addListener : function(eventName, handler, scope, opt){
11280 var els = this.elements;
11281 for(var i = 0, len = els.length; i < len; i++) {
11282 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11288 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11289 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11290 * a reference to the dom node, use el.dom.</b>
11291 * @param {Function} fn The function to call
11292 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11293 * @return {CompositeElement} this
11295 each : function(fn, scope){
11296 var els = this.elements;
11298 for(var i = 0, len = els.length; i < len; i++){
11300 if(fn.call(scope || el, el, this, i) === false){
11307 indexOf : function(el){
11308 return this.elements.indexOf(Roo.getDom(el));
11311 replaceElement : function(el, replacement, domReplace){
11312 var index = typeof el == 'number' ? el : this.indexOf(el);
11314 replacement = Roo.getDom(replacement);
11316 var d = this.elements[index];
11317 d.parentNode.insertBefore(replacement, d);
11318 d.parentNode.removeChild(d);
11320 this.elements.splice(index, 1, replacement);
11325 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11329 * Ext JS Library 1.1.1
11330 * Copyright(c) 2006-2007, Ext JS, LLC.
11332 * Originally Released Under LGPL - original licence link has changed is not relivant.
11335 * <script type="text/javascript">
11341 * @class Roo.data.Connection
11342 * @extends Roo.util.Observable
11343 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11344 * either to a configured URL, or to a URL specified at request time.<br><br>
11346 * Requests made by this class are asynchronous, and will return immediately. No data from
11347 * the server will be available to the statement immediately following the {@link #request} call.
11348 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11350 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11351 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11352 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11353 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11354 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11355 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11356 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11357 * standard DOM methods.
11359 * @param {Object} config a configuration object.
11361 Roo.data.Connection = function(config){
11362 Roo.apply(this, config);
11365 * @event beforerequest
11366 * Fires before a network request is made to retrieve a data object.
11367 * @param {Connection} conn This Connection object.
11368 * @param {Object} options The options config object passed to the {@link #request} method.
11370 "beforerequest" : true,
11372 * @event requestcomplete
11373 * Fires if the request was successfully completed.
11374 * @param {Connection} conn This Connection object.
11375 * @param {Object} response The XHR object containing the response data.
11376 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11377 * @param {Object} options The options config object passed to the {@link #request} method.
11379 "requestcomplete" : true,
11381 * @event requestexception
11382 * Fires if an error HTTP status was returned from the server.
11383 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11384 * @param {Connection} conn This Connection object.
11385 * @param {Object} response The XHR object containing the response data.
11386 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11387 * @param {Object} options The options config object passed to the {@link #request} method.
11389 "requestexception" : true
11391 Roo.data.Connection.superclass.constructor.call(this);
11394 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11396 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11399 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11400 * extra parameters to each request made by this object. (defaults to undefined)
11403 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11404 * to each request made by this object. (defaults to undefined)
11407 * @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)
11410 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11414 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11420 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11423 disableCaching: true,
11426 * Sends an HTTP request to a remote server.
11427 * @param {Object} options An object which may contain the following properties:<ul>
11428 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11429 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11430 * request, a url encoded string or a function to call to get either.</li>
11431 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11432 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11433 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11434 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11435 * <li>options {Object} The parameter to the request call.</li>
11436 * <li>success {Boolean} True if the request succeeded.</li>
11437 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11439 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11440 * The callback is passed the following parameters:<ul>
11441 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11442 * <li>options {Object} The parameter to the request call.</li>
11444 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11445 * The callback is passed the following parameters:<ul>
11446 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11447 * <li>options {Object} The parameter to the request call.</li>
11449 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11450 * for the callback function. Defaults to the browser window.</li>
11451 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11452 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11453 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11454 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11455 * params for the post data. Any params will be appended to the URL.</li>
11456 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11458 * @return {Number} transactionId
11460 request : function(o){
11461 if(this.fireEvent("beforerequest", this, o) !== false){
11464 if(typeof p == "function"){
11465 p = p.call(o.scope||window, o);
11467 if(typeof p == "object"){
11468 p = Roo.urlEncode(o.params);
11470 if(this.extraParams){
11471 var extras = Roo.urlEncode(this.extraParams);
11472 p = p ? (p + '&' + extras) : extras;
11475 var url = o.url || this.url;
11476 if(typeof url == 'function'){
11477 url = url.call(o.scope||window, o);
11481 var form = Roo.getDom(o.form);
11482 url = url || form.action;
11484 var enctype = form.getAttribute("enctype");
11485 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11486 return this.doFormUpload(o, p, url);
11488 var f = Roo.lib.Ajax.serializeForm(form);
11489 p = p ? (p + '&' + f) : f;
11492 var hs = o.headers;
11493 if(this.defaultHeaders){
11494 hs = Roo.apply(hs || {}, this.defaultHeaders);
11501 success: this.handleResponse,
11502 failure: this.handleFailure,
11504 argument: {options: o},
11505 timeout : o.timeout || this.timeout
11508 var method = o.method||this.method||(p ? "POST" : "GET");
11510 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11511 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11514 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11518 }else if(this.autoAbort !== false){
11522 if((method == 'GET' && p) || o.xmlData){
11523 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11526 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11527 return this.transId;
11529 Roo.callback(o.callback, o.scope, [o, null, null]);
11535 * Determine whether this object has a request outstanding.
11536 * @param {Number} transactionId (Optional) defaults to the last transaction
11537 * @return {Boolean} True if there is an outstanding request.
11539 isLoading : function(transId){
11541 return Roo.lib.Ajax.isCallInProgress(transId);
11543 return this.transId ? true : false;
11548 * Aborts any outstanding request.
11549 * @param {Number} transactionId (Optional) defaults to the last transaction
11551 abort : function(transId){
11552 if(transId || this.isLoading()){
11553 Roo.lib.Ajax.abort(transId || this.transId);
11558 handleResponse : function(response){
11559 this.transId = false;
11560 var options = response.argument.options;
11561 response.argument = options ? options.argument : null;
11562 this.fireEvent("requestcomplete", this, response, options);
11563 Roo.callback(options.success, options.scope, [response, options]);
11564 Roo.callback(options.callback, options.scope, [options, true, response]);
11568 handleFailure : function(response, e){
11569 this.transId = false;
11570 var options = response.argument.options;
11571 response.argument = options ? options.argument : null;
11572 this.fireEvent("requestexception", this, response, options, e);
11573 Roo.callback(options.failure, options.scope, [response, options]);
11574 Roo.callback(options.callback, options.scope, [options, false, response]);
11578 doFormUpload : function(o, ps, url){
11580 var frame = document.createElement('iframe');
11583 frame.className = 'x-hidden';
11585 frame.src = Roo.SSL_SECURE_URL;
11587 document.body.appendChild(frame);
11590 document.frames[id].name = id;
11593 var form = Roo.getDom(o.form);
11595 form.method = 'POST';
11596 form.enctype = form.encoding = 'multipart/form-data';
11602 if(ps){ // add dynamic params
11604 ps = Roo.urlDecode(ps, false);
11606 if(ps.hasOwnProperty(k)){
11607 hd = document.createElement('input');
11608 hd.type = 'hidden';
11611 form.appendChild(hd);
11618 var r = { // bogus response object
11623 r.argument = o ? o.argument : null;
11628 doc = frame.contentWindow.document;
11630 doc = (frame.contentDocument || window.frames[id].document);
11632 if(doc && doc.body){
11633 r.responseText = doc.body.innerHTML;
11635 if(doc && doc.XMLDocument){
11636 r.responseXML = doc.XMLDocument;
11638 r.responseXML = doc;
11645 Roo.EventManager.removeListener(frame, 'load', cb, this);
11647 this.fireEvent("requestcomplete", this, r, o);
11648 Roo.callback(o.success, o.scope, [r, o]);
11649 Roo.callback(o.callback, o.scope, [o, true, r]);
11651 setTimeout(function(){document.body.removeChild(frame);}, 100);
11654 Roo.EventManager.on(frame, 'load', cb, this);
11657 if(hiddens){ // remove dynamic params
11658 for(var i = 0, len = hiddens.length; i < len; i++){
11659 form.removeChild(hiddens[i]);
11666 * Ext JS Library 1.1.1
11667 * Copyright(c) 2006-2007, Ext JS, LLC.
11669 * Originally Released Under LGPL - original licence link has changed is not relivant.
11672 * <script type="text/javascript">
11676 * Global Ajax request class.
11679 * @extends Roo.data.Connection
11682 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11683 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11684 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11685 * @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)
11686 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11687 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11688 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11690 Roo.Ajax = new Roo.data.Connection({
11699 * Serialize the passed form into a url encoded string
11701 * @param {String/HTMLElement} form
11704 serializeForm : function(form){
11705 return Roo.lib.Ajax.serializeForm(form);
11709 * Ext JS Library 1.1.1
11710 * Copyright(c) 2006-2007, Ext JS, LLC.
11712 * Originally Released Under LGPL - original licence link has changed is not relivant.
11715 * <script type="text/javascript">
11720 * @class Roo.UpdateManager
11721 * @extends Roo.util.Observable
11722 * Provides AJAX-style update for Element object.<br><br>
11725 * // Get it from a Roo.Element object
11726 * var el = Roo.get("foo");
11727 * var mgr = el.getUpdateManager();
11728 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11730 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11732 * // or directly (returns the same UpdateManager instance)
11733 * var mgr = new Roo.UpdateManager("myElementId");
11734 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11735 * mgr.on("update", myFcnNeedsToKnow);
11737 // short handed call directly from the element object
11738 Roo.get("foo").load({
11742 text: "Loading Foo..."
11746 * Create new UpdateManager directly.
11747 * @param {String/HTMLElement/Roo.Element} el The element to update
11748 * @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).
11750 Roo.UpdateManager = function(el, forceNew){
11752 if(!forceNew && el.updateManager){
11753 return el.updateManager;
11756 * The Element object
11757 * @type Roo.Element
11761 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11764 this.defaultUrl = null;
11768 * @event beforeupdate
11769 * Fired before an update is made, return false from your handler and the update is cancelled.
11770 * @param {Roo.Element} el
11771 * @param {String/Object/Function} url
11772 * @param {String/Object} params
11774 "beforeupdate": true,
11777 * Fired after successful update is made.
11778 * @param {Roo.Element} el
11779 * @param {Object} oResponseObject The response Object
11784 * Fired on update failure.
11785 * @param {Roo.Element} el
11786 * @param {Object} oResponseObject The response Object
11790 var d = Roo.UpdateManager.defaults;
11792 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11795 this.sslBlankUrl = d.sslBlankUrl;
11797 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11800 this.disableCaching = d.disableCaching;
11802 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11805 this.indicatorText = d.indicatorText;
11807 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11810 this.showLoadIndicator = d.showLoadIndicator;
11812 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11815 this.timeout = d.timeout;
11818 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11821 this.loadScripts = d.loadScripts;
11824 * Transaction object of current executing transaction
11826 this.transaction = null;
11831 this.autoRefreshProcId = null;
11833 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11836 this.refreshDelegate = this.refresh.createDelegate(this);
11838 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11841 this.updateDelegate = this.update.createDelegate(this);
11843 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11846 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11850 this.successDelegate = this.processSuccess.createDelegate(this);
11854 this.failureDelegate = this.processFailure.createDelegate(this);
11856 if(!this.renderer){
11858 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11860 this.renderer = new Roo.UpdateManager.BasicRenderer();
11863 Roo.UpdateManager.superclass.constructor.call(this);
11866 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11868 * Get the Element this UpdateManager is bound to
11869 * @return {Roo.Element} The element
11871 getEl : function(){
11875 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11876 * @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:
11879 url: "your-url.php",<br/>
11880 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11881 callback: yourFunction,<br/>
11882 scope: yourObject, //(optional scope) <br/>
11883 discardUrl: false, <br/>
11884 nocache: false,<br/>
11885 text: "Loading...",<br/>
11887 scripts: false<br/>
11890 * The only required property is url. The optional properties nocache, text and scripts
11891 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11892 * @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}
11893 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11894 * @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.
11896 update : function(url, params, callback, discardUrl){
11897 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11898 var method = this.method,
11900 if(typeof url == "object"){ // must be config object
11903 params = params || cfg.params;
11904 callback = callback || cfg.callback;
11905 discardUrl = discardUrl || cfg.discardUrl;
11906 if(callback && cfg.scope){
11907 callback = callback.createDelegate(cfg.scope);
11909 if(typeof cfg.method != "undefined"){method = cfg.method;};
11910 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11911 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11912 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11913 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11915 this.showLoading();
11917 this.defaultUrl = url;
11919 if(typeof url == "function"){
11920 url = url.call(this);
11923 method = method || (params ? "POST" : "GET");
11924 if(method == "GET"){
11925 url = this.prepareUrl(url);
11928 var o = Roo.apply(cfg ||{}, {
11931 success: this.successDelegate,
11932 failure: this.failureDelegate,
11933 callback: undefined,
11934 timeout: (this.timeout*1000),
11935 argument: {"url": url, "form": null, "callback": callback, "params": params}
11937 Roo.log("updated manager called with timeout of " + o.timeout);
11938 this.transaction = Roo.Ajax.request(o);
11943 * 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.
11944 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11945 * @param {String/HTMLElement} form The form Id or form element
11946 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11947 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11948 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11950 formUpdate : function(form, url, reset, callback){
11951 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11952 if(typeof url == "function"){
11953 url = url.call(this);
11955 form = Roo.getDom(form);
11956 this.transaction = Roo.Ajax.request({
11959 success: this.successDelegate,
11960 failure: this.failureDelegate,
11961 timeout: (this.timeout*1000),
11962 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11964 this.showLoading.defer(1, this);
11969 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11970 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11972 refresh : function(callback){
11973 if(this.defaultUrl == null){
11976 this.update(this.defaultUrl, null, callback, true);
11980 * Set this element to auto refresh.
11981 * @param {Number} interval How often to update (in seconds).
11982 * @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)
11983 * @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}
11984 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11985 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11987 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11989 this.update(url || this.defaultUrl, params, callback, true);
11991 if(this.autoRefreshProcId){
11992 clearInterval(this.autoRefreshProcId);
11994 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11998 * Stop auto refresh on this element.
12000 stopAutoRefresh : function(){
12001 if(this.autoRefreshProcId){
12002 clearInterval(this.autoRefreshProcId);
12003 delete this.autoRefreshProcId;
12007 isAutoRefreshing : function(){
12008 return this.autoRefreshProcId ? true : false;
12011 * Called to update the element to "Loading" state. Override to perform custom action.
12013 showLoading : function(){
12014 if(this.showLoadIndicator){
12015 this.el.update(this.indicatorText);
12020 * Adds unique parameter to query string if disableCaching = true
12023 prepareUrl : function(url){
12024 if(this.disableCaching){
12025 var append = "_dc=" + (new Date().getTime());
12026 if(url.indexOf("?") !== -1){
12027 url += "&" + append;
12029 url += "?" + append;
12038 processSuccess : function(response){
12039 this.transaction = null;
12040 if(response.argument.form && response.argument.reset){
12041 try{ // put in try/catch since some older FF releases had problems with this
12042 response.argument.form.reset();
12045 if(this.loadScripts){
12046 this.renderer.render(this.el, response, this,
12047 this.updateComplete.createDelegate(this, [response]));
12049 this.renderer.render(this.el, response, this);
12050 this.updateComplete(response);
12054 updateComplete : function(response){
12055 this.fireEvent("update", this.el, response);
12056 if(typeof response.argument.callback == "function"){
12057 response.argument.callback(this.el, true, response);
12064 processFailure : function(response){
12065 this.transaction = null;
12066 this.fireEvent("failure", this.el, response);
12067 if(typeof response.argument.callback == "function"){
12068 response.argument.callback(this.el, false, response);
12073 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12074 * @param {Object} renderer The object implementing the render() method
12076 setRenderer : function(renderer){
12077 this.renderer = renderer;
12080 getRenderer : function(){
12081 return this.renderer;
12085 * Set the defaultUrl used for updates
12086 * @param {String/Function} defaultUrl The url or a function to call to get the url
12088 setDefaultUrl : function(defaultUrl){
12089 this.defaultUrl = defaultUrl;
12093 * Aborts the executing transaction
12095 abort : function(){
12096 if(this.transaction){
12097 Roo.Ajax.abort(this.transaction);
12102 * Returns true if an update is in progress
12103 * @return {Boolean}
12105 isUpdating : function(){
12106 if(this.transaction){
12107 return Roo.Ajax.isLoading(this.transaction);
12114 * @class Roo.UpdateManager.defaults
12115 * @static (not really - but it helps the doc tool)
12116 * The defaults collection enables customizing the default properties of UpdateManager
12118 Roo.UpdateManager.defaults = {
12120 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12126 * True to process scripts by default (Defaults to false).
12129 loadScripts : false,
12132 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12135 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12137 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12140 disableCaching : false,
12142 * Whether to show indicatorText when loading (Defaults to true).
12145 showLoadIndicator : true,
12147 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12150 indicatorText : '<div class="loading-indicator">Loading...</div>'
12154 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12156 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12157 * @param {String/HTMLElement/Roo.Element} el The element to update
12158 * @param {String} url The url
12159 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12160 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12163 * @member Roo.UpdateManager
12165 Roo.UpdateManager.updateElement = function(el, url, params, options){
12166 var um = Roo.get(el, true).getUpdateManager();
12167 Roo.apply(um, options);
12168 um.update(url, params, options ? options.callback : null);
12170 // alias for backwards compat
12171 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12173 * @class Roo.UpdateManager.BasicRenderer
12174 * Default Content renderer. Updates the elements innerHTML with the responseText.
12176 Roo.UpdateManager.BasicRenderer = function(){};
12178 Roo.UpdateManager.BasicRenderer.prototype = {
12180 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12181 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12182 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12183 * @param {Roo.Element} el The element being rendered
12184 * @param {Object} response The YUI Connect response object
12185 * @param {UpdateManager} updateManager The calling update manager
12186 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12188 render : function(el, response, updateManager, callback){
12189 el.update(response.responseText, updateManager.loadScripts, callback);
12195 * (c)) Alan Knowles
12201 * @class Roo.DomTemplate
12202 * @extends Roo.Template
12203 * An effort at a dom based template engine..
12205 * Similar to XTemplate, except it uses dom parsing to create the template..
12207 * Supported features:
12212 {a_variable} - output encoded.
12213 {a_variable.format:("Y-m-d")} - call a method on the variable
12214 {a_variable:raw} - unencoded output
12215 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12216 {a_variable:this.method_on_template(...)} - call a method on the template object.
12221 <div roo-for="a_variable or condition.."></div>
12222 <div roo-if="a_variable or condition"></div>
12223 <div roo-exec="some javascript"></div>
12224 <div roo-name="named_template"></div>
12229 Roo.DomTemplate = function()
12231 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12238 Roo.extend(Roo.DomTemplate, Roo.Template, {
12240 * id counter for sub templates.
12244 * flag to indicate if dom parser is inside a pre,
12245 * it will strip whitespace if not.
12250 * The various sub templates
12258 * basic tag replacing syntax
12261 * // you can fake an object call by doing this
12265 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12266 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12268 iterChild : function (node, method) {
12270 var oldPre = this.inPre;
12271 if (node.tagName == 'PRE') {
12274 for( var i = 0; i < node.childNodes.length; i++) {
12275 method.call(this, node.childNodes[i]);
12277 this.inPre = oldPre;
12283 * compile the template
12285 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12288 compile: function()
12292 // covert the html into DOM...
12296 doc = document.implementation.createHTMLDocument("");
12297 doc.documentElement.innerHTML = this.html ;
12298 div = doc.documentElement;
12300 // old IE... - nasty -- it causes all sorts of issues.. with
12301 // images getting pulled from server..
12302 div = document.createElement('div');
12303 div.innerHTML = this.html;
12305 //doc.documentElement.innerHTML = htmlBody
12311 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12313 var tpls = this.tpls;
12315 // create a top level template from the snippet..
12317 //Roo.log(div.innerHTML);
12324 body : div.innerHTML,
12337 Roo.each(tpls, function(tp){
12338 this.compileTpl(tp);
12339 this.tpls[tp.id] = tp;
12342 this.master = tpls[0];
12348 compileNode : function(node, istop) {
12353 // skip anything not a tag..
12354 if (node.nodeType != 1) {
12355 if (node.nodeType == 3 && !this.inPre) {
12356 // reduce white space..
12357 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12380 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12381 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12382 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12383 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12389 // just itterate children..
12390 this.iterChild(node,this.compileNode);
12393 tpl.uid = this.id++;
12394 tpl.value = node.getAttribute('roo-' + tpl.attr);
12395 node.removeAttribute('roo-'+ tpl.attr);
12396 if (tpl.attr != 'name') {
12397 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12398 node.parentNode.replaceChild(placeholder, node);
12401 var placeholder = document.createElement('span');
12402 placeholder.className = 'roo-tpl-' + tpl.value;
12403 node.parentNode.replaceChild(placeholder, node);
12406 // parent now sees '{domtplXXXX}
12407 this.iterChild(node,this.compileNode);
12409 // we should now have node body...
12410 var div = document.createElement('div');
12411 div.appendChild(node);
12413 // this has the unfortunate side effect of converting tagged attributes
12414 // eg. href="{...}" into %7C...%7D
12415 // this has been fixed by searching for those combo's although it's a bit hacky..
12418 tpl.body = div.innerHTML;
12425 switch (tpl.value) {
12426 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12427 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12428 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12433 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12437 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12441 tpl.id = tpl.value; // replace non characters???
12447 this.tpls.push(tpl);
12457 * Compile a segment of the template into a 'sub-template'
12463 compileTpl : function(tpl)
12465 var fm = Roo.util.Format;
12466 var useF = this.disableFormats !== true;
12468 var sep = Roo.isGecko ? "+\n" : ",\n";
12470 var undef = function(str) {
12471 Roo.debug && Roo.log("Property not found :" + str);
12475 //Roo.log(tpl.body);
12479 var fn = function(m, lbrace, name, format, args)
12482 //Roo.log(arguments);
12483 args = args ? args.replace(/\\'/g,"'") : args;
12484 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12485 if (typeof(format) == 'undefined') {
12486 format = 'htmlEncode';
12488 if (format == 'raw' ) {
12492 if(name.substr(0, 6) == 'domtpl'){
12493 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12496 // build an array of options to determine if value is undefined..
12498 // basically get 'xxxx.yyyy' then do
12499 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12500 // (function () { Roo.log("Property not found"); return ''; })() :
12505 Roo.each(name.split('.'), function(st) {
12506 lookfor += (lookfor.length ? '.': '') + st;
12507 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12510 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12513 if(format && useF){
12515 args = args ? ',' + args : "";
12517 if(format.substr(0, 5) != "this."){
12518 format = "fm." + format + '(';
12520 format = 'this.call("'+ format.substr(5) + '", ';
12524 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12527 if (args && args.length) {
12528 // called with xxyx.yuu:(test,test)
12530 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12532 // raw.. - :raw modifier..
12533 return "'"+ sep + udef_st + name + ")"+sep+"'";
12537 // branched to use + in gecko and [].join() in others
12539 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12540 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12543 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12544 body.push(tpl.body.replace(/(\r\n|\n)/g,
12545 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12546 body.push("'].join('');};};");
12547 body = body.join('');
12550 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12552 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12559 * same as applyTemplate, except it's done to one of the subTemplates
12560 * when using named templates, you can do:
12562 * var str = pl.applySubTemplate('your-name', values);
12565 * @param {Number} id of the template
12566 * @param {Object} values to apply to template
12567 * @param {Object} parent (normaly the instance of this object)
12569 applySubTemplate : function(id, values, parent)
12573 var t = this.tpls[id];
12577 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12578 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12582 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12589 if(t.execCall && t.execCall.call(this, values, parent)){
12593 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12599 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12600 parent = t.target ? values : parent;
12601 if(t.forCall && vs instanceof Array){
12603 for(var i = 0, len = vs.length; i < len; i++){
12605 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12607 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12609 //Roo.log(t.compiled);
12613 return buf.join('');
12616 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12621 return t.compiled.call(this, vs, parent);
12623 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12625 //Roo.log(t.compiled);
12633 applyTemplate : function(values){
12634 return this.master.compiled.call(this, values, {});
12635 //var s = this.subs;
12638 apply : function(){
12639 return this.applyTemplate.apply(this, arguments);
12644 Roo.DomTemplate.from = function(el){
12645 el = Roo.getDom(el);
12646 return new Roo.Domtemplate(el.value || el.innerHTML);
12649 * Ext JS Library 1.1.1
12650 * Copyright(c) 2006-2007, Ext JS, LLC.
12652 * Originally Released Under LGPL - original licence link has changed is not relivant.
12655 * <script type="text/javascript">
12659 * @class Roo.util.DelayedTask
12660 * Provides a convenient method of performing setTimeout where a new
12661 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12662 * You can use this class to buffer
12663 * the keypress events for a certain number of milliseconds, and perform only if they stop
12664 * for that amount of time.
12665 * @constructor The parameters to this constructor serve as defaults and are not required.
12666 * @param {Function} fn (optional) The default function to timeout
12667 * @param {Object} scope (optional) The default scope of that timeout
12668 * @param {Array} args (optional) The default Array of arguments
12670 Roo.util.DelayedTask = function(fn, scope, args){
12671 var id = null, d, t;
12673 var call = function(){
12674 var now = new Date().getTime();
12678 fn.apply(scope, args || []);
12682 * Cancels any pending timeout and queues a new one
12683 * @param {Number} delay The milliseconds to delay
12684 * @param {Function} newFn (optional) Overrides function passed to constructor
12685 * @param {Object} newScope (optional) Overrides scope passed to constructor
12686 * @param {Array} newArgs (optional) Overrides args passed to constructor
12688 this.delay = function(delay, newFn, newScope, newArgs){
12689 if(id && delay != d){
12693 t = new Date().getTime();
12695 scope = newScope || scope;
12696 args = newArgs || args;
12698 id = setInterval(call, d);
12703 * Cancel the last queued timeout
12705 this.cancel = function(){
12713 * Ext JS Library 1.1.1
12714 * Copyright(c) 2006-2007, Ext JS, LLC.
12716 * Originally Released Under LGPL - original licence link has changed is not relivant.
12719 * <script type="text/javascript">
12723 Roo.util.TaskRunner = function(interval){
12724 interval = interval || 10;
12725 var tasks = [], removeQueue = [];
12727 var running = false;
12729 var stopThread = function(){
12735 var startThread = function(){
12738 id = setInterval(runTasks, interval);
12742 var removeTask = function(task){
12743 removeQueue.push(task);
12749 var runTasks = function(){
12750 if(removeQueue.length > 0){
12751 for(var i = 0, len = removeQueue.length; i < len; i++){
12752 tasks.remove(removeQueue[i]);
12755 if(tasks.length < 1){
12760 var now = new Date().getTime();
12761 for(var i = 0, len = tasks.length; i < len; ++i){
12763 var itime = now - t.taskRunTime;
12764 if(t.interval <= itime){
12765 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12766 t.taskRunTime = now;
12767 if(rt === false || t.taskRunCount === t.repeat){
12772 if(t.duration && t.duration <= (now - t.taskStartTime)){
12779 * Queues a new task.
12780 * @param {Object} task
12782 this.start = function(task){
12784 task.taskStartTime = new Date().getTime();
12785 task.taskRunTime = 0;
12786 task.taskRunCount = 0;
12791 this.stop = function(task){
12796 this.stopAll = function(){
12798 for(var i = 0, len = tasks.length; i < len; i++){
12799 if(tasks[i].onStop){
12808 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12810 * Ext JS Library 1.1.1
12811 * Copyright(c) 2006-2007, Ext JS, LLC.
12813 * Originally Released Under LGPL - original licence link has changed is not relivant.
12816 * <script type="text/javascript">
12821 * @class Roo.util.MixedCollection
12822 * @extends Roo.util.Observable
12823 * A Collection class that maintains both numeric indexes and keys and exposes events.
12825 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12826 * collection (defaults to false)
12827 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12828 * and return the key value for that item. This is used when available to look up the key on items that
12829 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12830 * equivalent to providing an implementation for the {@link #getKey} method.
12832 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12840 * Fires when the collection is cleared.
12845 * Fires when an item is added to the collection.
12846 * @param {Number} index The index at which the item was added.
12847 * @param {Object} o The item added.
12848 * @param {String} key The key associated with the added item.
12853 * Fires when an item is replaced in the collection.
12854 * @param {String} key he key associated with the new added.
12855 * @param {Object} old The item being replaced.
12856 * @param {Object} new The new item.
12861 * Fires when an item is removed from the collection.
12862 * @param {Object} o The item being removed.
12863 * @param {String} key (optional) The key associated with the removed item.
12868 this.allowFunctions = allowFunctions === true;
12870 this.getKey = keyFn;
12872 Roo.util.MixedCollection.superclass.constructor.call(this);
12875 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12876 allowFunctions : false,
12879 * Adds an item to the collection.
12880 * @param {String} key The key to associate with the item
12881 * @param {Object} o The item to add.
12882 * @return {Object} The item added.
12884 add : function(key, o){
12885 if(arguments.length == 1){
12887 key = this.getKey(o);
12889 if(typeof key == "undefined" || key === null){
12891 this.items.push(o);
12892 this.keys.push(null);
12894 var old = this.map[key];
12896 return this.replace(key, o);
12899 this.items.push(o);
12901 this.keys.push(key);
12903 this.fireEvent("add", this.length-1, o, key);
12908 * MixedCollection has a generic way to fetch keys if you implement getKey.
12911 var mc = new Roo.util.MixedCollection();
12912 mc.add(someEl.dom.id, someEl);
12913 mc.add(otherEl.dom.id, otherEl);
12917 var mc = new Roo.util.MixedCollection();
12918 mc.getKey = function(el){
12924 // or via the constructor
12925 var mc = new Roo.util.MixedCollection(false, function(el){
12931 * @param o {Object} The item for which to find the key.
12932 * @return {Object} The key for the passed item.
12934 getKey : function(o){
12939 * Replaces an item in the collection.
12940 * @param {String} key The key associated with the item to replace, or the item to replace.
12941 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12942 * @return {Object} The new item.
12944 replace : function(key, o){
12945 if(arguments.length == 1){
12947 key = this.getKey(o);
12949 var old = this.item(key);
12950 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12951 return this.add(key, o);
12953 var index = this.indexOfKey(key);
12954 this.items[index] = o;
12956 this.fireEvent("replace", key, old, o);
12961 * Adds all elements of an Array or an Object to the collection.
12962 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12963 * an Array of values, each of which are added to the collection.
12965 addAll : function(objs){
12966 if(arguments.length > 1 || objs instanceof Array){
12967 var args = arguments.length > 1 ? arguments : objs;
12968 for(var i = 0, len = args.length; i < len; i++){
12972 for(var key in objs){
12973 if(this.allowFunctions || typeof objs[key] != "function"){
12974 this.add(key, objs[key]);
12981 * Executes the specified function once for every item in the collection, passing each
12982 * item as the first and only parameter. returning false from the function will stop the iteration.
12983 * @param {Function} fn The function to execute for each item.
12984 * @param {Object} scope (optional) The scope in which to execute the function.
12986 each : function(fn, scope){
12987 var items = [].concat(this.items); // each safe for removal
12988 for(var i = 0, len = items.length; i < len; i++){
12989 if(fn.call(scope || items[i], items[i], i, len) === false){
12996 * Executes the specified function once for every key in the collection, passing each
12997 * key, and its associated item as the first two parameters.
12998 * @param {Function} fn The function to execute for each item.
12999 * @param {Object} scope (optional) The scope in which to execute the function.
13001 eachKey : function(fn, scope){
13002 for(var i = 0, len = this.keys.length; i < len; i++){
13003 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13008 * Returns the first item in the collection which elicits a true return value from the
13009 * passed selection function.
13010 * @param {Function} fn The selection function to execute for each item.
13011 * @param {Object} scope (optional) The scope in which to execute the function.
13012 * @return {Object} The first item in the collection which returned true from the selection function.
13014 find : function(fn, scope){
13015 for(var i = 0, len = this.items.length; i < len; i++){
13016 if(fn.call(scope || window, this.items[i], this.keys[i])){
13017 return this.items[i];
13024 * Inserts an item at the specified index in the collection.
13025 * @param {Number} index The index to insert the item at.
13026 * @param {String} key The key to associate with the new item, or the item itself.
13027 * @param {Object} o (optional) If the second parameter was a key, the new item.
13028 * @return {Object} The item inserted.
13030 insert : function(index, key, o){
13031 if(arguments.length == 2){
13033 key = this.getKey(o);
13035 if(index >= this.length){
13036 return this.add(key, o);
13039 this.items.splice(index, 0, o);
13040 if(typeof key != "undefined" && key != null){
13043 this.keys.splice(index, 0, key);
13044 this.fireEvent("add", index, o, key);
13049 * Removed an item from the collection.
13050 * @param {Object} o The item to remove.
13051 * @return {Object} The item removed.
13053 remove : function(o){
13054 return this.removeAt(this.indexOf(o));
13058 * Remove an item from a specified index in the collection.
13059 * @param {Number} index The index within the collection of the item to remove.
13061 removeAt : function(index){
13062 if(index < this.length && index >= 0){
13064 var o = this.items[index];
13065 this.items.splice(index, 1);
13066 var key = this.keys[index];
13067 if(typeof key != "undefined"){
13068 delete this.map[key];
13070 this.keys.splice(index, 1);
13071 this.fireEvent("remove", o, key);
13076 * Removed an item associated with the passed key fom the collection.
13077 * @param {String} key The key of the item to remove.
13079 removeKey : function(key){
13080 return this.removeAt(this.indexOfKey(key));
13084 * Returns the number of items in the collection.
13085 * @return {Number} the number of items in the collection.
13087 getCount : function(){
13088 return this.length;
13092 * Returns index within the collection of the passed Object.
13093 * @param {Object} o The item to find the index of.
13094 * @return {Number} index of the item.
13096 indexOf : function(o){
13097 if(!this.items.indexOf){
13098 for(var i = 0, len = this.items.length; i < len; i++){
13099 if(this.items[i] == o) {
13105 return this.items.indexOf(o);
13110 * Returns index within the collection of the passed key.
13111 * @param {String} key The key to find the index of.
13112 * @return {Number} index of the key.
13114 indexOfKey : function(key){
13115 if(!this.keys.indexOf){
13116 for(var i = 0, len = this.keys.length; i < len; i++){
13117 if(this.keys[i] == key) {
13123 return this.keys.indexOf(key);
13128 * Returns the item associated with the passed key OR index. Key has priority over index.
13129 * @param {String/Number} key The key or index of the item.
13130 * @return {Object} The item associated with the passed key.
13132 item : function(key){
13133 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13134 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13138 * Returns the item at the specified index.
13139 * @param {Number} index The index of the item.
13142 itemAt : function(index){
13143 return this.items[index];
13147 * Returns the item associated with the passed key.
13148 * @param {String/Number} key The key of the item.
13149 * @return {Object} The item associated with the passed key.
13151 key : function(key){
13152 return this.map[key];
13156 * Returns true if the collection contains the passed Object as an item.
13157 * @param {Object} o The Object to look for in the collection.
13158 * @return {Boolean} True if the collection contains the Object as an item.
13160 contains : function(o){
13161 return this.indexOf(o) != -1;
13165 * Returns true if the collection contains the passed Object as a key.
13166 * @param {String} key The key to look for in the collection.
13167 * @return {Boolean} True if the collection contains the Object as a key.
13169 containsKey : function(key){
13170 return typeof this.map[key] != "undefined";
13174 * Removes all items from the collection.
13176 clear : function(){
13181 this.fireEvent("clear");
13185 * Returns the first item in the collection.
13186 * @return {Object} the first item in the collection..
13188 first : function(){
13189 return this.items[0];
13193 * Returns the last item in the collection.
13194 * @return {Object} the last item in the collection..
13197 return this.items[this.length-1];
13200 _sort : function(property, dir, fn){
13201 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13202 fn = fn || function(a, b){
13205 var c = [], k = this.keys, items = this.items;
13206 for(var i = 0, len = items.length; i < len; i++){
13207 c[c.length] = {key: k[i], value: items[i], index: i};
13209 c.sort(function(a, b){
13210 var v = fn(a[property], b[property]) * dsc;
13212 v = (a.index < b.index ? -1 : 1);
13216 for(var i = 0, len = c.length; i < len; i++){
13217 items[i] = c[i].value;
13220 this.fireEvent("sort", this);
13224 * Sorts this collection with the passed comparison function
13225 * @param {String} direction (optional) "ASC" or "DESC"
13226 * @param {Function} fn (optional) comparison function
13228 sort : function(dir, fn){
13229 this._sort("value", dir, fn);
13233 * Sorts this collection by keys
13234 * @param {String} direction (optional) "ASC" or "DESC"
13235 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13237 keySort : function(dir, fn){
13238 this._sort("key", dir, fn || function(a, b){
13239 return String(a).toUpperCase()-String(b).toUpperCase();
13244 * Returns a range of items in this collection
13245 * @param {Number} startIndex (optional) defaults to 0
13246 * @param {Number} endIndex (optional) default to the last item
13247 * @return {Array} An array of items
13249 getRange : function(start, end){
13250 var items = this.items;
13251 if(items.length < 1){
13254 start = start || 0;
13255 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13258 for(var i = start; i <= end; i++) {
13259 r[r.length] = items[i];
13262 for(var i = start; i >= end; i--) {
13263 r[r.length] = items[i];
13270 * Filter the <i>objects</i> in this collection by a specific property.
13271 * Returns a new collection that has been filtered.
13272 * @param {String} property A property on your objects
13273 * @param {String/RegExp} value Either string that the property values
13274 * should start with or a RegExp to test against the property
13275 * @return {MixedCollection} The new filtered collection
13277 filter : function(property, value){
13278 if(!value.exec){ // not a regex
13279 value = String(value);
13280 if(value.length == 0){
13281 return this.clone();
13283 value = new RegExp("^" + Roo.escapeRe(value), "i");
13285 return this.filterBy(function(o){
13286 return o && value.test(o[property]);
13291 * Filter by a function. * Returns a new collection that has been filtered.
13292 * The passed function will be called with each
13293 * object in the collection. If the function returns true, the value is included
13294 * otherwise it is filtered.
13295 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13296 * @param {Object} scope (optional) The scope of the function (defaults to this)
13297 * @return {MixedCollection} The new filtered collection
13299 filterBy : function(fn, scope){
13300 var r = new Roo.util.MixedCollection();
13301 r.getKey = this.getKey;
13302 var k = this.keys, it = this.items;
13303 for(var i = 0, len = it.length; i < len; i++){
13304 if(fn.call(scope||this, it[i], k[i])){
13305 r.add(k[i], it[i]);
13312 * Creates a duplicate of this collection
13313 * @return {MixedCollection}
13315 clone : function(){
13316 var r = new Roo.util.MixedCollection();
13317 var k = this.keys, it = this.items;
13318 for(var i = 0, len = it.length; i < len; i++){
13319 r.add(k[i], it[i]);
13321 r.getKey = this.getKey;
13326 * Returns the item associated with the passed key or index.
13328 * @param {String/Number} key The key or index of the item.
13329 * @return {Object} The item associated with the passed key.
13331 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13333 * Ext JS Library 1.1.1
13334 * Copyright(c) 2006-2007, Ext JS, LLC.
13336 * Originally Released Under LGPL - original licence link has changed is not relivant.
13339 * <script type="text/javascript">
13342 * @class Roo.util.JSON
13343 * Modified version of Douglas Crockford"s json.js that doesn"t
13344 * mess with the Object prototype
13345 * http://www.json.org/js.html
13348 Roo.util.JSON = new (function(){
13349 var useHasOwn = {}.hasOwnProperty ? true : false;
13351 // crashes Safari in some instances
13352 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13354 var pad = function(n) {
13355 return n < 10 ? "0" + n : n;
13368 var encodeString = function(s){
13369 if (/["\\\x00-\x1f]/.test(s)) {
13370 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13375 c = b.charCodeAt();
13377 Math.floor(c / 16).toString(16) +
13378 (c % 16).toString(16);
13381 return '"' + s + '"';
13384 var encodeArray = function(o){
13385 var a = ["["], b, i, l = o.length, v;
13386 for (i = 0; i < l; i += 1) {
13388 switch (typeof v) {
13397 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13405 var encodeDate = function(o){
13406 return '"' + o.getFullYear() + "-" +
13407 pad(o.getMonth() + 1) + "-" +
13408 pad(o.getDate()) + "T" +
13409 pad(o.getHours()) + ":" +
13410 pad(o.getMinutes()) + ":" +
13411 pad(o.getSeconds()) + '"';
13415 * Encodes an Object, Array or other value
13416 * @param {Mixed} o The variable to encode
13417 * @return {String} The JSON string
13419 this.encode = function(o)
13421 // should this be extended to fully wrap stringify..
13423 if(typeof o == "undefined" || o === null){
13425 }else if(o instanceof Array){
13426 return encodeArray(o);
13427 }else if(o instanceof Date){
13428 return encodeDate(o);
13429 }else if(typeof o == "string"){
13430 return encodeString(o);
13431 }else if(typeof o == "number"){
13432 return isFinite(o) ? String(o) : "null";
13433 }else if(typeof o == "boolean"){
13436 var a = ["{"], b, i, v;
13438 if(!useHasOwn || o.hasOwnProperty(i)) {
13440 switch (typeof v) {
13449 a.push(this.encode(i), ":",
13450 v === null ? "null" : this.encode(v));
13461 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13462 * @param {String} json The JSON string
13463 * @return {Object} The resulting object
13465 this.decode = function(json){
13467 return /** eval:var:json */ eval("(" + json + ')');
13471 * Shorthand for {@link Roo.util.JSON#encode}
13472 * @member Roo encode
13474 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13476 * Shorthand for {@link Roo.util.JSON#decode}
13477 * @member Roo decode
13479 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13482 * Ext JS Library 1.1.1
13483 * Copyright(c) 2006-2007, Ext JS, LLC.
13485 * Originally Released Under LGPL - original licence link has changed is not relivant.
13488 * <script type="text/javascript">
13492 * @class Roo.util.Format
13493 * Reusable data formatting functions
13496 Roo.util.Format = function(){
13497 var trimRe = /^\s+|\s+$/g;
13500 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13501 * @param {String} value The string to truncate
13502 * @param {Number} length The maximum length to allow before truncating
13503 * @return {String} The converted text
13505 ellipsis : function(value, len){
13506 if(value && value.length > len){
13507 return value.substr(0, len-3)+"...";
13513 * Checks a reference and converts it to empty string if it is undefined
13514 * @param {Mixed} value Reference to check
13515 * @return {Mixed} Empty string if converted, otherwise the original value
13517 undef : function(value){
13518 return typeof value != "undefined" ? value : "";
13522 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13523 * @param {String} value The string to encode
13524 * @return {String} The encoded text
13526 htmlEncode : function(value){
13527 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13531 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13532 * @param {String} value The string to decode
13533 * @return {String} The decoded text
13535 htmlDecode : function(value){
13536 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13540 * Trims any whitespace from either side of a string
13541 * @param {String} value The text to trim
13542 * @return {String} The trimmed text
13544 trim : function(value){
13545 return String(value).replace(trimRe, "");
13549 * Returns a substring from within an original string
13550 * @param {String} value The original text
13551 * @param {Number} start The start index of the substring
13552 * @param {Number} length The length of the substring
13553 * @return {String} The substring
13555 substr : function(value, start, length){
13556 return String(value).substr(start, length);
13560 * Converts a string to all lower case letters
13561 * @param {String} value The text to convert
13562 * @return {String} The converted text
13564 lowercase : function(value){
13565 return String(value).toLowerCase();
13569 * Converts a string to all upper case letters
13570 * @param {String} value The text to convert
13571 * @return {String} The converted text
13573 uppercase : function(value){
13574 return String(value).toUpperCase();
13578 * Converts the first character only of a string to upper case
13579 * @param {String} value The text to convert
13580 * @return {String} The converted text
13582 capitalize : function(value){
13583 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13587 call : function(value, fn){
13588 if(arguments.length > 2){
13589 var args = Array.prototype.slice.call(arguments, 2);
13590 args.unshift(value);
13592 return /** eval:var:value */ eval(fn).apply(window, args);
13594 /** eval:var:value */
13595 return /** eval:var:value */ eval(fn).call(window, value);
13601 * safer version of Math.toFixed..??/
13602 * @param {Number/String} value The numeric value to format
13603 * @param {Number/String} value Decimal places
13604 * @return {String} The formatted currency string
13606 toFixed : function(v, n)
13608 // why not use to fixed - precision is buggered???
13610 return Math.round(v-0);
13612 var fact = Math.pow(10,n+1);
13613 v = (Math.round((v-0)*fact))/fact;
13614 var z = (''+fact).substring(2);
13615 if (v == Math.floor(v)) {
13616 return Math.floor(v) + '.' + z;
13619 // now just padd decimals..
13620 var ps = String(v).split('.');
13621 var fd = (ps[1] + z);
13622 var r = fd.substring(0,n);
13623 var rm = fd.substring(n);
13625 return ps[0] + '.' + r;
13627 r*=1; // turn it into a number;
13629 if (String(r).length != n) {
13632 r = String(r).substring(1); // chop the end off.
13635 return ps[0] + '.' + r;
13640 * Format a number as US currency
13641 * @param {Number/String} value The numeric value to format
13642 * @return {String} The formatted currency string
13644 usMoney : function(v){
13645 return '$' + Roo.util.Format.number(v);
13650 * eventually this should probably emulate php's number_format
13651 * @param {Number/String} value The numeric value to format
13652 * @param {Number} decimals number of decimal places
13653 * @return {String} The formatted currency string
13655 number : function(v,decimals)
13657 // multiply and round.
13658 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13659 var mul = Math.pow(10, decimals);
13660 var zero = String(mul).substring(1);
13661 v = (Math.round((v-0)*mul))/mul;
13663 // if it's '0' number.. then
13665 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13667 var ps = v.split('.');
13671 var r = /(\d+)(\d{3})/;
13673 while (r.test(whole)) {
13674 whole = whole.replace(r, '$1' + ',' + '$2');
13680 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13681 // does not have decimals
13682 (decimals ? ('.' + zero) : '');
13685 return whole + sub ;
13689 * Parse a value into a formatted date using the specified format pattern.
13690 * @param {Mixed} value The value to format
13691 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13692 * @return {String} The formatted date string
13694 date : function(v, format){
13698 if(!(v instanceof Date)){
13699 v = new Date(Date.parse(v));
13701 return v.dateFormat(format || Roo.util.Format.defaults.date);
13705 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13706 * @param {String} format Any valid date format string
13707 * @return {Function} The date formatting function
13709 dateRenderer : function(format){
13710 return function(v){
13711 return Roo.util.Format.date(v, format);
13716 stripTagsRE : /<\/?[^>]+>/gi,
13719 * Strips all HTML tags
13720 * @param {Mixed} value The text from which to strip tags
13721 * @return {String} The stripped text
13723 stripTags : function(v){
13724 return !v ? v : String(v).replace(this.stripTagsRE, "");
13728 Roo.util.Format.defaults = {
13732 * Ext JS Library 1.1.1
13733 * Copyright(c) 2006-2007, Ext JS, LLC.
13735 * Originally Released Under LGPL - original licence link has changed is not relivant.
13738 * <script type="text/javascript">
13745 * @class Roo.MasterTemplate
13746 * @extends Roo.Template
13747 * Provides a template that can have child templates. The syntax is:
13749 var t = new Roo.MasterTemplate(
13750 '<select name="{name}">',
13751 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13754 t.add('options', {value: 'foo', text: 'bar'});
13755 // or you can add multiple child elements in one shot
13756 t.addAll('options', [
13757 {value: 'foo', text: 'bar'},
13758 {value: 'foo2', text: 'bar2'},
13759 {value: 'foo3', text: 'bar3'}
13761 // then append, applying the master template values
13762 t.append('my-form', {name: 'my-select'});
13764 * A name attribute for the child template is not required if you have only one child
13765 * template or you want to refer to them by index.
13767 Roo.MasterTemplate = function(){
13768 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13769 this.originalHtml = this.html;
13771 var m, re = this.subTemplateRe;
13774 while(m = re.exec(this.html)){
13775 var name = m[1], content = m[2];
13780 tpl : new Roo.Template(content)
13783 st[name] = st[subIndex];
13785 st[subIndex].tpl.compile();
13786 st[subIndex].tpl.call = this.call.createDelegate(this);
13789 this.subCount = subIndex;
13792 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13794 * The regular expression used to match sub templates
13798 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13801 * Applies the passed values to a child template.
13802 * @param {String/Number} name (optional) The name or index of the child template
13803 * @param {Array/Object} values The values to be applied to the template
13804 * @return {MasterTemplate} this
13806 add : function(name, values){
13807 if(arguments.length == 1){
13808 values = arguments[0];
13811 var s = this.subs[name];
13812 s.buffer[s.buffer.length] = s.tpl.apply(values);
13817 * Applies all the passed values to a child template.
13818 * @param {String/Number} name (optional) The name or index of the child template
13819 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13820 * @param {Boolean} reset (optional) True to reset the template first
13821 * @return {MasterTemplate} this
13823 fill : function(name, values, reset){
13825 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13833 for(var i = 0, len = values.length; i < len; i++){
13834 this.add(name, values[i]);
13840 * Resets the template for reuse
13841 * @return {MasterTemplate} this
13843 reset : function(){
13845 for(var i = 0; i < this.subCount; i++){
13851 applyTemplate : function(values){
13853 var replaceIndex = -1;
13854 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13855 return s[++replaceIndex].buffer.join("");
13857 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13860 apply : function(){
13861 return this.applyTemplate.apply(this, arguments);
13864 compile : function(){return this;}
13868 * Alias for fill().
13871 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13873 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13874 * var tpl = Roo.MasterTemplate.from('element-id');
13875 * @param {String/HTMLElement} el
13876 * @param {Object} config
13879 Roo.MasterTemplate.from = function(el, config){
13880 el = Roo.getDom(el);
13881 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13884 * Ext JS Library 1.1.1
13885 * Copyright(c) 2006-2007, Ext JS, LLC.
13887 * Originally Released Under LGPL - original licence link has changed is not relivant.
13890 * <script type="text/javascript">
13895 * @class Roo.util.CSS
13896 * Utility class for manipulating CSS rules
13899 Roo.util.CSS = function(){
13901 var doc = document;
13903 var camelRe = /(-[a-z])/gi;
13904 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13908 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13909 * tag and appended to the HEAD of the document.
13910 * @param {String|Object} cssText The text containing the css rules
13911 * @param {String} id An id to add to the stylesheet for later removal
13912 * @return {StyleSheet}
13914 createStyleSheet : function(cssText, id){
13916 var head = doc.getElementsByTagName("head")[0];
13917 var nrules = doc.createElement("style");
13918 nrules.setAttribute("type", "text/css");
13920 nrules.setAttribute("id", id);
13922 if (typeof(cssText) != 'string') {
13923 // support object maps..
13924 // not sure if this a good idea..
13925 // perhaps it should be merged with the general css handling
13926 // and handle js style props.
13927 var cssTextNew = [];
13928 for(var n in cssText) {
13930 for(var k in cssText[n]) {
13931 citems.push( k + ' : ' +cssText[n][k] + ';' );
13933 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13936 cssText = cssTextNew.join("\n");
13942 head.appendChild(nrules);
13943 ss = nrules.styleSheet;
13944 ss.cssText = cssText;
13947 nrules.appendChild(doc.createTextNode(cssText));
13949 nrules.cssText = cssText;
13951 head.appendChild(nrules);
13952 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13954 this.cacheStyleSheet(ss);
13959 * Removes a style or link tag by id
13960 * @param {String} id The id of the tag
13962 removeStyleSheet : function(id){
13963 var existing = doc.getElementById(id);
13965 existing.parentNode.removeChild(existing);
13970 * Dynamically swaps an existing stylesheet reference for a new one
13971 * @param {String} id The id of an existing link tag to remove
13972 * @param {String} url The href of the new stylesheet to include
13974 swapStyleSheet : function(id, url){
13975 this.removeStyleSheet(id);
13976 var ss = doc.createElement("link");
13977 ss.setAttribute("rel", "stylesheet");
13978 ss.setAttribute("type", "text/css");
13979 ss.setAttribute("id", id);
13980 ss.setAttribute("href", url);
13981 doc.getElementsByTagName("head")[0].appendChild(ss);
13985 * Refresh the rule cache if you have dynamically added stylesheets
13986 * @return {Object} An object (hash) of rules indexed by selector
13988 refreshCache : function(){
13989 return this.getRules(true);
13993 cacheStyleSheet : function(stylesheet){
13997 try{// try catch for cross domain access issue
13998 var ssRules = stylesheet.cssRules || stylesheet.rules;
13999 for(var j = ssRules.length-1; j >= 0; --j){
14000 rules[ssRules[j].selectorText] = ssRules[j];
14006 * Gets all css rules for the document
14007 * @param {Boolean} refreshCache true to refresh the internal cache
14008 * @return {Object} An object (hash) of rules indexed by selector
14010 getRules : function(refreshCache){
14011 if(rules == null || refreshCache){
14013 var ds = doc.styleSheets;
14014 for(var i =0, len = ds.length; i < len; i++){
14016 this.cacheStyleSheet(ds[i]);
14024 * Gets an an individual CSS rule by selector(s)
14025 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14026 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14027 * @return {CSSRule} The CSS rule or null if one is not found
14029 getRule : function(selector, refreshCache){
14030 var rs = this.getRules(refreshCache);
14031 if(!(selector instanceof Array)){
14032 return rs[selector];
14034 for(var i = 0; i < selector.length; i++){
14035 if(rs[selector[i]]){
14036 return rs[selector[i]];
14044 * Updates a rule property
14045 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14046 * @param {String} property The css property
14047 * @param {String} value The new value for the property
14048 * @return {Boolean} true If a rule was found and updated
14050 updateRule : function(selector, property, value){
14051 if(!(selector instanceof Array)){
14052 var rule = this.getRule(selector);
14054 rule.style[property.replace(camelRe, camelFn)] = value;
14058 for(var i = 0; i < selector.length; i++){
14059 if(this.updateRule(selector[i], property, value)){
14069 * Ext JS Library 1.1.1
14070 * Copyright(c) 2006-2007, Ext JS, LLC.
14072 * Originally Released Under LGPL - original licence link has changed is not relivant.
14075 * <script type="text/javascript">
14081 * @class Roo.util.ClickRepeater
14082 * @extends Roo.util.Observable
14084 * A wrapper class which can be applied to any element. Fires a "click" event while the
14085 * mouse is pressed. The interval between firings may be specified in the config but
14086 * defaults to 10 milliseconds.
14088 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14090 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14091 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14092 * Similar to an autorepeat key delay.
14093 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14094 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14095 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14096 * "interval" and "delay" are ignored. "immediate" is honored.
14097 * @cfg {Boolean} preventDefault True to prevent the default click event
14098 * @cfg {Boolean} stopDefault True to stop the default click event
14101 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14102 * 2007-02-02 jvs Renamed to ClickRepeater
14103 * 2007-02-03 jvs Modifications for FF Mac and Safari
14106 * @param {String/HTMLElement/Element} el The element to listen on
14107 * @param {Object} config
14109 Roo.util.ClickRepeater = function(el, config)
14111 this.el = Roo.get(el);
14112 this.el.unselectable();
14114 Roo.apply(this, config);
14119 * Fires when the mouse button is depressed.
14120 * @param {Roo.util.ClickRepeater} this
14122 "mousedown" : true,
14125 * Fires on a specified interval during the time the element is pressed.
14126 * @param {Roo.util.ClickRepeater} this
14131 * Fires when the mouse key is released.
14132 * @param {Roo.util.ClickRepeater} this
14137 this.el.on("mousedown", this.handleMouseDown, this);
14138 if(this.preventDefault || this.stopDefault){
14139 this.el.on("click", function(e){
14140 if(this.preventDefault){
14141 e.preventDefault();
14143 if(this.stopDefault){
14149 // allow inline handler
14151 this.on("click", this.handler, this.scope || this);
14154 Roo.util.ClickRepeater.superclass.constructor.call(this);
14157 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14160 preventDefault : true,
14161 stopDefault : false,
14165 handleMouseDown : function(){
14166 clearTimeout(this.timer);
14168 if(this.pressClass){
14169 this.el.addClass(this.pressClass);
14171 this.mousedownTime = new Date();
14173 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14174 this.el.on("mouseout", this.handleMouseOut, this);
14176 this.fireEvent("mousedown", this);
14177 this.fireEvent("click", this);
14179 this.timer = this.click.defer(this.delay || this.interval, this);
14183 click : function(){
14184 this.fireEvent("click", this);
14185 this.timer = this.click.defer(this.getInterval(), this);
14189 getInterval: function(){
14190 if(!this.accelerate){
14191 return this.interval;
14193 var pressTime = this.mousedownTime.getElapsed();
14194 if(pressTime < 500){
14196 }else if(pressTime < 1700){
14198 }else if(pressTime < 2600){
14200 }else if(pressTime < 3500){
14202 }else if(pressTime < 4400){
14204 }else if(pressTime < 5300){
14206 }else if(pressTime < 6200){
14214 handleMouseOut : function(){
14215 clearTimeout(this.timer);
14216 if(this.pressClass){
14217 this.el.removeClass(this.pressClass);
14219 this.el.on("mouseover", this.handleMouseReturn, this);
14223 handleMouseReturn : function(){
14224 this.el.un("mouseover", this.handleMouseReturn);
14225 if(this.pressClass){
14226 this.el.addClass(this.pressClass);
14232 handleMouseUp : function(){
14233 clearTimeout(this.timer);
14234 this.el.un("mouseover", this.handleMouseReturn);
14235 this.el.un("mouseout", this.handleMouseOut);
14236 Roo.get(document).un("mouseup", this.handleMouseUp);
14237 this.el.removeClass(this.pressClass);
14238 this.fireEvent("mouseup", this);
14242 * Ext JS Library 1.1.1
14243 * Copyright(c) 2006-2007, Ext JS, LLC.
14245 * Originally Released Under LGPL - original licence link has changed is not relivant.
14248 * <script type="text/javascript">
14253 * @class Roo.KeyNav
14254 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14255 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14256 * way to implement custom navigation schemes for any UI component.</p>
14257 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14258 * pageUp, pageDown, del, home, end. Usage:</p>
14260 var nav = new Roo.KeyNav("my-element", {
14261 "left" : function(e){
14262 this.moveLeft(e.ctrlKey);
14264 "right" : function(e){
14265 this.moveRight(e.ctrlKey);
14267 "enter" : function(e){
14274 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14275 * @param {Object} config The config
14277 Roo.KeyNav = function(el, config){
14278 this.el = Roo.get(el);
14279 Roo.apply(this, config);
14280 if(!this.disabled){
14281 this.disabled = true;
14286 Roo.KeyNav.prototype = {
14288 * @cfg {Boolean} disabled
14289 * True to disable this KeyNav instance (defaults to false)
14293 * @cfg {String} defaultEventAction
14294 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14295 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14296 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14298 defaultEventAction: "stopEvent",
14300 * @cfg {Boolean} forceKeyDown
14301 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14302 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14303 * handle keydown instead of keypress.
14305 forceKeyDown : false,
14308 prepareEvent : function(e){
14309 var k = e.getKey();
14310 var h = this.keyToHandler[k];
14311 //if(h && this[h]){
14312 // e.stopPropagation();
14314 if(Roo.isSafari && h && k >= 37 && k <= 40){
14320 relay : function(e){
14321 var k = e.getKey();
14322 var h = this.keyToHandler[k];
14324 if(this.doRelay(e, this[h], h) !== true){
14325 e[this.defaultEventAction]();
14331 doRelay : function(e, h, hname){
14332 return h.call(this.scope || this, e);
14335 // possible handlers
14349 // quick lookup hash
14366 * Enable this KeyNav
14368 enable: function(){
14370 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14371 // the EventObject will normalize Safari automatically
14372 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14373 this.el.on("keydown", this.relay, this);
14375 this.el.on("keydown", this.prepareEvent, this);
14376 this.el.on("keypress", this.relay, this);
14378 this.disabled = false;
14383 * Disable this KeyNav
14385 disable: function(){
14386 if(!this.disabled){
14387 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14388 this.el.un("keydown", this.relay);
14390 this.el.un("keydown", this.prepareEvent);
14391 this.el.un("keypress", this.relay);
14393 this.disabled = true;
14398 * Ext JS Library 1.1.1
14399 * Copyright(c) 2006-2007, Ext JS, LLC.
14401 * Originally Released Under LGPL - original licence link has changed is not relivant.
14404 * <script type="text/javascript">
14409 * @class Roo.KeyMap
14410 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14411 * The constructor accepts the same config object as defined by {@link #addBinding}.
14412 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14413 * combination it will call the function with this signature (if the match is a multi-key
14414 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14415 * A KeyMap can also handle a string representation of keys.<br />
14418 // map one key by key code
14419 var map = new Roo.KeyMap("my-element", {
14420 key: 13, // or Roo.EventObject.ENTER
14425 // map multiple keys to one action by string
14426 var map = new Roo.KeyMap("my-element", {
14432 // map multiple keys to multiple actions by strings and array of codes
14433 var map = new Roo.KeyMap("my-element", [
14436 fn: function(){ alert("Return was pressed"); }
14439 fn: function(){ alert('a, b or c was pressed'); }
14444 fn: function(){ alert('Control + shift + tab was pressed.'); }
14448 * <b>Note: A KeyMap starts enabled</b>
14450 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14451 * @param {Object} config The config (see {@link #addBinding})
14452 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14454 Roo.KeyMap = function(el, config, eventName){
14455 this.el = Roo.get(el);
14456 this.eventName = eventName || "keydown";
14457 this.bindings = [];
14459 this.addBinding(config);
14464 Roo.KeyMap.prototype = {
14466 * True to stop the event from bubbling and prevent the default browser action if the
14467 * key was handled by the KeyMap (defaults to false)
14473 * Add a new binding to this KeyMap. The following config object properties are supported:
14475 Property Type Description
14476 ---------- --------------- ----------------------------------------------------------------------
14477 key String/Array A single keycode or an array of keycodes to handle
14478 shift Boolean True to handle key only when shift is pressed (defaults to false)
14479 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14480 alt Boolean True to handle key only when alt is pressed (defaults to false)
14481 fn Function The function to call when KeyMap finds the expected key combination
14482 scope Object The scope of the callback function
14488 var map = new Roo.KeyMap(document, {
14489 key: Roo.EventObject.ENTER,
14494 //Add a new binding to the existing KeyMap later
14502 * @param {Object/Array} config A single KeyMap config or an array of configs
14504 addBinding : function(config){
14505 if(config instanceof Array){
14506 for(var i = 0, len = config.length; i < len; i++){
14507 this.addBinding(config[i]);
14511 var keyCode = config.key,
14512 shift = config.shift,
14513 ctrl = config.ctrl,
14516 scope = config.scope;
14517 if(typeof keyCode == "string"){
14519 var keyString = keyCode.toUpperCase();
14520 for(var j = 0, len = keyString.length; j < len; j++){
14521 ks.push(keyString.charCodeAt(j));
14525 var keyArray = keyCode instanceof Array;
14526 var handler = function(e){
14527 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14528 var k = e.getKey();
14530 for(var i = 0, len = keyCode.length; i < len; i++){
14531 if(keyCode[i] == k){
14532 if(this.stopEvent){
14535 fn.call(scope || window, k, e);
14541 if(this.stopEvent){
14544 fn.call(scope || window, k, e);
14549 this.bindings.push(handler);
14553 * Shorthand for adding a single key listener
14554 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14555 * following options:
14556 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14557 * @param {Function} fn The function to call
14558 * @param {Object} scope (optional) The scope of the function
14560 on : function(key, fn, scope){
14561 var keyCode, shift, ctrl, alt;
14562 if(typeof key == "object" && !(key instanceof Array)){
14581 handleKeyDown : function(e){
14582 if(this.enabled){ //just in case
14583 var b = this.bindings;
14584 for(var i = 0, len = b.length; i < len; i++){
14585 b[i].call(this, e);
14591 * Returns true if this KeyMap is enabled
14592 * @return {Boolean}
14594 isEnabled : function(){
14595 return this.enabled;
14599 * Enables this KeyMap
14601 enable: function(){
14603 this.el.on(this.eventName, this.handleKeyDown, this);
14604 this.enabled = true;
14609 * Disable this KeyMap
14611 disable: function(){
14613 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14614 this.enabled = false;
14619 * Ext JS Library 1.1.1
14620 * Copyright(c) 2006-2007, Ext JS, LLC.
14622 * Originally Released Under LGPL - original licence link has changed is not relivant.
14625 * <script type="text/javascript">
14630 * @class Roo.util.TextMetrics
14631 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14632 * wide, in pixels, a given block of text will be.
14635 Roo.util.TextMetrics = function(){
14639 * Measures the size of the specified text
14640 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14641 * that can affect the size of the rendered text
14642 * @param {String} text The text to measure
14643 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14644 * in order to accurately measure the text height
14645 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14647 measure : function(el, text, fixedWidth){
14649 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14652 shared.setFixedWidth(fixedWidth || 'auto');
14653 return shared.getSize(text);
14657 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14658 * the overhead of multiple calls to initialize the style properties on each measurement.
14659 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14660 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14661 * in order to accurately measure the text height
14662 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14664 createInstance : function(el, fixedWidth){
14665 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14672 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14673 var ml = new Roo.Element(document.createElement('div'));
14674 document.body.appendChild(ml.dom);
14675 ml.position('absolute');
14676 ml.setLeftTop(-1000, -1000);
14680 ml.setWidth(fixedWidth);
14685 * Returns the size of the specified text based on the internal element's style and width properties
14686 * @memberOf Roo.util.TextMetrics.Instance#
14687 * @param {String} text The text to measure
14688 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14690 getSize : function(text){
14692 var s = ml.getSize();
14698 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14699 * that can affect the size of the rendered text
14700 * @memberOf Roo.util.TextMetrics.Instance#
14701 * @param {String/HTMLElement} el The element, dom node or id
14703 bind : function(el){
14705 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14710 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14711 * to set a fixed width in order to accurately measure the text height.
14712 * @memberOf Roo.util.TextMetrics.Instance#
14713 * @param {Number} width The width to set on the element
14715 setFixedWidth : function(width){
14716 ml.setWidth(width);
14720 * Returns the measured width of the specified text
14721 * @memberOf Roo.util.TextMetrics.Instance#
14722 * @param {String} text The text to measure
14723 * @return {Number} width The width in pixels
14725 getWidth : function(text){
14726 ml.dom.style.width = 'auto';
14727 return this.getSize(text).width;
14731 * Returns the measured height of the specified text. For multiline text, be sure to call
14732 * {@link #setFixedWidth} if necessary.
14733 * @memberOf Roo.util.TextMetrics.Instance#
14734 * @param {String} text The text to measure
14735 * @return {Number} height The height in pixels
14737 getHeight : function(text){
14738 return this.getSize(text).height;
14742 instance.bind(bindTo);
14747 // backwards compat
14748 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14750 * Ext JS Library 1.1.1
14751 * Copyright(c) 2006-2007, Ext JS, LLC.
14753 * Originally Released Under LGPL - original licence link has changed is not relivant.
14756 * <script type="text/javascript">
14760 * @class Roo.state.Provider
14761 * Abstract base class for state provider implementations. This class provides methods
14762 * for encoding and decoding <b>typed</b> variables including dates and defines the
14763 * Provider interface.
14765 Roo.state.Provider = function(){
14767 * @event statechange
14768 * Fires when a state change occurs.
14769 * @param {Provider} this This state provider
14770 * @param {String} key The state key which was changed
14771 * @param {String} value The encoded value for the state
14774 "statechange": true
14777 Roo.state.Provider.superclass.constructor.call(this);
14779 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14781 * Returns the current value for a key
14782 * @param {String} name The key name
14783 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14784 * @return {Mixed} The state data
14786 get : function(name, defaultValue){
14787 return typeof this.state[name] == "undefined" ?
14788 defaultValue : this.state[name];
14792 * Clears a value from the state
14793 * @param {String} name The key name
14795 clear : function(name){
14796 delete this.state[name];
14797 this.fireEvent("statechange", this, name, null);
14801 * Sets the value for a key
14802 * @param {String} name The key name
14803 * @param {Mixed} value The value to set
14805 set : function(name, value){
14806 this.state[name] = value;
14807 this.fireEvent("statechange", this, name, value);
14811 * Decodes a string previously encoded with {@link #encodeValue}.
14812 * @param {String} value The value to decode
14813 * @return {Mixed} The decoded value
14815 decodeValue : function(cookie){
14816 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14817 var matches = re.exec(unescape(cookie));
14818 if(!matches || !matches[1]) {
14819 return; // non state cookie
14821 var type = matches[1];
14822 var v = matches[2];
14825 return parseFloat(v);
14827 return new Date(Date.parse(v));
14832 var values = v.split("^");
14833 for(var i = 0, len = values.length; i < len; i++){
14834 all.push(this.decodeValue(values[i]));
14839 var values = v.split("^");
14840 for(var i = 0, len = values.length; i < len; i++){
14841 var kv = values[i].split("=");
14842 all[kv[0]] = this.decodeValue(kv[1]);
14851 * Encodes a value including type information. Decode with {@link #decodeValue}.
14852 * @param {Mixed} value The value to encode
14853 * @return {String} The encoded value
14855 encodeValue : function(v){
14857 if(typeof v == "number"){
14859 }else if(typeof v == "boolean"){
14860 enc = "b:" + (v ? "1" : "0");
14861 }else if(v instanceof Date){
14862 enc = "d:" + v.toGMTString();
14863 }else if(v instanceof Array){
14865 for(var i = 0, len = v.length; i < len; i++){
14866 flat += this.encodeValue(v[i]);
14872 }else if(typeof v == "object"){
14875 if(typeof v[key] != "function"){
14876 flat += key + "=" + this.encodeValue(v[key]) + "^";
14879 enc = "o:" + flat.substring(0, flat.length-1);
14883 return escape(enc);
14889 * Ext JS Library 1.1.1
14890 * Copyright(c) 2006-2007, Ext JS, LLC.
14892 * Originally Released Under LGPL - original licence link has changed is not relivant.
14895 * <script type="text/javascript">
14898 * @class Roo.state.Manager
14899 * This is the global state manager. By default all components that are "state aware" check this class
14900 * for state information if you don't pass them a custom state provider. In order for this class
14901 * to be useful, it must be initialized with a provider when your application initializes.
14903 // in your initialization function
14905 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14907 // supposed you have a {@link Roo.BorderLayout}
14908 var layout = new Roo.BorderLayout(...);
14909 layout.restoreState();
14910 // or a {Roo.BasicDialog}
14911 var dialog = new Roo.BasicDialog(...);
14912 dialog.restoreState();
14916 Roo.state.Manager = function(){
14917 var provider = new Roo.state.Provider();
14921 * Configures the default state provider for your application
14922 * @param {Provider} stateProvider The state provider to set
14924 setProvider : function(stateProvider){
14925 provider = stateProvider;
14929 * Returns the current value for a key
14930 * @param {String} name The key name
14931 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14932 * @return {Mixed} The state data
14934 get : function(key, defaultValue){
14935 return provider.get(key, defaultValue);
14939 * Sets the value for a key
14940 * @param {String} name The key name
14941 * @param {Mixed} value The state data
14943 set : function(key, value){
14944 provider.set(key, value);
14948 * Clears a value from the state
14949 * @param {String} name The key name
14951 clear : function(key){
14952 provider.clear(key);
14956 * Gets the currently configured state provider
14957 * @return {Provider} The state provider
14959 getProvider : function(){
14966 * Ext JS Library 1.1.1
14967 * Copyright(c) 2006-2007, Ext JS, LLC.
14969 * Originally Released Under LGPL - original licence link has changed is not relivant.
14972 * <script type="text/javascript">
14975 * @class Roo.state.CookieProvider
14976 * @extends Roo.state.Provider
14977 * The default Provider implementation which saves state via cookies.
14980 var cp = new Roo.state.CookieProvider({
14982 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14983 domain: "roojs.com"
14985 Roo.state.Manager.setProvider(cp);
14987 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14988 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14989 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14990 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14991 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14992 * domain the page is running on including the 'www' like 'www.roojs.com')
14993 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14995 * Create a new CookieProvider
14996 * @param {Object} config The configuration object
14998 Roo.state.CookieProvider = function(config){
14999 Roo.state.CookieProvider.superclass.constructor.call(this);
15001 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15002 this.domain = null;
15003 this.secure = false;
15004 Roo.apply(this, config);
15005 this.state = this.readCookies();
15008 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15010 set : function(name, value){
15011 if(typeof value == "undefined" || value === null){
15015 this.setCookie(name, value);
15016 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15020 clear : function(name){
15021 this.clearCookie(name);
15022 Roo.state.CookieProvider.superclass.clear.call(this, name);
15026 readCookies : function(){
15028 var c = document.cookie + ";";
15029 var re = /\s?(.*?)=(.*?);/g;
15031 while((matches = re.exec(c)) != null){
15032 var name = matches[1];
15033 var value = matches[2];
15034 if(name && name.substring(0,3) == "ys-"){
15035 cookies[name.substr(3)] = this.decodeValue(value);
15042 setCookie : function(name, value){
15043 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15044 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15045 ((this.path == null) ? "" : ("; path=" + this.path)) +
15046 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15047 ((this.secure == true) ? "; secure" : "");
15051 clearCookie : function(name){
15052 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15053 ((this.path == null) ? "" : ("; path=" + this.path)) +
15054 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15055 ((this.secure == true) ? "; secure" : "");
15059 * Ext JS Library 1.1.1
15060 * Copyright(c) 2006-2007, Ext JS, LLC.
15062 * Originally Released Under LGPL - original licence link has changed is not relivant.
15065 * <script type="text/javascript">
15070 * @class Roo.ComponentMgr
15071 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15074 Roo.ComponentMgr = function(){
15075 var all = new Roo.util.MixedCollection();
15079 * Registers a component.
15080 * @param {Roo.Component} c The component
15082 register : function(c){
15087 * Unregisters a component.
15088 * @param {Roo.Component} c The component
15090 unregister : function(c){
15095 * Returns a component by id
15096 * @param {String} id The component id
15098 get : function(id){
15099 return all.get(id);
15103 * Registers a function that will be called when a specified component is added to ComponentMgr
15104 * @param {String} id The component id
15105 * @param {Funtction} fn The callback function
15106 * @param {Object} scope The scope of the callback
15108 onAvailable : function(id, fn, scope){
15109 all.on("add", function(index, o){
15111 fn.call(scope || o, o);
15112 all.un("add", fn, scope);
15119 * Ext JS Library 1.1.1
15120 * Copyright(c) 2006-2007, Ext JS, LLC.
15122 * Originally Released Under LGPL - original licence link has changed is not relivant.
15125 * <script type="text/javascript">
15129 * @class Roo.Component
15130 * @extends Roo.util.Observable
15131 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15132 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15133 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15134 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15135 * All visual components (widgets) that require rendering into a layout should subclass Component.
15137 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15138 * 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
15139 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15141 Roo.Component = function(config){
15142 config = config || {};
15143 if(config.tagName || config.dom || typeof config == "string"){ // element object
15144 config = {el: config, id: config.id || config};
15146 this.initialConfig = config;
15148 Roo.apply(this, config);
15152 * Fires after the component is disabled.
15153 * @param {Roo.Component} this
15158 * Fires after the component is enabled.
15159 * @param {Roo.Component} this
15163 * @event beforeshow
15164 * Fires before the component is shown. Return false to stop the show.
15165 * @param {Roo.Component} this
15170 * Fires after the component is shown.
15171 * @param {Roo.Component} this
15175 * @event beforehide
15176 * Fires before the component is hidden. Return false to stop the hide.
15177 * @param {Roo.Component} this
15182 * Fires after the component is hidden.
15183 * @param {Roo.Component} this
15187 * @event beforerender
15188 * Fires before the component is rendered. Return false to stop the render.
15189 * @param {Roo.Component} this
15191 beforerender : true,
15194 * Fires after the component is rendered.
15195 * @param {Roo.Component} this
15199 * @event beforedestroy
15200 * Fires before the component is destroyed. Return false to stop the destroy.
15201 * @param {Roo.Component} this
15203 beforedestroy : true,
15206 * Fires after the component is destroyed.
15207 * @param {Roo.Component} this
15212 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15214 Roo.ComponentMgr.register(this);
15215 Roo.Component.superclass.constructor.call(this);
15216 this.initComponent();
15217 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15218 this.render(this.renderTo);
15219 delete this.renderTo;
15224 Roo.Component.AUTO_ID = 1000;
15226 Roo.extend(Roo.Component, Roo.util.Observable, {
15228 * @scope Roo.Component.prototype
15230 * true if this component is hidden. Read-only.
15235 * true if this component is disabled. Read-only.
15240 * true if this component has been rendered. Read-only.
15244 /** @cfg {String} disableClass
15245 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15247 disabledClass : "x-item-disabled",
15248 /** @cfg {Boolean} allowDomMove
15249 * Whether the component can move the Dom node when rendering (defaults to true).
15251 allowDomMove : true,
15252 /** @cfg {String} hideMode (display|visibility)
15253 * How this component should hidden. Supported values are
15254 * "visibility" (css visibility), "offsets" (negative offset position) and
15255 * "display" (css display) - defaults to "display".
15257 hideMode: 'display',
15260 ctype : "Roo.Component",
15263 * @cfg {String} actionMode
15264 * which property holds the element that used for hide() / show() / disable() / enable()
15270 getActionEl : function(){
15271 return this[this.actionMode];
15274 initComponent : Roo.emptyFn,
15276 * If this is a lazy rendering component, render it to its container element.
15277 * @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.
15279 render : function(container, position){
15280 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15281 if(!container && this.el){
15282 this.el = Roo.get(this.el);
15283 container = this.el.dom.parentNode;
15284 this.allowDomMove = false;
15286 this.container = Roo.get(container);
15287 this.rendered = true;
15288 if(position !== undefined){
15289 if(typeof position == 'number'){
15290 position = this.container.dom.childNodes[position];
15292 position = Roo.getDom(position);
15295 this.onRender(this.container, position || null);
15297 this.el.addClass(this.cls);
15301 this.el.applyStyles(this.style);
15304 this.fireEvent("render", this);
15305 this.afterRender(this.container);
15317 // default function is not really useful
15318 onRender : function(ct, position){
15320 this.el = Roo.get(this.el);
15321 if(this.allowDomMove !== false){
15322 ct.dom.insertBefore(this.el.dom, position);
15328 getAutoCreate : function(){
15329 var cfg = typeof this.autoCreate == "object" ?
15330 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15331 if(this.id && !cfg.id){
15338 afterRender : Roo.emptyFn,
15341 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15342 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15344 destroy : function(){
15345 if(this.fireEvent("beforedestroy", this) !== false){
15346 this.purgeListeners();
15347 this.beforeDestroy();
15349 this.el.removeAllListeners();
15351 if(this.actionMode == "container"){
15352 this.container.remove();
15356 Roo.ComponentMgr.unregister(this);
15357 this.fireEvent("destroy", this);
15362 beforeDestroy : function(){
15367 onDestroy : function(){
15372 * Returns the underlying {@link Roo.Element}.
15373 * @return {Roo.Element} The element
15375 getEl : function(){
15380 * Returns the id of this component.
15383 getId : function(){
15388 * Try to focus this component.
15389 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15390 * @return {Roo.Component} this
15392 focus : function(selectText){
15395 if(selectText === true){
15396 this.el.dom.select();
15411 * Disable this component.
15412 * @return {Roo.Component} this
15414 disable : function(){
15418 this.disabled = true;
15419 this.fireEvent("disable", this);
15424 onDisable : function(){
15425 this.getActionEl().addClass(this.disabledClass);
15426 this.el.dom.disabled = true;
15430 * Enable this component.
15431 * @return {Roo.Component} this
15433 enable : function(){
15437 this.disabled = false;
15438 this.fireEvent("enable", this);
15443 onEnable : function(){
15444 this.getActionEl().removeClass(this.disabledClass);
15445 this.el.dom.disabled = false;
15449 * Convenience function for setting disabled/enabled by boolean.
15450 * @param {Boolean} disabled
15452 setDisabled : function(disabled){
15453 this[disabled ? "disable" : "enable"]();
15457 * Show this component.
15458 * @return {Roo.Component} this
15461 if(this.fireEvent("beforeshow", this) !== false){
15462 this.hidden = false;
15466 this.fireEvent("show", this);
15472 onShow : function(){
15473 var ae = this.getActionEl();
15474 if(this.hideMode == 'visibility'){
15475 ae.dom.style.visibility = "visible";
15476 }else if(this.hideMode == 'offsets'){
15477 ae.removeClass('x-hidden');
15479 ae.dom.style.display = "";
15484 * Hide this component.
15485 * @return {Roo.Component} this
15488 if(this.fireEvent("beforehide", this) !== false){
15489 this.hidden = true;
15493 this.fireEvent("hide", this);
15499 onHide : function(){
15500 var ae = this.getActionEl();
15501 if(this.hideMode == 'visibility'){
15502 ae.dom.style.visibility = "hidden";
15503 }else if(this.hideMode == 'offsets'){
15504 ae.addClass('x-hidden');
15506 ae.dom.style.display = "none";
15511 * Convenience function to hide or show this component by boolean.
15512 * @param {Boolean} visible True to show, false to hide
15513 * @return {Roo.Component} this
15515 setVisible: function(visible){
15525 * Returns true if this component is visible.
15527 isVisible : function(){
15528 return this.getActionEl().isVisible();
15531 cloneConfig : function(overrides){
15532 overrides = overrides || {};
15533 var id = overrides.id || Roo.id();
15534 var cfg = Roo.applyIf(overrides, this.initialConfig);
15535 cfg.id = id; // prevent dup id
15536 return new this.constructor(cfg);
15540 * Ext JS Library 1.1.1
15541 * Copyright(c) 2006-2007, Ext JS, LLC.
15543 * Originally Released Under LGPL - original licence link has changed is not relivant.
15546 * <script type="text/javascript">
15550 * @class Roo.BoxComponent
15551 * @extends Roo.Component
15552 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15553 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15554 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15555 * layout containers.
15557 * @param {Roo.Element/String/Object} config The configuration options.
15559 Roo.BoxComponent = function(config){
15560 Roo.Component.call(this, config);
15564 * Fires after the component is resized.
15565 * @param {Roo.Component} this
15566 * @param {Number} adjWidth The box-adjusted width that was set
15567 * @param {Number} adjHeight The box-adjusted height that was set
15568 * @param {Number} rawWidth The width that was originally specified
15569 * @param {Number} rawHeight The height that was originally specified
15574 * Fires after the component is moved.
15575 * @param {Roo.Component} this
15576 * @param {Number} x The new x position
15577 * @param {Number} y The new y position
15583 Roo.extend(Roo.BoxComponent, Roo.Component, {
15584 // private, set in afterRender to signify that the component has been rendered
15586 // private, used to defer height settings to subclasses
15587 deferHeight: false,
15588 /** @cfg {Number} width
15589 * width (optional) size of component
15591 /** @cfg {Number} height
15592 * height (optional) size of component
15596 * Sets the width and height of the component. This method fires the resize event. This method can accept
15597 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15598 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15599 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15600 * @return {Roo.BoxComponent} this
15602 setSize : function(w, h){
15603 // support for standard size objects
15604 if(typeof w == 'object'){
15609 if(!this.boxReady){
15615 // prevent recalcs when not needed
15616 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15619 this.lastSize = {width: w, height: h};
15621 var adj = this.adjustSize(w, h);
15622 var aw = adj.width, ah = adj.height;
15623 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15624 var rz = this.getResizeEl();
15625 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15626 rz.setSize(aw, ah);
15627 }else if(!this.deferHeight && ah !== undefined){
15629 }else if(aw !== undefined){
15632 this.onResize(aw, ah, w, h);
15633 this.fireEvent('resize', this, aw, ah, w, h);
15639 * Gets the current size of the component's underlying element.
15640 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15642 getSize : function(){
15643 return this.el.getSize();
15647 * Gets the current XY position of the component's underlying element.
15648 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15649 * @return {Array} The XY position of the element (e.g., [100, 200])
15651 getPosition : function(local){
15652 if(local === true){
15653 return [this.el.getLeft(true), this.el.getTop(true)];
15655 return this.xy || this.el.getXY();
15659 * Gets the current box measurements of the component's underlying element.
15660 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15661 * @returns {Object} box An object in the format {x, y, width, height}
15663 getBox : function(local){
15664 var s = this.el.getSize();
15666 s.x = this.el.getLeft(true);
15667 s.y = this.el.getTop(true);
15669 var xy = this.xy || this.el.getXY();
15677 * Sets the current box measurements of the component's underlying element.
15678 * @param {Object} box An object in the format {x, y, width, height}
15679 * @returns {Roo.BoxComponent} this
15681 updateBox : function(box){
15682 this.setSize(box.width, box.height);
15683 this.setPagePosition(box.x, box.y);
15688 getResizeEl : function(){
15689 return this.resizeEl || this.el;
15693 getPositionEl : function(){
15694 return this.positionEl || this.el;
15698 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15699 * This method fires the move event.
15700 * @param {Number} left The new left
15701 * @param {Number} top The new top
15702 * @returns {Roo.BoxComponent} this
15704 setPosition : function(x, y){
15707 if(!this.boxReady){
15710 var adj = this.adjustPosition(x, y);
15711 var ax = adj.x, ay = adj.y;
15713 var el = this.getPositionEl();
15714 if(ax !== undefined || ay !== undefined){
15715 if(ax !== undefined && ay !== undefined){
15716 el.setLeftTop(ax, ay);
15717 }else if(ax !== undefined){
15719 }else if(ay !== undefined){
15722 this.onPosition(ax, ay);
15723 this.fireEvent('move', this, ax, ay);
15729 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15730 * This method fires the move event.
15731 * @param {Number} x The new x position
15732 * @param {Number} y The new y position
15733 * @returns {Roo.BoxComponent} this
15735 setPagePosition : function(x, y){
15738 if(!this.boxReady){
15741 if(x === undefined || y === undefined){ // cannot translate undefined points
15744 var p = this.el.translatePoints(x, y);
15745 this.setPosition(p.left, p.top);
15750 onRender : function(ct, position){
15751 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15753 this.resizeEl = Roo.get(this.resizeEl);
15755 if(this.positionEl){
15756 this.positionEl = Roo.get(this.positionEl);
15761 afterRender : function(){
15762 Roo.BoxComponent.superclass.afterRender.call(this);
15763 this.boxReady = true;
15764 this.setSize(this.width, this.height);
15765 if(this.x || this.y){
15766 this.setPosition(this.x, this.y);
15768 if(this.pageX || this.pageY){
15769 this.setPagePosition(this.pageX, this.pageY);
15774 * Force the component's size to recalculate based on the underlying element's current height and width.
15775 * @returns {Roo.BoxComponent} this
15777 syncSize : function(){
15778 delete this.lastSize;
15779 this.setSize(this.el.getWidth(), this.el.getHeight());
15784 * Called after the component is resized, this method is empty by default but can be implemented by any
15785 * subclass that needs to perform custom logic after a resize occurs.
15786 * @param {Number} adjWidth The box-adjusted width that was set
15787 * @param {Number} adjHeight The box-adjusted height that was set
15788 * @param {Number} rawWidth The width that was originally specified
15789 * @param {Number} rawHeight The height that was originally specified
15791 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15796 * Called after the component is moved, this method is empty by default but can be implemented by any
15797 * subclass that needs to perform custom logic after a move occurs.
15798 * @param {Number} x The new x position
15799 * @param {Number} y The new y position
15801 onPosition : function(x, y){
15806 adjustSize : function(w, h){
15807 if(this.autoWidth){
15810 if(this.autoHeight){
15813 return {width : w, height: h};
15817 adjustPosition : function(x, y){
15818 return {x : x, y: y};
15821 * Original code for Roojs - LGPL
15822 * <script type="text/javascript">
15826 * @class Roo.XComponent
15827 * A delayed Element creator...
15828 * Or a way to group chunks of interface together.
15829 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15830 * used in conjunction with XComponent.build() it will create an instance of each element,
15831 * then call addxtype() to build the User interface.
15833 * Mypart.xyx = new Roo.XComponent({
15835 parent : 'Mypart.xyz', // empty == document.element.!!
15839 disabled : function() {}
15841 tree : function() { // return an tree of xtype declared components
15845 xtype : 'NestedLayoutPanel',
15852 * It can be used to build a big heiracy, with parent etc.
15853 * or you can just use this to render a single compoent to a dom element
15854 * MYPART.render(Roo.Element | String(id) | dom_element )
15861 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15862 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15864 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15866 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15867 * - if mulitple topModules exist, the last one is defined as the top module.
15871 * When the top level or multiple modules are to embedded into a existing HTML page,
15872 * the parent element can container '#id' of the element where the module will be drawn.
15876 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15877 * it relies more on a include mechanism, where sub modules are included into an outer page.
15878 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15880 * Bootstrap Roo Included elements
15882 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15883 * hence confusing the component builder as it thinks there are multiple top level elements.
15887 * @extends Roo.util.Observable
15889 * @param cfg {Object} configuration of component
15892 Roo.XComponent = function(cfg) {
15893 Roo.apply(this, cfg);
15897 * Fires when this the componnt is built
15898 * @param {Roo.XComponent} c the component
15903 this.region = this.region || 'center'; // default..
15904 Roo.XComponent.register(this);
15905 this.modules = false;
15906 this.el = false; // where the layout goes..
15910 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15913 * The created element (with Roo.factory())
15914 * @type {Roo.Layout}
15920 * for BC - use el in new code
15921 * @type {Roo.Layout}
15927 * for BC - use el in new code
15928 * @type {Roo.Layout}
15933 * @cfg {Function|boolean} disabled
15934 * If this module is disabled by some rule, return true from the funtion
15939 * @cfg {String} parent
15940 * Name of parent element which it get xtype added to..
15945 * @cfg {String} order
15946 * Used to set the order in which elements are created (usefull for multiple tabs)
15951 * @cfg {String} name
15952 * String to display while loading.
15956 * @cfg {String} region
15957 * Region to render component to (defaults to center)
15962 * @cfg {Array} items
15963 * A single item array - the first element is the root of the tree..
15964 * It's done this way to stay compatible with the Xtype system...
15970 * The method that retuns the tree of parts that make up this compoennt
15977 * render element to dom or tree
15978 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15981 render : function(el)
15985 var hp = this.parent ? 1 : 0;
15986 Roo.debug && Roo.log(this);
15988 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15989 // if parent is a '#.....' string, then let's use that..
15990 var ename = this.parent.substr(1);
15991 this.parent = false;
15992 Roo.debug && Roo.log(ename);
15994 case 'bootstrap-body' :
15995 if (typeof(Roo.bootstrap.Body) != 'undefined') {
15996 this.parent = { el : new Roo.bootstrap.Body() };
15997 Roo.debug && Roo.log("setting el to doc body");
16000 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16004 this.parent = { el : true};
16007 el = Roo.get(ename);
16012 if (!el && !this.parent) {
16013 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16017 Roo.debug && Roo.log("EL:");
16018 Roo.debug && Roo.log(el);
16019 Roo.debug && Roo.log("this.parent.el:");
16020 Roo.debug && Roo.log(this.parent.el);
16022 var tree = this._tree ? this._tree() : this.tree();
16024 // altertive root elements ??? - we need a better way to indicate these.
16025 var is_alt = Roo.XComponent.is_alt || (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16026 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16028 if (!this.parent && is_alt) {
16029 //el = Roo.get(document.body);
16030 this.parent = { el : true };
16035 if (!this.parent) {
16037 Roo.debug && Roo.log("no parent - creating one");
16039 el = el ? Roo.get(el) : false;
16041 // it's a top level one..
16043 el : new Roo.BorderLayout(el || document.body, {
16049 tabPosition: 'top',
16050 //resizeTabs: true,
16051 alwaysShowTabs: el && hp? false : true,
16052 hideTabs: el || !hp ? true : false,
16059 if (!this.parent.el) {
16060 // probably an old style ctor, which has been disabled.
16064 // The 'tree' method is '_tree now'
16066 tree.region = tree.region || this.region;
16067 var is_body = false;
16068 if (this.parent.el === true) {
16069 // bootstrap... - body..
16070 this.parent.el = Roo.factory(tree);
16074 this.el = this.parent.el.addxtype(tree, undefined, is_body);
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
16124 * Is an alternative Root - normally used by bootstrap or other systems,
16125 * where the top element in the tree can wrap 'body'
16126 * @type {boolean} true (default false)
16131 * @property build_from_html
16132 * Build elements from html - used by bootstrap HTML stuff
16133 * - this is cleared after build is completed
16134 * @type {boolean} true (default false)
16137 build_from_html : false,
16139 * Register components to be built later.
16141 * This solves the following issues
16142 * - Building is not done on page load, but after an authentication process has occured.
16143 * - Interface elements are registered on page load
16144 * - Parent Interface elements may not be loaded before child, so this handles that..
16151 module : 'Pman.Tab.projectMgr',
16153 parent : 'Pman.layout',
16154 disabled : false, // or use a function..
16157 * * @param {Object} details about module
16159 register : function(obj) {
16161 Roo.XComponent.event.fireEvent('register', obj);
16162 switch(typeof(obj.disabled) ) {
16168 if ( obj.disabled() ) {
16174 if (obj.disabled) {
16180 this.modules.push(obj);
16184 * convert a string to an object..
16185 * eg. 'AAA.BBB' -> finds AAA.BBB
16189 toObject : function(str)
16191 if (!str || typeof(str) == 'object') {
16194 if (str.substring(0,1) == '#') {
16198 var ar = str.split('.');
16203 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16205 throw "Module not found : " + str;
16209 throw "Module not found : " + str;
16211 Roo.each(ar, function(e) {
16212 if (typeof(o[e]) == 'undefined') {
16213 throw "Module not found : " + str;
16224 * move modules into their correct place in the tree..
16227 preBuild : function ()
16230 Roo.each(this.modules , function (obj)
16232 Roo.XComponent.event.fireEvent('beforebuild', obj);
16234 var opar = obj.parent;
16236 obj.parent = this.toObject(opar);
16238 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16243 Roo.debug && Roo.log("GOT top level module");
16244 Roo.debug && Roo.log(obj);
16245 obj.modules = new Roo.util.MixedCollection(false,
16246 function(o) { return o.order + '' }
16248 this.topModule = obj;
16251 // parent is a string (usually a dom element name..)
16252 if (typeof(obj.parent) == 'string') {
16253 this.elmodules.push(obj);
16256 if (obj.parent.constructor != Roo.XComponent) {
16257 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16259 if (!obj.parent.modules) {
16260 obj.parent.modules = new Roo.util.MixedCollection(false,
16261 function(o) { return o.order + '' }
16264 if (obj.parent.disabled) {
16265 obj.disabled = true;
16267 obj.parent.modules.add(obj);
16272 * make a list of modules to build.
16273 * @return {Array} list of modules.
16276 buildOrder : function()
16279 var cmp = function(a,b) {
16280 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16282 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16283 throw "No top level modules to build";
16286 // make a flat list in order of modules to build.
16287 var mods = this.topModule ? [ this.topModule ] : [];
16290 // elmodules (is a list of DOM based modules )
16291 Roo.each(this.elmodules, function(e) {
16293 if (!this.topModule &&
16294 typeof(e.parent) == 'string' &&
16295 e.parent.substring(0,1) == '#' &&
16296 Roo.get(e.parent.substr(1))
16299 _this.topModule = e;
16305 // add modules to their parents..
16306 var addMod = function(m) {
16307 Roo.debug && Roo.log("build Order: add: " + m.name);
16310 if (m.modules && !m.disabled) {
16311 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16312 m.modules.keySort('ASC', cmp );
16313 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16315 m.modules.each(addMod);
16317 Roo.debug && Roo.log("build Order: no child modules");
16319 // not sure if this is used any more..
16321 m.finalize.name = m.name + " (clean up) ";
16322 mods.push(m.finalize);
16326 if (this.topModule && this.topModule.modules) {
16327 this.topModule.modules.keySort('ASC', cmp );
16328 this.topModule.modules.each(addMod);
16334 * Build the registered modules.
16335 * @param {Object} parent element.
16336 * @param {Function} optional method to call after module has been added.
16340 build : function(opts)
16343 if (typeof(opts) != 'undefined') {
16344 Roo.apply(this,opts);
16348 var mods = this.buildOrder();
16350 //this.allmods = mods;
16351 //Roo.debug && Roo.log(mods);
16353 if (!mods.length) { // should not happen
16354 throw "NO modules!!!";
16358 var msg = "Building Interface...";
16359 // flash it up as modal - so we store the mask!?
16360 if (!this.hideProgress && Roo.MessageBox) {
16361 Roo.MessageBox.show({ title: 'loading' });
16362 Roo.MessageBox.show({
16363 title: "Please wait...",
16372 var total = mods.length;
16375 var progressRun = function() {
16376 if (!mods.length) {
16377 Roo.debug && Roo.log('hide?');
16378 if (!this.hideProgress && Roo.MessageBox) {
16379 Roo.MessageBox.hide();
16381 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16383 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16389 var m = mods.shift();
16392 Roo.debug && Roo.log(m);
16393 // not sure if this is supported any more.. - modules that are are just function
16394 if (typeof(m) == 'function') {
16396 return progressRun.defer(10, _this);
16400 msg = "Building Interface " + (total - mods.length) +
16402 (m.name ? (' - ' + m.name) : '');
16403 Roo.debug && Roo.log(msg);
16404 if (!this.hideProgress && Roo.MessageBox) {
16405 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16409 // is the module disabled?
16410 var disabled = (typeof(m.disabled) == 'function') ?
16411 m.disabled.call(m.module.disabled) : m.disabled;
16415 return progressRun(); // we do not update the display!
16423 // it's 10 on top level, and 1 on others??? why...
16424 return progressRun.defer(10, _this);
16427 progressRun.defer(1, _this);
16441 * wrapper for event.on - aliased later..
16442 * Typically use to register a event handler for register:
16444 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16453 Roo.XComponent.event = new Roo.util.Observable({
16457 * Fires when an Component is registered,
16458 * set the disable property on the Component to stop registration.
16459 * @param {Roo.XComponent} c the component being registerd.
16464 * @event beforebuild
16465 * Fires before each Component is built
16466 * can be used to apply permissions.
16467 * @param {Roo.XComponent} c the component being registerd.
16470 'beforebuild' : true,
16472 * @event buildcomplete
16473 * Fires on the top level element when all elements have been built
16474 * @param {Roo.XComponent} the top level component.
16476 'buildcomplete' : true
16481 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16484 * Ext JS Library 1.1.1
16485 * Copyright(c) 2006-2007, Ext JS, LLC.
16487 * Originally Released Under LGPL - original licence link has changed is not relivant.
16490 * <script type="text/javascript">
16496 * These classes are derivatives of the similarly named classes in the YUI Library.
16497 * The original license:
16498 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16499 * Code licensed under the BSD License:
16500 * http://developer.yahoo.net/yui/license.txt
16505 var Event=Roo.EventManager;
16506 var Dom=Roo.lib.Dom;
16509 * @class Roo.dd.DragDrop
16510 * @extends Roo.util.Observable
16511 * Defines the interface and base operation of items that that can be
16512 * dragged or can be drop targets. It was designed to be extended, overriding
16513 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16514 * Up to three html elements can be associated with a DragDrop instance:
16516 * <li>linked element: the element that is passed into the constructor.
16517 * This is the element which defines the boundaries for interaction with
16518 * other DragDrop objects.</li>
16519 * <li>handle element(s): The drag operation only occurs if the element that
16520 * was clicked matches a handle element. By default this is the linked
16521 * element, but there are times that you will want only a portion of the
16522 * linked element to initiate the drag operation, and the setHandleElId()
16523 * method provides a way to define this.</li>
16524 * <li>drag element: this represents the element that would be moved along
16525 * with the cursor during a drag operation. By default, this is the linked
16526 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16527 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16530 * This class should not be instantiated until the onload event to ensure that
16531 * the associated elements are available.
16532 * The following would define a DragDrop obj that would interact with any
16533 * other DragDrop obj in the "group1" group:
16535 * dd = new Roo.dd.DragDrop("div1", "group1");
16537 * Since none of the event handlers have been implemented, nothing would
16538 * actually happen if you were to run the code above. Normally you would
16539 * override this class or one of the default implementations, but you can
16540 * also override the methods you want on an instance of the class...
16542 * dd.onDragDrop = function(e, id) {
16543 * alert("dd was dropped on " + id);
16547 * @param {String} id of the element that is linked to this instance
16548 * @param {String} sGroup the group of related DragDrop objects
16549 * @param {object} config an object containing configurable attributes
16550 * Valid properties for DragDrop:
16551 * padding, isTarget, maintainOffset, primaryButtonOnly
16553 Roo.dd.DragDrop = function(id, sGroup, config) {
16555 this.init(id, sGroup, config);
16560 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16563 * The id of the element associated with this object. This is what we
16564 * refer to as the "linked element" because the size and position of
16565 * this element is used to determine when the drag and drop objects have
16573 * Configuration attributes passed into the constructor
16580 * The id of the element that will be dragged. By default this is same
16581 * as the linked element , but could be changed to another element. Ex:
16583 * @property dragElId
16590 * the id of the element that initiates the drag operation. By default
16591 * this is the linked element, but could be changed to be a child of this
16592 * element. This lets us do things like only starting the drag when the
16593 * header element within the linked html element is clicked.
16594 * @property handleElId
16601 * An associative array of HTML tags that will be ignored if clicked.
16602 * @property invalidHandleTypes
16603 * @type {string: string}
16605 invalidHandleTypes: null,
16608 * An associative array of ids for elements that will be ignored if clicked
16609 * @property invalidHandleIds
16610 * @type {string: string}
16612 invalidHandleIds: null,
16615 * An indexted array of css class names for elements that will be ignored
16617 * @property invalidHandleClasses
16620 invalidHandleClasses: null,
16623 * The linked element's absolute X position at the time the drag was
16625 * @property startPageX
16632 * The linked element's absolute X position at the time the drag was
16634 * @property startPageY
16641 * The group defines a logical collection of DragDrop objects that are
16642 * related. Instances only get events when interacting with other
16643 * DragDrop object in the same group. This lets us define multiple
16644 * groups using a single DragDrop subclass if we want.
16646 * @type {string: string}
16651 * Individual drag/drop instances can be locked. This will prevent
16652 * onmousedown start drag.
16660 * Lock this instance
16663 lock: function() { this.locked = true; },
16666 * Unlock this instace
16669 unlock: function() { this.locked = false; },
16672 * By default, all insances can be a drop target. This can be disabled by
16673 * setting isTarget to false.
16680 * The padding configured for this drag and drop object for calculating
16681 * the drop zone intersection with this object.
16688 * Cached reference to the linked element
16689 * @property _domRef
16695 * Internal typeof flag
16696 * @property __ygDragDrop
16699 __ygDragDrop: true,
16702 * Set to true when horizontal contraints are applied
16703 * @property constrainX
16710 * Set to true when vertical contraints are applied
16711 * @property constrainY
16718 * The left constraint
16726 * The right constraint
16734 * The up constraint
16743 * The down constraint
16751 * Maintain offsets when we resetconstraints. Set to true when you want
16752 * the position of the element relative to its parent to stay the same
16753 * when the page changes
16755 * @property maintainOffset
16758 maintainOffset: false,
16761 * Array of pixel locations the element will snap to if we specified a
16762 * horizontal graduation/interval. This array is generated automatically
16763 * when you define a tick interval.
16770 * Array of pixel locations the element will snap to if we specified a
16771 * vertical graduation/interval. This array is generated automatically
16772 * when you define a tick interval.
16779 * By default the drag and drop instance will only respond to the primary
16780 * button click (left button for a right-handed mouse). Set to true to
16781 * allow drag and drop to start with any mouse click that is propogated
16783 * @property primaryButtonOnly
16786 primaryButtonOnly: true,
16789 * The availabe property is false until the linked dom element is accessible.
16790 * @property available
16796 * By default, drags can only be initiated if the mousedown occurs in the
16797 * region the linked element is. This is done in part to work around a
16798 * bug in some browsers that mis-report the mousedown if the previous
16799 * mouseup happened outside of the window. This property is set to true
16800 * if outer handles are defined.
16802 * @property hasOuterHandles
16806 hasOuterHandles: false,
16809 * Code that executes immediately before the startDrag event
16810 * @method b4StartDrag
16813 b4StartDrag: function(x, y) { },
16816 * Abstract method called after a drag/drop object is clicked
16817 * and the drag or mousedown time thresholds have beeen met.
16818 * @method startDrag
16819 * @param {int} X click location
16820 * @param {int} Y click location
16822 startDrag: function(x, y) { /* override this */ },
16825 * Code that executes immediately before the onDrag event
16829 b4Drag: function(e) { },
16832 * Abstract method called during the onMouseMove event while dragging an
16835 * @param {Event} e the mousemove event
16837 onDrag: function(e) { /* override this */ },
16840 * Abstract method called when this element fist begins hovering over
16841 * another DragDrop obj
16842 * @method onDragEnter
16843 * @param {Event} e the mousemove event
16844 * @param {String|DragDrop[]} id In POINT mode, the element
16845 * id this is hovering over. In INTERSECT mode, an array of one or more
16846 * dragdrop items being hovered over.
16848 onDragEnter: function(e, id) { /* override this */ },
16851 * Code that executes immediately before the onDragOver event
16852 * @method b4DragOver
16855 b4DragOver: function(e) { },
16858 * Abstract method called when this element is hovering over another
16860 * @method onDragOver
16861 * @param {Event} e the mousemove event
16862 * @param {String|DragDrop[]} id In POINT mode, the element
16863 * id this is hovering over. In INTERSECT mode, an array of dd items
16864 * being hovered over.
16866 onDragOver: function(e, id) { /* override this */ },
16869 * Code that executes immediately before the onDragOut event
16870 * @method b4DragOut
16873 b4DragOut: function(e) { },
16876 * Abstract method called when we are no longer hovering over an element
16877 * @method onDragOut
16878 * @param {Event} e the mousemove event
16879 * @param {String|DragDrop[]} id In POINT mode, the element
16880 * id this was hovering over. In INTERSECT mode, an array of dd items
16881 * that the mouse is no longer over.
16883 onDragOut: function(e, id) { /* override this */ },
16886 * Code that executes immediately before the onDragDrop event
16887 * @method b4DragDrop
16890 b4DragDrop: function(e) { },
16893 * Abstract method called when this item is dropped on another DragDrop
16895 * @method onDragDrop
16896 * @param {Event} e the mouseup event
16897 * @param {String|DragDrop[]} id In POINT mode, the element
16898 * id this was dropped on. In INTERSECT mode, an array of dd items this
16901 onDragDrop: function(e, id) { /* override this */ },
16904 * Abstract method called when this item is dropped on an area with no
16906 * @method onInvalidDrop
16907 * @param {Event} e the mouseup event
16909 onInvalidDrop: function(e) { /* override this */ },
16912 * Code that executes immediately before the endDrag event
16913 * @method b4EndDrag
16916 b4EndDrag: function(e) { },
16919 * Fired when we are done dragging the object
16921 * @param {Event} e the mouseup event
16923 endDrag: function(e) { /* override this */ },
16926 * Code executed immediately before the onMouseDown event
16927 * @method b4MouseDown
16928 * @param {Event} e the mousedown event
16931 b4MouseDown: function(e) { },
16934 * Event handler that fires when a drag/drop obj gets a mousedown
16935 * @method onMouseDown
16936 * @param {Event} e the mousedown event
16938 onMouseDown: function(e) { /* override this */ },
16941 * Event handler that fires when a drag/drop obj gets a mouseup
16942 * @method onMouseUp
16943 * @param {Event} e the mouseup event
16945 onMouseUp: function(e) { /* override this */ },
16948 * Override the onAvailable method to do what is needed after the initial
16949 * position was determined.
16950 * @method onAvailable
16952 onAvailable: function () {
16956 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16959 defaultPadding : {left:0, right:0, top:0, bottom:0},
16962 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16966 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16967 { dragElId: "existingProxyDiv" });
16968 dd.startDrag = function(){
16969 this.constrainTo("parent-id");
16972 * Or you can initalize it using the {@link Roo.Element} object:
16974 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16975 startDrag : function(){
16976 this.constrainTo("parent-id");
16980 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16981 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16982 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16983 * an object containing the sides to pad. For example: {right:10, bottom:10}
16984 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16986 constrainTo : function(constrainTo, pad, inContent){
16987 if(typeof pad == "number"){
16988 pad = {left: pad, right:pad, top:pad, bottom:pad};
16990 pad = pad || this.defaultPadding;
16991 var b = Roo.get(this.getEl()).getBox();
16992 var ce = Roo.get(constrainTo);
16993 var s = ce.getScroll();
16994 var c, cd = ce.dom;
16995 if(cd == document.body){
16996 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16999 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
17003 var topSpace = b.y - c.y;
17004 var leftSpace = b.x - c.x;
17006 this.resetConstraints();
17007 this.setXConstraint(leftSpace - (pad.left||0), // left
17008 c.width - leftSpace - b.width - (pad.right||0) //right
17010 this.setYConstraint(topSpace - (pad.top||0), //top
17011 c.height - topSpace - b.height - (pad.bottom||0) //bottom
17016 * Returns a reference to the linked element
17018 * @return {HTMLElement} the html element
17020 getEl: function() {
17021 if (!this._domRef) {
17022 this._domRef = Roo.getDom(this.id);
17025 return this._domRef;
17029 * Returns a reference to the actual element to drag. By default this is
17030 * the same as the html element, but it can be assigned to another
17031 * element. An example of this can be found in Roo.dd.DDProxy
17032 * @method getDragEl
17033 * @return {HTMLElement} the html element
17035 getDragEl: function() {
17036 return Roo.getDom(this.dragElId);
17040 * Sets up the DragDrop object. Must be called in the constructor of any
17041 * Roo.dd.DragDrop subclass
17043 * @param id the id of the linked element
17044 * @param {String} sGroup the group of related items
17045 * @param {object} config configuration attributes
17047 init: function(id, sGroup, config) {
17048 this.initTarget(id, sGroup, config);
17049 if (!Roo.isTouch) {
17050 Event.on(this.id, "mousedown", this.handleMouseDown, this);
17052 Event.on(this.id, "touchstart", this.handleMouseDown, this);
17053 // Event.on(this.id, "selectstart", Event.preventDefault);
17057 * Initializes Targeting functionality only... the object does not
17058 * get a mousedown handler.
17059 * @method initTarget
17060 * @param id the id of the linked element
17061 * @param {String} sGroup the group of related items
17062 * @param {object} config configuration attributes
17064 initTarget: function(id, sGroup, config) {
17066 // configuration attributes
17067 this.config = config || {};
17069 // create a local reference to the drag and drop manager
17070 this.DDM = Roo.dd.DDM;
17071 // initialize the groups array
17074 // assume that we have an element reference instead of an id if the
17075 // parameter is not a string
17076 if (typeof id !== "string") {
17083 // add to an interaction group
17084 this.addToGroup((sGroup) ? sGroup : "default");
17086 // We don't want to register this as the handle with the manager
17087 // so we just set the id rather than calling the setter.
17088 this.handleElId = id;
17090 // the linked element is the element that gets dragged by default
17091 this.setDragElId(id);
17093 // by default, clicked anchors will not start drag operations.
17094 this.invalidHandleTypes = { A: "A" };
17095 this.invalidHandleIds = {};
17096 this.invalidHandleClasses = [];
17098 this.applyConfig();
17100 this.handleOnAvailable();
17104 * Applies the configuration parameters that were passed into the constructor.
17105 * This is supposed to happen at each level through the inheritance chain. So
17106 * a DDProxy implentation will execute apply config on DDProxy, DD, and
17107 * DragDrop in order to get all of the parameters that are available in
17109 * @method applyConfig
17111 applyConfig: function() {
17113 // configurable properties:
17114 // padding, isTarget, maintainOffset, primaryButtonOnly
17115 this.padding = this.config.padding || [0, 0, 0, 0];
17116 this.isTarget = (this.config.isTarget !== false);
17117 this.maintainOffset = (this.config.maintainOffset);
17118 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
17123 * Executed when the linked element is available
17124 * @method handleOnAvailable
17127 handleOnAvailable: function() {
17128 this.available = true;
17129 this.resetConstraints();
17130 this.onAvailable();
17134 * Configures the padding for the target zone in px. Effectively expands
17135 * (or reduces) the virtual object size for targeting calculations.
17136 * Supports css-style shorthand; if only one parameter is passed, all sides
17137 * will have that padding, and if only two are passed, the top and bottom
17138 * will have the first param, the left and right the second.
17139 * @method setPadding
17140 * @param {int} iTop Top pad
17141 * @param {int} iRight Right pad
17142 * @param {int} iBot Bot pad
17143 * @param {int} iLeft Left pad
17145 setPadding: function(iTop, iRight, iBot, iLeft) {
17146 // this.padding = [iLeft, iRight, iTop, iBot];
17147 if (!iRight && 0 !== iRight) {
17148 this.padding = [iTop, iTop, iTop, iTop];
17149 } else if (!iBot && 0 !== iBot) {
17150 this.padding = [iTop, iRight, iTop, iRight];
17152 this.padding = [iTop, iRight, iBot, iLeft];
17157 * Stores the initial placement of the linked element.
17158 * @method setInitialPosition
17159 * @param {int} diffX the X offset, default 0
17160 * @param {int} diffY the Y offset, default 0
17162 setInitPosition: function(diffX, diffY) {
17163 var el = this.getEl();
17165 if (!this.DDM.verifyEl(el)) {
17169 var dx = diffX || 0;
17170 var dy = diffY || 0;
17172 var p = Dom.getXY( el );
17174 this.initPageX = p[0] - dx;
17175 this.initPageY = p[1] - dy;
17177 this.lastPageX = p[0];
17178 this.lastPageY = p[1];
17181 this.setStartPosition(p);
17185 * Sets the start position of the element. This is set when the obj
17186 * is initialized, the reset when a drag is started.
17187 * @method setStartPosition
17188 * @param pos current position (from previous lookup)
17191 setStartPosition: function(pos) {
17192 var p = pos || Dom.getXY( this.getEl() );
17193 this.deltaSetXY = null;
17195 this.startPageX = p[0];
17196 this.startPageY = p[1];
17200 * Add this instance to a group of related drag/drop objects. All
17201 * instances belong to at least one group, and can belong to as many
17202 * groups as needed.
17203 * @method addToGroup
17204 * @param sGroup {string} the name of the group
17206 addToGroup: function(sGroup) {
17207 this.groups[sGroup] = true;
17208 this.DDM.regDragDrop(this, sGroup);
17212 * Remove's this instance from the supplied interaction group
17213 * @method removeFromGroup
17214 * @param {string} sGroup The group to drop
17216 removeFromGroup: function(sGroup) {
17217 if (this.groups[sGroup]) {
17218 delete this.groups[sGroup];
17221 this.DDM.removeDDFromGroup(this, sGroup);
17225 * Allows you to specify that an element other than the linked element
17226 * will be moved with the cursor during a drag
17227 * @method setDragElId
17228 * @param id {string} the id of the element that will be used to initiate the drag
17230 setDragElId: function(id) {
17231 this.dragElId = id;
17235 * Allows you to specify a child of the linked element that should be
17236 * used to initiate the drag operation. An example of this would be if
17237 * you have a content div with text and links. Clicking anywhere in the
17238 * content area would normally start the drag operation. Use this method
17239 * to specify that an element inside of the content div is the element
17240 * that starts the drag operation.
17241 * @method setHandleElId
17242 * @param id {string} the id of the element that will be used to
17243 * initiate the drag.
17245 setHandleElId: function(id) {
17246 if (typeof id !== "string") {
17249 this.handleElId = id;
17250 this.DDM.regHandle(this.id, id);
17254 * Allows you to set an element outside of the linked element as a drag
17256 * @method setOuterHandleElId
17257 * @param id the id of the element that will be used to initiate the drag
17259 setOuterHandleElId: function(id) {
17260 if (typeof id !== "string") {
17263 Event.on(id, "mousedown",
17264 this.handleMouseDown, this);
17265 this.setHandleElId(id);
17267 this.hasOuterHandles = true;
17271 * Remove all drag and drop hooks for this element
17274 unreg: function() {
17275 Event.un(this.id, "mousedown",
17276 this.handleMouseDown);
17277 Event.un(this.id, "touchstart",
17278 this.handleMouseDown);
17279 this._domRef = null;
17280 this.DDM._remove(this);
17283 destroy : function(){
17288 * Returns true if this instance is locked, or the drag drop mgr is locked
17289 * (meaning that all drag/drop is disabled on the page.)
17291 * @return {boolean} true if this obj or all drag/drop is locked, else
17294 isLocked: function() {
17295 return (this.DDM.isLocked() || this.locked);
17299 * Fired when this object is clicked
17300 * @method handleMouseDown
17302 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17305 handleMouseDown: function(e, oDD){
17307 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17308 //Roo.log('not touch/ button !=0');
17311 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17312 return; // double touch..
17316 if (this.isLocked()) {
17317 //Roo.log('locked');
17321 this.DDM.refreshCache(this.groups);
17322 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17323 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17324 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17325 //Roo.log('no outer handes or not over target');
17328 // Roo.log('check validator');
17329 if (this.clickValidator(e)) {
17330 // Roo.log('validate success');
17331 // set the initial element position
17332 this.setStartPosition();
17335 this.b4MouseDown(e);
17336 this.onMouseDown(e);
17338 this.DDM.handleMouseDown(e, this);
17340 this.DDM.stopEvent(e);
17348 clickValidator: function(e) {
17349 var target = e.getTarget();
17350 return ( this.isValidHandleChild(target) &&
17351 (this.id == this.handleElId ||
17352 this.DDM.handleWasClicked(target, this.id)) );
17356 * Allows you to specify a tag name that should not start a drag operation
17357 * when clicked. This is designed to facilitate embedding links within a
17358 * drag handle that do something other than start the drag.
17359 * @method addInvalidHandleType
17360 * @param {string} tagName the type of element to exclude
17362 addInvalidHandleType: function(tagName) {
17363 var type = tagName.toUpperCase();
17364 this.invalidHandleTypes[type] = type;
17368 * Lets you to specify an element id for a child of a drag handle
17369 * that should not initiate a drag
17370 * @method addInvalidHandleId
17371 * @param {string} id the element id of the element you wish to ignore
17373 addInvalidHandleId: function(id) {
17374 if (typeof id !== "string") {
17377 this.invalidHandleIds[id] = id;
17381 * Lets you specify a css class of elements that will not initiate a drag
17382 * @method addInvalidHandleClass
17383 * @param {string} cssClass the class of the elements you wish to ignore
17385 addInvalidHandleClass: function(cssClass) {
17386 this.invalidHandleClasses.push(cssClass);
17390 * Unsets an excluded tag name set by addInvalidHandleType
17391 * @method removeInvalidHandleType
17392 * @param {string} tagName the type of element to unexclude
17394 removeInvalidHandleType: function(tagName) {
17395 var type = tagName.toUpperCase();
17396 // this.invalidHandleTypes[type] = null;
17397 delete this.invalidHandleTypes[type];
17401 * Unsets an invalid handle id
17402 * @method removeInvalidHandleId
17403 * @param {string} id the id of the element to re-enable
17405 removeInvalidHandleId: function(id) {
17406 if (typeof id !== "string") {
17409 delete this.invalidHandleIds[id];
17413 * Unsets an invalid css class
17414 * @method removeInvalidHandleClass
17415 * @param {string} cssClass the class of the element(s) you wish to
17418 removeInvalidHandleClass: function(cssClass) {
17419 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17420 if (this.invalidHandleClasses[i] == cssClass) {
17421 delete this.invalidHandleClasses[i];
17427 * Checks the tag exclusion list to see if this click should be ignored
17428 * @method isValidHandleChild
17429 * @param {HTMLElement} node the HTMLElement to evaluate
17430 * @return {boolean} true if this is a valid tag type, false if not
17432 isValidHandleChild: function(node) {
17435 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17438 nodeName = node.nodeName.toUpperCase();
17440 nodeName = node.nodeName;
17442 valid = valid && !this.invalidHandleTypes[nodeName];
17443 valid = valid && !this.invalidHandleIds[node.id];
17445 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17446 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17455 * Create the array of horizontal tick marks if an interval was specified
17456 * in setXConstraint().
17457 * @method setXTicks
17460 setXTicks: function(iStartX, iTickSize) {
17462 this.xTickSize = iTickSize;
17466 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17468 this.xTicks[this.xTicks.length] = i;
17473 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17475 this.xTicks[this.xTicks.length] = i;
17480 this.xTicks.sort(this.DDM.numericSort) ;
17484 * Create the array of vertical tick marks if an interval was specified in
17485 * setYConstraint().
17486 * @method setYTicks
17489 setYTicks: function(iStartY, iTickSize) {
17491 this.yTickSize = iTickSize;
17495 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17497 this.yTicks[this.yTicks.length] = i;
17502 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17504 this.yTicks[this.yTicks.length] = i;
17509 this.yTicks.sort(this.DDM.numericSort) ;
17513 * By default, the element can be dragged any place on the screen. Use
17514 * this method to limit the horizontal travel of the element. Pass in
17515 * 0,0 for the parameters if you want to lock the drag to the y axis.
17516 * @method setXConstraint
17517 * @param {int} iLeft the number of pixels the element can move to the left
17518 * @param {int} iRight the number of pixels the element can move to the
17520 * @param {int} iTickSize optional parameter for specifying that the
17522 * should move iTickSize pixels at a time.
17524 setXConstraint: function(iLeft, iRight, iTickSize) {
17525 this.leftConstraint = iLeft;
17526 this.rightConstraint = iRight;
17528 this.minX = this.initPageX - iLeft;
17529 this.maxX = this.initPageX + iRight;
17530 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17532 this.constrainX = true;
17536 * Clears any constraints applied to this instance. Also clears ticks
17537 * since they can't exist independent of a constraint at this time.
17538 * @method clearConstraints
17540 clearConstraints: function() {
17541 this.constrainX = false;
17542 this.constrainY = false;
17547 * Clears any tick interval defined for this instance
17548 * @method clearTicks
17550 clearTicks: function() {
17551 this.xTicks = null;
17552 this.yTicks = null;
17553 this.xTickSize = 0;
17554 this.yTickSize = 0;
17558 * By default, the element can be dragged any place on the screen. Set
17559 * this to limit the vertical travel of the element. Pass in 0,0 for the
17560 * parameters if you want to lock the drag to the x axis.
17561 * @method setYConstraint
17562 * @param {int} iUp the number of pixels the element can move up
17563 * @param {int} iDown the number of pixels the element can move down
17564 * @param {int} iTickSize optional parameter for specifying that the
17565 * element should move iTickSize pixels at a time.
17567 setYConstraint: function(iUp, iDown, iTickSize) {
17568 this.topConstraint = iUp;
17569 this.bottomConstraint = iDown;
17571 this.minY = this.initPageY - iUp;
17572 this.maxY = this.initPageY + iDown;
17573 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17575 this.constrainY = true;
17580 * resetConstraints must be called if you manually reposition a dd element.
17581 * @method resetConstraints
17582 * @param {boolean} maintainOffset
17584 resetConstraints: function() {
17587 // Maintain offsets if necessary
17588 if (this.initPageX || this.initPageX === 0) {
17589 // figure out how much this thing has moved
17590 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17591 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17593 this.setInitPosition(dx, dy);
17595 // This is the first time we have detected the element's position
17597 this.setInitPosition();
17600 if (this.constrainX) {
17601 this.setXConstraint( this.leftConstraint,
17602 this.rightConstraint,
17606 if (this.constrainY) {
17607 this.setYConstraint( this.topConstraint,
17608 this.bottomConstraint,
17614 * Normally the drag element is moved pixel by pixel, but we can specify
17615 * that it move a number of pixels at a time. This method resolves the
17616 * location when we have it set up like this.
17618 * @param {int} val where we want to place the object
17619 * @param {int[]} tickArray sorted array of valid points
17620 * @return {int} the closest tick
17623 getTick: function(val, tickArray) {
17626 // If tick interval is not defined, it is effectively 1 pixel,
17627 // so we return the value passed to us.
17629 } else if (tickArray[0] >= val) {
17630 // The value is lower than the first tick, so we return the first
17632 return tickArray[0];
17634 for (var i=0, len=tickArray.length; i<len; ++i) {
17636 if (tickArray[next] && tickArray[next] >= val) {
17637 var diff1 = val - tickArray[i];
17638 var diff2 = tickArray[next] - val;
17639 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17643 // The value is larger than the last tick, so we return the last
17645 return tickArray[tickArray.length - 1];
17652 * @return {string} string representation of the dd obj
17654 toString: function() {
17655 return ("DragDrop " + this.id);
17663 * Ext JS Library 1.1.1
17664 * Copyright(c) 2006-2007, Ext JS, LLC.
17666 * Originally Released Under LGPL - original licence link has changed is not relivant.
17669 * <script type="text/javascript">
17674 * The drag and drop utility provides a framework for building drag and drop
17675 * applications. In addition to enabling drag and drop for specific elements,
17676 * the drag and drop elements are tracked by the manager class, and the
17677 * interactions between the various elements are tracked during the drag and
17678 * the implementing code is notified about these important moments.
17681 // Only load the library once. Rewriting the manager class would orphan
17682 // existing drag and drop instances.
17683 if (!Roo.dd.DragDropMgr) {
17686 * @class Roo.dd.DragDropMgr
17687 * DragDropMgr is a singleton that tracks the element interaction for
17688 * all DragDrop items in the window. Generally, you will not call
17689 * this class directly, but it does have helper methods that could
17690 * be useful in your DragDrop implementations.
17693 Roo.dd.DragDropMgr = function() {
17695 var Event = Roo.EventManager;
17700 * Two dimensional Array of registered DragDrop objects. The first
17701 * dimension is the DragDrop item group, the second the DragDrop
17704 * @type {string: string}
17711 * Array of element ids defined as drag handles. Used to determine
17712 * if the element that generated the mousedown event is actually the
17713 * handle and not the html element itself.
17714 * @property handleIds
17715 * @type {string: string}
17722 * the DragDrop object that is currently being dragged
17723 * @property dragCurrent
17731 * the DragDrop object(s) that are being hovered over
17732 * @property dragOvers
17740 * the X distance between the cursor and the object being dragged
17749 * the Y distance between the cursor and the object being dragged
17758 * Flag to determine if we should prevent the default behavior of the
17759 * events we define. By default this is true, but this can be set to
17760 * false if you need the default behavior (not recommended)
17761 * @property preventDefault
17765 preventDefault: true,
17768 * Flag to determine if we should stop the propagation of the events
17769 * we generate. This is true by default but you may want to set it to
17770 * false if the html element contains other features that require the
17772 * @property stopPropagation
17776 stopPropagation: true,
17779 * Internal flag that is set to true when drag and drop has been
17781 * @property initialized
17788 * All drag and drop can be disabled.
17796 * Called the first time an element is registered.
17802 this.initialized = true;
17806 * In point mode, drag and drop interaction is defined by the
17807 * location of the cursor during the drag/drop
17815 * In intersect mode, drag and drop interactio nis defined by the
17816 * overlap of two or more drag and drop objects.
17817 * @property INTERSECT
17824 * The current drag and drop mode. Default: POINT
17832 * Runs method on all drag and drop objects
17833 * @method _execOnAll
17837 _execOnAll: function(sMethod, args) {
17838 for (var i in this.ids) {
17839 for (var j in this.ids[i]) {
17840 var oDD = this.ids[i][j];
17841 if (! this.isTypeOfDD(oDD)) {
17844 oDD[sMethod].apply(oDD, args);
17850 * Drag and drop initialization. Sets up the global event handlers
17855 _onLoad: function() {
17859 if (!Roo.isTouch) {
17860 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17861 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17863 Event.on(document, "touchend", this.handleMouseUp, this, true);
17864 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17866 Event.on(window, "unload", this._onUnload, this, true);
17867 Event.on(window, "resize", this._onResize, this, true);
17868 // Event.on(window, "mouseout", this._test);
17873 * Reset constraints on all drag and drop objs
17874 * @method _onResize
17878 _onResize: function(e) {
17879 this._execOnAll("resetConstraints", []);
17883 * Lock all drag and drop functionality
17887 lock: function() { this.locked = true; },
17890 * Unlock all drag and drop functionality
17894 unlock: function() { this.locked = false; },
17897 * Is drag and drop locked?
17899 * @return {boolean} True if drag and drop is locked, false otherwise.
17902 isLocked: function() { return this.locked; },
17905 * Location cache that is set for all drag drop objects when a drag is
17906 * initiated, cleared when the drag is finished.
17907 * @property locationCache
17914 * Set useCache to false if you want to force object the lookup of each
17915 * drag and drop linked element constantly during a drag.
17916 * @property useCache
17923 * The number of pixels that the mouse needs to move after the
17924 * mousedown before the drag is initiated. Default=3;
17925 * @property clickPixelThresh
17929 clickPixelThresh: 3,
17932 * The number of milliseconds after the mousedown event to initiate the
17933 * drag if we don't get a mouseup event. Default=1000
17934 * @property clickTimeThresh
17938 clickTimeThresh: 350,
17941 * Flag that indicates that either the drag pixel threshold or the
17942 * mousdown time threshold has been met
17943 * @property dragThreshMet
17948 dragThreshMet: false,
17951 * Timeout used for the click time threshold
17952 * @property clickTimeout
17957 clickTimeout: null,
17960 * The X position of the mousedown event stored for later use when a
17961 * drag threshold is met.
17970 * The Y position of the mousedown event stored for later use when a
17971 * drag threshold is met.
17980 * Each DragDrop instance must be registered with the DragDropMgr.
17981 * This is executed in DragDrop.init()
17982 * @method regDragDrop
17983 * @param {DragDrop} oDD the DragDrop object to register
17984 * @param {String} sGroup the name of the group this element belongs to
17987 regDragDrop: function(oDD, sGroup) {
17988 if (!this.initialized) { this.init(); }
17990 if (!this.ids[sGroup]) {
17991 this.ids[sGroup] = {};
17993 this.ids[sGroup][oDD.id] = oDD;
17997 * Removes the supplied dd instance from the supplied group. Executed
17998 * by DragDrop.removeFromGroup, so don't call this function directly.
17999 * @method removeDDFromGroup
18003 removeDDFromGroup: function(oDD, sGroup) {
18004 if (!this.ids[sGroup]) {
18005 this.ids[sGroup] = {};
18008 var obj = this.ids[sGroup];
18009 if (obj && obj[oDD.id]) {
18010 delete obj[oDD.id];
18015 * Unregisters a drag and drop item. This is executed in
18016 * DragDrop.unreg, use that method instead of calling this directly.
18021 _remove: function(oDD) {
18022 for (var g in oDD.groups) {
18023 if (g && this.ids[g][oDD.id]) {
18024 delete this.ids[g][oDD.id];
18027 delete this.handleIds[oDD.id];
18031 * Each DragDrop handle element must be registered. This is done
18032 * automatically when executing DragDrop.setHandleElId()
18033 * @method regHandle
18034 * @param {String} sDDId the DragDrop id this element is a handle for
18035 * @param {String} sHandleId the id of the element that is the drag
18039 regHandle: function(sDDId, sHandleId) {
18040 if (!this.handleIds[sDDId]) {
18041 this.handleIds[sDDId] = {};
18043 this.handleIds[sDDId][sHandleId] = sHandleId;
18047 * Utility function to determine if a given element has been
18048 * registered as a drag drop item.
18049 * @method isDragDrop
18050 * @param {String} id the element id to check
18051 * @return {boolean} true if this element is a DragDrop item,
18055 isDragDrop: function(id) {
18056 return ( this.getDDById(id) ) ? true : false;
18060 * Returns the drag and drop instances that are in all groups the
18061 * passed in instance belongs to.
18062 * @method getRelated
18063 * @param {DragDrop} p_oDD the obj to get related data for
18064 * @param {boolean} bTargetsOnly if true, only return targetable objs
18065 * @return {DragDrop[]} the related instances
18068 getRelated: function(p_oDD, bTargetsOnly) {
18070 for (var i in p_oDD.groups) {
18071 for (j in this.ids[i]) {
18072 var dd = this.ids[i][j];
18073 if (! this.isTypeOfDD(dd)) {
18076 if (!bTargetsOnly || dd.isTarget) {
18077 oDDs[oDDs.length] = dd;
18086 * Returns true if the specified dd target is a legal target for
18087 * the specifice drag obj
18088 * @method isLegalTarget
18089 * @param {DragDrop} the drag obj
18090 * @param {DragDrop} the target
18091 * @return {boolean} true if the target is a legal target for the
18095 isLegalTarget: function (oDD, oTargetDD) {
18096 var targets = this.getRelated(oDD, true);
18097 for (var i=0, len=targets.length;i<len;++i) {
18098 if (targets[i].id == oTargetDD.id) {
18107 * My goal is to be able to transparently determine if an object is
18108 * typeof DragDrop, and the exact subclass of DragDrop. typeof
18109 * returns "object", oDD.constructor.toString() always returns
18110 * "DragDrop" and not the name of the subclass. So for now it just
18111 * evaluates a well-known variable in DragDrop.
18112 * @method isTypeOfDD
18113 * @param {Object} the object to evaluate
18114 * @return {boolean} true if typeof oDD = DragDrop
18117 isTypeOfDD: function (oDD) {
18118 return (oDD && oDD.__ygDragDrop);
18122 * Utility function to determine if a given element has been
18123 * registered as a drag drop handle for the given Drag Drop object.
18125 * @param {String} id the element id to check
18126 * @return {boolean} true if this element is a DragDrop handle, false
18130 isHandle: function(sDDId, sHandleId) {
18131 return ( this.handleIds[sDDId] &&
18132 this.handleIds[sDDId][sHandleId] );
18136 * Returns the DragDrop instance for a given id
18137 * @method getDDById
18138 * @param {String} id the id of the DragDrop object
18139 * @return {DragDrop} the drag drop object, null if it is not found
18142 getDDById: function(id) {
18143 for (var i in this.ids) {
18144 if (this.ids[i][id]) {
18145 return this.ids[i][id];
18152 * Fired after a registered DragDrop object gets the mousedown event.
18153 * Sets up the events required to track the object being dragged
18154 * @method handleMouseDown
18155 * @param {Event} e the event
18156 * @param oDD the DragDrop object being dragged
18160 handleMouseDown: function(e, oDD) {
18162 Roo.QuickTips.disable();
18164 this.currentTarget = e.getTarget();
18166 this.dragCurrent = oDD;
18168 var el = oDD.getEl();
18170 // track start position
18171 this.startX = e.getPageX();
18172 this.startY = e.getPageY();
18174 this.deltaX = this.startX - el.offsetLeft;
18175 this.deltaY = this.startY - el.offsetTop;
18177 this.dragThreshMet = false;
18179 this.clickTimeout = setTimeout(
18181 var DDM = Roo.dd.DDM;
18182 DDM.startDrag(DDM.startX, DDM.startY);
18184 this.clickTimeThresh );
18188 * Fired when either the drag pixel threshol or the mousedown hold
18189 * time threshold has been met.
18190 * @method startDrag
18191 * @param x {int} the X position of the original mousedown
18192 * @param y {int} the Y position of the original mousedown
18195 startDrag: function(x, y) {
18196 clearTimeout(this.clickTimeout);
18197 if (this.dragCurrent) {
18198 this.dragCurrent.b4StartDrag(x, y);
18199 this.dragCurrent.startDrag(x, y);
18201 this.dragThreshMet = true;
18205 * Internal function to handle the mouseup event. Will be invoked
18206 * from the context of the document.
18207 * @method handleMouseUp
18208 * @param {Event} e the event
18212 handleMouseUp: function(e) {
18215 Roo.QuickTips.enable();
18217 if (! this.dragCurrent) {
18221 clearTimeout(this.clickTimeout);
18223 if (this.dragThreshMet) {
18224 this.fireEvents(e, true);
18234 * Utility to stop event propagation and event default, if these
18235 * features are turned on.
18236 * @method stopEvent
18237 * @param {Event} e the event as returned by this.getEvent()
18240 stopEvent: function(e){
18241 if(this.stopPropagation) {
18242 e.stopPropagation();
18245 if (this.preventDefault) {
18246 e.preventDefault();
18251 * Internal function to clean up event handlers after the drag
18252 * operation is complete
18254 * @param {Event} e the event
18258 stopDrag: function(e) {
18259 // Fire the drag end event for the item that was dragged
18260 if (this.dragCurrent) {
18261 if (this.dragThreshMet) {
18262 this.dragCurrent.b4EndDrag(e);
18263 this.dragCurrent.endDrag(e);
18266 this.dragCurrent.onMouseUp(e);
18269 this.dragCurrent = null;
18270 this.dragOvers = {};
18274 * Internal function to handle the mousemove event. Will be invoked
18275 * from the context of the html element.
18277 * @TODO figure out what we can do about mouse events lost when the
18278 * user drags objects beyond the window boundary. Currently we can
18279 * detect this in internet explorer by verifying that the mouse is
18280 * down during the mousemove event. Firefox doesn't give us the
18281 * button state on the mousemove event.
18282 * @method handleMouseMove
18283 * @param {Event} e the event
18287 handleMouseMove: function(e) {
18288 if (! this.dragCurrent) {
18292 // var button = e.which || e.button;
18294 // check for IE mouseup outside of page boundary
18295 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18297 return this.handleMouseUp(e);
18300 if (!this.dragThreshMet) {
18301 var diffX = Math.abs(this.startX - e.getPageX());
18302 var diffY = Math.abs(this.startY - e.getPageY());
18303 if (diffX > this.clickPixelThresh ||
18304 diffY > this.clickPixelThresh) {
18305 this.startDrag(this.startX, this.startY);
18309 if (this.dragThreshMet) {
18310 this.dragCurrent.b4Drag(e);
18311 this.dragCurrent.onDrag(e);
18312 if(!this.dragCurrent.moveOnly){
18313 this.fireEvents(e, false);
18323 * Iterates over all of the DragDrop elements to find ones we are
18324 * hovering over or dropping on
18325 * @method fireEvents
18326 * @param {Event} e the event
18327 * @param {boolean} isDrop is this a drop op or a mouseover op?
18331 fireEvents: function(e, isDrop) {
18332 var dc = this.dragCurrent;
18334 // If the user did the mouse up outside of the window, we could
18335 // get here even though we have ended the drag.
18336 if (!dc || dc.isLocked()) {
18340 var pt = e.getPoint();
18342 // cache the previous dragOver array
18348 var enterEvts = [];
18350 // Check to see if the object(s) we were hovering over is no longer
18351 // being hovered over so we can fire the onDragOut event
18352 for (var i in this.dragOvers) {
18354 var ddo = this.dragOvers[i];
18356 if (! this.isTypeOfDD(ddo)) {
18360 if (! this.isOverTarget(pt, ddo, this.mode)) {
18361 outEvts.push( ddo );
18364 oldOvers[i] = true;
18365 delete this.dragOvers[i];
18368 for (var sGroup in dc.groups) {
18370 if ("string" != typeof sGroup) {
18374 for (i in this.ids[sGroup]) {
18375 var oDD = this.ids[sGroup][i];
18376 if (! this.isTypeOfDD(oDD)) {
18380 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18381 if (this.isOverTarget(pt, oDD, this.mode)) {
18382 // look for drop interactions
18384 dropEvts.push( oDD );
18385 // look for drag enter and drag over interactions
18388 // initial drag over: dragEnter fires
18389 if (!oldOvers[oDD.id]) {
18390 enterEvts.push( oDD );
18391 // subsequent drag overs: dragOver fires
18393 overEvts.push( oDD );
18396 this.dragOvers[oDD.id] = oDD;
18404 if (outEvts.length) {
18405 dc.b4DragOut(e, outEvts);
18406 dc.onDragOut(e, outEvts);
18409 if (enterEvts.length) {
18410 dc.onDragEnter(e, enterEvts);
18413 if (overEvts.length) {
18414 dc.b4DragOver(e, overEvts);
18415 dc.onDragOver(e, overEvts);
18418 if (dropEvts.length) {
18419 dc.b4DragDrop(e, dropEvts);
18420 dc.onDragDrop(e, dropEvts);
18424 // fire dragout events
18426 for (i=0, len=outEvts.length; i<len; ++i) {
18427 dc.b4DragOut(e, outEvts[i].id);
18428 dc.onDragOut(e, outEvts[i].id);
18431 // fire enter events
18432 for (i=0,len=enterEvts.length; i<len; ++i) {
18433 // dc.b4DragEnter(e, oDD.id);
18434 dc.onDragEnter(e, enterEvts[i].id);
18437 // fire over events
18438 for (i=0,len=overEvts.length; i<len; ++i) {
18439 dc.b4DragOver(e, overEvts[i].id);
18440 dc.onDragOver(e, overEvts[i].id);
18443 // fire drop events
18444 for (i=0, len=dropEvts.length; i<len; ++i) {
18445 dc.b4DragDrop(e, dropEvts[i].id);
18446 dc.onDragDrop(e, dropEvts[i].id);
18451 // notify about a drop that did not find a target
18452 if (isDrop && !dropEvts.length) {
18453 dc.onInvalidDrop(e);
18459 * Helper function for getting the best match from the list of drag
18460 * and drop objects returned by the drag and drop events when we are
18461 * in INTERSECT mode. It returns either the first object that the
18462 * cursor is over, or the object that has the greatest overlap with
18463 * the dragged element.
18464 * @method getBestMatch
18465 * @param {DragDrop[]} dds The array of drag and drop objects
18467 * @return {DragDrop} The best single match
18470 getBestMatch: function(dds) {
18472 // Return null if the input is not what we expect
18473 //if (!dds || !dds.length || dds.length == 0) {
18475 // If there is only one item, it wins
18476 //} else if (dds.length == 1) {
18478 var len = dds.length;
18483 // Loop through the targeted items
18484 for (var i=0; i<len; ++i) {
18486 // If the cursor is over the object, it wins. If the
18487 // cursor is over multiple matches, the first one we come
18489 if (dd.cursorIsOver) {
18492 // Otherwise the object with the most overlap wins
18495 winner.overlap.getArea() < dd.overlap.getArea()) {
18506 * Refreshes the cache of the top-left and bottom-right points of the
18507 * drag and drop objects in the specified group(s). This is in the
18508 * format that is stored in the drag and drop instance, so typical
18511 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18515 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18517 * @TODO this really should be an indexed array. Alternatively this
18518 * method could accept both.
18519 * @method refreshCache
18520 * @param {Object} groups an associative array of groups to refresh
18523 refreshCache: function(groups) {
18524 for (var sGroup in groups) {
18525 if ("string" != typeof sGroup) {
18528 for (var i in this.ids[sGroup]) {
18529 var oDD = this.ids[sGroup][i];
18531 if (this.isTypeOfDD(oDD)) {
18532 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18533 var loc = this.getLocation(oDD);
18535 this.locationCache[oDD.id] = loc;
18537 delete this.locationCache[oDD.id];
18538 // this will unregister the drag and drop object if
18539 // the element is not in a usable state
18548 * This checks to make sure an element exists and is in the DOM. The
18549 * main purpose is to handle cases where innerHTML is used to remove
18550 * drag and drop objects from the DOM. IE provides an 'unspecified
18551 * error' when trying to access the offsetParent of such an element
18553 * @param {HTMLElement} el the element to check
18554 * @return {boolean} true if the element looks usable
18557 verifyEl: function(el) {
18562 parent = el.offsetParent;
18565 parent = el.offsetParent;
18576 * Returns a Region object containing the drag and drop element's position
18577 * and size, including the padding configured for it
18578 * @method getLocation
18579 * @param {DragDrop} oDD the drag and drop object to get the
18581 * @return {Roo.lib.Region} a Region object representing the total area
18582 * the element occupies, including any padding
18583 * the instance is configured for.
18586 getLocation: function(oDD) {
18587 if (! this.isTypeOfDD(oDD)) {
18591 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18594 pos= Roo.lib.Dom.getXY(el);
18602 x2 = x1 + el.offsetWidth;
18604 y2 = y1 + el.offsetHeight;
18606 t = y1 - oDD.padding[0];
18607 r = x2 + oDD.padding[1];
18608 b = y2 + oDD.padding[2];
18609 l = x1 - oDD.padding[3];
18611 return new Roo.lib.Region( t, r, b, l );
18615 * Checks the cursor location to see if it over the target
18616 * @method isOverTarget
18617 * @param {Roo.lib.Point} pt The point to evaluate
18618 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18619 * @return {boolean} true if the mouse is over the target
18623 isOverTarget: function(pt, oTarget, intersect) {
18624 // use cache if available
18625 var loc = this.locationCache[oTarget.id];
18626 if (!loc || !this.useCache) {
18627 loc = this.getLocation(oTarget);
18628 this.locationCache[oTarget.id] = loc;
18636 oTarget.cursorIsOver = loc.contains( pt );
18638 // DragDrop is using this as a sanity check for the initial mousedown
18639 // in this case we are done. In POINT mode, if the drag obj has no
18640 // contraints, we are also done. Otherwise we need to evaluate the
18641 // location of the target as related to the actual location of the
18642 // dragged element.
18643 var dc = this.dragCurrent;
18644 if (!dc || !dc.getTargetCoord ||
18645 (!intersect && !dc.constrainX && !dc.constrainY)) {
18646 return oTarget.cursorIsOver;
18649 oTarget.overlap = null;
18651 // Get the current location of the drag element, this is the
18652 // location of the mouse event less the delta that represents
18653 // where the original mousedown happened on the element. We
18654 // need to consider constraints and ticks as well.
18655 var pos = dc.getTargetCoord(pt.x, pt.y);
18657 var el = dc.getDragEl();
18658 var curRegion = new Roo.lib.Region( pos.y,
18659 pos.x + el.offsetWidth,
18660 pos.y + el.offsetHeight,
18663 var overlap = curRegion.intersect(loc);
18666 oTarget.overlap = overlap;
18667 return (intersect) ? true : oTarget.cursorIsOver;
18674 * unload event handler
18675 * @method _onUnload
18679 _onUnload: function(e, me) {
18680 Roo.dd.DragDropMgr.unregAll();
18684 * Cleans up the drag and drop events and objects.
18689 unregAll: function() {
18691 if (this.dragCurrent) {
18693 this.dragCurrent = null;
18696 this._execOnAll("unreg", []);
18698 for (i in this.elementCache) {
18699 delete this.elementCache[i];
18702 this.elementCache = {};
18707 * A cache of DOM elements
18708 * @property elementCache
18715 * Get the wrapper for the DOM element specified
18716 * @method getElWrapper
18717 * @param {String} id the id of the element to get
18718 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18720 * @deprecated This wrapper isn't that useful
18723 getElWrapper: function(id) {
18724 var oWrapper = this.elementCache[id];
18725 if (!oWrapper || !oWrapper.el) {
18726 oWrapper = this.elementCache[id] =
18727 new this.ElementWrapper(Roo.getDom(id));
18733 * Returns the actual DOM element
18734 * @method getElement
18735 * @param {String} id the id of the elment to get
18736 * @return {Object} The element
18737 * @deprecated use Roo.getDom instead
18740 getElement: function(id) {
18741 return Roo.getDom(id);
18745 * Returns the style property for the DOM element (i.e.,
18746 * document.getElById(id).style)
18748 * @param {String} id the id of the elment to get
18749 * @return {Object} The style property of the element
18750 * @deprecated use Roo.getDom instead
18753 getCss: function(id) {
18754 var el = Roo.getDom(id);
18755 return (el) ? el.style : null;
18759 * Inner class for cached elements
18760 * @class DragDropMgr.ElementWrapper
18765 ElementWrapper: function(el) {
18770 this.el = el || null;
18775 this.id = this.el && el.id;
18777 * A reference to the style property
18780 this.css = this.el && el.style;
18784 * Returns the X position of an html element
18786 * @param el the element for which to get the position
18787 * @return {int} the X coordinate
18789 * @deprecated use Roo.lib.Dom.getX instead
18792 getPosX: function(el) {
18793 return Roo.lib.Dom.getX(el);
18797 * Returns the Y position of an html element
18799 * @param el the element for which to get the position
18800 * @return {int} the Y coordinate
18801 * @deprecated use Roo.lib.Dom.getY instead
18804 getPosY: function(el) {
18805 return Roo.lib.Dom.getY(el);
18809 * Swap two nodes. In IE, we use the native method, for others we
18810 * emulate the IE behavior
18812 * @param n1 the first node to swap
18813 * @param n2 the other node to swap
18816 swapNode: function(n1, n2) {
18820 var p = n2.parentNode;
18821 var s = n2.nextSibling;
18824 p.insertBefore(n1, n2);
18825 } else if (n2 == n1.nextSibling) {
18826 p.insertBefore(n2, n1);
18828 n1.parentNode.replaceChild(n2, n1);
18829 p.insertBefore(n1, s);
18835 * Returns the current scroll position
18836 * @method getScroll
18840 getScroll: function () {
18841 var t, l, dde=document.documentElement, db=document.body;
18842 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18844 l = dde.scrollLeft;
18851 return { top: t, left: l };
18855 * Returns the specified element style property
18857 * @param {HTMLElement} el the element
18858 * @param {string} styleProp the style property
18859 * @return {string} The value of the style property
18860 * @deprecated use Roo.lib.Dom.getStyle
18863 getStyle: function(el, styleProp) {
18864 return Roo.fly(el).getStyle(styleProp);
18868 * Gets the scrollTop
18869 * @method getScrollTop
18870 * @return {int} the document's scrollTop
18873 getScrollTop: function () { return this.getScroll().top; },
18876 * Gets the scrollLeft
18877 * @method getScrollLeft
18878 * @return {int} the document's scrollTop
18881 getScrollLeft: function () { return this.getScroll().left; },
18884 * Sets the x/y position of an element to the location of the
18887 * @param {HTMLElement} moveEl The element to move
18888 * @param {HTMLElement} targetEl The position reference element
18891 moveToEl: function (moveEl, targetEl) {
18892 var aCoord = Roo.lib.Dom.getXY(targetEl);
18893 Roo.lib.Dom.setXY(moveEl, aCoord);
18897 * Numeric array sort function
18898 * @method numericSort
18901 numericSort: function(a, b) { return (a - b); },
18905 * @property _timeoutCount
18912 * Trying to make the load order less important. Without this we get
18913 * an error if this file is loaded before the Event Utility.
18914 * @method _addListeners
18918 _addListeners: function() {
18919 var DDM = Roo.dd.DDM;
18920 if ( Roo.lib.Event && document ) {
18923 if (DDM._timeoutCount > 2000) {
18925 setTimeout(DDM._addListeners, 10);
18926 if (document && document.body) {
18927 DDM._timeoutCount += 1;
18934 * Recursively searches the immediate parent and all child nodes for
18935 * the handle element in order to determine wheter or not it was
18937 * @method handleWasClicked
18938 * @param node the html element to inspect
18941 handleWasClicked: function(node, id) {
18942 if (this.isHandle(id, node.id)) {
18945 // check to see if this is a text node child of the one we want
18946 var p = node.parentNode;
18949 if (this.isHandle(id, p.id)) {
18964 // shorter alias, save a few bytes
18965 Roo.dd.DDM = Roo.dd.DragDropMgr;
18966 Roo.dd.DDM._addListeners();
18970 * Ext JS Library 1.1.1
18971 * Copyright(c) 2006-2007, Ext JS, LLC.
18973 * Originally Released Under LGPL - original licence link has changed is not relivant.
18976 * <script type="text/javascript">
18981 * A DragDrop implementation where the linked element follows the
18982 * mouse cursor during a drag.
18983 * @extends Roo.dd.DragDrop
18985 * @param {String} id the id of the linked element
18986 * @param {String} sGroup the group of related DragDrop items
18987 * @param {object} config an object containing configurable attributes
18988 * Valid properties for DD:
18991 Roo.dd.DD = function(id, sGroup, config) {
18993 this.init(id, sGroup, config);
18997 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
19000 * When set to true, the utility automatically tries to scroll the browser
19001 * window wehn a drag and drop element is dragged near the viewport boundary.
19002 * Defaults to true.
19009 * Sets the pointer offset to the distance between the linked element's top
19010 * left corner and the location the element was clicked
19011 * @method autoOffset
19012 * @param {int} iPageX the X coordinate of the click
19013 * @param {int} iPageY the Y coordinate of the click
19015 autoOffset: function(iPageX, iPageY) {
19016 var x = iPageX - this.startPageX;
19017 var y = iPageY - this.startPageY;
19018 this.setDelta(x, y);
19022 * Sets the pointer offset. You can call this directly to force the
19023 * offset to be in a particular location (e.g., pass in 0,0 to set it
19024 * to the center of the object)
19026 * @param {int} iDeltaX the distance from the left
19027 * @param {int} iDeltaY the distance from the top
19029 setDelta: function(iDeltaX, iDeltaY) {
19030 this.deltaX = iDeltaX;
19031 this.deltaY = iDeltaY;
19035 * Sets the drag element to the location of the mousedown or click event,
19036 * maintaining the cursor location relative to the location on the element
19037 * that was clicked. Override this if you want to place the element in a
19038 * location other than where the cursor is.
19039 * @method setDragElPos
19040 * @param {int} iPageX the X coordinate of the mousedown or drag event
19041 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19043 setDragElPos: function(iPageX, iPageY) {
19044 // the first time we do this, we are going to check to make sure
19045 // the element has css positioning
19047 var el = this.getDragEl();
19048 this.alignElWithMouse(el, iPageX, iPageY);
19052 * Sets the element to the location of the mousedown or click event,
19053 * maintaining the cursor location relative to the location on the element
19054 * that was clicked. Override this if you want to place the element in a
19055 * location other than where the cursor is.
19056 * @method alignElWithMouse
19057 * @param {HTMLElement} el the element to move
19058 * @param {int} iPageX the X coordinate of the mousedown or drag event
19059 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19061 alignElWithMouse: function(el, iPageX, iPageY) {
19062 var oCoord = this.getTargetCoord(iPageX, iPageY);
19063 var fly = el.dom ? el : Roo.fly(el);
19064 if (!this.deltaSetXY) {
19065 var aCoord = [oCoord.x, oCoord.y];
19067 var newLeft = fly.getLeft(true);
19068 var newTop = fly.getTop(true);
19069 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
19071 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
19074 this.cachePosition(oCoord.x, oCoord.y);
19075 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
19080 * Saves the most recent position so that we can reset the constraints and
19081 * tick marks on-demand. We need to know this so that we can calculate the
19082 * number of pixels the element is offset from its original position.
19083 * @method cachePosition
19084 * @param iPageX the current x position (optional, this just makes it so we
19085 * don't have to look it up again)
19086 * @param iPageY the current y position (optional, this just makes it so we
19087 * don't have to look it up again)
19089 cachePosition: function(iPageX, iPageY) {
19091 this.lastPageX = iPageX;
19092 this.lastPageY = iPageY;
19094 var aCoord = Roo.lib.Dom.getXY(this.getEl());
19095 this.lastPageX = aCoord[0];
19096 this.lastPageY = aCoord[1];
19101 * Auto-scroll the window if the dragged object has been moved beyond the
19102 * visible window boundary.
19103 * @method autoScroll
19104 * @param {int} x the drag element's x position
19105 * @param {int} y the drag element's y position
19106 * @param {int} h the height of the drag element
19107 * @param {int} w the width of the drag element
19110 autoScroll: function(x, y, h, w) {
19113 // The client height
19114 var clientH = Roo.lib.Dom.getViewWidth();
19116 // The client width
19117 var clientW = Roo.lib.Dom.getViewHeight();
19119 // The amt scrolled down
19120 var st = this.DDM.getScrollTop();
19122 // The amt scrolled right
19123 var sl = this.DDM.getScrollLeft();
19125 // Location of the bottom of the element
19128 // Location of the right of the element
19131 // The distance from the cursor to the bottom of the visible area,
19132 // adjusted so that we don't scroll if the cursor is beyond the
19133 // element drag constraints
19134 var toBot = (clientH + st - y - this.deltaY);
19136 // The distance from the cursor to the right of the visible area
19137 var toRight = (clientW + sl - x - this.deltaX);
19140 // How close to the edge the cursor must be before we scroll
19141 // var thresh = (document.all) ? 100 : 40;
19144 // How many pixels to scroll per autoscroll op. This helps to reduce
19145 // clunky scrolling. IE is more sensitive about this ... it needs this
19146 // value to be higher.
19147 var scrAmt = (document.all) ? 80 : 30;
19149 // Scroll down if we are near the bottom of the visible page and the
19150 // obj extends below the crease
19151 if ( bot > clientH && toBot < thresh ) {
19152 window.scrollTo(sl, st + scrAmt);
19155 // Scroll up if the window is scrolled down and the top of the object
19156 // goes above the top border
19157 if ( y < st && st > 0 && y - st < thresh ) {
19158 window.scrollTo(sl, st - scrAmt);
19161 // Scroll right if the obj is beyond the right border and the cursor is
19162 // near the border.
19163 if ( right > clientW && toRight < thresh ) {
19164 window.scrollTo(sl + scrAmt, st);
19167 // Scroll left if the window has been scrolled to the right and the obj
19168 // extends past the left border
19169 if ( x < sl && sl > 0 && x - sl < thresh ) {
19170 window.scrollTo(sl - scrAmt, st);
19176 * Finds the location the element should be placed if we want to move
19177 * it to where the mouse location less the click offset would place us.
19178 * @method getTargetCoord
19179 * @param {int} iPageX the X coordinate of the click
19180 * @param {int} iPageY the Y coordinate of the click
19181 * @return an object that contains the coordinates (Object.x and Object.y)
19184 getTargetCoord: function(iPageX, iPageY) {
19187 var x = iPageX - this.deltaX;
19188 var y = iPageY - this.deltaY;
19190 if (this.constrainX) {
19191 if (x < this.minX) { x = this.minX; }
19192 if (x > this.maxX) { x = this.maxX; }
19195 if (this.constrainY) {
19196 if (y < this.minY) { y = this.minY; }
19197 if (y > this.maxY) { y = this.maxY; }
19200 x = this.getTick(x, this.xTicks);
19201 y = this.getTick(y, this.yTicks);
19208 * Sets up config options specific to this class. Overrides
19209 * Roo.dd.DragDrop, but all versions of this method through the
19210 * inheritance chain are called
19212 applyConfig: function() {
19213 Roo.dd.DD.superclass.applyConfig.call(this);
19214 this.scroll = (this.config.scroll !== false);
19218 * Event that fires prior to the onMouseDown event. Overrides
19221 b4MouseDown: function(e) {
19222 // this.resetConstraints();
19223 this.autoOffset(e.getPageX(),
19228 * Event that fires prior to the onDrag event. Overrides
19231 b4Drag: function(e) {
19232 this.setDragElPos(e.getPageX(),
19236 toString: function() {
19237 return ("DD " + this.id);
19240 //////////////////////////////////////////////////////////////////////////
19241 // Debugging ygDragDrop events that can be overridden
19242 //////////////////////////////////////////////////////////////////////////
19244 startDrag: function(x, y) {
19247 onDrag: function(e) {
19250 onDragEnter: function(e, id) {
19253 onDragOver: function(e, id) {
19256 onDragOut: function(e, id) {
19259 onDragDrop: function(e, id) {
19262 endDrag: function(e) {
19269 * Ext JS Library 1.1.1
19270 * Copyright(c) 2006-2007, Ext JS, LLC.
19272 * Originally Released Under LGPL - original licence link has changed is not relivant.
19275 * <script type="text/javascript">
19279 * @class Roo.dd.DDProxy
19280 * A DragDrop implementation that inserts an empty, bordered div into
19281 * the document that follows the cursor during drag operations. At the time of
19282 * the click, the frame div is resized to the dimensions of the linked html
19283 * element, and moved to the exact location of the linked element.
19285 * References to the "frame" element refer to the single proxy element that
19286 * was created to be dragged in place of all DDProxy elements on the
19289 * @extends Roo.dd.DD
19291 * @param {String} id the id of the linked html element
19292 * @param {String} sGroup the group of related DragDrop objects
19293 * @param {object} config an object containing configurable attributes
19294 * Valid properties for DDProxy in addition to those in DragDrop:
19295 * resizeFrame, centerFrame, dragElId
19297 Roo.dd.DDProxy = function(id, sGroup, config) {
19299 this.init(id, sGroup, config);
19305 * The default drag frame div id
19306 * @property Roo.dd.DDProxy.dragElId
19310 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19312 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19315 * By default we resize the drag frame to be the same size as the element
19316 * we want to drag (this is to get the frame effect). We can turn it off
19317 * if we want a different behavior.
19318 * @property resizeFrame
19324 * By default the frame is positioned exactly where the drag element is, so
19325 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19326 * you do not have constraints on the obj is to have the drag frame centered
19327 * around the cursor. Set centerFrame to true for this effect.
19328 * @property centerFrame
19331 centerFrame: false,
19334 * Creates the proxy element if it does not yet exist
19335 * @method createFrame
19337 createFrame: function() {
19339 var body = document.body;
19341 if (!body || !body.firstChild) {
19342 setTimeout( function() { self.createFrame(); }, 50 );
19346 var div = this.getDragEl();
19349 div = document.createElement("div");
19350 div.id = this.dragElId;
19353 s.position = "absolute";
19354 s.visibility = "hidden";
19356 s.border = "2px solid #aaa";
19359 // appendChild can blow up IE if invoked prior to the window load event
19360 // while rendering a table. It is possible there are other scenarios
19361 // that would cause this to happen as well.
19362 body.insertBefore(div, body.firstChild);
19367 * Initialization for the drag frame element. Must be called in the
19368 * constructor of all subclasses
19369 * @method initFrame
19371 initFrame: function() {
19372 this.createFrame();
19375 applyConfig: function() {
19376 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19378 this.resizeFrame = (this.config.resizeFrame !== false);
19379 this.centerFrame = (this.config.centerFrame);
19380 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19384 * Resizes the drag frame to the dimensions of the clicked object, positions
19385 * it over the object, and finally displays it
19386 * @method showFrame
19387 * @param {int} iPageX X click position
19388 * @param {int} iPageY Y click position
19391 showFrame: function(iPageX, iPageY) {
19392 var el = this.getEl();
19393 var dragEl = this.getDragEl();
19394 var s = dragEl.style;
19396 this._resizeProxy();
19398 if (this.centerFrame) {
19399 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19400 Math.round(parseInt(s.height, 10)/2) );
19403 this.setDragElPos(iPageX, iPageY);
19405 Roo.fly(dragEl).show();
19409 * The proxy is automatically resized to the dimensions of the linked
19410 * element when a drag is initiated, unless resizeFrame is set to false
19411 * @method _resizeProxy
19414 _resizeProxy: function() {
19415 if (this.resizeFrame) {
19416 var el = this.getEl();
19417 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19421 // overrides Roo.dd.DragDrop
19422 b4MouseDown: function(e) {
19423 var x = e.getPageX();
19424 var y = e.getPageY();
19425 this.autoOffset(x, y);
19426 this.setDragElPos(x, y);
19429 // overrides Roo.dd.DragDrop
19430 b4StartDrag: function(x, y) {
19431 // show the drag frame
19432 this.showFrame(x, y);
19435 // overrides Roo.dd.DragDrop
19436 b4EndDrag: function(e) {
19437 Roo.fly(this.getDragEl()).hide();
19440 // overrides Roo.dd.DragDrop
19441 // By default we try to move the element to the last location of the frame.
19442 // This is so that the default behavior mirrors that of Roo.dd.DD.
19443 endDrag: function(e) {
19445 var lel = this.getEl();
19446 var del = this.getDragEl();
19448 // Show the drag frame briefly so we can get its position
19449 del.style.visibility = "";
19452 // Hide the linked element before the move to get around a Safari
19454 lel.style.visibility = "hidden";
19455 Roo.dd.DDM.moveToEl(lel, del);
19456 del.style.visibility = "hidden";
19457 lel.style.visibility = "";
19462 beforeMove : function(){
19466 afterDrag : function(){
19470 toString: function() {
19471 return ("DDProxy " + this.id);
19477 * Ext JS Library 1.1.1
19478 * Copyright(c) 2006-2007, Ext JS, LLC.
19480 * Originally Released Under LGPL - original licence link has changed is not relivant.
19483 * <script type="text/javascript">
19487 * @class Roo.dd.DDTarget
19488 * A DragDrop implementation that does not move, but can be a drop
19489 * target. You would get the same result by simply omitting implementation
19490 * for the event callbacks, but this way we reduce the processing cost of the
19491 * event listener and the callbacks.
19492 * @extends Roo.dd.DragDrop
19494 * @param {String} id the id of the element that is a drop target
19495 * @param {String} sGroup the group of related DragDrop objects
19496 * @param {object} config an object containing configurable attributes
19497 * Valid properties for DDTarget in addition to those in
19501 Roo.dd.DDTarget = function(id, sGroup, config) {
19503 this.initTarget(id, sGroup, config);
19505 if (config.listeners || config.events) {
19506 Roo.dd.DragDrop.superclass.constructor.call(this, {
19507 listeners : config.listeners || {},
19508 events : config.events || {}
19513 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19514 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19515 toString: function() {
19516 return ("DDTarget " + this.id);
19521 * Ext JS Library 1.1.1
19522 * Copyright(c) 2006-2007, Ext JS, LLC.
19524 * Originally Released Under LGPL - original licence link has changed is not relivant.
19527 * <script type="text/javascript">
19532 * @class Roo.dd.ScrollManager
19533 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19534 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19537 Roo.dd.ScrollManager = function(){
19538 var ddm = Roo.dd.DragDropMgr;
19545 var onStop = function(e){
19550 var triggerRefresh = function(){
19551 if(ddm.dragCurrent){
19552 ddm.refreshCache(ddm.dragCurrent.groups);
19556 var doScroll = function(){
19557 if(ddm.dragCurrent){
19558 var dds = Roo.dd.ScrollManager;
19560 if(proc.el.scroll(proc.dir, dds.increment)){
19564 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19569 var clearProc = function(){
19571 clearInterval(proc.id);
19578 var startProc = function(el, dir){
19579 Roo.log('scroll startproc');
19583 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19586 var onFire = function(e, isDrop){
19588 if(isDrop || !ddm.dragCurrent){ return; }
19589 var dds = Roo.dd.ScrollManager;
19590 if(!dragEl || dragEl != ddm.dragCurrent){
19591 dragEl = ddm.dragCurrent;
19592 // refresh regions on drag start
19593 dds.refreshCache();
19596 var xy = Roo.lib.Event.getXY(e);
19597 var pt = new Roo.lib.Point(xy[0], xy[1]);
19598 for(var id in els){
19599 var el = els[id], r = el._region;
19600 if(r && r.contains(pt) && el.isScrollable()){
19601 if(r.bottom - pt.y <= dds.thresh){
19603 startProc(el, "down");
19606 }else if(r.right - pt.x <= dds.thresh){
19608 startProc(el, "left");
19611 }else if(pt.y - r.top <= dds.thresh){
19613 startProc(el, "up");
19616 }else if(pt.x - r.left <= dds.thresh){
19618 startProc(el, "right");
19627 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19628 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19632 * Registers new overflow element(s) to auto scroll
19633 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19635 register : function(el){
19636 if(el instanceof Array){
19637 for(var i = 0, len = el.length; i < len; i++) {
19638 this.register(el[i]);
19644 Roo.dd.ScrollManager.els = els;
19648 * Unregisters overflow element(s) so they are no longer scrolled
19649 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19651 unregister : function(el){
19652 if(el instanceof Array){
19653 for(var i = 0, len = el.length; i < len; i++) {
19654 this.unregister(el[i]);
19663 * The number of pixels from the edge of a container the pointer needs to be to
19664 * trigger scrolling (defaults to 25)
19670 * The number of pixels to scroll in each scroll increment (defaults to 50)
19676 * The frequency of scrolls in milliseconds (defaults to 500)
19682 * True to animate the scroll (defaults to true)
19688 * The animation duration in seconds -
19689 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19695 * Manually trigger a cache refresh.
19697 refreshCache : function(){
19698 for(var id in els){
19699 if(typeof els[id] == 'object'){ // for people extending the object prototype
19700 els[id]._region = els[id].getRegion();
19707 * Ext JS Library 1.1.1
19708 * Copyright(c) 2006-2007, Ext JS, LLC.
19710 * Originally Released Under LGPL - original licence link has changed is not relivant.
19713 * <script type="text/javascript">
19718 * @class Roo.dd.Registry
19719 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19720 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19723 Roo.dd.Registry = function(){
19726 var autoIdSeed = 0;
19728 var getId = function(el, autogen){
19729 if(typeof el == "string"){
19733 if(!id && autogen !== false){
19734 id = "roodd-" + (++autoIdSeed);
19742 * Register a drag drop element
19743 * @param {String|HTMLElement} element The id or DOM node to register
19744 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19745 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19746 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19747 * populated in the data object (if applicable):
19749 Value Description<br />
19750 --------- ------------------------------------------<br />
19751 handles Array of DOM nodes that trigger dragging<br />
19752 for the element being registered<br />
19753 isHandle True if the element passed in triggers<br />
19754 dragging itself, else false
19757 register : function(el, data){
19759 if(typeof el == "string"){
19760 el = document.getElementById(el);
19763 elements[getId(el)] = data;
19764 if(data.isHandle !== false){
19765 handles[data.ddel.id] = data;
19768 var hs = data.handles;
19769 for(var i = 0, len = hs.length; i < len; i++){
19770 handles[getId(hs[i])] = data;
19776 * Unregister a drag drop element
19777 * @param {String|HTMLElement} element The id or DOM node to unregister
19779 unregister : function(el){
19780 var id = getId(el, false);
19781 var data = elements[id];
19783 delete elements[id];
19785 var hs = data.handles;
19786 for(var i = 0, len = hs.length; i < len; i++){
19787 delete handles[getId(hs[i], false)];
19794 * Returns the handle registered for a DOM Node by id
19795 * @param {String|HTMLElement} id The DOM node or id to look up
19796 * @return {Object} handle The custom handle data
19798 getHandle : function(id){
19799 if(typeof id != "string"){ // must be element?
19802 return handles[id];
19806 * Returns the handle that is registered for the DOM node that is the target of the event
19807 * @param {Event} e The event
19808 * @return {Object} handle The custom handle data
19810 getHandleFromEvent : function(e){
19811 var t = Roo.lib.Event.getTarget(e);
19812 return t ? handles[t.id] : null;
19816 * Returns a custom data object that is registered for a DOM node by id
19817 * @param {String|HTMLElement} id The DOM node or id to look up
19818 * @return {Object} data The custom data
19820 getTarget : function(id){
19821 if(typeof id != "string"){ // must be element?
19824 return elements[id];
19828 * Returns a custom data object that is registered for the DOM node that is the target of the event
19829 * @param {Event} e The event
19830 * @return {Object} data The custom data
19832 getTargetFromEvent : function(e){
19833 var t = Roo.lib.Event.getTarget(e);
19834 return t ? elements[t.id] || handles[t.id] : null;
19839 * Ext JS Library 1.1.1
19840 * Copyright(c) 2006-2007, Ext JS, LLC.
19842 * Originally Released Under LGPL - original licence link has changed is not relivant.
19845 * <script type="text/javascript">
19850 * @class Roo.dd.StatusProxy
19851 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19852 * default drag proxy used by all Roo.dd components.
19854 * @param {Object} config
19856 Roo.dd.StatusProxy = function(config){
19857 Roo.apply(this, config);
19858 this.id = this.id || Roo.id();
19859 this.el = new Roo.Layer({
19861 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19862 {tag: "div", cls: "x-dd-drop-icon"},
19863 {tag: "div", cls: "x-dd-drag-ghost"}
19866 shadow: !config || config.shadow !== false
19868 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19869 this.dropStatus = this.dropNotAllowed;
19872 Roo.dd.StatusProxy.prototype = {
19874 * @cfg {String} dropAllowed
19875 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19877 dropAllowed : "x-dd-drop-ok",
19879 * @cfg {String} dropNotAllowed
19880 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19882 dropNotAllowed : "x-dd-drop-nodrop",
19885 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19886 * over the current target element.
19887 * @param {String} cssClass The css class for the new drop status indicator image
19889 setStatus : function(cssClass){
19890 cssClass = cssClass || this.dropNotAllowed;
19891 if(this.dropStatus != cssClass){
19892 this.el.replaceClass(this.dropStatus, cssClass);
19893 this.dropStatus = cssClass;
19898 * Resets the status indicator to the default dropNotAllowed value
19899 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19901 reset : function(clearGhost){
19902 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19903 this.dropStatus = this.dropNotAllowed;
19905 this.ghost.update("");
19910 * Updates the contents of the ghost element
19911 * @param {String} html The html that will replace the current innerHTML of the ghost element
19913 update : function(html){
19914 if(typeof html == "string"){
19915 this.ghost.update(html);
19917 this.ghost.update("");
19918 html.style.margin = "0";
19919 this.ghost.dom.appendChild(html);
19921 // ensure float = none set?? cant remember why though.
19922 var el = this.ghost.dom.firstChild;
19924 Roo.fly(el).setStyle('float', 'none');
19929 * Returns the underlying proxy {@link Roo.Layer}
19930 * @return {Roo.Layer} el
19932 getEl : function(){
19937 * Returns the ghost element
19938 * @return {Roo.Element} el
19940 getGhost : function(){
19946 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19948 hide : function(clear){
19956 * Stops the repair animation if it's currently running
19959 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19965 * Displays this proxy
19972 * Force the Layer to sync its shadow and shim positions to the element
19979 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19980 * invalid drop operation by the item being dragged.
19981 * @param {Array} xy The XY position of the element ([x, y])
19982 * @param {Function} callback The function to call after the repair is complete
19983 * @param {Object} scope The scope in which to execute the callback
19985 repair : function(xy, callback, scope){
19986 this.callback = callback;
19987 this.scope = scope;
19988 if(xy && this.animRepair !== false){
19989 this.el.addClass("x-dd-drag-repair");
19990 this.el.hideUnders(true);
19991 this.anim = this.el.shift({
19992 duration: this.repairDuration || .5,
19996 callback: this.afterRepair,
20000 this.afterRepair();
20005 afterRepair : function(){
20007 if(typeof this.callback == "function"){
20008 this.callback.call(this.scope || this);
20010 this.callback = null;
20015 * Ext JS Library 1.1.1
20016 * Copyright(c) 2006-2007, Ext JS, LLC.
20018 * Originally Released Under LGPL - original licence link has changed is not relivant.
20021 * <script type="text/javascript">
20025 * @class Roo.dd.DragSource
20026 * @extends Roo.dd.DDProxy
20027 * A simple class that provides the basic implementation needed to make any element draggable.
20029 * @param {String/HTMLElement/Element} el The container element
20030 * @param {Object} config
20032 Roo.dd.DragSource = function(el, config){
20033 this.el = Roo.get(el);
20034 this.dragData = {};
20036 Roo.apply(this, config);
20039 this.proxy = new Roo.dd.StatusProxy();
20042 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
20043 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
20045 this.dragging = false;
20048 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
20050 * @cfg {String} dropAllowed
20051 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20053 dropAllowed : "x-dd-drop-ok",
20055 * @cfg {String} dropNotAllowed
20056 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20058 dropNotAllowed : "x-dd-drop-nodrop",
20061 * Returns the data object associated with this drag source
20062 * @return {Object} data An object containing arbitrary data
20064 getDragData : function(e){
20065 return this.dragData;
20069 onDragEnter : function(e, id){
20070 var target = Roo.dd.DragDropMgr.getDDById(id);
20071 this.cachedTarget = target;
20072 if(this.beforeDragEnter(target, e, id) !== false){
20073 if(target.isNotifyTarget){
20074 var status = target.notifyEnter(this, e, this.dragData);
20075 this.proxy.setStatus(status);
20077 this.proxy.setStatus(this.dropAllowed);
20080 if(this.afterDragEnter){
20082 * An empty function by default, but provided so that you can perform a custom action
20083 * when the dragged item enters the drop target by providing an implementation.
20084 * @param {Roo.dd.DragDrop} target The drop target
20085 * @param {Event} e The event object
20086 * @param {String} id The id of the dragged element
20087 * @method afterDragEnter
20089 this.afterDragEnter(target, e, id);
20095 * An empty function by default, but provided so that you can perform a custom action
20096 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
20097 * @param {Roo.dd.DragDrop} target The drop target
20098 * @param {Event} e The event object
20099 * @param {String} id The id of the dragged element
20100 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20102 beforeDragEnter : function(target, e, id){
20107 alignElWithMouse: function() {
20108 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
20113 onDragOver : function(e, id){
20114 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20115 if(this.beforeDragOver(target, e, id) !== false){
20116 if(target.isNotifyTarget){
20117 var status = target.notifyOver(this, e, this.dragData);
20118 this.proxy.setStatus(status);
20121 if(this.afterDragOver){
20123 * An empty function by default, but provided so that you can perform a custom action
20124 * while the dragged item is over the drop target by providing an implementation.
20125 * @param {Roo.dd.DragDrop} target The drop target
20126 * @param {Event} e The event object
20127 * @param {String} id The id of the dragged element
20128 * @method afterDragOver
20130 this.afterDragOver(target, e, id);
20136 * An empty function by default, but provided so that you can perform a custom action
20137 * while the dragged item is over the drop target and optionally cancel the onDragOver.
20138 * @param {Roo.dd.DragDrop} target The drop target
20139 * @param {Event} e The event object
20140 * @param {String} id The id of the dragged element
20141 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20143 beforeDragOver : function(target, e, id){
20148 onDragOut : function(e, id){
20149 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20150 if(this.beforeDragOut(target, e, id) !== false){
20151 if(target.isNotifyTarget){
20152 target.notifyOut(this, e, this.dragData);
20154 this.proxy.reset();
20155 if(this.afterDragOut){
20157 * An empty function by default, but provided so that you can perform a custom action
20158 * after the dragged item is dragged out of the target without dropping.
20159 * @param {Roo.dd.DragDrop} target The drop target
20160 * @param {Event} e The event object
20161 * @param {String} id The id of the dragged element
20162 * @method afterDragOut
20164 this.afterDragOut(target, e, id);
20167 this.cachedTarget = null;
20171 * An empty function by default, but provided so that you can perform a custom action before the dragged
20172 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20173 * @param {Roo.dd.DragDrop} target The drop target
20174 * @param {Event} e The event object
20175 * @param {String} id The id of the dragged element
20176 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20178 beforeDragOut : function(target, e, id){
20183 onDragDrop : function(e, id){
20184 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20185 if(this.beforeDragDrop(target, e, id) !== false){
20186 if(target.isNotifyTarget){
20187 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20188 this.onValidDrop(target, e, id);
20190 this.onInvalidDrop(target, e, id);
20193 this.onValidDrop(target, e, id);
20196 if(this.afterDragDrop){
20198 * An empty function by default, but provided so that you can perform a custom action
20199 * after a valid drag drop has occurred by providing an implementation.
20200 * @param {Roo.dd.DragDrop} target The drop target
20201 * @param {Event} e The event object
20202 * @param {String} id The id of the dropped element
20203 * @method afterDragDrop
20205 this.afterDragDrop(target, e, id);
20208 delete this.cachedTarget;
20212 * An empty function by default, but provided so that you can perform a custom action before the dragged
20213 * item is dropped onto the target and optionally cancel the onDragDrop.
20214 * @param {Roo.dd.DragDrop} target The drop target
20215 * @param {Event} e The event object
20216 * @param {String} id The id of the dragged element
20217 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20219 beforeDragDrop : function(target, e, id){
20224 onValidDrop : function(target, e, id){
20226 if(this.afterValidDrop){
20228 * An empty function by default, but provided so that you can perform a custom action
20229 * after a valid drop has occurred by providing an implementation.
20230 * @param {Object} target The target DD
20231 * @param {Event} e The event object
20232 * @param {String} id The id of the dropped element
20233 * @method afterInvalidDrop
20235 this.afterValidDrop(target, e, id);
20240 getRepairXY : function(e, data){
20241 return this.el.getXY();
20245 onInvalidDrop : function(target, e, id){
20246 this.beforeInvalidDrop(target, e, id);
20247 if(this.cachedTarget){
20248 if(this.cachedTarget.isNotifyTarget){
20249 this.cachedTarget.notifyOut(this, e, this.dragData);
20251 this.cacheTarget = null;
20253 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20255 if(this.afterInvalidDrop){
20257 * An empty function by default, but provided so that you can perform a custom action
20258 * after an invalid drop has occurred by providing an implementation.
20259 * @param {Event} e The event object
20260 * @param {String} id The id of the dropped element
20261 * @method afterInvalidDrop
20263 this.afterInvalidDrop(e, id);
20268 afterRepair : function(){
20270 this.el.highlight(this.hlColor || "c3daf9");
20272 this.dragging = false;
20276 * An empty function by default, but provided so that you can perform a custom action after an invalid
20277 * drop has occurred.
20278 * @param {Roo.dd.DragDrop} target The drop target
20279 * @param {Event} e The event object
20280 * @param {String} id The id of the dragged element
20281 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20283 beforeInvalidDrop : function(target, e, id){
20288 handleMouseDown : function(e){
20289 if(this.dragging) {
20292 var data = this.getDragData(e);
20293 if(data && this.onBeforeDrag(data, e) !== false){
20294 this.dragData = data;
20296 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20301 * An empty function by default, but provided so that you can perform a custom action before the initial
20302 * drag event begins and optionally cancel it.
20303 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20304 * @param {Event} e The event object
20305 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20307 onBeforeDrag : function(data, e){
20312 * An empty function by default, but provided so that you can perform a custom action once the initial
20313 * drag event has begun. The drag cannot be canceled from this function.
20314 * @param {Number} x The x position of the click on the dragged object
20315 * @param {Number} y The y position of the click on the dragged object
20317 onStartDrag : Roo.emptyFn,
20319 // private - YUI override
20320 startDrag : function(x, y){
20321 this.proxy.reset();
20322 this.dragging = true;
20323 this.proxy.update("");
20324 this.onInitDrag(x, y);
20329 onInitDrag : function(x, y){
20330 var clone = this.el.dom.cloneNode(true);
20331 clone.id = Roo.id(); // prevent duplicate ids
20332 this.proxy.update(clone);
20333 this.onStartDrag(x, y);
20338 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20339 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20341 getProxy : function(){
20346 * Hides the drag source's {@link Roo.dd.StatusProxy}
20348 hideProxy : function(){
20350 this.proxy.reset(true);
20351 this.dragging = false;
20355 triggerCacheRefresh : function(){
20356 Roo.dd.DDM.refreshCache(this.groups);
20359 // private - override to prevent hiding
20360 b4EndDrag: function(e) {
20363 // private - override to prevent moving
20364 endDrag : function(e){
20365 this.onEndDrag(this.dragData, e);
20369 onEndDrag : function(data, e){
20372 // private - pin to cursor
20373 autoOffset : function(x, y) {
20374 this.setDelta(-12, -20);
20378 * Ext JS Library 1.1.1
20379 * Copyright(c) 2006-2007, Ext JS, LLC.
20381 * Originally Released Under LGPL - original licence link has changed is not relivant.
20384 * <script type="text/javascript">
20389 * @class Roo.dd.DropTarget
20390 * @extends Roo.dd.DDTarget
20391 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20392 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20394 * @param {String/HTMLElement/Element} el The container element
20395 * @param {Object} config
20397 Roo.dd.DropTarget = function(el, config){
20398 this.el = Roo.get(el);
20400 var listeners = false; ;
20401 if (config && config.listeners) {
20402 listeners= config.listeners;
20403 delete config.listeners;
20405 Roo.apply(this, config);
20407 if(this.containerScroll){
20408 Roo.dd.ScrollManager.register(this.el);
20412 * @scope Roo.dd.DropTarget
20417 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20418 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20419 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20421 * IMPORTANT : it should set this.overClass and this.dropAllowed
20423 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20424 * @param {Event} e The event
20425 * @param {Object} data An object containing arbitrary data supplied by the drag source
20431 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20432 * This method will be called on every mouse movement while the drag source is over the drop target.
20433 * This default implementation simply returns the dropAllowed config value.
20435 * IMPORTANT : it should set this.dropAllowed
20437 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20438 * @param {Event} e The event
20439 * @param {Object} data An object containing arbitrary data supplied by the drag source
20445 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20446 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20447 * overClass (if any) from the drop element.
20449 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20450 * @param {Event} e The event
20451 * @param {Object} data An object containing arbitrary data supplied by the drag source
20457 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20458 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20459 * implementation that does something to process the drop event and returns true so that the drag source's
20460 * repair action does not run.
20462 * IMPORTANT : it should set this.success
20464 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20465 * @param {Event} e The event
20466 * @param {Object} data An object containing arbitrary data supplied by the drag source
20472 Roo.dd.DropTarget.superclass.constructor.call( this,
20474 this.ddGroup || this.group,
20477 listeners : listeners || {}
20485 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20487 * @cfg {String} overClass
20488 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20491 * @cfg {String} ddGroup
20492 * The drag drop group to handle drop events for
20496 * @cfg {String} dropAllowed
20497 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20499 dropAllowed : "x-dd-drop-ok",
20501 * @cfg {String} dropNotAllowed
20502 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20504 dropNotAllowed : "x-dd-drop-nodrop",
20506 * @cfg {boolean} success
20507 * set this after drop listener..
20511 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20512 * if the drop point is valid for over/enter..
20519 isNotifyTarget : true,
20524 notifyEnter : function(dd, e, data)
20527 this.fireEvent('enter', dd, e, data);
20528 if(this.overClass){
20529 this.el.addClass(this.overClass);
20531 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20532 this.valid ? this.dropAllowed : this.dropNotAllowed
20539 notifyOver : function(dd, e, data)
20542 this.fireEvent('over', dd, e, data);
20543 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20544 this.valid ? this.dropAllowed : this.dropNotAllowed
20551 notifyOut : function(dd, e, data)
20553 this.fireEvent('out', dd, e, data);
20554 if(this.overClass){
20555 this.el.removeClass(this.overClass);
20562 notifyDrop : function(dd, e, data)
20564 this.success = false;
20565 this.fireEvent('drop', dd, e, data);
20566 return this.success;
20570 * Ext JS Library 1.1.1
20571 * Copyright(c) 2006-2007, Ext JS, LLC.
20573 * Originally Released Under LGPL - original licence link has changed is not relivant.
20576 * <script type="text/javascript">
20581 * @class Roo.dd.DragZone
20582 * @extends Roo.dd.DragSource
20583 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20584 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20586 * @param {String/HTMLElement/Element} el The container element
20587 * @param {Object} config
20589 Roo.dd.DragZone = function(el, config){
20590 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20591 if(this.containerScroll){
20592 Roo.dd.ScrollManager.register(this.el);
20596 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20598 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20599 * for auto scrolling during drag operations.
20602 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20603 * method after a failed drop (defaults to "c3daf9" - light blue)
20607 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20608 * for a valid target to drag based on the mouse down. Override this method
20609 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20610 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20611 * @param {EventObject} e The mouse down event
20612 * @return {Object} The dragData
20614 getDragData : function(e){
20615 return Roo.dd.Registry.getHandleFromEvent(e);
20619 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20620 * this.dragData.ddel
20621 * @param {Number} x The x position of the click on the dragged object
20622 * @param {Number} y The y position of the click on the dragged object
20623 * @return {Boolean} true to continue the drag, false to cancel
20625 onInitDrag : function(x, y){
20626 this.proxy.update(this.dragData.ddel.cloneNode(true));
20627 this.onStartDrag(x, y);
20632 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20634 afterRepair : function(){
20636 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20638 this.dragging = false;
20642 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20643 * the XY of this.dragData.ddel
20644 * @param {EventObject} e The mouse up event
20645 * @return {Array} The xy location (e.g. [100, 200])
20647 getRepairXY : function(e){
20648 return Roo.Element.fly(this.dragData.ddel).getXY();
20652 * Ext JS Library 1.1.1
20653 * Copyright(c) 2006-2007, Ext JS, LLC.
20655 * Originally Released Under LGPL - original licence link has changed is not relivant.
20658 * <script type="text/javascript">
20661 * @class Roo.dd.DropZone
20662 * @extends Roo.dd.DropTarget
20663 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20664 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20666 * @param {String/HTMLElement/Element} el The container element
20667 * @param {Object} config
20669 Roo.dd.DropZone = function(el, config){
20670 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20673 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20675 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20676 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20677 * provide your own custom lookup.
20678 * @param {Event} e The event
20679 * @return {Object} data The custom data
20681 getTargetFromEvent : function(e){
20682 return Roo.dd.Registry.getTargetFromEvent(e);
20686 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20687 * that it has registered. This method has no default implementation and should be overridden to provide
20688 * node-specific processing if necessary.
20689 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20690 * {@link #getTargetFromEvent} for this node)
20691 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20692 * @param {Event} e The event
20693 * @param {Object} data An object containing arbitrary data supplied by the drag source
20695 onNodeEnter : function(n, dd, e, data){
20700 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20701 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20702 * overridden to provide the proper feedback.
20703 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20704 * {@link #getTargetFromEvent} for this node)
20705 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20706 * @param {Event} e The event
20707 * @param {Object} data An object containing arbitrary data supplied by the drag source
20708 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20709 * underlying {@link Roo.dd.StatusProxy} can be updated
20711 onNodeOver : function(n, dd, e, data){
20712 return this.dropAllowed;
20716 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20717 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20718 * node-specific processing if necessary.
20719 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20720 * {@link #getTargetFromEvent} for this node)
20721 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20722 * @param {Event} e The event
20723 * @param {Object} data An object containing arbitrary data supplied by the drag source
20725 onNodeOut : function(n, dd, e, data){
20730 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20731 * the drop node. The default implementation returns false, so it should be overridden to provide the
20732 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20733 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20734 * {@link #getTargetFromEvent} for this node)
20735 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20736 * @param {Event} e The event
20737 * @param {Object} data An object containing arbitrary data supplied by the drag source
20738 * @return {Boolean} True if the drop was valid, else false
20740 onNodeDrop : function(n, dd, e, data){
20745 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20746 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20747 * it should be overridden to provide the proper feedback if necessary.
20748 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20749 * @param {Event} e The event
20750 * @param {Object} data An object containing arbitrary data supplied by the drag source
20751 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20752 * underlying {@link Roo.dd.StatusProxy} can be updated
20754 onContainerOver : function(dd, e, data){
20755 return this.dropNotAllowed;
20759 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20760 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20761 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20762 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20763 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20764 * @param {Event} e The event
20765 * @param {Object} data An object containing arbitrary data supplied by the drag source
20766 * @return {Boolean} True if the drop was valid, else false
20768 onContainerDrop : function(dd, e, data){
20773 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20774 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20775 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20776 * you should override this method and provide a custom implementation.
20777 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20778 * @param {Event} e The event
20779 * @param {Object} data An object containing arbitrary data supplied by the drag source
20780 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20781 * underlying {@link Roo.dd.StatusProxy} can be updated
20783 notifyEnter : function(dd, e, data){
20784 return this.dropNotAllowed;
20788 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20789 * This method will be called on every mouse movement while the drag source is over the drop zone.
20790 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20791 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20792 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20793 * registered node, it will call {@link #onContainerOver}.
20794 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20795 * @param {Event} e The event
20796 * @param {Object} data An object containing arbitrary data supplied by the drag source
20797 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20798 * underlying {@link Roo.dd.StatusProxy} can be updated
20800 notifyOver : function(dd, e, data){
20801 var n = this.getTargetFromEvent(e);
20802 if(!n){ // not over valid drop target
20803 if(this.lastOverNode){
20804 this.onNodeOut(this.lastOverNode, dd, e, data);
20805 this.lastOverNode = null;
20807 return this.onContainerOver(dd, e, data);
20809 if(this.lastOverNode != n){
20810 if(this.lastOverNode){
20811 this.onNodeOut(this.lastOverNode, dd, e, data);
20813 this.onNodeEnter(n, dd, e, data);
20814 this.lastOverNode = n;
20816 return this.onNodeOver(n, dd, e, data);
20820 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20821 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20822 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20823 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20824 * @param {Event} e The event
20825 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20827 notifyOut : function(dd, e, data){
20828 if(this.lastOverNode){
20829 this.onNodeOut(this.lastOverNode, dd, e, data);
20830 this.lastOverNode = null;
20835 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20836 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20837 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20838 * otherwise it will call {@link #onContainerDrop}.
20839 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20840 * @param {Event} e The event
20841 * @param {Object} data An object containing arbitrary data supplied by the drag source
20842 * @return {Boolean} True if the drop was valid, else false
20844 notifyDrop : function(dd, e, data){
20845 if(this.lastOverNode){
20846 this.onNodeOut(this.lastOverNode, dd, e, data);
20847 this.lastOverNode = null;
20849 var n = this.getTargetFromEvent(e);
20851 this.onNodeDrop(n, dd, e, data) :
20852 this.onContainerDrop(dd, e, data);
20856 triggerCacheRefresh : function(){
20857 Roo.dd.DDM.refreshCache(this.groups);
20861 * Ext JS Library 1.1.1
20862 * Copyright(c) 2006-2007, Ext JS, LLC.
20864 * Originally Released Under LGPL - original licence link has changed is not relivant.
20867 * <script type="text/javascript">
20872 * @class Roo.data.SortTypes
20874 * Defines the default sorting (casting?) comparison functions used when sorting data.
20876 Roo.data.SortTypes = {
20878 * Default sort that does nothing
20879 * @param {Mixed} s The value being converted
20880 * @return {Mixed} The comparison value
20882 none : function(s){
20887 * The regular expression used to strip tags
20891 stripTagsRE : /<\/?[^>]+>/gi,
20894 * Strips all HTML tags to sort on text only
20895 * @param {Mixed} s The value being converted
20896 * @return {String} The comparison value
20898 asText : function(s){
20899 return String(s).replace(this.stripTagsRE, "");
20903 * Strips all HTML tags to sort on text only - Case insensitive
20904 * @param {Mixed} s The value being converted
20905 * @return {String} The comparison value
20907 asUCText : function(s){
20908 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20912 * Case insensitive string
20913 * @param {Mixed} s The value being converted
20914 * @return {String} The comparison value
20916 asUCString : function(s) {
20917 return String(s).toUpperCase();
20922 * @param {Mixed} s The value being converted
20923 * @return {Number} The comparison value
20925 asDate : function(s) {
20929 if(s instanceof Date){
20930 return s.getTime();
20932 return Date.parse(String(s));
20937 * @param {Mixed} s The value being converted
20938 * @return {Float} The comparison value
20940 asFloat : function(s) {
20941 var val = parseFloat(String(s).replace(/,/g, ""));
20950 * @param {Mixed} s The value being converted
20951 * @return {Number} The comparison value
20953 asInt : function(s) {
20954 var val = parseInt(String(s).replace(/,/g, ""));
20962 * Ext JS Library 1.1.1
20963 * Copyright(c) 2006-2007, Ext JS, LLC.
20965 * Originally Released Under LGPL - original licence link has changed is not relivant.
20968 * <script type="text/javascript">
20972 * @class Roo.data.Record
20973 * Instances of this class encapsulate both record <em>definition</em> information, and record
20974 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20975 * to access Records cached in an {@link Roo.data.Store} object.<br>
20977 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20978 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20981 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20983 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20984 * {@link #create}. The parameters are the same.
20985 * @param {Array} data An associative Array of data values keyed by the field name.
20986 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20987 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20988 * not specified an integer id is generated.
20990 Roo.data.Record = function(data, id){
20991 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20996 * Generate a constructor for a specific record layout.
20997 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20998 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20999 * Each field definition object may contain the following properties: <ul>
21000 * <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,
21001 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
21002 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
21003 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
21004 * is being used, then this is a string containing the javascript expression to reference the data relative to
21005 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
21006 * to the data item relative to the record element. If the mapping expression is the same as the field name,
21007 * this may be omitted.</p></li>
21008 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
21009 * <ul><li>auto (Default, implies no conversion)</li>
21014 * <li>date</li></ul></p></li>
21015 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
21016 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
21017 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
21018 * by the Reader into an object that will be stored in the Record. It is passed the
21019 * following parameters:<ul>
21020 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
21022 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
21024 * <br>usage:<br><pre><code>
21025 var TopicRecord = Roo.data.Record.create(
21026 {name: 'title', mapping: 'topic_title'},
21027 {name: 'author', mapping: 'username'},
21028 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
21029 {name: 'lastPost', mapping: 'post_time', type: 'date'},
21030 {name: 'lastPoster', mapping: 'user2'},
21031 {name: 'excerpt', mapping: 'post_text'}
21034 var myNewRecord = new TopicRecord({
21035 title: 'Do my job please',
21038 lastPost: new Date(),
21039 lastPoster: 'Animal',
21040 excerpt: 'No way dude!'
21042 myStore.add(myNewRecord);
21047 Roo.data.Record.create = function(o){
21048 var f = function(){
21049 f.superclass.constructor.apply(this, arguments);
21051 Roo.extend(f, Roo.data.Record);
21052 var p = f.prototype;
21053 p.fields = new Roo.util.MixedCollection(false, function(field){
21056 for(var i = 0, len = o.length; i < len; i++){
21057 p.fields.add(new Roo.data.Field(o[i]));
21059 f.getField = function(name){
21060 return p.fields.get(name);
21065 Roo.data.Record.AUTO_ID = 1000;
21066 Roo.data.Record.EDIT = 'edit';
21067 Roo.data.Record.REJECT = 'reject';
21068 Roo.data.Record.COMMIT = 'commit';
21070 Roo.data.Record.prototype = {
21072 * Readonly flag - true if this record has been modified.
21081 join : function(store){
21082 this.store = store;
21086 * Set the named field to the specified value.
21087 * @param {String} name The name of the field to set.
21088 * @param {Object} value The value to set the field to.
21090 set : function(name, value){
21091 if(this.data[name] == value){
21095 if(!this.modified){
21096 this.modified = {};
21098 if(typeof this.modified[name] == 'undefined'){
21099 this.modified[name] = this.data[name];
21101 this.data[name] = value;
21102 if(!this.editing && this.store){
21103 this.store.afterEdit(this);
21108 * Get the value of the named field.
21109 * @param {String} name The name of the field to get the value of.
21110 * @return {Object} The value of the field.
21112 get : function(name){
21113 return this.data[name];
21117 beginEdit : function(){
21118 this.editing = true;
21119 this.modified = {};
21123 cancelEdit : function(){
21124 this.editing = false;
21125 delete this.modified;
21129 endEdit : function(){
21130 this.editing = false;
21131 if(this.dirty && this.store){
21132 this.store.afterEdit(this);
21137 * Usually called by the {@link Roo.data.Store} which owns the Record.
21138 * Rejects all changes made to the Record since either creation, or the last commit operation.
21139 * Modified fields are reverted to their original values.
21141 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21142 * of reject operations.
21144 reject : function(){
21145 var m = this.modified;
21147 if(typeof m[n] != "function"){
21148 this.data[n] = m[n];
21151 this.dirty = false;
21152 delete this.modified;
21153 this.editing = false;
21155 this.store.afterReject(this);
21160 * Usually called by the {@link Roo.data.Store} which owns the Record.
21161 * Commits all changes made to the Record since either creation, or the last commit operation.
21163 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21164 * of commit operations.
21166 commit : function(){
21167 this.dirty = false;
21168 delete this.modified;
21169 this.editing = false;
21171 this.store.afterCommit(this);
21176 hasError : function(){
21177 return this.error != null;
21181 clearError : function(){
21186 * Creates a copy of this record.
21187 * @param {String} id (optional) A new record id if you don't want to use this record's id
21190 copy : function(newId) {
21191 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21195 * Ext JS Library 1.1.1
21196 * Copyright(c) 2006-2007, Ext JS, LLC.
21198 * Originally Released Under LGPL - original licence link has changed is not relivant.
21201 * <script type="text/javascript">
21207 * @class Roo.data.Store
21208 * @extends Roo.util.Observable
21209 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21210 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21212 * 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
21213 * has no knowledge of the format of the data returned by the Proxy.<br>
21215 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21216 * instances from the data object. These records are cached and made available through accessor functions.
21218 * Creates a new Store.
21219 * @param {Object} config A config object containing the objects needed for the Store to access data,
21220 * and read the data into Records.
21222 Roo.data.Store = function(config){
21223 this.data = new Roo.util.MixedCollection(false);
21224 this.data.getKey = function(o){
21227 this.baseParams = {};
21229 this.paramNames = {
21234 "multisort" : "_multisort"
21237 if(config && config.data){
21238 this.inlineData = config.data;
21239 delete config.data;
21242 Roo.apply(this, config);
21244 if(this.reader){ // reader passed
21245 this.reader = Roo.factory(this.reader, Roo.data);
21246 this.reader.xmodule = this.xmodule || false;
21247 if(!this.recordType){
21248 this.recordType = this.reader.recordType;
21250 if(this.reader.onMetaChange){
21251 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21255 if(this.recordType){
21256 this.fields = this.recordType.prototype.fields;
21258 this.modified = [];
21262 * @event datachanged
21263 * Fires when the data cache has changed, and a widget which is using this Store
21264 * as a Record cache should refresh its view.
21265 * @param {Store} this
21267 datachanged : true,
21269 * @event metachange
21270 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21271 * @param {Store} this
21272 * @param {Object} meta The JSON metadata
21277 * Fires when Records have been added to the Store
21278 * @param {Store} this
21279 * @param {Roo.data.Record[]} records The array of Records added
21280 * @param {Number} index The index at which the record(s) were added
21285 * Fires when a Record has been removed from the Store
21286 * @param {Store} this
21287 * @param {Roo.data.Record} record The Record that was removed
21288 * @param {Number} index The index at which the record was removed
21293 * Fires when a Record has been updated
21294 * @param {Store} this
21295 * @param {Roo.data.Record} record The Record that was updated
21296 * @param {String} operation The update operation being performed. Value may be one of:
21298 Roo.data.Record.EDIT
21299 Roo.data.Record.REJECT
21300 Roo.data.Record.COMMIT
21306 * Fires when the data cache has been cleared.
21307 * @param {Store} this
21311 * @event beforeload
21312 * Fires before a request is made for a new data object. If the beforeload handler returns false
21313 * the load action will be canceled.
21314 * @param {Store} this
21315 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21319 * @event beforeloadadd
21320 * Fires after a new set of Records has been loaded.
21321 * @param {Store} this
21322 * @param {Roo.data.Record[]} records The Records that were loaded
21323 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21325 beforeloadadd : true,
21328 * Fires after a new set of Records has been loaded, before they are added to the store.
21329 * @param {Store} this
21330 * @param {Roo.data.Record[]} records The Records that were loaded
21331 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21332 * @params {Object} return from reader
21336 * @event loadexception
21337 * Fires if an exception occurs in the Proxy during loading.
21338 * Called with the signature of the Proxy's "loadexception" event.
21339 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21342 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21343 * @param {Object} load options
21344 * @param {Object} jsonData from your request (normally this contains the Exception)
21346 loadexception : true
21350 this.proxy = Roo.factory(this.proxy, Roo.data);
21351 this.proxy.xmodule = this.xmodule || false;
21352 this.relayEvents(this.proxy, ["loadexception"]);
21354 this.sortToggle = {};
21355 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21357 Roo.data.Store.superclass.constructor.call(this);
21359 if(this.inlineData){
21360 this.loadData(this.inlineData);
21361 delete this.inlineData;
21365 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21367 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21368 * without a remote query - used by combo/forms at present.
21372 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21375 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21378 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21379 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21382 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21383 * on any HTTP request
21386 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21389 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21393 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21394 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21396 remoteSort : false,
21399 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21400 * loaded or when a record is removed. (defaults to false).
21402 pruneModifiedRecords : false,
21405 lastOptions : null,
21408 * Add Records to the Store and fires the add event.
21409 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21411 add : function(records){
21412 records = [].concat(records);
21413 for(var i = 0, len = records.length; i < len; i++){
21414 records[i].join(this);
21416 var index = this.data.length;
21417 this.data.addAll(records);
21418 this.fireEvent("add", this, records, index);
21422 * Remove a Record from the Store and fires the remove event.
21423 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21425 remove : function(record){
21426 var index = this.data.indexOf(record);
21427 this.data.removeAt(index);
21428 if(this.pruneModifiedRecords){
21429 this.modified.remove(record);
21431 this.fireEvent("remove", this, record, index);
21435 * Remove all Records from the Store and fires the clear event.
21437 removeAll : function(){
21439 if(this.pruneModifiedRecords){
21440 this.modified = [];
21442 this.fireEvent("clear", this);
21446 * Inserts Records to the Store at the given index and fires the add event.
21447 * @param {Number} index The start index at which to insert the passed Records.
21448 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21450 insert : function(index, records){
21451 records = [].concat(records);
21452 for(var i = 0, len = records.length; i < len; i++){
21453 this.data.insert(index, records[i]);
21454 records[i].join(this);
21456 this.fireEvent("add", this, records, index);
21460 * Get the index within the cache of the passed Record.
21461 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21462 * @return {Number} The index of the passed Record. Returns -1 if not found.
21464 indexOf : function(record){
21465 return this.data.indexOf(record);
21469 * Get the index within the cache of the Record with the passed id.
21470 * @param {String} id The id of the Record to find.
21471 * @return {Number} The index of the Record. Returns -1 if not found.
21473 indexOfId : function(id){
21474 return this.data.indexOfKey(id);
21478 * Get the Record with the specified id.
21479 * @param {String} id The id of the Record to find.
21480 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21482 getById : function(id){
21483 return this.data.key(id);
21487 * Get the Record at the specified index.
21488 * @param {Number} index The index of the Record to find.
21489 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21491 getAt : function(index){
21492 return this.data.itemAt(index);
21496 * Returns a range of Records between specified indices.
21497 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21498 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21499 * @return {Roo.data.Record[]} An array of Records
21501 getRange : function(start, end){
21502 return this.data.getRange(start, end);
21506 storeOptions : function(o){
21507 o = Roo.apply({}, o);
21510 this.lastOptions = o;
21514 * Loads the Record cache from the configured Proxy using the configured Reader.
21516 * If using remote paging, then the first load call must specify the <em>start</em>
21517 * and <em>limit</em> properties in the options.params property to establish the initial
21518 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21520 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21521 * and this call will return before the new data has been loaded. Perform any post-processing
21522 * in a callback function, or in a "load" event handler.</strong>
21524 * @param {Object} options An object containing properties which control loading options:<ul>
21525 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21526 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21527 * passed the following arguments:<ul>
21528 * <li>r : Roo.data.Record[]</li>
21529 * <li>options: Options object from the load call</li>
21530 * <li>success: Boolean success indicator</li></ul></li>
21531 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21532 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21535 load : function(options){
21536 options = options || {};
21537 if(this.fireEvent("beforeload", this, options) !== false){
21538 this.storeOptions(options);
21539 var p = Roo.apply(options.params || {}, this.baseParams);
21540 // if meta was not loaded from remote source.. try requesting it.
21541 if (!this.reader.metaFromRemote) {
21542 p._requestMeta = 1;
21544 if(this.sortInfo && this.remoteSort){
21545 var pn = this.paramNames;
21546 p[pn["sort"]] = this.sortInfo.field;
21547 p[pn["dir"]] = this.sortInfo.direction;
21549 if (this.multiSort) {
21550 var pn = this.paramNames;
21551 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21554 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21559 * Reloads the Record cache from the configured Proxy using the configured Reader and
21560 * the options from the last load operation performed.
21561 * @param {Object} options (optional) An object containing properties which may override the options
21562 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21563 * the most recently used options are reused).
21565 reload : function(options){
21566 this.load(Roo.applyIf(options||{}, this.lastOptions));
21570 // Called as a callback by the Reader during a load operation.
21571 loadRecords : function(o, options, success){
21572 if(!o || success === false){
21573 if(success !== false){
21574 this.fireEvent("load", this, [], options, o);
21576 if(options.callback){
21577 options.callback.call(options.scope || this, [], options, false);
21581 // if data returned failure - throw an exception.
21582 if (o.success === false) {
21583 // show a message if no listener is registered.
21584 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21585 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21587 // loadmask wil be hooked into this..
21588 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21591 var r = o.records, t = o.totalRecords || r.length;
21593 this.fireEvent("beforeloadadd", this, r, options, o);
21595 if(!options || options.add !== true){
21596 if(this.pruneModifiedRecords){
21597 this.modified = [];
21599 for(var i = 0, len = r.length; i < len; i++){
21603 this.data = this.snapshot;
21604 delete this.snapshot;
21607 this.data.addAll(r);
21608 this.totalLength = t;
21610 this.fireEvent("datachanged", this);
21612 this.totalLength = Math.max(t, this.data.length+r.length);
21615 this.fireEvent("load", this, r, options, o);
21616 if(options.callback){
21617 options.callback.call(options.scope || this, r, options, true);
21623 * Loads data from a passed data block. A Reader which understands the format of the data
21624 * must have been configured in the constructor.
21625 * @param {Object} data The data block from which to read the Records. The format of the data expected
21626 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21627 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21629 loadData : function(o, append){
21630 var r = this.reader.readRecords(o);
21631 this.loadRecords(r, {add: append}, true);
21635 * Gets the number of cached records.
21637 * <em>If using paging, this may not be the total size of the dataset. If the data object
21638 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21639 * the data set size</em>
21641 getCount : function(){
21642 return this.data.length || 0;
21646 * Gets the total number of records in the dataset as returned by the server.
21648 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21649 * the dataset size</em>
21651 getTotalCount : function(){
21652 return this.totalLength || 0;
21656 * Returns the sort state of the Store as an object with two properties:
21658 field {String} The name of the field by which the Records are sorted
21659 direction {String} The sort order, "ASC" or "DESC"
21662 getSortState : function(){
21663 return this.sortInfo;
21667 applySort : function(){
21668 if(this.sortInfo && !this.remoteSort){
21669 var s = this.sortInfo, f = s.field;
21670 var st = this.fields.get(f).sortType;
21671 var fn = function(r1, r2){
21672 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21673 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21675 this.data.sort(s.direction, fn);
21676 if(this.snapshot && this.snapshot != this.data){
21677 this.snapshot.sort(s.direction, fn);
21683 * Sets the default sort column and order to be used by the next load operation.
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 setDefaultSort : function(field, dir){
21688 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21692 * Sort the Records.
21693 * If remote sorting is used, the sort is performed on the server, and the cache is
21694 * reloaded. If local sorting is used, the cache is sorted internally.
21695 * @param {String} fieldName The name of the field to sort by.
21696 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21698 sort : function(fieldName, dir){
21699 var f = this.fields.get(fieldName);
21701 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21703 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21704 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21709 this.sortToggle[f.name] = dir;
21710 this.sortInfo = {field: f.name, direction: dir};
21711 if(!this.remoteSort){
21713 this.fireEvent("datachanged", this);
21715 this.load(this.lastOptions);
21720 * Calls the specified function for each of the Records in the cache.
21721 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21722 * Returning <em>false</em> aborts and exits the iteration.
21723 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21725 each : function(fn, scope){
21726 this.data.each(fn, scope);
21730 * Gets all records modified since the last commit. Modified records are persisted across load operations
21731 * (e.g., during paging).
21732 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21734 getModifiedRecords : function(){
21735 return this.modified;
21739 createFilterFn : function(property, value, anyMatch){
21740 if(!value.exec){ // not a regex
21741 value = String(value);
21742 if(value.length == 0){
21745 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21747 return function(r){
21748 return value.test(r.data[property]);
21753 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21754 * @param {String} property A field on your records
21755 * @param {Number} start The record index to start at (defaults to 0)
21756 * @param {Number} end The last record index to include (defaults to length - 1)
21757 * @return {Number} The sum
21759 sum : function(property, start, end){
21760 var rs = this.data.items, v = 0;
21761 start = start || 0;
21762 end = (end || end === 0) ? end : rs.length-1;
21764 for(var i = start; i <= end; i++){
21765 v += (rs[i].data[property] || 0);
21771 * Filter the records by a specified property.
21772 * @param {String} field A field on your records
21773 * @param {String/RegExp} value Either a string that the field
21774 * should start with or a RegExp to test against the field
21775 * @param {Boolean} anyMatch True to match any part not just the beginning
21777 filter : function(property, value, anyMatch){
21778 var fn = this.createFilterFn(property, value, anyMatch);
21779 return fn ? this.filterBy(fn) : this.clearFilter();
21783 * Filter by a function. The specified function will be called with each
21784 * record in this data source. If the function returns true the record is included,
21785 * otherwise it is filtered.
21786 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21787 * @param {Object} scope (optional) The scope of the function (defaults to this)
21789 filterBy : function(fn, scope){
21790 this.snapshot = this.snapshot || this.data;
21791 this.data = this.queryBy(fn, scope||this);
21792 this.fireEvent("datachanged", this);
21796 * Query the records by a specified property.
21797 * @param {String} field A field on your records
21798 * @param {String/RegExp} value Either a string that the field
21799 * should start with or a RegExp to test against the field
21800 * @param {Boolean} anyMatch True to match any part not just the beginning
21801 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21803 query : function(property, value, anyMatch){
21804 var fn = this.createFilterFn(property, value, anyMatch);
21805 return fn ? this.queryBy(fn) : this.data.clone();
21809 * Query by a function. The specified function will be called with each
21810 * record in this data source. If the function returns true the record is included
21812 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21813 * @param {Object} scope (optional) The scope of the function (defaults to this)
21814 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21816 queryBy : function(fn, scope){
21817 var data = this.snapshot || this.data;
21818 return data.filterBy(fn, scope||this);
21822 * Collects unique values for a particular dataIndex from this store.
21823 * @param {String} dataIndex The property to collect
21824 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21825 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21826 * @return {Array} An array of the unique values
21828 collect : function(dataIndex, allowNull, bypassFilter){
21829 var d = (bypassFilter === true && this.snapshot) ?
21830 this.snapshot.items : this.data.items;
21831 var v, sv, r = [], l = {};
21832 for(var i = 0, len = d.length; i < len; i++){
21833 v = d[i].data[dataIndex];
21835 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21844 * Revert to a view of the Record cache with no filtering applied.
21845 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21847 clearFilter : function(suppressEvent){
21848 if(this.snapshot && this.snapshot != this.data){
21849 this.data = this.snapshot;
21850 delete this.snapshot;
21851 if(suppressEvent !== true){
21852 this.fireEvent("datachanged", this);
21858 afterEdit : function(record){
21859 if(this.modified.indexOf(record) == -1){
21860 this.modified.push(record);
21862 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21866 afterReject : function(record){
21867 this.modified.remove(record);
21868 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21872 afterCommit : function(record){
21873 this.modified.remove(record);
21874 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21878 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21879 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21881 commitChanges : function(){
21882 var m = this.modified.slice(0);
21883 this.modified = [];
21884 for(var i = 0, len = m.length; i < len; i++){
21890 * Cancel outstanding changes on all changed records.
21892 rejectChanges : function(){
21893 var m = this.modified.slice(0);
21894 this.modified = [];
21895 for(var i = 0, len = m.length; i < len; i++){
21900 onMetaChange : function(meta, rtype, o){
21901 this.recordType = rtype;
21902 this.fields = rtype.prototype.fields;
21903 delete this.snapshot;
21904 this.sortInfo = meta.sortInfo || this.sortInfo;
21905 this.modified = [];
21906 this.fireEvent('metachange', this, this.reader.meta);
21909 moveIndex : function(data, type)
21911 var index = this.indexOf(data);
21913 var newIndex = index + type;
21917 this.insert(newIndex, data);
21922 * Ext JS Library 1.1.1
21923 * Copyright(c) 2006-2007, Ext JS, LLC.
21925 * Originally Released Under LGPL - original licence link has changed is not relivant.
21928 * <script type="text/javascript">
21932 * @class Roo.data.SimpleStore
21933 * @extends Roo.data.Store
21934 * Small helper class to make creating Stores from Array data easier.
21935 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21936 * @cfg {Array} fields An array of field definition objects, or field name strings.
21937 * @cfg {Array} data The multi-dimensional array of data
21939 * @param {Object} config
21941 Roo.data.SimpleStore = function(config){
21942 Roo.data.SimpleStore.superclass.constructor.call(this, {
21944 reader: new Roo.data.ArrayReader({
21947 Roo.data.Record.create(config.fields)
21949 proxy : new Roo.data.MemoryProxy(config.data)
21953 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21955 * Ext JS Library 1.1.1
21956 * Copyright(c) 2006-2007, Ext JS, LLC.
21958 * Originally Released Under LGPL - original licence link has changed is not relivant.
21961 * <script type="text/javascript">
21966 * @extends Roo.data.Store
21967 * @class Roo.data.JsonStore
21968 * Small helper class to make creating Stores for JSON data easier. <br/>
21970 var store = new Roo.data.JsonStore({
21971 url: 'get-images.php',
21973 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21976 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21977 * JsonReader and HttpProxy (unless inline data is provided).</b>
21978 * @cfg {Array} fields An array of field definition objects, or field name strings.
21980 * @param {Object} config
21982 Roo.data.JsonStore = function(c){
21983 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21984 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21985 reader: new Roo.data.JsonReader(c, c.fields)
21988 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21990 * Ext JS Library 1.1.1
21991 * Copyright(c) 2006-2007, Ext JS, LLC.
21993 * Originally Released Under LGPL - original licence link has changed is not relivant.
21996 * <script type="text/javascript">
22000 Roo.data.Field = function(config){
22001 if(typeof config == "string"){
22002 config = {name: config};
22004 Roo.apply(this, config);
22007 this.type = "auto";
22010 var st = Roo.data.SortTypes;
22011 // named sortTypes are supported, here we look them up
22012 if(typeof this.sortType == "string"){
22013 this.sortType = st[this.sortType];
22016 // set default sortType for strings and dates
22017 if(!this.sortType){
22020 this.sortType = st.asUCString;
22023 this.sortType = st.asDate;
22026 this.sortType = st.none;
22031 var stripRe = /[\$,%]/g;
22033 // prebuilt conversion function for this field, instead of
22034 // switching every time we're reading a value
22036 var cv, dateFormat = this.dateFormat;
22041 cv = function(v){ return v; };
22044 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
22048 return v !== undefined && v !== null && v !== '' ?
22049 parseInt(String(v).replace(stripRe, ""), 10) : '';
22054 return v !== undefined && v !== null && v !== '' ?
22055 parseFloat(String(v).replace(stripRe, ""), 10) : '';
22060 cv = function(v){ return v === true || v === "true" || v == 1; };
22067 if(v instanceof Date){
22071 if(dateFormat == "timestamp"){
22072 return new Date(v*1000);
22074 return Date.parseDate(v, dateFormat);
22076 var parsed = Date.parse(v);
22077 return parsed ? new Date(parsed) : null;
22086 Roo.data.Field.prototype = {
22094 * Ext JS Library 1.1.1
22095 * Copyright(c) 2006-2007, Ext JS, LLC.
22097 * Originally Released Under LGPL - original licence link has changed is not relivant.
22100 * <script type="text/javascript">
22103 // Base class for reading structured data from a data source. This class is intended to be
22104 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
22107 * @class Roo.data.DataReader
22108 * Base class for reading structured data from a data source. This class is intended to be
22109 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
22112 Roo.data.DataReader = function(meta, recordType){
22116 this.recordType = recordType instanceof Array ?
22117 Roo.data.Record.create(recordType) : recordType;
22120 Roo.data.DataReader.prototype = {
22122 * Create an empty record
22123 * @param {Object} data (optional) - overlay some values
22124 * @return {Roo.data.Record} record created.
22126 newRow : function(d) {
22128 this.recordType.prototype.fields.each(function(c) {
22130 case 'int' : da[c.name] = 0; break;
22131 case 'date' : da[c.name] = new Date(); break;
22132 case 'float' : da[c.name] = 0.0; break;
22133 case 'boolean' : da[c.name] = false; break;
22134 default : da[c.name] = ""; break;
22138 return new this.recordType(Roo.apply(da, d));
22143 * Ext JS Library 1.1.1
22144 * Copyright(c) 2006-2007, Ext JS, LLC.
22146 * Originally Released Under LGPL - original licence link has changed is not relivant.
22149 * <script type="text/javascript">
22153 * @class Roo.data.DataProxy
22154 * @extends Roo.data.Observable
22155 * This class is an abstract base class for implementations which provide retrieval of
22156 * unformatted data objects.<br>
22158 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
22159 * (of the appropriate type which knows how to parse the data object) to provide a block of
22160 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
22162 * Custom implementations must implement the load method as described in
22163 * {@link Roo.data.HttpProxy#load}.
22165 Roo.data.DataProxy = function(){
22168 * @event beforeload
22169 * Fires before a network request is made to retrieve a data object.
22170 * @param {Object} This DataProxy object.
22171 * @param {Object} params The params parameter to the load function.
22176 * Fires before the load method's callback is called.
22177 * @param {Object} This DataProxy object.
22178 * @param {Object} o The data object.
22179 * @param {Object} arg The callback argument object passed to the load function.
22183 * @event loadexception
22184 * Fires if an Exception occurs during data retrieval.
22185 * @param {Object} This DataProxy object.
22186 * @param {Object} o The data object.
22187 * @param {Object} arg The callback argument object passed to the load function.
22188 * @param {Object} e The Exception.
22190 loadexception : true
22192 Roo.data.DataProxy.superclass.constructor.call(this);
22195 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22198 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22202 * Ext JS Library 1.1.1
22203 * Copyright(c) 2006-2007, Ext JS, LLC.
22205 * Originally Released Under LGPL - original licence link has changed is not relivant.
22208 * <script type="text/javascript">
22211 * @class Roo.data.MemoryProxy
22212 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22213 * to the Reader when its load method is called.
22215 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22217 Roo.data.MemoryProxy = function(data){
22221 Roo.data.MemoryProxy.superclass.constructor.call(this);
22225 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22227 * Load data from the requested source (in this case an in-memory
22228 * data object passed to the constructor), read the data object into
22229 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22230 * process that block using the passed callback.
22231 * @param {Object} params This parameter is not used by the MemoryProxy class.
22232 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22233 * object into a block of Roo.data.Records.
22234 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22235 * The function must be passed <ul>
22236 * <li>The Record block object</li>
22237 * <li>The "arg" argument from the load function</li>
22238 * <li>A boolean success indicator</li>
22240 * @param {Object} scope The scope in which to call the callback
22241 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22243 load : function(params, reader, callback, scope, arg){
22244 params = params || {};
22247 result = reader.readRecords(this.data);
22249 this.fireEvent("loadexception", this, arg, null, e);
22250 callback.call(scope, null, arg, false);
22253 callback.call(scope, result, arg, true);
22257 update : function(params, records){
22262 * Ext JS Library 1.1.1
22263 * Copyright(c) 2006-2007, Ext JS, LLC.
22265 * Originally Released Under LGPL - original licence link has changed is not relivant.
22268 * <script type="text/javascript">
22271 * @class Roo.data.HttpProxy
22272 * @extends Roo.data.DataProxy
22273 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22274 * configured to reference a certain URL.<br><br>
22276 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22277 * from which the running page was served.<br><br>
22279 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22281 * Be aware that to enable the browser to parse an XML document, the server must set
22282 * the Content-Type header in the HTTP response to "text/xml".
22284 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22285 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22286 * will be used to make the request.
22288 Roo.data.HttpProxy = function(conn){
22289 Roo.data.HttpProxy.superclass.constructor.call(this);
22290 // is conn a conn config or a real conn?
22292 this.useAjax = !conn || !conn.events;
22296 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22297 // thse are take from connection...
22300 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22303 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22304 * extra parameters to each request made by this object. (defaults to undefined)
22307 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22308 * to each request made by this object. (defaults to undefined)
22311 * @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)
22314 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22317 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22323 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22327 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22328 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22329 * a finer-grained basis than the DataProxy events.
22331 getConnection : function(){
22332 return this.useAjax ? Roo.Ajax : this.conn;
22336 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22337 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22338 * process that block using the passed callback.
22339 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22340 * for the request to the remote server.
22341 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22342 * object into a block of Roo.data.Records.
22343 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22344 * The function must be passed <ul>
22345 * <li>The Record block object</li>
22346 * <li>The "arg" argument from the load function</li>
22347 * <li>A boolean success indicator</li>
22349 * @param {Object} scope The scope in which to call the callback
22350 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22352 load : function(params, reader, callback, scope, arg){
22353 if(this.fireEvent("beforeload", this, params) !== false){
22355 params : params || {},
22357 callback : callback,
22362 callback : this.loadResponse,
22366 Roo.applyIf(o, this.conn);
22367 if(this.activeRequest){
22368 Roo.Ajax.abort(this.activeRequest);
22370 this.activeRequest = Roo.Ajax.request(o);
22372 this.conn.request(o);
22375 callback.call(scope||this, null, arg, false);
22380 loadResponse : function(o, success, response){
22381 delete this.activeRequest;
22383 this.fireEvent("loadexception", this, o, response);
22384 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22389 result = o.reader.read(response);
22391 this.fireEvent("loadexception", this, o, response, e);
22392 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22396 this.fireEvent("load", this, o, o.request.arg);
22397 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22401 update : function(dataSet){
22406 updateResponse : function(dataSet){
22411 * Ext JS Library 1.1.1
22412 * Copyright(c) 2006-2007, Ext JS, LLC.
22414 * Originally Released Under LGPL - original licence link has changed is not relivant.
22417 * <script type="text/javascript">
22421 * @class Roo.data.ScriptTagProxy
22422 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22423 * other than the originating domain of the running page.<br><br>
22425 * <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
22426 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22428 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22429 * source code that is used as the source inside a <script> tag.<br><br>
22431 * In order for the browser to process the returned data, the server must wrap the data object
22432 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22433 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22434 * depending on whether the callback name was passed:
22437 boolean scriptTag = false;
22438 String cb = request.getParameter("callback");
22441 response.setContentType("text/javascript");
22443 response.setContentType("application/x-json");
22445 Writer out = response.getWriter();
22447 out.write(cb + "(");
22449 out.print(dataBlock.toJsonString());
22456 * @param {Object} config A configuration object.
22458 Roo.data.ScriptTagProxy = function(config){
22459 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22460 Roo.apply(this, config);
22461 this.head = document.getElementsByTagName("head")[0];
22464 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22466 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22468 * @cfg {String} url The URL from which to request the data object.
22471 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22475 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22476 * the server the name of the callback function set up by the load call to process the returned data object.
22477 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22478 * javascript output which calls this named function passing the data object as its only parameter.
22480 callbackParam : "callback",
22482 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22483 * name to the request.
22488 * Load data from the configured URL, read the data object into
22489 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22490 * process that block using the passed callback.
22491 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22492 * for the request to the remote server.
22493 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22494 * object into a block of Roo.data.Records.
22495 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22496 * The function must be passed <ul>
22497 * <li>The Record block object</li>
22498 * <li>The "arg" argument from the load function</li>
22499 * <li>A boolean success indicator</li>
22501 * @param {Object} scope The scope in which to call the callback
22502 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22504 load : function(params, reader, callback, scope, arg){
22505 if(this.fireEvent("beforeload", this, params) !== false){
22507 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22509 var url = this.url;
22510 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22512 url += "&_dc=" + (new Date().getTime());
22514 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22517 cb : "stcCallback"+transId,
22518 scriptId : "stcScript"+transId,
22522 callback : callback,
22528 window[trans.cb] = function(o){
22529 conn.handleResponse(o, trans);
22532 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22534 if(this.autoAbort !== false){
22538 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22540 var script = document.createElement("script");
22541 script.setAttribute("src", url);
22542 script.setAttribute("type", "text/javascript");
22543 script.setAttribute("id", trans.scriptId);
22544 this.head.appendChild(script);
22546 this.trans = trans;
22548 callback.call(scope||this, null, arg, false);
22553 isLoading : function(){
22554 return this.trans ? true : false;
22558 * Abort the current server request.
22560 abort : function(){
22561 if(this.isLoading()){
22562 this.destroyTrans(this.trans);
22567 destroyTrans : function(trans, isLoaded){
22568 this.head.removeChild(document.getElementById(trans.scriptId));
22569 clearTimeout(trans.timeoutId);
22571 window[trans.cb] = undefined;
22573 delete window[trans.cb];
22576 // if hasn't been loaded, wait for load to remove it to prevent script error
22577 window[trans.cb] = function(){
22578 window[trans.cb] = undefined;
22580 delete window[trans.cb];
22587 handleResponse : function(o, trans){
22588 this.trans = false;
22589 this.destroyTrans(trans, true);
22592 result = trans.reader.readRecords(o);
22594 this.fireEvent("loadexception", this, o, trans.arg, e);
22595 trans.callback.call(trans.scope||window, null, trans.arg, false);
22598 this.fireEvent("load", this, o, trans.arg);
22599 trans.callback.call(trans.scope||window, result, trans.arg, true);
22603 handleFailure : function(trans){
22604 this.trans = false;
22605 this.destroyTrans(trans, false);
22606 this.fireEvent("loadexception", this, null, trans.arg);
22607 trans.callback.call(trans.scope||window, null, trans.arg, false);
22611 * Ext JS Library 1.1.1
22612 * Copyright(c) 2006-2007, Ext JS, LLC.
22614 * Originally Released Under LGPL - original licence link has changed is not relivant.
22617 * <script type="text/javascript">
22621 * @class Roo.data.JsonReader
22622 * @extends Roo.data.DataReader
22623 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22624 * based on mappings in a provided Roo.data.Record constructor.
22626 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22627 * in the reply previously.
22632 var RecordDef = Roo.data.Record.create([
22633 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22634 {name: 'occupation'} // This field will use "occupation" as the mapping.
22636 var myReader = new Roo.data.JsonReader({
22637 totalProperty: "results", // The property which contains the total dataset size (optional)
22638 root: "rows", // The property which contains an Array of row objects
22639 id: "id" // The property within each row object that provides an ID for the record (optional)
22643 * This would consume a JSON file like this:
22645 { 'results': 2, 'rows': [
22646 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22647 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22650 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22651 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22652 * paged from the remote server.
22653 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22654 * @cfg {String} root name of the property which contains the Array of row objects.
22655 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22656 * @cfg {Array} fields Array of field definition objects
22658 * Create a new JsonReader
22659 * @param {Object} meta Metadata configuration options
22660 * @param {Object} recordType Either an Array of field definition objects,
22661 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22663 Roo.data.JsonReader = function(meta, recordType){
22666 // set some defaults:
22667 Roo.applyIf(meta, {
22668 totalProperty: 'total',
22669 successProperty : 'success',
22674 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22676 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22679 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22680 * Used by Store query builder to append _requestMeta to params.
22683 metaFromRemote : false,
22685 * This method is only used by a DataProxy which has retrieved data from a remote server.
22686 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22687 * @return {Object} data A data block which is used by an Roo.data.Store object as
22688 * a cache of Roo.data.Records.
22690 read : function(response){
22691 var json = response.responseText;
22693 var o = /* eval:var:o */ eval("("+json+")");
22695 throw {message: "JsonReader.read: Json object not found"};
22701 this.metaFromRemote = true;
22702 this.meta = o.metaData;
22703 this.recordType = Roo.data.Record.create(o.metaData.fields);
22704 this.onMetaChange(this.meta, this.recordType, o);
22706 return this.readRecords(o);
22709 // private function a store will implement
22710 onMetaChange : function(meta, recordType, o){
22717 simpleAccess: function(obj, subsc) {
22724 getJsonAccessor: function(){
22726 return function(expr) {
22728 return(re.test(expr))
22729 ? new Function("obj", "return obj." + expr)
22734 return Roo.emptyFn;
22739 * Create a data block containing Roo.data.Records from an XML document.
22740 * @param {Object} o An object which contains an Array of row objects in the property specified
22741 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22742 * which contains the total size of the dataset.
22743 * @return {Object} data A data block which is used by an Roo.data.Store object as
22744 * a cache of Roo.data.Records.
22746 readRecords : function(o){
22748 * After any data loads, the raw JSON data is available for further custom processing.
22752 var s = this.meta, Record = this.recordType,
22753 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
22755 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22757 if(s.totalProperty) {
22758 this.getTotal = this.getJsonAccessor(s.totalProperty);
22760 if(s.successProperty) {
22761 this.getSuccess = this.getJsonAccessor(s.successProperty);
22763 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22765 var g = this.getJsonAccessor(s.id);
22766 this.getId = function(rec) {
22768 return (r === undefined || r === "") ? null : r;
22771 this.getId = function(){return null;};
22774 for(var jj = 0; jj < fl; jj++){
22776 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22777 this.ef[jj] = this.getJsonAccessor(map);
22781 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22782 if(s.totalProperty){
22783 var vt = parseInt(this.getTotal(o), 10);
22788 if(s.successProperty){
22789 var vs = this.getSuccess(o);
22790 if(vs === false || vs === 'false'){
22795 for(var i = 0; i < c; i++){
22798 var id = this.getId(n);
22799 for(var j = 0; j < fl; j++){
22801 var v = this.ef[j](n);
22803 Roo.log('missing convert for ' + f.name);
22807 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22809 var record = new Record(values, id);
22811 records[i] = record;
22817 totalRecords : totalRecords
22822 * Ext JS Library 1.1.1
22823 * Copyright(c) 2006-2007, Ext JS, LLC.
22825 * Originally Released Under LGPL - original licence link has changed is not relivant.
22828 * <script type="text/javascript">
22832 * @class Roo.data.XmlReader
22833 * @extends Roo.data.DataReader
22834 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22835 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22837 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22838 * header in the HTTP response must be set to "text/xml".</em>
22842 var RecordDef = Roo.data.Record.create([
22843 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22844 {name: 'occupation'} // This field will use "occupation" as the mapping.
22846 var myReader = new Roo.data.XmlReader({
22847 totalRecords: "results", // The element which contains the total dataset size (optional)
22848 record: "row", // The repeated element which contains row information
22849 id: "id" // The element within the row that provides an ID for the record (optional)
22853 * This would consume an XML file like this:
22857 <results>2</results>
22860 <name>Bill</name>
22861 <occupation>Gardener</occupation>
22865 <name>Ben</name>
22866 <occupation>Horticulturalist</occupation>
22870 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22871 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22872 * paged from the remote server.
22873 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22874 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22875 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22876 * a record identifier value.
22878 * Create a new XmlReader
22879 * @param {Object} meta Metadata configuration options
22880 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22881 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22882 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22884 Roo.data.XmlReader = function(meta, recordType){
22886 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22888 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22890 * This method is only used by a DataProxy which has retrieved data from a remote server.
22891 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22892 * to contain a method called 'responseXML' that returns an XML document object.
22893 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22894 * a cache of Roo.data.Records.
22896 read : function(response){
22897 var doc = response.responseXML;
22899 throw {message: "XmlReader.read: XML Document not available"};
22901 return this.readRecords(doc);
22905 * Create a data block containing Roo.data.Records from an XML document.
22906 * @param {Object} doc A parsed XML document.
22907 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22908 * a cache of Roo.data.Records.
22910 readRecords : function(doc){
22912 * After any data loads/reads, the raw XML Document is available for further custom processing.
22913 * @type XMLDocument
22915 this.xmlData = doc;
22916 var root = doc.documentElement || doc;
22917 var q = Roo.DomQuery;
22918 var recordType = this.recordType, fields = recordType.prototype.fields;
22919 var sid = this.meta.id;
22920 var totalRecords = 0, success = true;
22921 if(this.meta.totalRecords){
22922 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22925 if(this.meta.success){
22926 var sv = q.selectValue(this.meta.success, root, true);
22927 success = sv !== false && sv !== 'false';
22930 var ns = q.select(this.meta.record, root);
22931 for(var i = 0, len = ns.length; i < len; i++) {
22934 var id = sid ? q.selectValue(sid, n) : undefined;
22935 for(var j = 0, jlen = fields.length; j < jlen; j++){
22936 var f = fields.items[j];
22937 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22939 values[f.name] = v;
22941 var record = new recordType(values, id);
22943 records[records.length] = record;
22949 totalRecords : totalRecords || records.length
22954 * Ext JS Library 1.1.1
22955 * Copyright(c) 2006-2007, Ext JS, LLC.
22957 * Originally Released Under LGPL - original licence link has changed is not relivant.
22960 * <script type="text/javascript">
22964 * @class Roo.data.ArrayReader
22965 * @extends Roo.data.DataReader
22966 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22967 * Each element of that Array represents a row of data fields. The
22968 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22969 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22973 var RecordDef = Roo.data.Record.create([
22974 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22975 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22977 var myReader = new Roo.data.ArrayReader({
22978 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22982 * This would consume an Array like this:
22984 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22986 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22988 * Create a new JsonReader
22989 * @param {Object} meta Metadata configuration options.
22990 * @param {Object} recordType Either an Array of field definition objects
22991 * as specified to {@link Roo.data.Record#create},
22992 * or an {@link Roo.data.Record} object
22993 * created using {@link Roo.data.Record#create}.
22995 Roo.data.ArrayReader = function(meta, recordType){
22996 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22999 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
23001 * Create a data block containing Roo.data.Records from an XML document.
23002 * @param {Object} o An Array of row objects which represents the dataset.
23003 * @return {Object} data A data block which is used by an Roo.data.Store object as
23004 * a cache of Roo.data.Records.
23006 readRecords : function(o){
23007 var sid = this.meta ? this.meta.id : null;
23008 var recordType = this.recordType, fields = recordType.prototype.fields;
23011 for(var i = 0; i < root.length; i++){
23014 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
23015 for(var j = 0, jlen = fields.length; j < jlen; j++){
23016 var f = fields.items[j];
23017 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
23018 var v = n[k] !== undefined ? n[k] : f.defaultValue;
23020 values[f.name] = v;
23022 var record = new recordType(values, id);
23024 records[records.length] = record;
23028 totalRecords : records.length
23033 * Ext JS Library 1.1.1
23034 * Copyright(c) 2006-2007, Ext JS, LLC.
23036 * Originally Released Under LGPL - original licence link has changed is not relivant.
23039 * <script type="text/javascript">
23044 * @class Roo.data.Tree
23045 * @extends Roo.util.Observable
23046 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
23047 * in the tree have most standard DOM functionality.
23049 * @param {Node} root (optional) The root node
23051 Roo.data.Tree = function(root){
23052 this.nodeHash = {};
23054 * The root node for this tree
23059 this.setRootNode(root);
23064 * Fires when a new child node is appended to a node in this tree.
23065 * @param {Tree} tree The owner tree
23066 * @param {Node} parent The parent node
23067 * @param {Node} node The newly appended node
23068 * @param {Number} index The index of the newly appended node
23073 * Fires when a child node is removed from a node in this tree.
23074 * @param {Tree} tree The owner tree
23075 * @param {Node} parent The parent node
23076 * @param {Node} node The child node removed
23081 * Fires when a node is moved to a new location in the tree
23082 * @param {Tree} tree The owner tree
23083 * @param {Node} node The node moved
23084 * @param {Node} oldParent The old parent of this node
23085 * @param {Node} newParent The new parent of this node
23086 * @param {Number} index The index it was moved to
23091 * Fires when a new child node is inserted in a node in this tree.
23092 * @param {Tree} tree The owner tree
23093 * @param {Node} parent The parent node
23094 * @param {Node} node The child node inserted
23095 * @param {Node} refNode The child node the node was inserted before
23099 * @event beforeappend
23100 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
23101 * @param {Tree} tree The owner tree
23102 * @param {Node} parent The parent node
23103 * @param {Node} node The child node to be appended
23105 "beforeappend" : true,
23107 * @event beforeremove
23108 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
23109 * @param {Tree} tree The owner tree
23110 * @param {Node} parent The parent node
23111 * @param {Node} node The child node to be removed
23113 "beforeremove" : true,
23115 * @event beforemove
23116 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
23117 * @param {Tree} tree The owner tree
23118 * @param {Node} node The node being moved
23119 * @param {Node} oldParent The parent of the node
23120 * @param {Node} newParent The new parent the node is moving to
23121 * @param {Number} index The index it is being moved to
23123 "beforemove" : true,
23125 * @event beforeinsert
23126 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
23127 * @param {Tree} tree The owner tree
23128 * @param {Node} parent The parent node
23129 * @param {Node} node The child node to be inserted
23130 * @param {Node} refNode The child node the node is being inserted before
23132 "beforeinsert" : true
23135 Roo.data.Tree.superclass.constructor.call(this);
23138 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
23139 pathSeparator: "/",
23141 proxyNodeEvent : function(){
23142 return this.fireEvent.apply(this, arguments);
23146 * Returns the root node for this tree.
23149 getRootNode : function(){
23154 * Sets the root node for this tree.
23155 * @param {Node} node
23158 setRootNode : function(node){
23160 node.ownerTree = this;
23161 node.isRoot = true;
23162 this.registerNode(node);
23167 * Gets a node in this tree by its id.
23168 * @param {String} id
23171 getNodeById : function(id){
23172 return this.nodeHash[id];
23175 registerNode : function(node){
23176 this.nodeHash[node.id] = node;
23179 unregisterNode : function(node){
23180 delete this.nodeHash[node.id];
23183 toString : function(){
23184 return "[Tree"+(this.id?" "+this.id:"")+"]";
23189 * @class Roo.data.Node
23190 * @extends Roo.util.Observable
23191 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23192 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23194 * @param {Object} attributes The attributes/config for the node
23196 Roo.data.Node = function(attributes){
23198 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23201 this.attributes = attributes || {};
23202 this.leaf = this.attributes.leaf;
23204 * The node id. @type String
23206 this.id = this.attributes.id;
23208 this.id = Roo.id(null, "ynode-");
23209 this.attributes.id = this.id;
23214 * All child nodes of this node. @type Array
23216 this.childNodes = [];
23217 if(!this.childNodes.indexOf){ // indexOf is a must
23218 this.childNodes.indexOf = function(o){
23219 for(var i = 0, len = this.length; i < len; i++){
23228 * The parent node for this node. @type Node
23230 this.parentNode = null;
23232 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23234 this.firstChild = null;
23236 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23238 this.lastChild = null;
23240 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23242 this.previousSibling = null;
23244 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23246 this.nextSibling = null;
23251 * Fires when a new child node is appended
23252 * @param {Tree} tree The owner tree
23253 * @param {Node} this This node
23254 * @param {Node} node The newly appended node
23255 * @param {Number} index The index of the newly appended node
23260 * Fires when a child node is removed
23261 * @param {Tree} tree The owner tree
23262 * @param {Node} this This node
23263 * @param {Node} node The removed node
23268 * Fires when this node is moved to a new location in the tree
23269 * @param {Tree} tree The owner tree
23270 * @param {Node} this This node
23271 * @param {Node} oldParent The old parent of this node
23272 * @param {Node} newParent The new parent of this node
23273 * @param {Number} index The index it was moved to
23278 * Fires when a new child node is inserted.
23279 * @param {Tree} tree The owner tree
23280 * @param {Node} this This node
23281 * @param {Node} node The child node inserted
23282 * @param {Node} refNode The child node the node was inserted before
23286 * @event beforeappend
23287 * Fires before a new child is appended, return false to cancel the append.
23288 * @param {Tree} tree The owner tree
23289 * @param {Node} this This node
23290 * @param {Node} node The child node to be appended
23292 "beforeappend" : true,
23294 * @event beforeremove
23295 * Fires before a child is removed, return false to cancel the remove.
23296 * @param {Tree} tree The owner tree
23297 * @param {Node} this This node
23298 * @param {Node} node The child node to be removed
23300 "beforeremove" : true,
23302 * @event beforemove
23303 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23304 * @param {Tree} tree The owner tree
23305 * @param {Node} this This node
23306 * @param {Node} oldParent The parent of this node
23307 * @param {Node} newParent The new parent this node is moving to
23308 * @param {Number} index The index it is being moved to
23310 "beforemove" : true,
23312 * @event beforeinsert
23313 * Fires before a new child is inserted, return false to cancel the insert.
23314 * @param {Tree} tree The owner tree
23315 * @param {Node} this This node
23316 * @param {Node} node The child node to be inserted
23317 * @param {Node} refNode The child node the node is being inserted before
23319 "beforeinsert" : true
23321 this.listeners = this.attributes.listeners;
23322 Roo.data.Node.superclass.constructor.call(this);
23325 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23326 fireEvent : function(evtName){
23327 // first do standard event for this node
23328 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23331 // then bubble it up to the tree if the event wasn't cancelled
23332 var ot = this.getOwnerTree();
23334 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23342 * Returns true if this node is a leaf
23343 * @return {Boolean}
23345 isLeaf : function(){
23346 return this.leaf === true;
23350 setFirstChild : function(node){
23351 this.firstChild = node;
23355 setLastChild : function(node){
23356 this.lastChild = node;
23361 * Returns true if this node is the last child of its parent
23362 * @return {Boolean}
23364 isLast : function(){
23365 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23369 * Returns true if this node is the first child of its parent
23370 * @return {Boolean}
23372 isFirst : function(){
23373 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23376 hasChildNodes : function(){
23377 return !this.isLeaf() && this.childNodes.length > 0;
23381 * Insert node(s) as the last child node of this node.
23382 * @param {Node/Array} node The node or Array of nodes to append
23383 * @return {Node} The appended node if single append, or null if an array was passed
23385 appendChild : function(node){
23387 if(node instanceof Array){
23389 }else if(arguments.length > 1){
23392 // if passed an array or multiple args do them one by one
23394 for(var i = 0, len = multi.length; i < len; i++) {
23395 this.appendChild(multi[i]);
23398 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23401 var index = this.childNodes.length;
23402 var oldParent = node.parentNode;
23403 // it's a move, make sure we move it cleanly
23405 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23408 oldParent.removeChild(node);
23410 index = this.childNodes.length;
23412 this.setFirstChild(node);
23414 this.childNodes.push(node);
23415 node.parentNode = this;
23416 var ps = this.childNodes[index-1];
23418 node.previousSibling = ps;
23419 ps.nextSibling = node;
23421 node.previousSibling = null;
23423 node.nextSibling = null;
23424 this.setLastChild(node);
23425 node.setOwnerTree(this.getOwnerTree());
23426 this.fireEvent("append", this.ownerTree, this, node, index);
23428 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23435 * Removes a child node from this node.
23436 * @param {Node} node The node to remove
23437 * @return {Node} The removed node
23439 removeChild : function(node){
23440 var index = this.childNodes.indexOf(node);
23444 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23448 // remove it from childNodes collection
23449 this.childNodes.splice(index, 1);
23452 if(node.previousSibling){
23453 node.previousSibling.nextSibling = node.nextSibling;
23455 if(node.nextSibling){
23456 node.nextSibling.previousSibling = node.previousSibling;
23459 // update child refs
23460 if(this.firstChild == node){
23461 this.setFirstChild(node.nextSibling);
23463 if(this.lastChild == node){
23464 this.setLastChild(node.previousSibling);
23467 node.setOwnerTree(null);
23468 // clear any references from the node
23469 node.parentNode = null;
23470 node.previousSibling = null;
23471 node.nextSibling = null;
23472 this.fireEvent("remove", this.ownerTree, this, node);
23477 * Inserts the first node before the second node in this nodes childNodes collection.
23478 * @param {Node} node The node to insert
23479 * @param {Node} refNode The node to insert before (if null the node is appended)
23480 * @return {Node} The inserted node
23482 insertBefore : function(node, refNode){
23483 if(!refNode){ // like standard Dom, refNode can be null for append
23484 return this.appendChild(node);
23487 if(node == refNode){
23491 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23494 var index = this.childNodes.indexOf(refNode);
23495 var oldParent = node.parentNode;
23496 var refIndex = index;
23498 // when moving internally, indexes will change after remove
23499 if(oldParent == this && this.childNodes.indexOf(node) < index){
23503 // it's a move, make sure we move it cleanly
23505 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23508 oldParent.removeChild(node);
23511 this.setFirstChild(node);
23513 this.childNodes.splice(refIndex, 0, node);
23514 node.parentNode = this;
23515 var ps = this.childNodes[refIndex-1];
23517 node.previousSibling = ps;
23518 ps.nextSibling = node;
23520 node.previousSibling = null;
23522 node.nextSibling = refNode;
23523 refNode.previousSibling = node;
23524 node.setOwnerTree(this.getOwnerTree());
23525 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23527 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23533 * Returns the child node at the specified index.
23534 * @param {Number} index
23537 item : function(index){
23538 return this.childNodes[index];
23542 * Replaces one child node in this node with another.
23543 * @param {Node} newChild The replacement node
23544 * @param {Node} oldChild The node to replace
23545 * @return {Node} The replaced node
23547 replaceChild : function(newChild, oldChild){
23548 this.insertBefore(newChild, oldChild);
23549 this.removeChild(oldChild);
23554 * Returns the index of a child node
23555 * @param {Node} node
23556 * @return {Number} The index of the node or -1 if it was not found
23558 indexOf : function(child){
23559 return this.childNodes.indexOf(child);
23563 * Returns the tree this node is in.
23566 getOwnerTree : function(){
23567 // if it doesn't have one, look for one
23568 if(!this.ownerTree){
23572 this.ownerTree = p.ownerTree;
23578 return this.ownerTree;
23582 * Returns depth of this node (the root node has a depth of 0)
23585 getDepth : function(){
23588 while(p.parentNode){
23596 setOwnerTree : function(tree){
23597 // if it's move, we need to update everyone
23598 if(tree != this.ownerTree){
23599 if(this.ownerTree){
23600 this.ownerTree.unregisterNode(this);
23602 this.ownerTree = tree;
23603 var cs = this.childNodes;
23604 for(var i = 0, len = cs.length; i < len; i++) {
23605 cs[i].setOwnerTree(tree);
23608 tree.registerNode(this);
23614 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23615 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23616 * @return {String} The path
23618 getPath : function(attr){
23619 attr = attr || "id";
23620 var p = this.parentNode;
23621 var b = [this.attributes[attr]];
23623 b.unshift(p.attributes[attr]);
23626 var sep = this.getOwnerTree().pathSeparator;
23627 return sep + b.join(sep);
23631 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23632 * function call will be the scope provided or the current node. The arguments to the function
23633 * will be the args provided or the current node. If the function returns false at any point,
23634 * the bubble is stopped.
23635 * @param {Function} fn The function to call
23636 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23637 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23639 bubble : function(fn, scope, args){
23642 if(fn.call(scope || p, args || p) === false){
23650 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23651 * function call will be the scope provided or the current node. The arguments to the function
23652 * will be the args provided or the current node. If the function returns false at any point,
23653 * the cascade is stopped on that branch.
23654 * @param {Function} fn The function to call
23655 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23656 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23658 cascade : function(fn, scope, args){
23659 if(fn.call(scope || this, args || this) !== false){
23660 var cs = this.childNodes;
23661 for(var i = 0, len = cs.length; i < len; i++) {
23662 cs[i].cascade(fn, scope, args);
23668 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23669 * function call will be the scope provided or the current node. The arguments to the function
23670 * will be the args provided or the current node. If the function returns false at any point,
23671 * the iteration stops.
23672 * @param {Function} fn The function to call
23673 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23674 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23676 eachChild : function(fn, scope, args){
23677 var cs = this.childNodes;
23678 for(var i = 0, len = cs.length; i < len; i++) {
23679 if(fn.call(scope || this, args || cs[i]) === false){
23686 * Finds the first child that has the attribute with the specified value.
23687 * @param {String} attribute The attribute name
23688 * @param {Mixed} value The value to search for
23689 * @return {Node} The found child or null if none was found
23691 findChild : function(attribute, value){
23692 var cs = this.childNodes;
23693 for(var i = 0, len = cs.length; i < len; i++) {
23694 if(cs[i].attributes[attribute] == value){
23702 * Finds the first child by a custom function. The child matches if the function passed
23704 * @param {Function} fn
23705 * @param {Object} scope (optional)
23706 * @return {Node} The found child or null if none was found
23708 findChildBy : function(fn, scope){
23709 var cs = this.childNodes;
23710 for(var i = 0, len = cs.length; i < len; i++) {
23711 if(fn.call(scope||cs[i], cs[i]) === true){
23719 * Sorts this nodes children using the supplied sort function
23720 * @param {Function} fn
23721 * @param {Object} scope (optional)
23723 sort : function(fn, scope){
23724 var cs = this.childNodes;
23725 var len = cs.length;
23727 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23729 for(var i = 0; i < len; i++){
23731 n.previousSibling = cs[i-1];
23732 n.nextSibling = cs[i+1];
23734 this.setFirstChild(n);
23737 this.setLastChild(n);
23744 * Returns true if this node is an ancestor (at any point) of the passed node.
23745 * @param {Node} node
23746 * @return {Boolean}
23748 contains : function(node){
23749 return node.isAncestor(this);
23753 * Returns true if the passed node is an ancestor (at any point) of this node.
23754 * @param {Node} node
23755 * @return {Boolean}
23757 isAncestor : function(node){
23758 var p = this.parentNode;
23768 toString : function(){
23769 return "[Node"+(this.id?" "+this.id:"")+"]";
23773 * Ext JS Library 1.1.1
23774 * Copyright(c) 2006-2007, Ext JS, LLC.
23776 * Originally Released Under LGPL - original licence link has changed is not relivant.
23779 * <script type="text/javascript">
23784 * @extends Roo.Element
23785 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23786 * automatic maintaining of shadow/shim positions.
23787 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23788 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23789 * you can pass a string with a CSS class name. False turns off the shadow.
23790 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23791 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23792 * @cfg {String} cls CSS class to add to the element
23793 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23794 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23796 * @param {Object} config An object with config options.
23797 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23800 Roo.Layer = function(config, existingEl){
23801 config = config || {};
23802 var dh = Roo.DomHelper;
23803 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23805 this.dom = Roo.getDom(existingEl);
23808 var o = config.dh || {tag: "div", cls: "x-layer"};
23809 this.dom = dh.append(pel, o);
23812 this.addClass(config.cls);
23814 this.constrain = config.constrain !== false;
23815 this.visibilityMode = Roo.Element.VISIBILITY;
23817 this.id = this.dom.id = config.id;
23819 this.id = Roo.id(this.dom);
23821 this.zindex = config.zindex || this.getZIndex();
23822 this.position("absolute", this.zindex);
23824 this.shadowOffset = config.shadowOffset || 4;
23825 this.shadow = new Roo.Shadow({
23826 offset : this.shadowOffset,
23827 mode : config.shadow
23830 this.shadowOffset = 0;
23832 this.useShim = config.shim !== false && Roo.useShims;
23833 this.useDisplay = config.useDisplay;
23837 var supr = Roo.Element.prototype;
23839 // shims are shared among layer to keep from having 100 iframes
23842 Roo.extend(Roo.Layer, Roo.Element, {
23844 getZIndex : function(){
23845 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23848 getShim : function(){
23855 var shim = shims.shift();
23857 shim = this.createShim();
23858 shim.enableDisplayMode('block');
23859 shim.dom.style.display = 'none';
23860 shim.dom.style.visibility = 'visible';
23862 var pn = this.dom.parentNode;
23863 if(shim.dom.parentNode != pn){
23864 pn.insertBefore(shim.dom, this.dom);
23866 shim.setStyle('z-index', this.getZIndex()-2);
23871 hideShim : function(){
23873 this.shim.setDisplayed(false);
23874 shims.push(this.shim);
23879 disableShadow : function(){
23881 this.shadowDisabled = true;
23882 this.shadow.hide();
23883 this.lastShadowOffset = this.shadowOffset;
23884 this.shadowOffset = 0;
23888 enableShadow : function(show){
23890 this.shadowDisabled = false;
23891 this.shadowOffset = this.lastShadowOffset;
23892 delete this.lastShadowOffset;
23900 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23901 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23902 sync : function(doShow){
23903 var sw = this.shadow;
23904 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23905 var sh = this.getShim();
23907 var w = this.getWidth(),
23908 h = this.getHeight();
23910 var l = this.getLeft(true),
23911 t = this.getTop(true);
23913 if(sw && !this.shadowDisabled){
23914 if(doShow && !sw.isVisible()){
23917 sw.realign(l, t, w, h);
23923 // fit the shim behind the shadow, so it is shimmed too
23924 var a = sw.adjusts, s = sh.dom.style;
23925 s.left = (Math.min(l, l+a.l))+"px";
23926 s.top = (Math.min(t, t+a.t))+"px";
23927 s.width = (w+a.w)+"px";
23928 s.height = (h+a.h)+"px";
23935 sh.setLeftTop(l, t);
23942 destroy : function(){
23945 this.shadow.hide();
23947 this.removeAllListeners();
23948 var pn = this.dom.parentNode;
23950 pn.removeChild(this.dom);
23952 Roo.Element.uncache(this.id);
23955 remove : function(){
23960 beginUpdate : function(){
23961 this.updating = true;
23965 endUpdate : function(){
23966 this.updating = false;
23971 hideUnders : function(negOffset){
23973 this.shadow.hide();
23979 constrainXY : function(){
23980 if(this.constrain){
23981 var vw = Roo.lib.Dom.getViewWidth(),
23982 vh = Roo.lib.Dom.getViewHeight();
23983 var s = Roo.get(document).getScroll();
23985 var xy = this.getXY();
23986 var x = xy[0], y = xy[1];
23987 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23988 // only move it if it needs it
23990 // first validate right/bottom
23991 if((x + w) > vw+s.left){
23992 x = vw - w - this.shadowOffset;
23995 if((y + h) > vh+s.top){
23996 y = vh - h - this.shadowOffset;
23999 // then make sure top/left isn't negative
24010 var ay = this.avoidY;
24011 if(y <= ay && (y+h) >= ay){
24017 supr.setXY.call(this, xy);
24023 isVisible : function(){
24024 return this.visible;
24028 showAction : function(){
24029 this.visible = true; // track visibility to prevent getStyle calls
24030 if(this.useDisplay === true){
24031 this.setDisplayed("");
24032 }else if(this.lastXY){
24033 supr.setXY.call(this, this.lastXY);
24034 }else if(this.lastLT){
24035 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
24040 hideAction : function(){
24041 this.visible = false;
24042 if(this.useDisplay === true){
24043 this.setDisplayed(false);
24045 this.setLeftTop(-10000,-10000);
24049 // overridden Element method
24050 setVisible : function(v, a, d, c, e){
24055 var cb = function(){
24060 }.createDelegate(this);
24061 supr.setVisible.call(this, true, true, d, cb, e);
24064 this.hideUnders(true);
24073 }.createDelegate(this);
24075 supr.setVisible.call(this, v, a, d, cb, e);
24084 storeXY : function(xy){
24085 delete this.lastLT;
24089 storeLeftTop : function(left, top){
24090 delete this.lastXY;
24091 this.lastLT = [left, top];
24095 beforeFx : function(){
24096 this.beforeAction();
24097 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
24101 afterFx : function(){
24102 Roo.Layer.superclass.afterFx.apply(this, arguments);
24103 this.sync(this.isVisible());
24107 beforeAction : function(){
24108 if(!this.updating && this.shadow){
24109 this.shadow.hide();
24113 // overridden Element method
24114 setLeft : function(left){
24115 this.storeLeftTop(left, this.getTop(true));
24116 supr.setLeft.apply(this, arguments);
24120 setTop : function(top){
24121 this.storeLeftTop(this.getLeft(true), top);
24122 supr.setTop.apply(this, arguments);
24126 setLeftTop : function(left, top){
24127 this.storeLeftTop(left, top);
24128 supr.setLeftTop.apply(this, arguments);
24132 setXY : function(xy, a, d, c, e){
24134 this.beforeAction();
24136 var cb = this.createCB(c);
24137 supr.setXY.call(this, xy, a, d, cb, e);
24144 createCB : function(c){
24155 // overridden Element method
24156 setX : function(x, a, d, c, e){
24157 this.setXY([x, this.getY()], a, d, c, e);
24160 // overridden Element method
24161 setY : function(y, a, d, c, e){
24162 this.setXY([this.getX(), y], a, d, c, e);
24165 // overridden Element method
24166 setSize : function(w, h, a, d, c, e){
24167 this.beforeAction();
24168 var cb = this.createCB(c);
24169 supr.setSize.call(this, w, h, a, d, cb, e);
24175 // overridden Element method
24176 setWidth : function(w, a, d, c, e){
24177 this.beforeAction();
24178 var cb = this.createCB(c);
24179 supr.setWidth.call(this, w, a, d, cb, e);
24185 // overridden Element method
24186 setHeight : function(h, a, d, c, e){
24187 this.beforeAction();
24188 var cb = this.createCB(c);
24189 supr.setHeight.call(this, h, a, d, cb, e);
24195 // overridden Element method
24196 setBounds : function(x, y, w, h, a, d, c, e){
24197 this.beforeAction();
24198 var cb = this.createCB(c);
24200 this.storeXY([x, y]);
24201 supr.setXY.call(this, [x, y]);
24202 supr.setSize.call(this, w, h, a, d, cb, e);
24205 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24211 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24212 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24213 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24214 * @param {Number} zindex The new z-index to set
24215 * @return {this} The Layer
24217 setZIndex : function(zindex){
24218 this.zindex = zindex;
24219 this.setStyle("z-index", zindex + 2);
24221 this.shadow.setZIndex(zindex + 1);
24224 this.shim.setStyle("z-index", zindex);
24230 * Ext JS Library 1.1.1
24231 * Copyright(c) 2006-2007, Ext JS, LLC.
24233 * Originally Released Under LGPL - original licence link has changed is not relivant.
24236 * <script type="text/javascript">
24241 * @class Roo.Shadow
24242 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24243 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24244 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24246 * Create a new Shadow
24247 * @param {Object} config The config object
24249 Roo.Shadow = function(config){
24250 Roo.apply(this, config);
24251 if(typeof this.mode != "string"){
24252 this.mode = this.defaultMode;
24254 var o = this.offset, a = {h: 0};
24255 var rad = Math.floor(this.offset/2);
24256 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24262 a.l -= this.offset + rad;
24263 a.t -= this.offset + rad;
24274 a.l -= (this.offset - rad);
24275 a.t -= this.offset + rad;
24277 a.w -= (this.offset - rad)*2;
24288 a.l -= (this.offset - rad);
24289 a.t -= (this.offset - rad);
24291 a.w -= (this.offset + rad + 1);
24292 a.h -= (this.offset + rad);
24301 Roo.Shadow.prototype = {
24303 * @cfg {String} mode
24304 * The shadow display mode. Supports the following options:<br />
24305 * sides: Shadow displays on both sides and bottom only<br />
24306 * frame: Shadow displays equally on all four sides<br />
24307 * drop: Traditional bottom-right drop shadow (default)
24310 * @cfg {String} offset
24311 * The number of pixels to offset the shadow from the element (defaults to 4)
24316 defaultMode: "drop",
24319 * Displays the shadow under the target element
24320 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24322 show : function(target){
24323 target = Roo.get(target);
24325 this.el = Roo.Shadow.Pool.pull();
24326 if(this.el.dom.nextSibling != target.dom){
24327 this.el.insertBefore(target);
24330 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24332 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24335 target.getLeft(true),
24336 target.getTop(true),
24340 this.el.dom.style.display = "block";
24344 * Returns true if the shadow is visible, else false
24346 isVisible : function(){
24347 return this.el ? true : false;
24351 * Direct alignment when values are already available. Show must be called at least once before
24352 * calling this method to ensure it is initialized.
24353 * @param {Number} left The target element left position
24354 * @param {Number} top The target element top position
24355 * @param {Number} width The target element width
24356 * @param {Number} height The target element height
24358 realign : function(l, t, w, h){
24362 var a = this.adjusts, d = this.el.dom, s = d.style;
24364 s.left = (l+a.l)+"px";
24365 s.top = (t+a.t)+"px";
24366 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24368 if(s.width != sws || s.height != shs){
24372 var cn = d.childNodes;
24373 var sww = Math.max(0, (sw-12))+"px";
24374 cn[0].childNodes[1].style.width = sww;
24375 cn[1].childNodes[1].style.width = sww;
24376 cn[2].childNodes[1].style.width = sww;
24377 cn[1].style.height = Math.max(0, (sh-12))+"px";
24383 * Hides this shadow
24387 this.el.dom.style.display = "none";
24388 Roo.Shadow.Pool.push(this.el);
24394 * Adjust the z-index of this shadow
24395 * @param {Number} zindex The new z-index
24397 setZIndex : function(z){
24400 this.el.setStyle("z-index", z);
24405 // Private utility class that manages the internal Shadow cache
24406 Roo.Shadow.Pool = function(){
24408 var markup = Roo.isIE ?
24409 '<div class="x-ie-shadow"></div>' :
24410 '<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>';
24413 var sh = p.shift();
24415 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24416 sh.autoBoxAdjust = false;
24421 push : function(sh){
24427 * Ext JS Library 1.1.1
24428 * Copyright(c) 2006-2007, Ext JS, LLC.
24430 * Originally Released Under LGPL - original licence link has changed is not relivant.
24433 * <script type="text/javascript">
24438 * @class Roo.SplitBar
24439 * @extends Roo.util.Observable
24440 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24444 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24445 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24446 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24447 split.minSize = 100;
24448 split.maxSize = 600;
24449 split.animate = true;
24450 split.on('moved', splitterMoved);
24453 * Create a new SplitBar
24454 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24455 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24456 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24457 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24458 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24459 position of the SplitBar).
24461 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24464 this.el = Roo.get(dragElement, true);
24465 this.el.dom.unselectable = "on";
24467 this.resizingEl = Roo.get(resizingElement, true);
24471 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24472 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24475 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24478 * The minimum size of the resizing element. (Defaults to 0)
24484 * The maximum size of the resizing element. (Defaults to 2000)
24487 this.maxSize = 2000;
24490 * Whether to animate the transition to the new size
24493 this.animate = false;
24496 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24499 this.useShim = false;
24504 if(!existingProxy){
24506 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24508 this.proxy = Roo.get(existingProxy).dom;
24511 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24514 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24517 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24520 this.dragSpecs = {};
24523 * @private The adapter to use to positon and resize elements
24525 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24526 this.adapter.init(this);
24528 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24530 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24531 this.el.addClass("x-splitbar-h");
24534 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24535 this.el.addClass("x-splitbar-v");
24541 * Fires when the splitter is moved (alias for {@link #event-moved})
24542 * @param {Roo.SplitBar} this
24543 * @param {Number} newSize the new width or height
24548 * Fires when the splitter is moved
24549 * @param {Roo.SplitBar} this
24550 * @param {Number} newSize the new width or height
24554 * @event beforeresize
24555 * Fires before the splitter is dragged
24556 * @param {Roo.SplitBar} this
24558 "beforeresize" : true,
24560 "beforeapply" : true
24563 Roo.util.Observable.call(this);
24566 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24567 onStartProxyDrag : function(x, y){
24568 this.fireEvent("beforeresize", this);
24570 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24572 o.enableDisplayMode("block");
24573 // all splitbars share the same overlay
24574 Roo.SplitBar.prototype.overlay = o;
24576 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24577 this.overlay.show();
24578 Roo.get(this.proxy).setDisplayed("block");
24579 var size = this.adapter.getElementSize(this);
24580 this.activeMinSize = this.getMinimumSize();;
24581 this.activeMaxSize = this.getMaximumSize();;
24582 var c1 = size - this.activeMinSize;
24583 var c2 = Math.max(this.activeMaxSize - size, 0);
24584 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24585 this.dd.resetConstraints();
24586 this.dd.setXConstraint(
24587 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24588 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24590 this.dd.setYConstraint(0, 0);
24592 this.dd.resetConstraints();
24593 this.dd.setXConstraint(0, 0);
24594 this.dd.setYConstraint(
24595 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24596 this.placement == Roo.SplitBar.TOP ? c2 : c1
24599 this.dragSpecs.startSize = size;
24600 this.dragSpecs.startPoint = [x, y];
24601 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24605 * @private Called after the drag operation by the DDProxy
24607 onEndProxyDrag : function(e){
24608 Roo.get(this.proxy).setDisplayed(false);
24609 var endPoint = Roo.lib.Event.getXY(e);
24611 this.overlay.hide();
24614 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24615 newSize = this.dragSpecs.startSize +
24616 (this.placement == Roo.SplitBar.LEFT ?
24617 endPoint[0] - this.dragSpecs.startPoint[0] :
24618 this.dragSpecs.startPoint[0] - endPoint[0]
24621 newSize = this.dragSpecs.startSize +
24622 (this.placement == Roo.SplitBar.TOP ?
24623 endPoint[1] - this.dragSpecs.startPoint[1] :
24624 this.dragSpecs.startPoint[1] - endPoint[1]
24627 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24628 if(newSize != this.dragSpecs.startSize){
24629 if(this.fireEvent('beforeapply', this, newSize) !== false){
24630 this.adapter.setElementSize(this, newSize);
24631 this.fireEvent("moved", this, newSize);
24632 this.fireEvent("resize", this, newSize);
24638 * Get the adapter this SplitBar uses
24639 * @return The adapter object
24641 getAdapter : function(){
24642 return this.adapter;
24646 * Set the adapter this SplitBar uses
24647 * @param {Object} adapter A SplitBar adapter object
24649 setAdapter : function(adapter){
24650 this.adapter = adapter;
24651 this.adapter.init(this);
24655 * Gets the minimum size for the resizing element
24656 * @return {Number} The minimum size
24658 getMinimumSize : function(){
24659 return this.minSize;
24663 * Sets the minimum size for the resizing element
24664 * @param {Number} minSize The minimum size
24666 setMinimumSize : function(minSize){
24667 this.minSize = minSize;
24671 * Gets the maximum size for the resizing element
24672 * @return {Number} The maximum size
24674 getMaximumSize : function(){
24675 return this.maxSize;
24679 * Sets the maximum size for the resizing element
24680 * @param {Number} maxSize The maximum size
24682 setMaximumSize : function(maxSize){
24683 this.maxSize = maxSize;
24687 * Sets the initialize size for the resizing element
24688 * @param {Number} size The initial size
24690 setCurrentSize : function(size){
24691 var oldAnimate = this.animate;
24692 this.animate = false;
24693 this.adapter.setElementSize(this, size);
24694 this.animate = oldAnimate;
24698 * Destroy this splitbar.
24699 * @param {Boolean} removeEl True to remove the element
24701 destroy : function(removeEl){
24703 this.shim.remove();
24706 this.proxy.parentNode.removeChild(this.proxy);
24714 * @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.
24716 Roo.SplitBar.createProxy = function(dir){
24717 var proxy = new Roo.Element(document.createElement("div"));
24718 proxy.unselectable();
24719 var cls = 'x-splitbar-proxy';
24720 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24721 document.body.appendChild(proxy.dom);
24726 * @class Roo.SplitBar.BasicLayoutAdapter
24727 * Default Adapter. It assumes the splitter and resizing element are not positioned
24728 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24730 Roo.SplitBar.BasicLayoutAdapter = function(){
24733 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24734 // do nothing for now
24735 init : function(s){
24739 * Called before drag operations to get the current size of the resizing element.
24740 * @param {Roo.SplitBar} s The SplitBar using this adapter
24742 getElementSize : function(s){
24743 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24744 return s.resizingEl.getWidth();
24746 return s.resizingEl.getHeight();
24751 * Called after drag operations to set the size of the resizing element.
24752 * @param {Roo.SplitBar} s The SplitBar using this adapter
24753 * @param {Number} newSize The new size to set
24754 * @param {Function} onComplete A function to be invoked when resizing is complete
24756 setElementSize : function(s, newSize, onComplete){
24757 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24759 s.resizingEl.setWidth(newSize);
24761 onComplete(s, newSize);
24764 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24769 s.resizingEl.setHeight(newSize);
24771 onComplete(s, newSize);
24774 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24781 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24782 * @extends Roo.SplitBar.BasicLayoutAdapter
24783 * Adapter that moves the splitter element to align with the resized sizing element.
24784 * Used with an absolute positioned SplitBar.
24785 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24786 * document.body, make sure you assign an id to the body element.
24788 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24789 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24790 this.container = Roo.get(container);
24793 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24794 init : function(s){
24795 this.basic.init(s);
24798 getElementSize : function(s){
24799 return this.basic.getElementSize(s);
24802 setElementSize : function(s, newSize, onComplete){
24803 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24806 moveSplitter : function(s){
24807 var yes = Roo.SplitBar;
24808 switch(s.placement){
24810 s.el.setX(s.resizingEl.getRight());
24813 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24816 s.el.setY(s.resizingEl.getBottom());
24819 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24826 * Orientation constant - Create a vertical SplitBar
24830 Roo.SplitBar.VERTICAL = 1;
24833 * Orientation constant - Create a horizontal SplitBar
24837 Roo.SplitBar.HORIZONTAL = 2;
24840 * Placement constant - The resizing element is to the left of the splitter element
24844 Roo.SplitBar.LEFT = 1;
24847 * Placement constant - The resizing element is to the right of the splitter element
24851 Roo.SplitBar.RIGHT = 2;
24854 * Placement constant - The resizing element is positioned above the splitter element
24858 Roo.SplitBar.TOP = 3;
24861 * Placement constant - The resizing element is positioned under splitter element
24865 Roo.SplitBar.BOTTOM = 4;
24868 * Ext JS Library 1.1.1
24869 * Copyright(c) 2006-2007, Ext JS, LLC.
24871 * Originally Released Under LGPL - original licence link has changed is not relivant.
24874 * <script type="text/javascript">
24879 * @extends Roo.util.Observable
24880 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24881 * This class also supports single and multi selection modes. <br>
24882 * Create a data model bound view:
24884 var store = new Roo.data.Store(...);
24886 var view = new Roo.View({
24888 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24890 singleSelect: true,
24891 selectedClass: "ydataview-selected",
24895 // listen for node click?
24896 view.on("click", function(vw, index, node, e){
24897 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24901 dataModel.load("foobar.xml");
24903 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24905 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24906 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24908 * Note: old style constructor is still suported (container, template, config)
24911 * Create a new View
24912 * @param {Object} config The config object
24915 Roo.View = function(config, depreciated_tpl, depreciated_config){
24917 this.parent = false;
24919 if (typeof(depreciated_tpl) == 'undefined') {
24920 // new way.. - universal constructor.
24921 Roo.apply(this, config);
24922 this.el = Roo.get(this.el);
24925 this.el = Roo.get(config);
24926 this.tpl = depreciated_tpl;
24927 Roo.apply(this, depreciated_config);
24929 this.wrapEl = this.el.wrap().wrap();
24930 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24933 if(typeof(this.tpl) == "string"){
24934 this.tpl = new Roo.Template(this.tpl);
24936 // support xtype ctors..
24937 this.tpl = new Roo.factory(this.tpl, Roo);
24941 this.tpl.compile();
24946 * @event beforeclick
24947 * Fires before a click is processed. Returns false to cancel the default action.
24948 * @param {Roo.View} this
24949 * @param {Number} index The index of the target node
24950 * @param {HTMLElement} node The target node
24951 * @param {Roo.EventObject} e The raw event object
24953 "beforeclick" : true,
24956 * Fires when a template node is clicked.
24957 * @param {Roo.View} this
24958 * @param {Number} index The index of the target node
24959 * @param {HTMLElement} node The target node
24960 * @param {Roo.EventObject} e The raw event object
24965 * Fires when a template node is double clicked.
24966 * @param {Roo.View} this
24967 * @param {Number} index The index of the target node
24968 * @param {HTMLElement} node The target node
24969 * @param {Roo.EventObject} e The raw event object
24973 * @event contextmenu
24974 * Fires when a template node is right clicked.
24975 * @param {Roo.View} this
24976 * @param {Number} index The index of the target node
24977 * @param {HTMLElement} node The target node
24978 * @param {Roo.EventObject} e The raw event object
24980 "contextmenu" : true,
24982 * @event selectionchange
24983 * Fires when the selected nodes change.
24984 * @param {Roo.View} this
24985 * @param {Array} selections Array of the selected nodes
24987 "selectionchange" : true,
24990 * @event beforeselect
24991 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24992 * @param {Roo.View} this
24993 * @param {HTMLElement} node The node to be selected
24994 * @param {Array} selections Array of currently selected nodes
24996 "beforeselect" : true,
24998 * @event preparedata
24999 * Fires on every row to render, to allow you to change the data.
25000 * @param {Roo.View} this
25001 * @param {Object} data to be rendered (change this)
25003 "preparedata" : true
25011 "click": this.onClick,
25012 "dblclick": this.onDblClick,
25013 "contextmenu": this.onContextMenu,
25017 this.selections = [];
25019 this.cmp = new Roo.CompositeElementLite([]);
25021 this.store = Roo.factory(this.store, Roo.data);
25022 this.setStore(this.store, true);
25025 if ( this.footer && this.footer.xtype) {
25027 var fctr = this.wrapEl.appendChild(document.createElement("div"));
25029 this.footer.dataSource = this.store;
25030 this.footer.container = fctr;
25031 this.footer = Roo.factory(this.footer, Roo);
25032 fctr.insertFirst(this.el);
25034 // this is a bit insane - as the paging toolbar seems to detach the el..
25035 // dom.parentNode.parentNode.parentNode
25036 // they get detached?
25040 Roo.View.superclass.constructor.call(this);
25045 Roo.extend(Roo.View, Roo.util.Observable, {
25048 * @cfg {Roo.data.Store} store Data store to load data from.
25053 * @cfg {String|Roo.Element} el The container element.
25058 * @cfg {String|Roo.Template} tpl The template used by this View
25062 * @cfg {String} dataName the named area of the template to use as the data area
25063 * Works with domtemplates roo-name="name"
25067 * @cfg {String} selectedClass The css class to add to selected nodes
25069 selectedClass : "x-view-selected",
25071 * @cfg {String} emptyText The empty text to show when nothing is loaded.
25076 * @cfg {String} text to display on mask (default Loading)
25080 * @cfg {Boolean} multiSelect Allow multiple selection
25082 multiSelect : false,
25084 * @cfg {Boolean} singleSelect Allow single selection
25086 singleSelect: false,
25089 * @cfg {Boolean} toggleSelect - selecting
25091 toggleSelect : false,
25094 * @cfg {Boolean} tickable - selecting
25099 * Returns the element this view is bound to.
25100 * @return {Roo.Element}
25102 getEl : function(){
25103 return this.wrapEl;
25109 * Refreshes the view. - called by datachanged on the store. - do not call directly.
25111 refresh : function(){
25112 //Roo.log('refresh');
25115 // if we are using something like 'domtemplate', then
25116 // the what gets used is:
25117 // t.applySubtemplate(NAME, data, wrapping data..)
25118 // the outer template then get' applied with
25119 // the store 'extra data'
25120 // and the body get's added to the
25121 // roo-name="data" node?
25122 // <span class='roo-tpl-{name}'></span> ?????
25126 this.clearSelections();
25127 this.el.update("");
25129 var records = this.store.getRange();
25130 if(records.length < 1) {
25132 // is this valid?? = should it render a template??
25134 this.el.update(this.emptyText);
25138 if (this.dataName) {
25139 this.el.update(t.apply(this.store.meta)); //????
25140 el = this.el.child('.roo-tpl-' + this.dataName);
25143 for(var i = 0, len = records.length; i < len; i++){
25144 var data = this.prepareData(records[i].data, i, records[i]);
25145 this.fireEvent("preparedata", this, data, i, records[i]);
25147 var d = Roo.apply({}, data);
25150 Roo.apply(d, {'roo-id' : Roo.id()});
25154 Roo.each(this.parent.item, function(item){
25155 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
25158 Roo.apply(d, {'roo-data-checked' : 'checked'});
25162 html[html.length] = Roo.util.Format.trim(
25164 t.applySubtemplate(this.dataName, d, this.store.meta) :
25171 el.update(html.join(""));
25172 this.nodes = el.dom.childNodes;
25173 this.updateIndexes(0);
25178 * Function to override to reformat the data that is sent to
25179 * the template for each node.
25180 * DEPRICATED - use the preparedata event handler.
25181 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25182 * a JSON object for an UpdateManager bound view).
25184 prepareData : function(data, index, record)
25186 this.fireEvent("preparedata", this, data, index, record);
25190 onUpdate : function(ds, record){
25191 // Roo.log('on update');
25192 this.clearSelections();
25193 var index = this.store.indexOf(record);
25194 var n = this.nodes[index];
25195 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25196 n.parentNode.removeChild(n);
25197 this.updateIndexes(index, index);
25203 onAdd : function(ds, records, index)
25205 //Roo.log(['on Add', ds, records, index] );
25206 this.clearSelections();
25207 if(this.nodes.length == 0){
25211 var n = this.nodes[index];
25212 for(var i = 0, len = records.length; i < len; i++){
25213 var d = this.prepareData(records[i].data, i, records[i]);
25215 this.tpl.insertBefore(n, d);
25218 this.tpl.append(this.el, d);
25221 this.updateIndexes(index);
25224 onRemove : function(ds, record, index){
25225 // Roo.log('onRemove');
25226 this.clearSelections();
25227 var el = this.dataName ?
25228 this.el.child('.roo-tpl-' + this.dataName) :
25231 el.dom.removeChild(this.nodes[index]);
25232 this.updateIndexes(index);
25236 * Refresh an individual node.
25237 * @param {Number} index
25239 refreshNode : function(index){
25240 this.onUpdate(this.store, this.store.getAt(index));
25243 updateIndexes : function(startIndex, endIndex){
25244 var ns = this.nodes;
25245 startIndex = startIndex || 0;
25246 endIndex = endIndex || ns.length - 1;
25247 for(var i = startIndex; i <= endIndex; i++){
25248 ns[i].nodeIndex = i;
25253 * Changes the data store this view uses and refresh the view.
25254 * @param {Store} store
25256 setStore : function(store, initial){
25257 if(!initial && this.store){
25258 this.store.un("datachanged", this.refresh);
25259 this.store.un("add", this.onAdd);
25260 this.store.un("remove", this.onRemove);
25261 this.store.un("update", this.onUpdate);
25262 this.store.un("clear", this.refresh);
25263 this.store.un("beforeload", this.onBeforeLoad);
25264 this.store.un("load", this.onLoad);
25265 this.store.un("loadexception", this.onLoad);
25269 store.on("datachanged", this.refresh, this);
25270 store.on("add", this.onAdd, this);
25271 store.on("remove", this.onRemove, this);
25272 store.on("update", this.onUpdate, this);
25273 store.on("clear", this.refresh, this);
25274 store.on("beforeload", this.onBeforeLoad, this);
25275 store.on("load", this.onLoad, this);
25276 store.on("loadexception", this.onLoad, this);
25284 * onbeforeLoad - masks the loading area.
25287 onBeforeLoad : function(store,opts)
25289 //Roo.log('onBeforeLoad');
25291 this.el.update("");
25293 this.el.mask(this.mask ? this.mask : "Loading" );
25295 onLoad : function ()
25302 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25303 * @param {HTMLElement} node
25304 * @return {HTMLElement} The template node
25306 findItemFromChild : function(node){
25307 var el = this.dataName ?
25308 this.el.child('.roo-tpl-' + this.dataName,true) :
25311 if(!node || node.parentNode == el){
25314 var p = node.parentNode;
25315 while(p && p != el){
25316 if(p.parentNode == el){
25325 onClick : function(e){
25326 var item = this.findItemFromChild(e.getTarget());
25328 var index = this.indexOf(item);
25329 if(this.onItemClick(item, index, e) !== false){
25330 this.fireEvent("click", this, index, item, e);
25333 this.clearSelections();
25338 onContextMenu : function(e){
25339 var item = this.findItemFromChild(e.getTarget());
25341 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25346 onDblClick : function(e){
25347 var item = this.findItemFromChild(e.getTarget());
25349 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25353 onItemClick : function(item, index, e)
25355 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25358 if (this.toggleSelect) {
25359 var m = this.isSelected(item) ? 'unselect' : 'select';
25362 _t[m](item, true, false);
25365 if(this.multiSelect || this.singleSelect){
25366 if(this.multiSelect && e.shiftKey && this.lastSelection){
25367 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25369 this.select(item, this.multiSelect && e.ctrlKey);
25370 this.lastSelection = item;
25373 if(!this.tickable){
25374 e.preventDefault();
25382 * Get the number of selected nodes.
25385 getSelectionCount : function(){
25386 return this.selections.length;
25390 * Get the currently selected nodes.
25391 * @return {Array} An array of HTMLElements
25393 getSelectedNodes : function(){
25394 return this.selections;
25398 * Get the indexes of the selected nodes.
25401 getSelectedIndexes : function(){
25402 var indexes = [], s = this.selections;
25403 for(var i = 0, len = s.length; i < len; i++){
25404 indexes.push(s[i].nodeIndex);
25410 * Clear all selections
25411 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25413 clearSelections : function(suppressEvent){
25414 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25415 this.cmp.elements = this.selections;
25416 this.cmp.removeClass(this.selectedClass);
25417 this.selections = [];
25418 if(!suppressEvent){
25419 this.fireEvent("selectionchange", this, this.selections);
25425 * Returns true if the passed node is selected
25426 * @param {HTMLElement/Number} node The node or node index
25427 * @return {Boolean}
25429 isSelected : function(node){
25430 var s = this.selections;
25434 node = this.getNode(node);
25435 return s.indexOf(node) !== -1;
25440 * @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
25441 * @param {Boolean} keepExisting (optional) true to keep existing selections
25442 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25444 select : function(nodeInfo, keepExisting, suppressEvent){
25445 if(nodeInfo instanceof Array){
25447 this.clearSelections(true);
25449 for(var i = 0, len = nodeInfo.length; i < len; i++){
25450 this.select(nodeInfo[i], true, true);
25454 var node = this.getNode(nodeInfo);
25455 if(!node || this.isSelected(node)){
25456 return; // already selected.
25459 this.clearSelections(true);
25462 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25463 Roo.fly(node).addClass(this.selectedClass);
25464 this.selections.push(node);
25465 if(!suppressEvent){
25466 this.fireEvent("selectionchange", this, this.selections);
25474 * @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
25475 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25476 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25478 unselect : function(nodeInfo, keepExisting, suppressEvent)
25480 if(nodeInfo instanceof Array){
25481 Roo.each(this.selections, function(s) {
25482 this.unselect(s, nodeInfo);
25486 var node = this.getNode(nodeInfo);
25487 if(!node || !this.isSelected(node)){
25488 //Roo.log("not selected");
25489 return; // not selected.
25493 Roo.each(this.selections, function(s) {
25495 Roo.fly(node).removeClass(this.selectedClass);
25502 this.selections= ns;
25503 this.fireEvent("selectionchange", this, this.selections);
25507 * Gets a template node.
25508 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25509 * @return {HTMLElement} The node or null if it wasn't found
25511 getNode : function(nodeInfo){
25512 if(typeof nodeInfo == "string"){
25513 return document.getElementById(nodeInfo);
25514 }else if(typeof nodeInfo == "number"){
25515 return this.nodes[nodeInfo];
25521 * Gets a range template nodes.
25522 * @param {Number} startIndex
25523 * @param {Number} endIndex
25524 * @return {Array} An array of nodes
25526 getNodes : function(start, end){
25527 var ns = this.nodes;
25528 start = start || 0;
25529 end = typeof end == "undefined" ? ns.length - 1 : end;
25532 for(var i = start; i <= end; i++){
25536 for(var i = start; i >= end; i--){
25544 * Finds the index of the passed node
25545 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25546 * @return {Number} The index of the node or -1
25548 indexOf : function(node){
25549 node = this.getNode(node);
25550 if(typeof node.nodeIndex == "number"){
25551 return node.nodeIndex;
25553 var ns = this.nodes;
25554 for(var i = 0, len = ns.length; i < len; i++){
25564 * Ext JS Library 1.1.1
25565 * Copyright(c) 2006-2007, Ext JS, LLC.
25567 * Originally Released Under LGPL - original licence link has changed is not relivant.
25570 * <script type="text/javascript">
25574 * @class Roo.JsonView
25575 * @extends Roo.View
25576 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25578 var view = new Roo.JsonView({
25579 container: "my-element",
25580 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25585 // listen for node click?
25586 view.on("click", function(vw, index, node, e){
25587 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25590 // direct load of JSON data
25591 view.load("foobar.php");
25593 // Example from my blog list
25594 var tpl = new Roo.Template(
25595 '<div class="entry">' +
25596 '<a class="entry-title" href="{link}">{title}</a>' +
25597 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25598 "</div><hr />"
25601 var moreView = new Roo.JsonView({
25602 container : "entry-list",
25606 moreView.on("beforerender", this.sortEntries, this);
25608 url: "/blog/get-posts.php",
25609 params: "allposts=true",
25610 text: "Loading Blog Entries..."
25614 * Note: old code is supported with arguments : (container, template, config)
25618 * Create a new JsonView
25620 * @param {Object} config The config object
25623 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25626 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25628 var um = this.el.getUpdateManager();
25629 um.setRenderer(this);
25630 um.on("update", this.onLoad, this);
25631 um.on("failure", this.onLoadException, this);
25634 * @event beforerender
25635 * Fires before rendering of the downloaded JSON data.
25636 * @param {Roo.JsonView} this
25637 * @param {Object} data The JSON data loaded
25641 * Fires when data is loaded.
25642 * @param {Roo.JsonView} this
25643 * @param {Object} data The JSON data loaded
25644 * @param {Object} response The raw Connect response object
25647 * @event loadexception
25648 * Fires when loading fails.
25649 * @param {Roo.JsonView} this
25650 * @param {Object} response The raw Connect response object
25653 'beforerender' : true,
25655 'loadexception' : true
25658 Roo.extend(Roo.JsonView, Roo.View, {
25660 * @type {String} The root property in the loaded JSON object that contains the data
25665 * Refreshes the view.
25667 refresh : function(){
25668 this.clearSelections();
25669 this.el.update("");
25671 var o = this.jsonData;
25672 if(o && o.length > 0){
25673 for(var i = 0, len = o.length; i < len; i++){
25674 var data = this.prepareData(o[i], i, o);
25675 html[html.length] = this.tpl.apply(data);
25678 html.push(this.emptyText);
25680 this.el.update(html.join(""));
25681 this.nodes = this.el.dom.childNodes;
25682 this.updateIndexes(0);
25686 * 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.
25687 * @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:
25690 url: "your-url.php",
25691 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25692 callback: yourFunction,
25693 scope: yourObject, //(optional scope)
25696 text: "Loading...",
25701 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25702 * 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.
25703 * @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}
25704 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25705 * @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.
25708 var um = this.el.getUpdateManager();
25709 um.update.apply(um, arguments);
25712 render : function(el, response){
25713 this.clearSelections();
25714 this.el.update("");
25717 o = Roo.util.JSON.decode(response.responseText);
25720 o = o[this.jsonRoot];
25725 * The current JSON data or null
25728 this.beforeRender();
25733 * Get the number of records in the current JSON dataset
25736 getCount : function(){
25737 return this.jsonData ? this.jsonData.length : 0;
25741 * Returns the JSON object for the specified node(s)
25742 * @param {HTMLElement/Array} node The node or an array of nodes
25743 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25744 * you get the JSON object for the node
25746 getNodeData : function(node){
25747 if(node instanceof Array){
25749 for(var i = 0, len = node.length; i < len; i++){
25750 data.push(this.getNodeData(node[i]));
25754 return this.jsonData[this.indexOf(node)] || null;
25757 beforeRender : function(){
25758 this.snapshot = this.jsonData;
25760 this.sort.apply(this, this.sortInfo);
25762 this.fireEvent("beforerender", this, this.jsonData);
25765 onLoad : function(el, o){
25766 this.fireEvent("load", this, this.jsonData, o);
25769 onLoadException : function(el, o){
25770 this.fireEvent("loadexception", this, o);
25774 * Filter the data by a specific property.
25775 * @param {String} property A property on your JSON objects
25776 * @param {String/RegExp} value Either string that the property values
25777 * should start with, or a RegExp to test against the property
25779 filter : function(property, value){
25782 var ss = this.snapshot;
25783 if(typeof value == "string"){
25784 var vlen = value.length;
25786 this.clearFilter();
25789 value = value.toLowerCase();
25790 for(var i = 0, len = ss.length; i < len; i++){
25792 if(o[property].substr(0, vlen).toLowerCase() == value){
25796 } else if(value.exec){ // regex?
25797 for(var i = 0, len = ss.length; i < len; i++){
25799 if(value.test(o[property])){
25806 this.jsonData = data;
25812 * Filter by a function. The passed function will be called with each
25813 * object in the current dataset. If the function returns true the value is kept,
25814 * otherwise it is filtered.
25815 * @param {Function} fn
25816 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25818 filterBy : function(fn, scope){
25821 var ss = this.snapshot;
25822 for(var i = 0, len = ss.length; i < len; i++){
25824 if(fn.call(scope || this, o)){
25828 this.jsonData = data;
25834 * Clears the current filter.
25836 clearFilter : function(){
25837 if(this.snapshot && this.jsonData != this.snapshot){
25838 this.jsonData = this.snapshot;
25845 * Sorts the data for this view and refreshes it.
25846 * @param {String} property A property on your JSON objects to sort on
25847 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25848 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25850 sort : function(property, dir, sortType){
25851 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25854 var dsc = dir && dir.toLowerCase() == "desc";
25855 var f = function(o1, o2){
25856 var v1 = sortType ? sortType(o1[p]) : o1[p];
25857 var v2 = sortType ? sortType(o2[p]) : o2[p];
25860 return dsc ? +1 : -1;
25861 } else if(v1 > v2){
25862 return dsc ? -1 : +1;
25867 this.jsonData.sort(f);
25869 if(this.jsonData != this.snapshot){
25870 this.snapshot.sort(f);
25876 * Ext JS Library 1.1.1
25877 * Copyright(c) 2006-2007, Ext JS, LLC.
25879 * Originally Released Under LGPL - original licence link has changed is not relivant.
25882 * <script type="text/javascript">
25887 * @class Roo.ColorPalette
25888 * @extends Roo.Component
25889 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25890 * Here's an example of typical usage:
25892 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25893 cp.render('my-div');
25895 cp.on('select', function(palette, selColor){
25896 // do something with selColor
25900 * Create a new ColorPalette
25901 * @param {Object} config The config object
25903 Roo.ColorPalette = function(config){
25904 Roo.ColorPalette.superclass.constructor.call(this, config);
25908 * Fires when a color is selected
25909 * @param {ColorPalette} this
25910 * @param {String} color The 6-digit color hex code (without the # symbol)
25916 this.on("select", this.handler, this.scope, true);
25919 Roo.extend(Roo.ColorPalette, Roo.Component, {
25921 * @cfg {String} itemCls
25922 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25924 itemCls : "x-color-palette",
25926 * @cfg {String} value
25927 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25928 * the hex codes are case-sensitive.
25931 clickEvent:'click',
25933 ctype: "Roo.ColorPalette",
25936 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25938 allowReselect : false,
25941 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25942 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25943 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25944 * of colors with the width setting until the box is symmetrical.</p>
25945 * <p>You can override individual colors if needed:</p>
25947 var cp = new Roo.ColorPalette();
25948 cp.colors[0] = "FF0000"; // change the first box to red
25951 Or you can provide a custom array of your own for complete control:
25953 var cp = new Roo.ColorPalette();
25954 cp.colors = ["000000", "993300", "333300"];
25959 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25960 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25961 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25962 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25963 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25967 onRender : function(container, position){
25968 var t = new Roo.MasterTemplate(
25969 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25971 var c = this.colors;
25972 for(var i = 0, len = c.length; i < len; i++){
25975 var el = document.createElement("div");
25976 el.className = this.itemCls;
25978 container.dom.insertBefore(el, position);
25979 this.el = Roo.get(el);
25980 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25981 if(this.clickEvent != 'click'){
25982 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25987 afterRender : function(){
25988 Roo.ColorPalette.superclass.afterRender.call(this);
25990 var s = this.value;
25997 handleClick : function(e, t){
25998 e.preventDefault();
25999 if(!this.disabled){
26000 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
26001 this.select(c.toUpperCase());
26006 * Selects the specified color in the palette (fires the select event)
26007 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
26009 select : function(color){
26010 color = color.replace("#", "");
26011 if(color != this.value || this.allowReselect){
26014 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
26016 el.child("a.color-"+color).addClass("x-color-palette-sel");
26017 this.value = color;
26018 this.fireEvent("select", this, color);
26023 * Ext JS Library 1.1.1
26024 * Copyright(c) 2006-2007, Ext JS, LLC.
26026 * Originally Released Under LGPL - original licence link has changed is not relivant.
26029 * <script type="text/javascript">
26033 * @class Roo.DatePicker
26034 * @extends Roo.Component
26035 * Simple date picker class.
26037 * Create a new DatePicker
26038 * @param {Object} config The config object
26040 Roo.DatePicker = function(config){
26041 Roo.DatePicker.superclass.constructor.call(this, config);
26043 this.value = config && config.value ?
26044 config.value.clearTime() : new Date().clearTime();
26049 * Fires when a date is selected
26050 * @param {DatePicker} this
26051 * @param {Date} date The selected date
26055 * @event monthchange
26056 * Fires when the displayed month changes
26057 * @param {DatePicker} this
26058 * @param {Date} date The selected month
26060 'monthchange': true
26064 this.on("select", this.handler, this.scope || this);
26066 // build the disabledDatesRE
26067 if(!this.disabledDatesRE && this.disabledDates){
26068 var dd = this.disabledDates;
26070 for(var i = 0; i < dd.length; i++){
26072 if(i != dd.length-1) {
26076 this.disabledDatesRE = new RegExp(re + ")");
26080 Roo.extend(Roo.DatePicker, Roo.Component, {
26082 * @cfg {String} todayText
26083 * The text to display on the button that selects the current date (defaults to "Today")
26085 todayText : "Today",
26087 * @cfg {String} okText
26088 * The text to display on the ok button
26090 okText : " OK ", //   to give the user extra clicking room
26092 * @cfg {String} cancelText
26093 * The text to display on the cancel button
26095 cancelText : "Cancel",
26097 * @cfg {String} todayTip
26098 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
26100 todayTip : "{0} (Spacebar)",
26102 * @cfg {Date} minDate
26103 * Minimum allowable date (JavaScript date object, defaults to null)
26107 * @cfg {Date} maxDate
26108 * Maximum allowable date (JavaScript date object, defaults to null)
26112 * @cfg {String} minText
26113 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
26115 minText : "This date is before the minimum date",
26117 * @cfg {String} maxText
26118 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
26120 maxText : "This date is after the maximum date",
26122 * @cfg {String} format
26123 * The default date format string which can be overriden for localization support. The format must be
26124 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
26128 * @cfg {Array} disabledDays
26129 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
26131 disabledDays : null,
26133 * @cfg {String} disabledDaysText
26134 * The tooltip to display when the date falls on a disabled day (defaults to "")
26136 disabledDaysText : "",
26138 * @cfg {RegExp} disabledDatesRE
26139 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
26141 disabledDatesRE : null,
26143 * @cfg {String} disabledDatesText
26144 * The tooltip text to display when the date falls on a disabled date (defaults to "")
26146 disabledDatesText : "",
26148 * @cfg {Boolean} constrainToViewport
26149 * True to constrain the date picker to the viewport (defaults to true)
26151 constrainToViewport : true,
26153 * @cfg {Array} monthNames
26154 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
26156 monthNames : Date.monthNames,
26158 * @cfg {Array} dayNames
26159 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
26161 dayNames : Date.dayNames,
26163 * @cfg {String} nextText
26164 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
26166 nextText: 'Next Month (Control+Right)',
26168 * @cfg {String} prevText
26169 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
26171 prevText: 'Previous Month (Control+Left)',
26173 * @cfg {String} monthYearText
26174 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
26176 monthYearText: 'Choose a month (Control+Up/Down to move years)',
26178 * @cfg {Number} startDay
26179 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
26183 * @cfg {Bool} showClear
26184 * Show a clear button (usefull for date form elements that can be blank.)
26190 * Sets the value of the date field
26191 * @param {Date} value The date to set
26193 setValue : function(value){
26194 var old = this.value;
26196 if (typeof(value) == 'string') {
26198 value = Date.parseDate(value, this.format);
26201 value = new Date();
26204 this.value = value.clearTime(true);
26206 this.update(this.value);
26211 * Gets the current selected value of the date field
26212 * @return {Date} The selected date
26214 getValue : function(){
26219 focus : function(){
26221 this.update(this.activeDate);
26226 onRender : function(container, position){
26229 '<table cellspacing="0">',
26230 '<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>',
26231 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26232 var dn = this.dayNames;
26233 for(var i = 0; i < 7; i++){
26234 var d = this.startDay+i;
26238 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26240 m[m.length] = "</tr></thead><tbody><tr>";
26241 for(var i = 0; i < 42; i++) {
26242 if(i % 7 == 0 && i != 0){
26243 m[m.length] = "</tr><tr>";
26245 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26247 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26248 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26250 var el = document.createElement("div");
26251 el.className = "x-date-picker";
26252 el.innerHTML = m.join("");
26254 container.dom.insertBefore(el, position);
26256 this.el = Roo.get(el);
26257 this.eventEl = Roo.get(el.firstChild);
26259 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26260 handler: this.showPrevMonth,
26262 preventDefault:true,
26266 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26267 handler: this.showNextMonth,
26269 preventDefault:true,
26273 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26275 this.monthPicker = this.el.down('div.x-date-mp');
26276 this.monthPicker.enableDisplayMode('block');
26278 var kn = new Roo.KeyNav(this.eventEl, {
26279 "left" : function(e){
26281 this.showPrevMonth() :
26282 this.update(this.activeDate.add("d", -1));
26285 "right" : function(e){
26287 this.showNextMonth() :
26288 this.update(this.activeDate.add("d", 1));
26291 "up" : function(e){
26293 this.showNextYear() :
26294 this.update(this.activeDate.add("d", -7));
26297 "down" : function(e){
26299 this.showPrevYear() :
26300 this.update(this.activeDate.add("d", 7));
26303 "pageUp" : function(e){
26304 this.showNextMonth();
26307 "pageDown" : function(e){
26308 this.showPrevMonth();
26311 "enter" : function(e){
26312 e.stopPropagation();
26319 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26321 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26323 this.el.unselectable();
26325 this.cells = this.el.select("table.x-date-inner tbody td");
26326 this.textNodes = this.el.query("table.x-date-inner tbody span");
26328 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26330 tooltip: this.monthYearText
26333 this.mbtn.on('click', this.showMonthPicker, this);
26334 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26337 var today = (new Date()).dateFormat(this.format);
26339 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26340 if (this.showClear) {
26341 baseTb.add( new Roo.Toolbar.Fill());
26344 text: String.format(this.todayText, today),
26345 tooltip: String.format(this.todayTip, today),
26346 handler: this.selectToday,
26350 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26353 if (this.showClear) {
26355 baseTb.add( new Roo.Toolbar.Fill());
26358 cls: 'x-btn-icon x-btn-clear',
26359 handler: function() {
26361 this.fireEvent("select", this, '');
26371 this.update(this.value);
26374 createMonthPicker : function(){
26375 if(!this.monthPicker.dom.firstChild){
26376 var buf = ['<table border="0" cellspacing="0">'];
26377 for(var i = 0; i < 6; i++){
26379 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26380 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26382 '<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>' :
26383 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26387 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26389 '</button><button type="button" class="x-date-mp-cancel">',
26391 '</button></td></tr>',
26394 this.monthPicker.update(buf.join(''));
26395 this.monthPicker.on('click', this.onMonthClick, this);
26396 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26398 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26399 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26401 this.mpMonths.each(function(m, a, i){
26404 m.dom.xmonth = 5 + Math.round(i * .5);
26406 m.dom.xmonth = Math.round((i-1) * .5);
26412 showMonthPicker : function(){
26413 this.createMonthPicker();
26414 var size = this.el.getSize();
26415 this.monthPicker.setSize(size);
26416 this.monthPicker.child('table').setSize(size);
26418 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26419 this.updateMPMonth(this.mpSelMonth);
26420 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26421 this.updateMPYear(this.mpSelYear);
26423 this.monthPicker.slideIn('t', {duration:.2});
26426 updateMPYear : function(y){
26428 var ys = this.mpYears.elements;
26429 for(var i = 1; i <= 10; i++){
26430 var td = ys[i-1], y2;
26432 y2 = y + Math.round(i * .5);
26433 td.firstChild.innerHTML = y2;
26436 y2 = y - (5-Math.round(i * .5));
26437 td.firstChild.innerHTML = y2;
26440 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26444 updateMPMonth : function(sm){
26445 this.mpMonths.each(function(m, a, i){
26446 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26450 selectMPMonth: function(m){
26454 onMonthClick : function(e, t){
26456 var el = new Roo.Element(t), pn;
26457 if(el.is('button.x-date-mp-cancel')){
26458 this.hideMonthPicker();
26460 else if(el.is('button.x-date-mp-ok')){
26461 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26462 this.hideMonthPicker();
26464 else if(pn = el.up('td.x-date-mp-month', 2)){
26465 this.mpMonths.removeClass('x-date-mp-sel');
26466 pn.addClass('x-date-mp-sel');
26467 this.mpSelMonth = pn.dom.xmonth;
26469 else if(pn = el.up('td.x-date-mp-year', 2)){
26470 this.mpYears.removeClass('x-date-mp-sel');
26471 pn.addClass('x-date-mp-sel');
26472 this.mpSelYear = pn.dom.xyear;
26474 else if(el.is('a.x-date-mp-prev')){
26475 this.updateMPYear(this.mpyear-10);
26477 else if(el.is('a.x-date-mp-next')){
26478 this.updateMPYear(this.mpyear+10);
26482 onMonthDblClick : function(e, t){
26484 var el = new Roo.Element(t), pn;
26485 if(pn = el.up('td.x-date-mp-month', 2)){
26486 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26487 this.hideMonthPicker();
26489 else if(pn = el.up('td.x-date-mp-year', 2)){
26490 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26491 this.hideMonthPicker();
26495 hideMonthPicker : function(disableAnim){
26496 if(this.monthPicker){
26497 if(disableAnim === true){
26498 this.monthPicker.hide();
26500 this.monthPicker.slideOut('t', {duration:.2});
26506 showPrevMonth : function(e){
26507 this.update(this.activeDate.add("mo", -1));
26511 showNextMonth : function(e){
26512 this.update(this.activeDate.add("mo", 1));
26516 showPrevYear : function(){
26517 this.update(this.activeDate.add("y", -1));
26521 showNextYear : function(){
26522 this.update(this.activeDate.add("y", 1));
26526 handleMouseWheel : function(e){
26527 var delta = e.getWheelDelta();
26529 this.showPrevMonth();
26531 } else if(delta < 0){
26532 this.showNextMonth();
26538 handleDateClick : function(e, t){
26540 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26541 this.setValue(new Date(t.dateValue));
26542 this.fireEvent("select", this, this.value);
26547 selectToday : function(){
26548 this.setValue(new Date().clearTime());
26549 this.fireEvent("select", this, this.value);
26553 update : function(date)
26555 var vd = this.activeDate;
26556 this.activeDate = date;
26558 var t = date.getTime();
26559 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26560 this.cells.removeClass("x-date-selected");
26561 this.cells.each(function(c){
26562 if(c.dom.firstChild.dateValue == t){
26563 c.addClass("x-date-selected");
26564 setTimeout(function(){
26565 try{c.dom.firstChild.focus();}catch(e){}
26574 var days = date.getDaysInMonth();
26575 var firstOfMonth = date.getFirstDateOfMonth();
26576 var startingPos = firstOfMonth.getDay()-this.startDay;
26578 if(startingPos <= this.startDay){
26582 var pm = date.add("mo", -1);
26583 var prevStart = pm.getDaysInMonth()-startingPos;
26585 var cells = this.cells.elements;
26586 var textEls = this.textNodes;
26587 days += startingPos;
26589 // convert everything to numbers so it's fast
26590 var day = 86400000;
26591 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26592 var today = new Date().clearTime().getTime();
26593 var sel = date.clearTime().getTime();
26594 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26595 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26596 var ddMatch = this.disabledDatesRE;
26597 var ddText = this.disabledDatesText;
26598 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26599 var ddaysText = this.disabledDaysText;
26600 var format = this.format;
26602 var setCellClass = function(cal, cell){
26604 var t = d.getTime();
26605 cell.firstChild.dateValue = t;
26607 cell.className += " x-date-today";
26608 cell.title = cal.todayText;
26611 cell.className += " x-date-selected";
26612 setTimeout(function(){
26613 try{cell.firstChild.focus();}catch(e){}
26618 cell.className = " x-date-disabled";
26619 cell.title = cal.minText;
26623 cell.className = " x-date-disabled";
26624 cell.title = cal.maxText;
26628 if(ddays.indexOf(d.getDay()) != -1){
26629 cell.title = ddaysText;
26630 cell.className = " x-date-disabled";
26633 if(ddMatch && format){
26634 var fvalue = d.dateFormat(format);
26635 if(ddMatch.test(fvalue)){
26636 cell.title = ddText.replace("%0", fvalue);
26637 cell.className = " x-date-disabled";
26643 for(; i < startingPos; i++) {
26644 textEls[i].innerHTML = (++prevStart);
26645 d.setDate(d.getDate()+1);
26646 cells[i].className = "x-date-prevday";
26647 setCellClass(this, cells[i]);
26649 for(; i < days; i++){
26650 intDay = i - startingPos + 1;
26651 textEls[i].innerHTML = (intDay);
26652 d.setDate(d.getDate()+1);
26653 cells[i].className = "x-date-active";
26654 setCellClass(this, cells[i]);
26657 for(; i < 42; i++) {
26658 textEls[i].innerHTML = (++extraDays);
26659 d.setDate(d.getDate()+1);
26660 cells[i].className = "x-date-nextday";
26661 setCellClass(this, cells[i]);
26664 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26665 this.fireEvent('monthchange', this, date);
26667 if(!this.internalRender){
26668 var main = this.el.dom.firstChild;
26669 var w = main.offsetWidth;
26670 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26671 Roo.fly(main).setWidth(w);
26672 this.internalRender = true;
26673 // opera does not respect the auto grow header center column
26674 // then, after it gets a width opera refuses to recalculate
26675 // without a second pass
26676 if(Roo.isOpera && !this.secondPass){
26677 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26678 this.secondPass = true;
26679 this.update.defer(10, this, [date]);
26687 * Ext JS Library 1.1.1
26688 * Copyright(c) 2006-2007, Ext JS, LLC.
26690 * Originally Released Under LGPL - original licence link has changed is not relivant.
26693 * <script type="text/javascript">
26696 * @class Roo.TabPanel
26697 * @extends Roo.util.Observable
26698 * A lightweight tab container.
26702 // basic tabs 1, built from existing content
26703 var tabs = new Roo.TabPanel("tabs1");
26704 tabs.addTab("script", "View Script");
26705 tabs.addTab("markup", "View Markup");
26706 tabs.activate("script");
26708 // more advanced tabs, built from javascript
26709 var jtabs = new Roo.TabPanel("jtabs");
26710 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26712 // set up the UpdateManager
26713 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26714 var updater = tab2.getUpdateManager();
26715 updater.setDefaultUrl("ajax1.htm");
26716 tab2.on('activate', updater.refresh, updater, true);
26718 // Use setUrl for Ajax loading
26719 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26720 tab3.setUrl("ajax2.htm", null, true);
26723 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26726 jtabs.activate("jtabs-1");
26729 * Create a new TabPanel.
26730 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26731 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26733 Roo.TabPanel = function(container, config){
26735 * The container element for this TabPanel.
26736 * @type Roo.Element
26738 this.el = Roo.get(container, true);
26740 if(typeof config == "boolean"){
26741 this.tabPosition = config ? "bottom" : "top";
26743 Roo.apply(this, config);
26746 if(this.tabPosition == "bottom"){
26747 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26748 this.el.addClass("x-tabs-bottom");
26750 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26751 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26752 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26754 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26756 if(this.tabPosition != "bottom"){
26757 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26758 * @type Roo.Element
26760 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26761 this.el.addClass("x-tabs-top");
26765 this.bodyEl.setStyle("position", "relative");
26767 this.active = null;
26768 this.activateDelegate = this.activate.createDelegate(this);
26773 * Fires when the active tab changes
26774 * @param {Roo.TabPanel} this
26775 * @param {Roo.TabPanelItem} activePanel The new active tab
26779 * @event beforetabchange
26780 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26781 * @param {Roo.TabPanel} this
26782 * @param {Object} e Set cancel to true on this object to cancel the tab change
26783 * @param {Roo.TabPanelItem} tab The tab being changed to
26785 "beforetabchange" : true
26788 Roo.EventManager.onWindowResize(this.onResize, this);
26789 this.cpad = this.el.getPadding("lr");
26790 this.hiddenCount = 0;
26793 // toolbar on the tabbar support...
26794 if (this.toolbar) {
26795 var tcfg = this.toolbar;
26796 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26797 this.toolbar = new Roo.Toolbar(tcfg);
26798 if (Roo.isSafari) {
26799 var tbl = tcfg.container.child('table', true);
26800 tbl.setAttribute('width', '100%');
26807 Roo.TabPanel.superclass.constructor.call(this);
26810 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26812 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26814 tabPosition : "top",
26816 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26818 currentTabWidth : 0,
26820 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26824 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26828 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26830 preferredTabWidth : 175,
26832 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26834 resizeTabs : false,
26836 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26838 monitorResize : true,
26840 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26845 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26846 * @param {String} id The id of the div to use <b>or create</b>
26847 * @param {String} text The text for the tab
26848 * @param {String} content (optional) Content to put in the TabPanelItem body
26849 * @param {Boolean} closable (optional) True to create a close icon on the tab
26850 * @return {Roo.TabPanelItem} The created TabPanelItem
26852 addTab : function(id, text, content, closable){
26853 var item = new Roo.TabPanelItem(this, id, text, closable);
26854 this.addTabItem(item);
26856 item.setContent(content);
26862 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26863 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26864 * @return {Roo.TabPanelItem}
26866 getTab : function(id){
26867 return this.items[id];
26871 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26872 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26874 hideTab : function(id){
26875 var t = this.items[id];
26878 this.hiddenCount++;
26879 this.autoSizeTabs();
26884 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26885 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26887 unhideTab : function(id){
26888 var t = this.items[id];
26890 t.setHidden(false);
26891 this.hiddenCount--;
26892 this.autoSizeTabs();
26897 * Adds an existing {@link Roo.TabPanelItem}.
26898 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26900 addTabItem : function(item){
26901 this.items[item.id] = item;
26902 this.items.push(item);
26903 if(this.resizeTabs){
26904 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26905 this.autoSizeTabs();
26912 * Removes a {@link Roo.TabPanelItem}.
26913 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26915 removeTab : function(id){
26916 var items = this.items;
26917 var tab = items[id];
26918 if(!tab) { return; }
26919 var index = items.indexOf(tab);
26920 if(this.active == tab && items.length > 1){
26921 var newTab = this.getNextAvailable(index);
26926 this.stripEl.dom.removeChild(tab.pnode.dom);
26927 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26928 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26930 items.splice(index, 1);
26931 delete this.items[tab.id];
26932 tab.fireEvent("close", tab);
26933 tab.purgeListeners();
26934 this.autoSizeTabs();
26937 getNextAvailable : function(start){
26938 var items = this.items;
26940 // look for a next tab that will slide over to
26941 // replace the one being removed
26942 while(index < items.length){
26943 var item = items[++index];
26944 if(item && !item.isHidden()){
26948 // if one isn't found select the previous tab (on the left)
26951 var item = items[--index];
26952 if(item && !item.isHidden()){
26960 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26961 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26963 disableTab : function(id){
26964 var tab = this.items[id];
26965 if(tab && this.active != tab){
26971 * Enables a {@link Roo.TabPanelItem} that is disabled.
26972 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26974 enableTab : function(id){
26975 var tab = this.items[id];
26980 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26981 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26982 * @return {Roo.TabPanelItem} The TabPanelItem.
26984 activate : function(id){
26985 var tab = this.items[id];
26989 if(tab == this.active || tab.disabled){
26993 this.fireEvent("beforetabchange", this, e, tab);
26994 if(e.cancel !== true && !tab.disabled){
26996 this.active.hide();
26998 this.active = this.items[id];
26999 this.active.show();
27000 this.fireEvent("tabchange", this, this.active);
27006 * Gets the active {@link Roo.TabPanelItem}.
27007 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
27009 getActiveTab : function(){
27010 return this.active;
27014 * Updates the tab body element to fit the height of the container element
27015 * for overflow scrolling
27016 * @param {Number} targetHeight (optional) Override the starting height from the elements height
27018 syncHeight : function(targetHeight){
27019 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
27020 var bm = this.bodyEl.getMargins();
27021 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
27022 this.bodyEl.setHeight(newHeight);
27026 onResize : function(){
27027 if(this.monitorResize){
27028 this.autoSizeTabs();
27033 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
27035 beginUpdate : function(){
27036 this.updating = true;
27040 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
27042 endUpdate : function(){
27043 this.updating = false;
27044 this.autoSizeTabs();
27048 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
27050 autoSizeTabs : function(){
27051 var count = this.items.length;
27052 var vcount = count - this.hiddenCount;
27053 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
27056 var w = Math.max(this.el.getWidth() - this.cpad, 10);
27057 var availWidth = Math.floor(w / vcount);
27058 var b = this.stripBody;
27059 if(b.getWidth() > w){
27060 var tabs = this.items;
27061 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
27062 if(availWidth < this.minTabWidth){
27063 /*if(!this.sleft){ // incomplete scrolling code
27064 this.createScrollButtons();
27067 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
27070 if(this.currentTabWidth < this.preferredTabWidth){
27071 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
27077 * Returns the number of tabs in this TabPanel.
27080 getCount : function(){
27081 return this.items.length;
27085 * Resizes all the tabs to the passed width
27086 * @param {Number} The new width
27088 setTabWidth : function(width){
27089 this.currentTabWidth = width;
27090 for(var i = 0, len = this.items.length; i < len; i++) {
27091 if(!this.items[i].isHidden()) {
27092 this.items[i].setWidth(width);
27098 * Destroys this TabPanel
27099 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
27101 destroy : function(removeEl){
27102 Roo.EventManager.removeResizeListener(this.onResize, this);
27103 for(var i = 0, len = this.items.length; i < len; i++){
27104 this.items[i].purgeListeners();
27106 if(removeEl === true){
27107 this.el.update("");
27114 * @class Roo.TabPanelItem
27115 * @extends Roo.util.Observable
27116 * Represents an individual item (tab plus body) in a TabPanel.
27117 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
27118 * @param {String} id The id of this TabPanelItem
27119 * @param {String} text The text for the tab of this TabPanelItem
27120 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
27122 Roo.TabPanelItem = function(tabPanel, id, text, closable){
27124 * The {@link Roo.TabPanel} this TabPanelItem belongs to
27125 * @type Roo.TabPanel
27127 this.tabPanel = tabPanel;
27129 * The id for this TabPanelItem
27134 this.disabled = false;
27138 this.loaded = false;
27139 this.closable = closable;
27142 * The body element for this TabPanelItem.
27143 * @type Roo.Element
27145 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
27146 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
27147 this.bodyEl.setStyle("display", "block");
27148 this.bodyEl.setStyle("zoom", "1");
27151 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
27153 this.el = Roo.get(els.el, true);
27154 this.inner = Roo.get(els.inner, true);
27155 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
27156 this.pnode = Roo.get(els.el.parentNode, true);
27157 this.el.on("mousedown", this.onTabMouseDown, this);
27158 this.el.on("click", this.onTabClick, this);
27161 var c = Roo.get(els.close, true);
27162 c.dom.title = this.closeText;
27163 c.addClassOnOver("close-over");
27164 c.on("click", this.closeClick, this);
27170 * Fires when this tab becomes the active tab.
27171 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27172 * @param {Roo.TabPanelItem} this
27176 * @event beforeclose
27177 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
27178 * @param {Roo.TabPanelItem} this
27179 * @param {Object} e Set cancel to true on this object to cancel the close.
27181 "beforeclose": true,
27184 * Fires when this tab is closed.
27185 * @param {Roo.TabPanelItem} this
27189 * @event deactivate
27190 * Fires when this tab is no longer the active tab.
27191 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27192 * @param {Roo.TabPanelItem} this
27194 "deactivate" : true
27196 this.hidden = false;
27198 Roo.TabPanelItem.superclass.constructor.call(this);
27201 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27202 purgeListeners : function(){
27203 Roo.util.Observable.prototype.purgeListeners.call(this);
27204 this.el.removeAllListeners();
27207 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27210 this.pnode.addClass("on");
27213 this.tabPanel.stripWrap.repaint();
27215 this.fireEvent("activate", this.tabPanel, this);
27219 * Returns true if this tab is the active tab.
27220 * @return {Boolean}
27222 isActive : function(){
27223 return this.tabPanel.getActiveTab() == this;
27227 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27230 this.pnode.removeClass("on");
27232 this.fireEvent("deactivate", this.tabPanel, this);
27235 hideAction : function(){
27236 this.bodyEl.hide();
27237 this.bodyEl.setStyle("position", "absolute");
27238 this.bodyEl.setLeft("-20000px");
27239 this.bodyEl.setTop("-20000px");
27242 showAction : function(){
27243 this.bodyEl.setStyle("position", "relative");
27244 this.bodyEl.setTop("");
27245 this.bodyEl.setLeft("");
27246 this.bodyEl.show();
27250 * Set the tooltip for the tab.
27251 * @param {String} tooltip The tab's tooltip
27253 setTooltip : function(text){
27254 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27255 this.textEl.dom.qtip = text;
27256 this.textEl.dom.removeAttribute('title');
27258 this.textEl.dom.title = text;
27262 onTabClick : function(e){
27263 e.preventDefault();
27264 this.tabPanel.activate(this.id);
27267 onTabMouseDown : function(e){
27268 e.preventDefault();
27269 this.tabPanel.activate(this.id);
27272 getWidth : function(){
27273 return this.inner.getWidth();
27276 setWidth : function(width){
27277 var iwidth = width - this.pnode.getPadding("lr");
27278 this.inner.setWidth(iwidth);
27279 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27280 this.pnode.setWidth(width);
27284 * Show or hide the tab
27285 * @param {Boolean} hidden True to hide or false to show.
27287 setHidden : function(hidden){
27288 this.hidden = hidden;
27289 this.pnode.setStyle("display", hidden ? "none" : "");
27293 * Returns true if this tab is "hidden"
27294 * @return {Boolean}
27296 isHidden : function(){
27297 return this.hidden;
27301 * Returns the text for this tab
27304 getText : function(){
27308 autoSize : function(){
27309 //this.el.beginMeasure();
27310 this.textEl.setWidth(1);
27312 * #2804 [new] Tabs in Roojs
27313 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
27315 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
27316 //this.el.endMeasure();
27320 * Sets the text for the tab (Note: this also sets the tooltip text)
27321 * @param {String} text The tab's text and tooltip
27323 setText : function(text){
27325 this.textEl.update(text);
27326 this.setTooltip(text);
27327 if(!this.tabPanel.resizeTabs){
27332 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27334 activate : function(){
27335 this.tabPanel.activate(this.id);
27339 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27341 disable : function(){
27342 if(this.tabPanel.active != this){
27343 this.disabled = true;
27344 this.pnode.addClass("disabled");
27349 * Enables this TabPanelItem if it was previously disabled.
27351 enable : function(){
27352 this.disabled = false;
27353 this.pnode.removeClass("disabled");
27357 * Sets the content for this TabPanelItem.
27358 * @param {String} content The content
27359 * @param {Boolean} loadScripts true to look for and load scripts
27361 setContent : function(content, loadScripts){
27362 this.bodyEl.update(content, loadScripts);
27366 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27367 * @return {Roo.UpdateManager} The UpdateManager
27369 getUpdateManager : function(){
27370 return this.bodyEl.getUpdateManager();
27374 * Set a URL to be used to load the content for this TabPanelItem.
27375 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27376 * @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)
27377 * @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)
27378 * @return {Roo.UpdateManager} The UpdateManager
27380 setUrl : function(url, params, loadOnce){
27381 if(this.refreshDelegate){
27382 this.un('activate', this.refreshDelegate);
27384 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27385 this.on("activate", this.refreshDelegate);
27386 return this.bodyEl.getUpdateManager();
27390 _handleRefresh : function(url, params, loadOnce){
27391 if(!loadOnce || !this.loaded){
27392 var updater = this.bodyEl.getUpdateManager();
27393 updater.update(url, params, this._setLoaded.createDelegate(this));
27398 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27399 * Will fail silently if the setUrl method has not been called.
27400 * This does not activate the panel, just updates its content.
27402 refresh : function(){
27403 if(this.refreshDelegate){
27404 this.loaded = false;
27405 this.refreshDelegate();
27410 _setLoaded : function(){
27411 this.loaded = true;
27415 closeClick : function(e){
27418 this.fireEvent("beforeclose", this, o);
27419 if(o.cancel !== true){
27420 this.tabPanel.removeTab(this.id);
27424 * The text displayed in the tooltip for the close icon.
27427 closeText : "Close this tab"
27431 Roo.TabPanel.prototype.createStrip = function(container){
27432 var strip = document.createElement("div");
27433 strip.className = "x-tabs-wrap";
27434 container.appendChild(strip);
27438 Roo.TabPanel.prototype.createStripList = function(strip){
27439 // div wrapper for retard IE
27440 // returns the "tr" element.
27441 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27442 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27443 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27444 return strip.firstChild.firstChild.firstChild.firstChild;
27447 Roo.TabPanel.prototype.createBody = function(container){
27448 var body = document.createElement("div");
27449 Roo.id(body, "tab-body");
27450 Roo.fly(body).addClass("x-tabs-body");
27451 container.appendChild(body);
27455 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27456 var body = Roo.getDom(id);
27458 body = document.createElement("div");
27461 Roo.fly(body).addClass("x-tabs-item-body");
27462 bodyEl.insertBefore(body, bodyEl.firstChild);
27466 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27467 var td = document.createElement("td");
27468 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27469 //stripEl.appendChild(td);
27471 td.className = "x-tabs-closable";
27472 if(!this.closeTpl){
27473 this.closeTpl = new Roo.Template(
27474 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27475 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27476 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27479 var el = this.closeTpl.overwrite(td, {"text": text});
27480 var close = el.getElementsByTagName("div")[0];
27481 var inner = el.getElementsByTagName("em")[0];
27482 return {"el": el, "close": close, "inner": inner};
27485 this.tabTpl = new Roo.Template(
27486 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27487 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27490 var el = this.tabTpl.overwrite(td, {"text": text});
27491 var inner = el.getElementsByTagName("em")[0];
27492 return {"el": el, "inner": inner};
27496 * Ext JS Library 1.1.1
27497 * Copyright(c) 2006-2007, Ext JS, LLC.
27499 * Originally Released Under LGPL - original licence link has changed is not relivant.
27502 * <script type="text/javascript">
27506 * @class Roo.Button
27507 * @extends Roo.util.Observable
27508 * Simple Button class
27509 * @cfg {String} text The button text
27510 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27511 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27512 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27513 * @cfg {Object} scope The scope of the handler
27514 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27515 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27516 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27517 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27518 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27519 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27520 applies if enableToggle = true)
27521 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27522 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27523 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27525 * Create a new button
27526 * @param {Object} config The config object
27528 Roo.Button = function(renderTo, config)
27532 renderTo = config.renderTo || false;
27535 Roo.apply(this, config);
27539 * Fires when this button is clicked
27540 * @param {Button} this
27541 * @param {EventObject} e The click event
27546 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27547 * @param {Button} this
27548 * @param {Boolean} pressed
27553 * Fires when the mouse hovers over the button
27554 * @param {Button} this
27555 * @param {Event} e The event object
27557 'mouseover' : true,
27560 * Fires when the mouse exits the button
27561 * @param {Button} this
27562 * @param {Event} e The event object
27567 * Fires when the button is rendered
27568 * @param {Button} this
27573 this.menu = Roo.menu.MenuMgr.get(this.menu);
27575 // register listeners first!! - so render can be captured..
27576 Roo.util.Observable.call(this);
27578 this.render(renderTo);
27584 Roo.extend(Roo.Button, Roo.util.Observable, {
27590 * Read-only. True if this button is hidden
27595 * Read-only. True if this button is disabled
27600 * Read-only. True if this button is pressed (only if enableToggle = true)
27606 * @cfg {Number} tabIndex
27607 * The DOM tabIndex for this button (defaults to undefined)
27609 tabIndex : undefined,
27612 * @cfg {Boolean} enableToggle
27613 * True to enable pressed/not pressed toggling (defaults to false)
27615 enableToggle: false,
27617 * @cfg {Mixed} menu
27618 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27622 * @cfg {String} menuAlign
27623 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27625 menuAlign : "tl-bl?",
27628 * @cfg {String} iconCls
27629 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27631 iconCls : undefined,
27633 * @cfg {String} type
27634 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27639 menuClassTarget: 'tr',
27642 * @cfg {String} clickEvent
27643 * The type of event to map to the button's event handler (defaults to 'click')
27645 clickEvent : 'click',
27648 * @cfg {Boolean} handleMouseEvents
27649 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27651 handleMouseEvents : true,
27654 * @cfg {String} tooltipType
27655 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27657 tooltipType : 'qtip',
27660 * @cfg {String} cls
27661 * A CSS class to apply to the button's main element.
27665 * @cfg {Roo.Template} template (Optional)
27666 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27667 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27668 * require code modifications if required elements (e.g. a button) aren't present.
27672 render : function(renderTo){
27674 if(this.hideParent){
27675 this.parentEl = Roo.get(renderTo);
27677 if(!this.dhconfig){
27678 if(!this.template){
27679 if(!Roo.Button.buttonTemplate){
27680 // hideous table template
27681 Roo.Button.buttonTemplate = new Roo.Template(
27682 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27683 '<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>',
27684 "</tr></tbody></table>");
27686 this.template = Roo.Button.buttonTemplate;
27688 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27689 var btnEl = btn.child("button:first");
27690 btnEl.on('focus', this.onFocus, this);
27691 btnEl.on('blur', this.onBlur, this);
27693 btn.addClass(this.cls);
27696 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27699 btnEl.addClass(this.iconCls);
27701 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27704 if(this.tabIndex !== undefined){
27705 btnEl.dom.tabIndex = this.tabIndex;
27708 if(typeof this.tooltip == 'object'){
27709 Roo.QuickTips.tips(Roo.apply({
27713 btnEl.dom[this.tooltipType] = this.tooltip;
27717 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27721 this.el.dom.id = this.el.id = this.id;
27724 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27725 this.menu.on("show", this.onMenuShow, this);
27726 this.menu.on("hide", this.onMenuHide, this);
27728 btn.addClass("x-btn");
27729 if(Roo.isIE && !Roo.isIE7){
27730 this.autoWidth.defer(1, this);
27734 if(this.handleMouseEvents){
27735 btn.on("mouseover", this.onMouseOver, this);
27736 btn.on("mouseout", this.onMouseOut, this);
27737 btn.on("mousedown", this.onMouseDown, this);
27739 btn.on(this.clickEvent, this.onClick, this);
27740 //btn.on("mouseup", this.onMouseUp, this);
27747 Roo.ButtonToggleMgr.register(this);
27749 this.el.addClass("x-btn-pressed");
27752 var repeater = new Roo.util.ClickRepeater(btn,
27753 typeof this.repeat == "object" ? this.repeat : {}
27755 repeater.on("click", this.onClick, this);
27758 this.fireEvent('render', this);
27762 * Returns the button's underlying element
27763 * @return {Roo.Element} The element
27765 getEl : function(){
27770 * Destroys this Button and removes any listeners.
27772 destroy : function(){
27773 Roo.ButtonToggleMgr.unregister(this);
27774 this.el.removeAllListeners();
27775 this.purgeListeners();
27780 autoWidth : function(){
27782 this.el.setWidth("auto");
27783 if(Roo.isIE7 && Roo.isStrict){
27784 var ib = this.el.child('button');
27785 if(ib && ib.getWidth() > 20){
27787 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27792 this.el.beginMeasure();
27794 if(this.el.getWidth() < this.minWidth){
27795 this.el.setWidth(this.minWidth);
27798 this.el.endMeasure();
27805 * Assigns this button's click handler
27806 * @param {Function} handler The function to call when the button is clicked
27807 * @param {Object} scope (optional) Scope for the function passed in
27809 setHandler : function(handler, scope){
27810 this.handler = handler;
27811 this.scope = scope;
27815 * Sets this button's text
27816 * @param {String} text The button text
27818 setText : function(text){
27821 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27827 * Gets the text for this button
27828 * @return {String} The button text
27830 getText : function(){
27838 this.hidden = false;
27840 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27848 this.hidden = true;
27850 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27855 * Convenience function for boolean show/hide
27856 * @param {Boolean} visible True to show, false to hide
27858 setVisible: function(visible){
27867 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27868 * @param {Boolean} state (optional) Force a particular state
27870 toggle : function(state){
27871 state = state === undefined ? !this.pressed : state;
27872 if(state != this.pressed){
27874 this.el.addClass("x-btn-pressed");
27875 this.pressed = true;
27876 this.fireEvent("toggle", this, true);
27878 this.el.removeClass("x-btn-pressed");
27879 this.pressed = false;
27880 this.fireEvent("toggle", this, false);
27882 if(this.toggleHandler){
27883 this.toggleHandler.call(this.scope || this, this, state);
27891 focus : function(){
27892 this.el.child('button:first').focus();
27896 * Disable this button
27898 disable : function(){
27900 this.el.addClass("x-btn-disabled");
27902 this.disabled = true;
27906 * Enable this button
27908 enable : function(){
27910 this.el.removeClass("x-btn-disabled");
27912 this.disabled = false;
27916 * Convenience function for boolean enable/disable
27917 * @param {Boolean} enabled True to enable, false to disable
27919 setDisabled : function(v){
27920 this[v !== true ? "enable" : "disable"]();
27924 onClick : function(e)
27927 e.preventDefault();
27932 if(!this.disabled){
27933 if(this.enableToggle){
27936 if(this.menu && !this.menu.isVisible()){
27937 this.menu.show(this.el, this.menuAlign);
27939 this.fireEvent("click", this, e);
27941 this.el.removeClass("x-btn-over");
27942 this.handler.call(this.scope || this, this, e);
27947 onMouseOver : function(e){
27948 if(!this.disabled){
27949 this.el.addClass("x-btn-over");
27950 this.fireEvent('mouseover', this, e);
27954 onMouseOut : function(e){
27955 if(!e.within(this.el, true)){
27956 this.el.removeClass("x-btn-over");
27957 this.fireEvent('mouseout', this, e);
27961 onFocus : function(e){
27962 if(!this.disabled){
27963 this.el.addClass("x-btn-focus");
27967 onBlur : function(e){
27968 this.el.removeClass("x-btn-focus");
27971 onMouseDown : function(e){
27972 if(!this.disabled && e.button == 0){
27973 this.el.addClass("x-btn-click");
27974 Roo.get(document).on('mouseup', this.onMouseUp, this);
27978 onMouseUp : function(e){
27980 this.el.removeClass("x-btn-click");
27981 Roo.get(document).un('mouseup', this.onMouseUp, this);
27985 onMenuShow : function(e){
27986 this.el.addClass("x-btn-menu-active");
27989 onMenuHide : function(e){
27990 this.el.removeClass("x-btn-menu-active");
27994 // Private utility class used by Button
27995 Roo.ButtonToggleMgr = function(){
27998 function toggleGroup(btn, state){
28000 var g = groups[btn.toggleGroup];
28001 for(var i = 0, l = g.length; i < l; i++){
28003 g[i].toggle(false);
28010 register : function(btn){
28011 if(!btn.toggleGroup){
28014 var g = groups[btn.toggleGroup];
28016 g = groups[btn.toggleGroup] = [];
28019 btn.on("toggle", toggleGroup);
28022 unregister : function(btn){
28023 if(!btn.toggleGroup){
28026 var g = groups[btn.toggleGroup];
28029 btn.un("toggle", toggleGroup);
28035 * Ext JS Library 1.1.1
28036 * Copyright(c) 2006-2007, Ext JS, LLC.
28038 * Originally Released Under LGPL - original licence link has changed is not relivant.
28041 * <script type="text/javascript">
28045 * @class Roo.SplitButton
28046 * @extends Roo.Button
28047 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
28048 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
28049 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
28050 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
28051 * @cfg {String} arrowTooltip The title attribute of the arrow
28053 * Create a new menu button
28054 * @param {String/HTMLElement/Element} renderTo The element to append the button to
28055 * @param {Object} config The config object
28057 Roo.SplitButton = function(renderTo, config){
28058 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
28060 * @event arrowclick
28061 * Fires when this button's arrow is clicked
28062 * @param {SplitButton} this
28063 * @param {EventObject} e The click event
28065 this.addEvents({"arrowclick":true});
28068 Roo.extend(Roo.SplitButton, Roo.Button, {
28069 render : function(renderTo){
28070 // this is one sweet looking template!
28071 var tpl = new Roo.Template(
28072 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
28073 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
28074 '<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>',
28075 "</tbody></table></td><td>",
28076 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
28077 '<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>',
28078 "</tbody></table></td></tr></table>"
28080 var btn = tpl.append(renderTo, [this.text, this.type], true);
28081 var btnEl = btn.child("button");
28083 btn.addClass(this.cls);
28086 btnEl.setStyle('background-image', 'url(' +this.icon +')');
28089 btnEl.addClass(this.iconCls);
28091 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
28095 if(this.handleMouseEvents){
28096 btn.on("mouseover", this.onMouseOver, this);
28097 btn.on("mouseout", this.onMouseOut, this);
28098 btn.on("mousedown", this.onMouseDown, this);
28099 btn.on("mouseup", this.onMouseUp, this);
28101 btn.on(this.clickEvent, this.onClick, this);
28103 if(typeof this.tooltip == 'object'){
28104 Roo.QuickTips.tips(Roo.apply({
28108 btnEl.dom[this.tooltipType] = this.tooltip;
28111 if(this.arrowTooltip){
28112 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
28121 this.el.addClass("x-btn-pressed");
28123 if(Roo.isIE && !Roo.isIE7){
28124 this.autoWidth.defer(1, this);
28129 this.menu.on("show", this.onMenuShow, this);
28130 this.menu.on("hide", this.onMenuHide, this);
28132 this.fireEvent('render', this);
28136 autoWidth : function(){
28138 var tbl = this.el.child("table:first");
28139 var tbl2 = this.el.child("table:last");
28140 this.el.setWidth("auto");
28141 tbl.setWidth("auto");
28142 if(Roo.isIE7 && Roo.isStrict){
28143 var ib = this.el.child('button:first');
28144 if(ib && ib.getWidth() > 20){
28146 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
28151 this.el.beginMeasure();
28153 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
28154 tbl.setWidth(this.minWidth-tbl2.getWidth());
28157 this.el.endMeasure();
28160 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
28164 * Sets this button's click handler
28165 * @param {Function} handler The function to call when the button is clicked
28166 * @param {Object} scope (optional) Scope for the function passed above
28168 setHandler : function(handler, scope){
28169 this.handler = handler;
28170 this.scope = scope;
28174 * Sets this button's arrow click handler
28175 * @param {Function} handler The function to call when the arrow is clicked
28176 * @param {Object} scope (optional) Scope for the function passed above
28178 setArrowHandler : function(handler, scope){
28179 this.arrowHandler = handler;
28180 this.scope = scope;
28186 focus : function(){
28188 this.el.child("button:first").focus();
28193 onClick : function(e){
28194 e.preventDefault();
28195 if(!this.disabled){
28196 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28197 if(this.menu && !this.menu.isVisible()){
28198 this.menu.show(this.el, this.menuAlign);
28200 this.fireEvent("arrowclick", this, e);
28201 if(this.arrowHandler){
28202 this.arrowHandler.call(this.scope || this, this, e);
28205 this.fireEvent("click", this, e);
28207 this.handler.call(this.scope || this, this, e);
28213 onMouseDown : function(e){
28214 if(!this.disabled){
28215 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28219 onMouseUp : function(e){
28220 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28225 // backwards compat
28226 Roo.MenuButton = Roo.SplitButton;/*
28228 * Ext JS Library 1.1.1
28229 * Copyright(c) 2006-2007, Ext JS, LLC.
28231 * Originally Released Under LGPL - original licence link has changed is not relivant.
28234 * <script type="text/javascript">
28238 * @class Roo.Toolbar
28239 * Basic Toolbar class.
28241 * Creates a new Toolbar
28242 * @param {Object} container The config object
28244 Roo.Toolbar = function(container, buttons, config)
28246 /// old consturctor format still supported..
28247 if(container instanceof Array){ // omit the container for later rendering
28248 buttons = container;
28252 if (typeof(container) == 'object' && container.xtype) {
28253 config = container;
28254 container = config.container;
28255 buttons = config.buttons || []; // not really - use items!!
28258 if (config && config.items) {
28259 xitems = config.items;
28260 delete config.items;
28262 Roo.apply(this, config);
28263 this.buttons = buttons;
28266 this.render(container);
28268 this.xitems = xitems;
28269 Roo.each(xitems, function(b) {
28275 Roo.Toolbar.prototype = {
28277 * @cfg {Array} items
28278 * array of button configs or elements to add (will be converted to a MixedCollection)
28282 * @cfg {String/HTMLElement/Element} container
28283 * The id or element that will contain the toolbar
28286 render : function(ct){
28287 this.el = Roo.get(ct);
28289 this.el.addClass(this.cls);
28291 // using a table allows for vertical alignment
28292 // 100% width is needed by Safari...
28293 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28294 this.tr = this.el.child("tr", true);
28296 this.items = new Roo.util.MixedCollection(false, function(o){
28297 return o.id || ("item" + (++autoId));
28300 this.add.apply(this, this.buttons);
28301 delete this.buttons;
28306 * Adds element(s) to the toolbar -- this function takes a variable number of
28307 * arguments of mixed type and adds them to the toolbar.
28308 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28310 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28311 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28312 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28313 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28314 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28315 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28316 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28317 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28318 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28320 * @param {Mixed} arg2
28321 * @param {Mixed} etc.
28324 var a = arguments, l = a.length;
28325 for(var i = 0; i < l; i++){
28330 _add : function(el) {
28333 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28336 if (el.applyTo){ // some kind of form field
28337 return this.addField(el);
28339 if (el.render){ // some kind of Toolbar.Item
28340 return this.addItem(el);
28342 if (typeof el == "string"){ // string
28343 if(el == "separator" || el == "-"){
28344 return this.addSeparator();
28347 return this.addSpacer();
28350 return this.addFill();
28352 return this.addText(el);
28355 if(el.tagName){ // element
28356 return this.addElement(el);
28358 if(typeof el == "object"){ // must be button config?
28359 return this.addButton(el);
28361 // and now what?!?!
28367 * Add an Xtype element
28368 * @param {Object} xtype Xtype Object
28369 * @return {Object} created Object
28371 addxtype : function(e){
28372 return this.add(e);
28376 * Returns the Element for this toolbar.
28377 * @return {Roo.Element}
28379 getEl : function(){
28385 * @return {Roo.Toolbar.Item} The separator item
28387 addSeparator : function(){
28388 return this.addItem(new Roo.Toolbar.Separator());
28392 * Adds a spacer element
28393 * @return {Roo.Toolbar.Spacer} The spacer item
28395 addSpacer : function(){
28396 return this.addItem(new Roo.Toolbar.Spacer());
28400 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28401 * @return {Roo.Toolbar.Fill} The fill item
28403 addFill : function(){
28404 return this.addItem(new Roo.Toolbar.Fill());
28408 * Adds any standard HTML element to the toolbar
28409 * @param {String/HTMLElement/Element} el The element or id of the element to add
28410 * @return {Roo.Toolbar.Item} The element's item
28412 addElement : function(el){
28413 return this.addItem(new Roo.Toolbar.Item(el));
28416 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28417 * @type Roo.util.MixedCollection
28422 * Adds any Toolbar.Item or subclass
28423 * @param {Roo.Toolbar.Item} item
28424 * @return {Roo.Toolbar.Item} The item
28426 addItem : function(item){
28427 var td = this.nextBlock();
28429 this.items.add(item);
28434 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28435 * @param {Object/Array} config A button config or array of configs
28436 * @return {Roo.Toolbar.Button/Array}
28438 addButton : function(config){
28439 if(config instanceof Array){
28441 for(var i = 0, len = config.length; i < len; i++) {
28442 buttons.push(this.addButton(config[i]));
28447 if(!(config instanceof Roo.Toolbar.Button)){
28449 new Roo.Toolbar.SplitButton(config) :
28450 new Roo.Toolbar.Button(config);
28452 var td = this.nextBlock();
28459 * Adds text to the toolbar
28460 * @param {String} text The text to add
28461 * @return {Roo.Toolbar.Item} The element's item
28463 addText : function(text){
28464 return this.addItem(new Roo.Toolbar.TextItem(text));
28468 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28469 * @param {Number} index The index where the item is to be inserted
28470 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28471 * @return {Roo.Toolbar.Button/Item}
28473 insertButton : function(index, item){
28474 if(item instanceof Array){
28476 for(var i = 0, len = item.length; i < len; i++) {
28477 buttons.push(this.insertButton(index + i, item[i]));
28481 if (!(item instanceof Roo.Toolbar.Button)){
28482 item = new Roo.Toolbar.Button(item);
28484 var td = document.createElement("td");
28485 this.tr.insertBefore(td, this.tr.childNodes[index]);
28487 this.items.insert(index, item);
28492 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28493 * @param {Object} config
28494 * @return {Roo.Toolbar.Item} The element's item
28496 addDom : function(config, returnEl){
28497 var td = this.nextBlock();
28498 Roo.DomHelper.overwrite(td, config);
28499 var ti = new Roo.Toolbar.Item(td.firstChild);
28501 this.items.add(ti);
28506 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28507 * @type Roo.util.MixedCollection
28512 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28513 * Note: the field should not have been rendered yet. For a field that has already been
28514 * rendered, use {@link #addElement}.
28515 * @param {Roo.form.Field} field
28516 * @return {Roo.ToolbarItem}
28520 addField : function(field) {
28521 if (!this.fields) {
28523 this.fields = new Roo.util.MixedCollection(false, function(o){
28524 return o.id || ("item" + (++autoId));
28529 var td = this.nextBlock();
28531 var ti = new Roo.Toolbar.Item(td.firstChild);
28533 this.items.add(ti);
28534 this.fields.add(field);
28545 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28546 this.el.child('div').hide();
28554 this.el.child('div').show();
28558 nextBlock : function(){
28559 var td = document.createElement("td");
28560 this.tr.appendChild(td);
28565 destroy : function(){
28566 if(this.items){ // rendered?
28567 Roo.destroy.apply(Roo, this.items.items);
28569 if(this.fields){ // rendered?
28570 Roo.destroy.apply(Roo, this.fields.items);
28572 Roo.Element.uncache(this.el, this.tr);
28577 * @class Roo.Toolbar.Item
28578 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28580 * Creates a new Item
28581 * @param {HTMLElement} el
28583 Roo.Toolbar.Item = function(el){
28585 if (typeof (el.xtype) != 'undefined') {
28590 this.el = Roo.getDom(el);
28591 this.id = Roo.id(this.el);
28592 this.hidden = false;
28597 * Fires when the button is rendered
28598 * @param {Button} this
28602 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
28604 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
28605 //Roo.Toolbar.Item.prototype = {
28608 * Get this item's HTML Element
28609 * @return {HTMLElement}
28611 getEl : function(){
28616 render : function(td){
28619 td.appendChild(this.el);
28621 this.fireEvent('render', this);
28625 * Removes and destroys this item.
28627 destroy : function(){
28628 this.td.parentNode.removeChild(this.td);
28635 this.hidden = false;
28636 this.td.style.display = "";
28643 this.hidden = true;
28644 this.td.style.display = "none";
28648 * Convenience function for boolean show/hide.
28649 * @param {Boolean} visible true to show/false to hide
28651 setVisible: function(visible){
28660 * Try to focus this item.
28662 focus : function(){
28663 Roo.fly(this.el).focus();
28667 * Disables this item.
28669 disable : function(){
28670 Roo.fly(this.td).addClass("x-item-disabled");
28671 this.disabled = true;
28672 this.el.disabled = true;
28676 * Enables this item.
28678 enable : function(){
28679 Roo.fly(this.td).removeClass("x-item-disabled");
28680 this.disabled = false;
28681 this.el.disabled = false;
28687 * @class Roo.Toolbar.Separator
28688 * @extends Roo.Toolbar.Item
28689 * A simple toolbar separator class
28691 * Creates a new Separator
28693 Roo.Toolbar.Separator = function(cfg){
28695 var s = document.createElement("span");
28696 s.className = "ytb-sep";
28701 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
28703 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28704 enable:Roo.emptyFn,
28705 disable:Roo.emptyFn,
28710 * @class Roo.Toolbar.Spacer
28711 * @extends Roo.Toolbar.Item
28712 * A simple element that adds extra horizontal space to a toolbar.
28714 * Creates a new Spacer
28716 Roo.Toolbar.Spacer = function(cfg){
28717 var s = document.createElement("div");
28718 s.className = "ytb-spacer";
28722 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
28724 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28725 enable:Roo.emptyFn,
28726 disable:Roo.emptyFn,
28731 * @class Roo.Toolbar.Fill
28732 * @extends Roo.Toolbar.Spacer
28733 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28735 * Creates a new Spacer
28737 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28739 render : function(td){
28740 td.style.width = '100%';
28741 Roo.Toolbar.Fill.superclass.render.call(this, td);
28746 * @class Roo.Toolbar.TextItem
28747 * @extends Roo.Toolbar.Item
28748 * A simple class that renders text directly into a toolbar.
28750 * Creates a new TextItem
28751 * @param {String} text
28753 Roo.Toolbar.TextItem = function(cfg){
28754 var text = cfg || "";
28755 if (typeof(cfg) == 'object') {
28756 text = cfg.text || "";
28760 var s = document.createElement("span");
28761 s.className = "ytb-text";
28762 s.innerHTML = text;
28767 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
28769 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28772 enable:Roo.emptyFn,
28773 disable:Roo.emptyFn,
28778 * @class Roo.Toolbar.Button
28779 * @extends Roo.Button
28780 * A button that renders into a toolbar.
28782 * Creates a new Button
28783 * @param {Object} config A standard {@link Roo.Button} config object
28785 Roo.Toolbar.Button = function(config){
28786 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28788 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28789 render : function(td){
28791 Roo.Toolbar.Button.superclass.render.call(this, td);
28795 * Removes and destroys this button
28797 destroy : function(){
28798 Roo.Toolbar.Button.superclass.destroy.call(this);
28799 this.td.parentNode.removeChild(this.td);
28803 * Shows this button
28806 this.hidden = false;
28807 this.td.style.display = "";
28811 * Hides this button
28814 this.hidden = true;
28815 this.td.style.display = "none";
28819 * Disables this item
28821 disable : function(){
28822 Roo.fly(this.td).addClass("x-item-disabled");
28823 this.disabled = true;
28827 * Enables this item
28829 enable : function(){
28830 Roo.fly(this.td).removeClass("x-item-disabled");
28831 this.disabled = false;
28834 // backwards compat
28835 Roo.ToolbarButton = Roo.Toolbar.Button;
28838 * @class Roo.Toolbar.SplitButton
28839 * @extends Roo.SplitButton
28840 * A menu button that renders into a toolbar.
28842 * Creates a new SplitButton
28843 * @param {Object} config A standard {@link Roo.SplitButton} config object
28845 Roo.Toolbar.SplitButton = function(config){
28846 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28848 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28849 render : function(td){
28851 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28855 * Removes and destroys this button
28857 destroy : function(){
28858 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28859 this.td.parentNode.removeChild(this.td);
28863 * Shows this button
28866 this.hidden = false;
28867 this.td.style.display = "";
28871 * Hides this button
28874 this.hidden = true;
28875 this.td.style.display = "none";
28879 // backwards compat
28880 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28882 * Ext JS Library 1.1.1
28883 * Copyright(c) 2006-2007, Ext JS, LLC.
28885 * Originally Released Under LGPL - original licence link has changed is not relivant.
28888 * <script type="text/javascript">
28892 * @class Roo.PagingToolbar
28893 * @extends Roo.Toolbar
28894 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28896 * Create a new PagingToolbar
28897 * @param {Object} config The config object
28899 Roo.PagingToolbar = function(el, ds, config)
28901 // old args format still supported... - xtype is prefered..
28902 if (typeof(el) == 'object' && el.xtype) {
28903 // created from xtype...
28905 ds = el.dataSource;
28906 el = config.container;
28909 if (config.items) {
28910 items = config.items;
28914 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28917 this.renderButtons(this.el);
28920 // supprot items array.
28922 Roo.each(items, function(e) {
28923 this.add(Roo.factory(e));
28928 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28930 * @cfg {Roo.data.Store} dataSource
28931 * The underlying data store providing the paged data
28934 * @cfg {String/HTMLElement/Element} container
28935 * container The id or element that will contain the toolbar
28938 * @cfg {Boolean} displayInfo
28939 * True to display the displayMsg (defaults to false)
28942 * @cfg {Number} pageSize
28943 * The number of records to display per page (defaults to 20)
28947 * @cfg {String} displayMsg
28948 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28950 displayMsg : 'Displaying {0} - {1} of {2}',
28952 * @cfg {String} emptyMsg
28953 * The message to display when no records are found (defaults to "No data to display")
28955 emptyMsg : 'No data to display',
28957 * Customizable piece of the default paging text (defaults to "Page")
28960 beforePageText : "Page",
28962 * Customizable piece of the default paging text (defaults to "of %0")
28965 afterPageText : "of {0}",
28967 * Customizable piece of the default paging text (defaults to "First Page")
28970 firstText : "First Page",
28972 * Customizable piece of the default paging text (defaults to "Previous Page")
28975 prevText : "Previous Page",
28977 * Customizable piece of the default paging text (defaults to "Next Page")
28980 nextText : "Next Page",
28982 * Customizable piece of the default paging text (defaults to "Last Page")
28985 lastText : "Last Page",
28987 * Customizable piece of the default paging text (defaults to "Refresh")
28990 refreshText : "Refresh",
28993 renderButtons : function(el){
28994 Roo.PagingToolbar.superclass.render.call(this, el);
28995 this.first = this.addButton({
28996 tooltip: this.firstText,
28997 cls: "x-btn-icon x-grid-page-first",
28999 handler: this.onClick.createDelegate(this, ["first"])
29001 this.prev = this.addButton({
29002 tooltip: this.prevText,
29003 cls: "x-btn-icon x-grid-page-prev",
29005 handler: this.onClick.createDelegate(this, ["prev"])
29007 //this.addSeparator();
29008 this.add(this.beforePageText);
29009 this.field = Roo.get(this.addDom({
29014 cls: "x-grid-page-number"
29016 this.field.on("keydown", this.onPagingKeydown, this);
29017 this.field.on("focus", function(){this.dom.select();});
29018 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
29019 this.field.setHeight(18);
29020 //this.addSeparator();
29021 this.next = this.addButton({
29022 tooltip: this.nextText,
29023 cls: "x-btn-icon x-grid-page-next",
29025 handler: this.onClick.createDelegate(this, ["next"])
29027 this.last = this.addButton({
29028 tooltip: this.lastText,
29029 cls: "x-btn-icon x-grid-page-last",
29031 handler: this.onClick.createDelegate(this, ["last"])
29033 //this.addSeparator();
29034 this.loading = this.addButton({
29035 tooltip: this.refreshText,
29036 cls: "x-btn-icon x-grid-loading",
29037 handler: this.onClick.createDelegate(this, ["refresh"])
29040 if(this.displayInfo){
29041 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
29046 updateInfo : function(){
29047 if(this.displayEl){
29048 var count = this.ds.getCount();
29049 var msg = count == 0 ?
29053 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
29055 this.displayEl.update(msg);
29060 onLoad : function(ds, r, o){
29061 this.cursor = o.params ? o.params.start : 0;
29062 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
29064 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
29065 this.field.dom.value = ap;
29066 this.first.setDisabled(ap == 1);
29067 this.prev.setDisabled(ap == 1);
29068 this.next.setDisabled(ap == ps);
29069 this.last.setDisabled(ap == ps);
29070 this.loading.enable();
29075 getPageData : function(){
29076 var total = this.ds.getTotalCount();
29079 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
29080 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
29085 onLoadError : function(){
29086 this.loading.enable();
29090 onPagingKeydown : function(e){
29091 var k = e.getKey();
29092 var d = this.getPageData();
29094 var v = this.field.dom.value, pageNum;
29095 if(!v || isNaN(pageNum = parseInt(v, 10))){
29096 this.field.dom.value = d.activePage;
29099 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
29100 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29103 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))
29105 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
29106 this.field.dom.value = pageNum;
29107 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
29110 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29112 var v = this.field.dom.value, pageNum;
29113 var increment = (e.shiftKey) ? 10 : 1;
29114 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
29117 if(!v || isNaN(pageNum = parseInt(v, 10))) {
29118 this.field.dom.value = d.activePage;
29121 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
29123 this.field.dom.value = parseInt(v, 10) + increment;
29124 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
29125 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29132 beforeLoad : function(){
29134 this.loading.disable();
29139 onClick : function(which){
29143 ds.load({params:{start: 0, limit: this.pageSize}});
29146 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
29149 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
29152 var total = ds.getTotalCount();
29153 var extra = total % this.pageSize;
29154 var lastStart = extra ? (total - extra) : total-this.pageSize;
29155 ds.load({params:{start: lastStart, limit: this.pageSize}});
29158 ds.load({params:{start: this.cursor, limit: this.pageSize}});
29164 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
29165 * @param {Roo.data.Store} store The data store to unbind
29167 unbind : function(ds){
29168 ds.un("beforeload", this.beforeLoad, this);
29169 ds.un("load", this.onLoad, this);
29170 ds.un("loadexception", this.onLoadError, this);
29171 ds.un("remove", this.updateInfo, this);
29172 ds.un("add", this.updateInfo, this);
29173 this.ds = undefined;
29177 * Binds the paging toolbar to the specified {@link Roo.data.Store}
29178 * @param {Roo.data.Store} store The data store to bind
29180 bind : function(ds){
29181 ds.on("beforeload", this.beforeLoad, this);
29182 ds.on("load", this.onLoad, this);
29183 ds.on("loadexception", this.onLoadError, this);
29184 ds.on("remove", this.updateInfo, this);
29185 ds.on("add", this.updateInfo, this);
29190 * Ext JS Library 1.1.1
29191 * Copyright(c) 2006-2007, Ext JS, LLC.
29193 * Originally Released Under LGPL - original licence link has changed is not relivant.
29196 * <script type="text/javascript">
29200 * @class Roo.Resizable
29201 * @extends Roo.util.Observable
29202 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
29203 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
29204 * 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
29205 * the element will be wrapped for you automatically.</p>
29206 * <p>Here is the list of valid resize handles:</p>
29209 ------ -------------------
29218 'hd' horizontal drag
29221 * <p>Here's an example showing the creation of a typical Resizable:</p>
29223 var resizer = new Roo.Resizable("element-id", {
29231 resizer.on("resize", myHandler);
29233 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29234 * resizer.east.setDisplayed(false);</p>
29235 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29236 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29237 * resize operation's new size (defaults to [0, 0])
29238 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29239 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29240 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29241 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29242 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29243 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29244 * @cfg {Number} width The width of the element in pixels (defaults to null)
29245 * @cfg {Number} height The height of the element in pixels (defaults to null)
29246 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29247 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29248 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29249 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29250 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29251 * in favor of the handles config option (defaults to false)
29252 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29253 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29254 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29255 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29256 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29257 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29258 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29259 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29260 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29261 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29262 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29264 * Create a new resizable component
29265 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29266 * @param {Object} config configuration options
29268 Roo.Resizable = function(el, config)
29270 this.el = Roo.get(el);
29272 if(config && config.wrap){
29273 config.resizeChild = this.el;
29274 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29275 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29276 this.el.setStyle("overflow", "hidden");
29277 this.el.setPositioning(config.resizeChild.getPositioning());
29278 config.resizeChild.clearPositioning();
29279 if(!config.width || !config.height){
29280 var csize = config.resizeChild.getSize();
29281 this.el.setSize(csize.width, csize.height);
29283 if(config.pinned && !config.adjustments){
29284 config.adjustments = "auto";
29288 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29289 this.proxy.unselectable();
29290 this.proxy.enableDisplayMode('block');
29292 Roo.apply(this, config);
29295 this.disableTrackOver = true;
29296 this.el.addClass("x-resizable-pinned");
29298 // if the element isn't positioned, make it relative
29299 var position = this.el.getStyle("position");
29300 if(position != "absolute" && position != "fixed"){
29301 this.el.setStyle("position", "relative");
29303 if(!this.handles){ // no handles passed, must be legacy style
29304 this.handles = 's,e,se';
29305 if(this.multiDirectional){
29306 this.handles += ',n,w';
29309 if(this.handles == "all"){
29310 this.handles = "n s e w ne nw se sw";
29312 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29313 var ps = Roo.Resizable.positions;
29314 for(var i = 0, len = hs.length; i < len; i++){
29315 if(hs[i] && ps[hs[i]]){
29316 var pos = ps[hs[i]];
29317 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29321 this.corner = this.southeast;
29323 // updateBox = the box can move..
29324 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29325 this.updateBox = true;
29328 this.activeHandle = null;
29330 if(this.resizeChild){
29331 if(typeof this.resizeChild == "boolean"){
29332 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29334 this.resizeChild = Roo.get(this.resizeChild, true);
29338 if(this.adjustments == "auto"){
29339 var rc = this.resizeChild;
29340 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29341 if(rc && (hw || hn)){
29342 rc.position("relative");
29343 rc.setLeft(hw ? hw.el.getWidth() : 0);
29344 rc.setTop(hn ? hn.el.getHeight() : 0);
29346 this.adjustments = [
29347 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29348 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29352 if(this.draggable){
29353 this.dd = this.dynamic ?
29354 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29355 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29361 * @event beforeresize
29362 * Fired before resize is allowed. Set enabled to false to cancel resize.
29363 * @param {Roo.Resizable} this
29364 * @param {Roo.EventObject} e The mousedown event
29366 "beforeresize" : true,
29369 * Fired a resizing.
29370 * @param {Roo.Resizable} this
29371 * @param {Number} x The new x position
29372 * @param {Number} y The new y position
29373 * @param {Number} w The new w width
29374 * @param {Number} h The new h hight
29375 * @param {Roo.EventObject} e The mouseup event
29380 * Fired after a resize.
29381 * @param {Roo.Resizable} this
29382 * @param {Number} width The new width
29383 * @param {Number} height The new height
29384 * @param {Roo.EventObject} e The mouseup event
29389 if(this.width !== null && this.height !== null){
29390 this.resizeTo(this.width, this.height);
29392 this.updateChildSize();
29395 this.el.dom.style.zoom = 1;
29397 Roo.Resizable.superclass.constructor.call(this);
29400 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29401 resizeChild : false,
29402 adjustments : [0, 0],
29412 multiDirectional : false,
29413 disableTrackOver : false,
29414 easing : 'easeOutStrong',
29415 widthIncrement : 0,
29416 heightIncrement : 0,
29420 preserveRatio : false,
29421 transparent: false,
29427 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29429 constrainTo: undefined,
29431 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29433 resizeRegion: undefined,
29437 * Perform a manual resize
29438 * @param {Number} width
29439 * @param {Number} height
29441 resizeTo : function(width, height){
29442 this.el.setSize(width, height);
29443 this.updateChildSize();
29444 this.fireEvent("resize", this, width, height, null);
29448 startSizing : function(e, handle){
29449 this.fireEvent("beforeresize", this, e);
29450 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29453 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29454 this.overlay.unselectable();
29455 this.overlay.enableDisplayMode("block");
29456 this.overlay.on("mousemove", this.onMouseMove, this);
29457 this.overlay.on("mouseup", this.onMouseUp, this);
29459 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29461 this.resizing = true;
29462 this.startBox = this.el.getBox();
29463 this.startPoint = e.getXY();
29464 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29465 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29467 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29468 this.overlay.show();
29470 if(this.constrainTo) {
29471 var ct = Roo.get(this.constrainTo);
29472 this.resizeRegion = ct.getRegion().adjust(
29473 ct.getFrameWidth('t'),
29474 ct.getFrameWidth('l'),
29475 -ct.getFrameWidth('b'),
29476 -ct.getFrameWidth('r')
29480 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29482 this.proxy.setBox(this.startBox);
29484 this.proxy.setStyle('visibility', 'visible');
29490 onMouseDown : function(handle, e){
29493 this.activeHandle = handle;
29494 this.startSizing(e, handle);
29499 onMouseUp : function(e){
29500 var size = this.resizeElement();
29501 this.resizing = false;
29503 this.overlay.hide();
29505 this.fireEvent("resize", this, size.width, size.height, e);
29509 updateChildSize : function(){
29511 if(this.resizeChild){
29513 var child = this.resizeChild;
29514 var adj = this.adjustments;
29515 if(el.dom.offsetWidth){
29516 var b = el.getSize(true);
29517 child.setSize(b.width+adj[0], b.height+adj[1]);
29519 // Second call here for IE
29520 // The first call enables instant resizing and
29521 // the second call corrects scroll bars if they
29524 setTimeout(function(){
29525 if(el.dom.offsetWidth){
29526 var b = el.getSize(true);
29527 child.setSize(b.width+adj[0], b.height+adj[1]);
29535 snap : function(value, inc, min){
29536 if(!inc || !value) {
29539 var newValue = value;
29540 var m = value % inc;
29543 newValue = value + (inc-m);
29545 newValue = value - m;
29548 return Math.max(min, newValue);
29552 resizeElement : function(){
29553 var box = this.proxy.getBox();
29554 if(this.updateBox){
29555 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29557 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29559 this.updateChildSize();
29567 constrain : function(v, diff, m, mx){
29570 }else if(v - diff > mx){
29577 onMouseMove : function(e){
29580 try{// try catch so if something goes wrong the user doesn't get hung
29582 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29586 //var curXY = this.startPoint;
29587 var curSize = this.curSize || this.startBox;
29588 var x = this.startBox.x, y = this.startBox.y;
29589 var ox = x, oy = y;
29590 var w = curSize.width, h = curSize.height;
29591 var ow = w, oh = h;
29592 var mw = this.minWidth, mh = this.minHeight;
29593 var mxw = this.maxWidth, mxh = this.maxHeight;
29594 var wi = this.widthIncrement;
29595 var hi = this.heightIncrement;
29597 var eventXY = e.getXY();
29598 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29599 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29601 var pos = this.activeHandle.position;
29606 w = Math.min(Math.max(mw, w), mxw);
29611 h = Math.min(Math.max(mh, h), mxh);
29616 w = Math.min(Math.max(mw, w), mxw);
29617 h = Math.min(Math.max(mh, h), mxh);
29620 diffY = this.constrain(h, diffY, mh, mxh);
29627 var adiffX = Math.abs(diffX);
29628 var sub = (adiffX % wi); // how much
29629 if (sub > (wi/2)) { // far enough to snap
29630 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29632 // remove difference..
29633 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29637 x = Math.max(this.minX, x);
29640 diffX = this.constrain(w, diffX, mw, mxw);
29646 w = Math.min(Math.max(mw, w), mxw);
29647 diffY = this.constrain(h, diffY, mh, mxh);
29652 diffX = this.constrain(w, diffX, mw, mxw);
29653 diffY = this.constrain(h, diffY, mh, mxh);
29660 diffX = this.constrain(w, diffX, mw, mxw);
29662 h = Math.min(Math.max(mh, h), mxh);
29668 var sw = this.snap(w, wi, mw);
29669 var sh = this.snap(h, hi, mh);
29670 if(sw != w || sh != h){
29693 if(this.preserveRatio){
29698 h = Math.min(Math.max(mh, h), mxh);
29703 w = Math.min(Math.max(mw, w), mxw);
29708 w = Math.min(Math.max(mw, w), mxw);
29714 w = Math.min(Math.max(mw, w), mxw);
29720 h = Math.min(Math.max(mh, h), mxh);
29728 h = Math.min(Math.max(mh, h), mxh);
29738 h = Math.min(Math.max(mh, h), mxh);
29746 if (pos == 'hdrag') {
29749 this.proxy.setBounds(x, y, w, h);
29751 this.resizeElement();
29755 this.fireEvent("resizing", this, x, y, w, h, e);
29759 handleOver : function(){
29761 this.el.addClass("x-resizable-over");
29766 handleOut : function(){
29767 if(!this.resizing){
29768 this.el.removeClass("x-resizable-over");
29773 * Returns the element this component is bound to.
29774 * @return {Roo.Element}
29776 getEl : function(){
29781 * Returns the resizeChild element (or null).
29782 * @return {Roo.Element}
29784 getResizeChild : function(){
29785 return this.resizeChild;
29787 groupHandler : function()
29792 * Destroys this resizable. If the element was wrapped and
29793 * removeEl is not true then the element remains.
29794 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29796 destroy : function(removeEl){
29797 this.proxy.remove();
29799 this.overlay.removeAllListeners();
29800 this.overlay.remove();
29802 var ps = Roo.Resizable.positions;
29804 if(typeof ps[k] != "function" && this[ps[k]]){
29805 var h = this[ps[k]];
29806 h.el.removeAllListeners();
29811 this.el.update("");
29818 // hash to map config positions to true positions
29819 Roo.Resizable.positions = {
29820 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29825 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29827 // only initialize the template if resizable is used
29828 var tpl = Roo.DomHelper.createTemplate(
29829 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29832 Roo.Resizable.Handle.prototype.tpl = tpl;
29834 this.position = pos;
29836 // show north drag fro topdra
29837 var handlepos = pos == 'hdrag' ? 'north' : pos;
29839 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29840 if (pos == 'hdrag') {
29841 this.el.setStyle('cursor', 'pointer');
29843 this.el.unselectable();
29845 this.el.setOpacity(0);
29847 this.el.on("mousedown", this.onMouseDown, this);
29848 if(!disableTrackOver){
29849 this.el.on("mouseover", this.onMouseOver, this);
29850 this.el.on("mouseout", this.onMouseOut, this);
29855 Roo.Resizable.Handle.prototype = {
29856 afterResize : function(rz){
29861 onMouseDown : function(e){
29862 this.rz.onMouseDown(this, e);
29865 onMouseOver : function(e){
29866 this.rz.handleOver(this, e);
29869 onMouseOut : function(e){
29870 this.rz.handleOut(this, e);
29874 * Ext JS Library 1.1.1
29875 * Copyright(c) 2006-2007, Ext JS, LLC.
29877 * Originally Released Under LGPL - original licence link has changed is not relivant.
29880 * <script type="text/javascript">
29884 * @class Roo.Editor
29885 * @extends Roo.Component
29886 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29888 * Create a new Editor
29889 * @param {Roo.form.Field} field The Field object (or descendant)
29890 * @param {Object} config The config object
29892 Roo.Editor = function(field, config){
29893 Roo.Editor.superclass.constructor.call(this, config);
29894 this.field = field;
29897 * @event beforestartedit
29898 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29899 * false from the handler of this event.
29900 * @param {Editor} this
29901 * @param {Roo.Element} boundEl The underlying element bound to this editor
29902 * @param {Mixed} value The field value being set
29904 "beforestartedit" : true,
29907 * Fires when this editor is displayed
29908 * @param {Roo.Element} boundEl The underlying element bound to this editor
29909 * @param {Mixed} value The starting field value
29911 "startedit" : true,
29913 * @event beforecomplete
29914 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29915 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29916 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29917 * event will not fire since no edit actually occurred.
29918 * @param {Editor} this
29919 * @param {Mixed} value The current field value
29920 * @param {Mixed} startValue The original field value
29922 "beforecomplete" : true,
29925 * Fires after editing is complete and any changed value has been written to the underlying field.
29926 * @param {Editor} this
29927 * @param {Mixed} value The current field value
29928 * @param {Mixed} startValue The original field value
29932 * @event specialkey
29933 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29934 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29935 * @param {Roo.form.Field} this
29936 * @param {Roo.EventObject} e The event object
29938 "specialkey" : true
29942 Roo.extend(Roo.Editor, Roo.Component, {
29944 * @cfg {Boolean/String} autosize
29945 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29946 * or "height" to adopt the height only (defaults to false)
29949 * @cfg {Boolean} revertInvalid
29950 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29951 * validation fails (defaults to true)
29954 * @cfg {Boolean} ignoreNoChange
29955 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29956 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29957 * will never be ignored.
29960 * @cfg {Boolean} hideEl
29961 * False to keep the bound element visible while the editor is displayed (defaults to true)
29964 * @cfg {Mixed} value
29965 * The data value of the underlying field (defaults to "")
29969 * @cfg {String} alignment
29970 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29974 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29975 * for bottom-right shadow (defaults to "frame")
29979 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29983 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29985 completeOnEnter : false,
29987 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29989 cancelOnEsc : false,
29991 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29996 onRender : function(ct, position){
29997 this.el = new Roo.Layer({
29998 shadow: this.shadow,
30004 constrain: this.constrain
30006 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
30007 if(this.field.msgTarget != 'title'){
30008 this.field.msgTarget = 'qtip';
30010 this.field.render(this.el);
30012 this.field.el.dom.setAttribute('autocomplete', 'off');
30014 this.field.on("specialkey", this.onSpecialKey, this);
30015 if(this.swallowKeys){
30016 this.field.el.swallowEvent(['keydown','keypress']);
30019 this.field.on("blur", this.onBlur, this);
30020 if(this.field.grow){
30021 this.field.on("autosize", this.el.sync, this.el, {delay:1});
30025 onSpecialKey : function(field, e)
30027 //Roo.log('editor onSpecialKey');
30028 if(this.completeOnEnter && e.getKey() == e.ENTER){
30030 this.completeEdit();
30033 // do not fire special key otherwise it might hide close the editor...
30034 if(e.getKey() == e.ENTER){
30037 if(this.cancelOnEsc && e.getKey() == e.ESC){
30041 this.fireEvent('specialkey', field, e);
30046 * Starts the editing process and shows the editor.
30047 * @param {String/HTMLElement/Element} el The element to edit
30048 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
30049 * to the innerHTML of el.
30051 startEdit : function(el, value){
30053 this.completeEdit();
30055 this.boundEl = Roo.get(el);
30056 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
30057 if(!this.rendered){
30058 this.render(this.parentEl || document.body);
30060 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
30063 this.startValue = v;
30064 this.field.setValue(v);
30066 var sz = this.boundEl.getSize();
30067 switch(this.autoSize){
30069 this.setSize(sz.width, "");
30072 this.setSize("", sz.height);
30075 this.setSize(sz.width, sz.height);
30078 this.el.alignTo(this.boundEl, this.alignment);
30079 this.editing = true;
30081 Roo.QuickTips.disable();
30087 * Sets the height and width of this editor.
30088 * @param {Number} width The new width
30089 * @param {Number} height The new height
30091 setSize : function(w, h){
30092 this.field.setSize(w, h);
30099 * Realigns the editor to the bound field based on the current alignment config value.
30101 realign : function(){
30102 this.el.alignTo(this.boundEl, this.alignment);
30106 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
30107 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
30109 completeEdit : function(remainVisible){
30113 var v = this.getValue();
30114 if(this.revertInvalid !== false && !this.field.isValid()){
30115 v = this.startValue;
30116 this.cancelEdit(true);
30118 if(String(v) === String(this.startValue) && this.ignoreNoChange){
30119 this.editing = false;
30123 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
30124 this.editing = false;
30125 if(this.updateEl && this.boundEl){
30126 this.boundEl.update(v);
30128 if(remainVisible !== true){
30131 this.fireEvent("complete", this, v, this.startValue);
30136 onShow : function(){
30138 if(this.hideEl !== false){
30139 this.boundEl.hide();
30142 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
30143 this.fixIEFocus = true;
30144 this.deferredFocus.defer(50, this);
30146 this.field.focus();
30148 this.fireEvent("startedit", this.boundEl, this.startValue);
30151 deferredFocus : function(){
30153 this.field.focus();
30158 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
30159 * reverted to the original starting value.
30160 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
30161 * cancel (defaults to false)
30163 cancelEdit : function(remainVisible){
30165 this.setValue(this.startValue);
30166 if(remainVisible !== true){
30173 onBlur : function(){
30174 if(this.allowBlur !== true && this.editing){
30175 this.completeEdit();
30180 onHide : function(){
30182 this.completeEdit();
30186 if(this.field.collapse){
30187 this.field.collapse();
30190 if(this.hideEl !== false){
30191 this.boundEl.show();
30194 Roo.QuickTips.enable();
30199 * Sets the data value of the editor
30200 * @param {Mixed} value Any valid value supported by the underlying field
30202 setValue : function(v){
30203 this.field.setValue(v);
30207 * Gets the data value of the editor
30208 * @return {Mixed} The data value
30210 getValue : function(){
30211 return this.field.getValue();
30215 * Ext JS Library 1.1.1
30216 * Copyright(c) 2006-2007, Ext JS, LLC.
30218 * Originally Released Under LGPL - original licence link has changed is not relivant.
30221 * <script type="text/javascript">
30225 * @class Roo.BasicDialog
30226 * @extends Roo.util.Observable
30227 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
30229 var dlg = new Roo.BasicDialog("my-dlg", {
30238 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30239 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30240 dlg.addButton('Cancel', dlg.hide, dlg);
30243 <b>A Dialog should always be a direct child of the body element.</b>
30244 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30245 * @cfg {String} title Default text to display in the title bar (defaults to null)
30246 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30247 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30248 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30249 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30250 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30251 * (defaults to null with no animation)
30252 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30253 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30254 * property for valid values (defaults to 'all')
30255 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30256 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30257 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30258 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30259 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30260 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30261 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30262 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30263 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30264 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30265 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30266 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30267 * draggable = true (defaults to false)
30268 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30269 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30270 * shadow (defaults to false)
30271 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30272 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30273 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30274 * @cfg {Array} buttons Array of buttons
30275 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30277 * Create a new BasicDialog.
30278 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30279 * @param {Object} config Configuration options
30281 Roo.BasicDialog = function(el, config){
30282 this.el = Roo.get(el);
30283 var dh = Roo.DomHelper;
30284 if(!this.el && config && config.autoCreate){
30285 if(typeof config.autoCreate == "object"){
30286 if(!config.autoCreate.id){
30287 config.autoCreate.id = el;
30289 this.el = dh.append(document.body,
30290 config.autoCreate, true);
30292 this.el = dh.append(document.body,
30293 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30297 el.setDisplayed(true);
30298 el.hide = this.hideAction;
30300 el.addClass("x-dlg");
30302 Roo.apply(this, config);
30304 this.proxy = el.createProxy("x-dlg-proxy");
30305 this.proxy.hide = this.hideAction;
30306 this.proxy.setOpacity(.5);
30310 el.setWidth(config.width);
30313 el.setHeight(config.height);
30315 this.size = el.getSize();
30316 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30317 this.xy = [config.x,config.y];
30319 this.xy = el.getCenterXY(true);
30321 /** The header element @type Roo.Element */
30322 this.header = el.child("> .x-dlg-hd");
30323 /** The body element @type Roo.Element */
30324 this.body = el.child("> .x-dlg-bd");
30325 /** The footer element @type Roo.Element */
30326 this.footer = el.child("> .x-dlg-ft");
30329 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30332 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30335 this.header.unselectable();
30337 this.header.update(this.title);
30339 // this element allows the dialog to be focused for keyboard event
30340 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30341 this.focusEl.swallowEvent("click", true);
30343 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30345 // wrap the body and footer for special rendering
30346 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30348 this.bwrap.dom.appendChild(this.footer.dom);
30351 this.bg = this.el.createChild({
30352 tag: "div", cls:"x-dlg-bg",
30353 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30355 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30358 if(this.autoScroll !== false && !this.autoTabs){
30359 this.body.setStyle("overflow", "auto");
30362 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30364 if(this.closable !== false){
30365 this.el.addClass("x-dlg-closable");
30366 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30367 this.close.on("click", this.closeClick, this);
30368 this.close.addClassOnOver("x-dlg-close-over");
30370 if(this.collapsible !== false){
30371 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30372 this.collapseBtn.on("click", this.collapseClick, this);
30373 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30374 this.header.on("dblclick", this.collapseClick, this);
30376 if(this.resizable !== false){
30377 this.el.addClass("x-dlg-resizable");
30378 this.resizer = new Roo.Resizable(el, {
30379 minWidth: this.minWidth || 80,
30380 minHeight:this.minHeight || 80,
30381 handles: this.resizeHandles || "all",
30384 this.resizer.on("beforeresize", this.beforeResize, this);
30385 this.resizer.on("resize", this.onResize, this);
30387 if(this.draggable !== false){
30388 el.addClass("x-dlg-draggable");
30389 if (!this.proxyDrag) {
30390 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30393 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30395 dd.setHandleElId(this.header.id);
30396 dd.endDrag = this.endMove.createDelegate(this);
30397 dd.startDrag = this.startMove.createDelegate(this);
30398 dd.onDrag = this.onDrag.createDelegate(this);
30403 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30404 this.mask.enableDisplayMode("block");
30406 this.el.addClass("x-dlg-modal");
30409 this.shadow = new Roo.Shadow({
30410 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30411 offset : this.shadowOffset
30414 this.shadowOffset = 0;
30416 if(Roo.useShims && this.shim !== false){
30417 this.shim = this.el.createShim();
30418 this.shim.hide = this.hideAction;
30426 if (this.buttons) {
30427 var bts= this.buttons;
30429 Roo.each(bts, function(b) {
30438 * Fires when a key is pressed
30439 * @param {Roo.BasicDialog} this
30440 * @param {Roo.EventObject} e
30445 * Fires when this dialog is moved by the user.
30446 * @param {Roo.BasicDialog} this
30447 * @param {Number} x The new page X
30448 * @param {Number} y The new page Y
30453 * Fires when this dialog is resized by the user.
30454 * @param {Roo.BasicDialog} this
30455 * @param {Number} width The new width
30456 * @param {Number} height The new height
30460 * @event beforehide
30461 * Fires before this dialog is hidden.
30462 * @param {Roo.BasicDialog} this
30464 "beforehide" : true,
30467 * Fires when this dialog is hidden.
30468 * @param {Roo.BasicDialog} this
30472 * @event beforeshow
30473 * Fires before this dialog is shown.
30474 * @param {Roo.BasicDialog} this
30476 "beforeshow" : true,
30479 * Fires when this dialog is shown.
30480 * @param {Roo.BasicDialog} this
30484 el.on("keydown", this.onKeyDown, this);
30485 el.on("mousedown", this.toFront, this);
30486 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30488 Roo.DialogManager.register(this);
30489 Roo.BasicDialog.superclass.constructor.call(this);
30492 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30493 shadowOffset: Roo.isIE ? 6 : 5,
30496 minButtonWidth: 75,
30497 defaultButton: null,
30498 buttonAlign: "right",
30503 * Sets the dialog title text
30504 * @param {String} text The title text to display
30505 * @return {Roo.BasicDialog} this
30507 setTitle : function(text){
30508 this.header.update(text);
30513 closeClick : function(){
30518 collapseClick : function(){
30519 this[this.collapsed ? "expand" : "collapse"]();
30523 * Collapses the dialog to its minimized state (only the title bar is visible).
30524 * Equivalent to the user clicking the collapse dialog button.
30526 collapse : function(){
30527 if(!this.collapsed){
30528 this.collapsed = true;
30529 this.el.addClass("x-dlg-collapsed");
30530 this.restoreHeight = this.el.getHeight();
30531 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30536 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30537 * clicking the expand dialog button.
30539 expand : function(){
30540 if(this.collapsed){
30541 this.collapsed = false;
30542 this.el.removeClass("x-dlg-collapsed");
30543 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30548 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30549 * @return {Roo.TabPanel} The tabs component
30551 initTabs : function(){
30552 var tabs = this.getTabs();
30553 while(tabs.getTab(0)){
30556 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30558 tabs.addTab(Roo.id(dom), dom.title);
30566 beforeResize : function(){
30567 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30571 onResize : function(){
30572 this.refreshSize();
30573 this.syncBodyHeight();
30574 this.adjustAssets();
30576 this.fireEvent("resize", this, this.size.width, this.size.height);
30580 onKeyDown : function(e){
30581 if(this.isVisible()){
30582 this.fireEvent("keydown", this, e);
30587 * Resizes the dialog.
30588 * @param {Number} width
30589 * @param {Number} height
30590 * @return {Roo.BasicDialog} this
30592 resizeTo : function(width, height){
30593 this.el.setSize(width, height);
30594 this.size = {width: width, height: height};
30595 this.syncBodyHeight();
30596 if(this.fixedcenter){
30599 if(this.isVisible()){
30600 this.constrainXY();
30601 this.adjustAssets();
30603 this.fireEvent("resize", this, width, height);
30609 * Resizes the dialog to fit the specified content size.
30610 * @param {Number} width
30611 * @param {Number} height
30612 * @return {Roo.BasicDialog} this
30614 setContentSize : function(w, h){
30615 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30616 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30617 //if(!this.el.isBorderBox()){
30618 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30619 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30622 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30623 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30625 this.resizeTo(w, h);
30630 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30631 * executed in response to a particular key being pressed while the dialog is active.
30632 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30633 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30634 * @param {Function} fn The function to call
30635 * @param {Object} scope (optional) The scope of the function
30636 * @return {Roo.BasicDialog} this
30638 addKeyListener : function(key, fn, scope){
30639 var keyCode, shift, ctrl, alt;
30640 if(typeof key == "object" && !(key instanceof Array)){
30641 keyCode = key["key"];
30642 shift = key["shift"];
30643 ctrl = key["ctrl"];
30648 var handler = function(dlg, e){
30649 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30650 var k = e.getKey();
30651 if(keyCode instanceof Array){
30652 for(var i = 0, len = keyCode.length; i < len; i++){
30653 if(keyCode[i] == k){
30654 fn.call(scope || window, dlg, k, e);
30660 fn.call(scope || window, dlg, k, e);
30665 this.on("keydown", handler);
30670 * Returns the TabPanel component (creates it if it doesn't exist).
30671 * Note: If you wish to simply check for the existence of tabs without creating them,
30672 * check for a null 'tabs' property.
30673 * @return {Roo.TabPanel} The tabs component
30675 getTabs : function(){
30677 this.el.addClass("x-dlg-auto-tabs");
30678 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30679 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30685 * Adds a button to the footer section of the dialog.
30686 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30687 * object or a valid Roo.DomHelper element config
30688 * @param {Function} handler The function called when the button is clicked
30689 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30690 * @return {Roo.Button} The new button
30692 addButton : function(config, handler, scope){
30693 var dh = Roo.DomHelper;
30695 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30697 if(!this.btnContainer){
30698 var tb = this.footer.createChild({
30700 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30701 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30703 this.btnContainer = tb.firstChild.firstChild.firstChild;
30708 minWidth: this.minButtonWidth,
30711 if(typeof config == "string"){
30712 bconfig.text = config;
30715 bconfig.dhconfig = config;
30717 Roo.apply(bconfig, config);
30721 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30722 bconfig.position = Math.max(0, bconfig.position);
30723 fc = this.btnContainer.childNodes[bconfig.position];
30726 var btn = new Roo.Button(
30728 this.btnContainer.insertBefore(document.createElement("td"),fc)
30729 : this.btnContainer.appendChild(document.createElement("td")),
30730 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30733 this.syncBodyHeight();
30736 * Array of all the buttons that have been added to this dialog via addButton
30741 this.buttons.push(btn);
30746 * Sets the default button to be focused when the dialog is displayed.
30747 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30748 * @return {Roo.BasicDialog} this
30750 setDefaultButton : function(btn){
30751 this.defaultButton = btn;
30756 getHeaderFooterHeight : function(safe){
30759 height += this.header.getHeight();
30762 var fm = this.footer.getMargins();
30763 height += (this.footer.getHeight()+fm.top+fm.bottom);
30765 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30766 height += this.centerBg.getPadding("tb");
30771 syncBodyHeight : function()
30773 var bd = this.body, // the text
30774 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30776 var height = this.size.height - this.getHeaderFooterHeight(false);
30777 bd.setHeight(height-bd.getMargins("tb"));
30778 var hh = this.header.getHeight();
30779 var h = this.size.height-hh;
30782 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30783 bw.setHeight(h-cb.getPadding("tb"));
30785 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30786 bd.setWidth(bw.getWidth(true));
30788 this.tabs.syncHeight();
30790 this.tabs.el.repaint();
30796 * Restores the previous state of the dialog if Roo.state is configured.
30797 * @return {Roo.BasicDialog} this
30799 restoreState : function(){
30800 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30801 if(box && box.width){
30802 this.xy = [box.x, box.y];
30803 this.resizeTo(box.width, box.height);
30809 beforeShow : function(){
30811 if(this.fixedcenter){
30812 this.xy = this.el.getCenterXY(true);
30815 Roo.get(document.body).addClass("x-body-masked");
30816 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30819 this.constrainXY();
30823 animShow : function(){
30824 var b = Roo.get(this.animateTarget).getBox();
30825 this.proxy.setSize(b.width, b.height);
30826 this.proxy.setLocation(b.x, b.y);
30828 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30829 true, .35, this.showEl.createDelegate(this));
30833 * Shows the dialog.
30834 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30835 * @return {Roo.BasicDialog} this
30837 show : function(animateTarget){
30838 if (this.fireEvent("beforeshow", this) === false){
30841 if(this.syncHeightBeforeShow){
30842 this.syncBodyHeight();
30843 }else if(this.firstShow){
30844 this.firstShow = false;
30845 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30847 this.animateTarget = animateTarget || this.animateTarget;
30848 if(!this.el.isVisible()){
30850 if(this.animateTarget && Roo.get(this.animateTarget)){
30860 showEl : function(){
30862 this.el.setXY(this.xy);
30864 this.adjustAssets(true);
30867 // IE peekaboo bug - fix found by Dave Fenwick
30871 this.fireEvent("show", this);
30875 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30876 * dialog itself will receive focus.
30878 focus : function(){
30879 if(this.defaultButton){
30880 this.defaultButton.focus();
30882 this.focusEl.focus();
30887 constrainXY : function(){
30888 if(this.constraintoviewport !== false){
30889 if(!this.viewSize){
30890 if(this.container){
30891 var s = this.container.getSize();
30892 this.viewSize = [s.width, s.height];
30894 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30897 var s = Roo.get(this.container||document).getScroll();
30899 var x = this.xy[0], y = this.xy[1];
30900 var w = this.size.width, h = this.size.height;
30901 var vw = this.viewSize[0], vh = this.viewSize[1];
30902 // only move it if it needs it
30904 // first validate right/bottom
30905 if(x + w > vw+s.left){
30909 if(y + h > vh+s.top){
30913 // then make sure top/left isn't negative
30925 if(this.isVisible()){
30926 this.el.setLocation(x, y);
30927 this.adjustAssets();
30934 onDrag : function(){
30935 if(!this.proxyDrag){
30936 this.xy = this.el.getXY();
30937 this.adjustAssets();
30942 adjustAssets : function(doShow){
30943 var x = this.xy[0], y = this.xy[1];
30944 var w = this.size.width, h = this.size.height;
30945 if(doShow === true){
30947 this.shadow.show(this.el);
30953 if(this.shadow && this.shadow.isVisible()){
30954 this.shadow.show(this.el);
30956 if(this.shim && this.shim.isVisible()){
30957 this.shim.setBounds(x, y, w, h);
30962 adjustViewport : function(w, h){
30964 w = Roo.lib.Dom.getViewWidth();
30965 h = Roo.lib.Dom.getViewHeight();
30968 this.viewSize = [w, h];
30969 if(this.modal && this.mask.isVisible()){
30970 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30971 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30973 if(this.isVisible()){
30974 this.constrainXY();
30979 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30980 * shadow, proxy, mask, etc.) Also removes all event listeners.
30981 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30983 destroy : function(removeEl){
30984 if(this.isVisible()){
30985 this.animateTarget = null;
30988 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30990 this.tabs.destroy(removeEl);
31003 for(var i = 0, len = this.buttons.length; i < len; i++){
31004 this.buttons[i].destroy();
31007 this.el.removeAllListeners();
31008 if(removeEl === true){
31009 this.el.update("");
31012 Roo.DialogManager.unregister(this);
31016 startMove : function(){
31017 if(this.proxyDrag){
31020 if(this.constraintoviewport !== false){
31021 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
31026 endMove : function(){
31027 if(!this.proxyDrag){
31028 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
31030 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
31033 this.refreshSize();
31034 this.adjustAssets();
31036 this.fireEvent("move", this, this.xy[0], this.xy[1]);
31040 * Brings this dialog to the front of any other visible dialogs
31041 * @return {Roo.BasicDialog} this
31043 toFront : function(){
31044 Roo.DialogManager.bringToFront(this);
31049 * Sends this dialog to the back (under) of any other visible dialogs
31050 * @return {Roo.BasicDialog} this
31052 toBack : function(){
31053 Roo.DialogManager.sendToBack(this);
31058 * Centers this dialog in the viewport
31059 * @return {Roo.BasicDialog} this
31061 center : function(){
31062 var xy = this.el.getCenterXY(true);
31063 this.moveTo(xy[0], xy[1]);
31068 * Moves the dialog's top-left corner to the specified point
31069 * @param {Number} x
31070 * @param {Number} y
31071 * @return {Roo.BasicDialog} this
31073 moveTo : function(x, y){
31075 if(this.isVisible()){
31076 this.el.setXY(this.xy);
31077 this.adjustAssets();
31083 * Aligns the dialog to the specified element
31084 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31085 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
31086 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31087 * @return {Roo.BasicDialog} this
31089 alignTo : function(element, position, offsets){
31090 this.xy = this.el.getAlignToXY(element, position, offsets);
31091 if(this.isVisible()){
31092 this.el.setXY(this.xy);
31093 this.adjustAssets();
31099 * Anchors an element to another element and realigns it when the window is resized.
31100 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31101 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
31102 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31103 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
31104 * is a number, it is used as the buffer delay (defaults to 50ms).
31105 * @return {Roo.BasicDialog} this
31107 anchorTo : function(el, alignment, offsets, monitorScroll){
31108 var action = function(){
31109 this.alignTo(el, alignment, offsets);
31111 Roo.EventManager.onWindowResize(action, this);
31112 var tm = typeof monitorScroll;
31113 if(tm != 'undefined'){
31114 Roo.EventManager.on(window, 'scroll', action, this,
31115 {buffer: tm == 'number' ? monitorScroll : 50});
31122 * Returns true if the dialog is visible
31123 * @return {Boolean}
31125 isVisible : function(){
31126 return this.el.isVisible();
31130 animHide : function(callback){
31131 var b = Roo.get(this.animateTarget).getBox();
31133 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
31135 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
31136 this.hideEl.createDelegate(this, [callback]));
31140 * Hides the dialog.
31141 * @param {Function} callback (optional) Function to call when the dialog is hidden
31142 * @return {Roo.BasicDialog} this
31144 hide : function(callback){
31145 if (this.fireEvent("beforehide", this) === false){
31149 this.shadow.hide();
31154 // sometimes animateTarget seems to get set.. causing problems...
31155 // this just double checks..
31156 if(this.animateTarget && Roo.get(this.animateTarget)) {
31157 this.animHide(callback);
31160 this.hideEl(callback);
31166 hideEl : function(callback){
31170 Roo.get(document.body).removeClass("x-body-masked");
31172 this.fireEvent("hide", this);
31173 if(typeof callback == "function"){
31179 hideAction : function(){
31180 this.setLeft("-10000px");
31181 this.setTop("-10000px");
31182 this.setStyle("visibility", "hidden");
31186 refreshSize : function(){
31187 this.size = this.el.getSize();
31188 this.xy = this.el.getXY();
31189 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
31193 // z-index is managed by the DialogManager and may be overwritten at any time
31194 setZIndex : function(index){
31196 this.mask.setStyle("z-index", index);
31199 this.shim.setStyle("z-index", ++index);
31202 this.shadow.setZIndex(++index);
31204 this.el.setStyle("z-index", ++index);
31206 this.proxy.setStyle("z-index", ++index);
31209 this.resizer.proxy.setStyle("z-index", ++index);
31212 this.lastZIndex = index;
31216 * Returns the element for this dialog
31217 * @return {Roo.Element} The underlying dialog Element
31219 getEl : function(){
31225 * @class Roo.DialogManager
31226 * Provides global access to BasicDialogs that have been created and
31227 * support for z-indexing (layering) multiple open dialogs.
31229 Roo.DialogManager = function(){
31231 var accessList = [];
31235 var sortDialogs = function(d1, d2){
31236 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31240 var orderDialogs = function(){
31241 accessList.sort(sortDialogs);
31242 var seed = Roo.DialogManager.zseed;
31243 for(var i = 0, len = accessList.length; i < len; i++){
31244 var dlg = accessList[i];
31246 dlg.setZIndex(seed + (i*10));
31253 * The starting z-index for BasicDialogs (defaults to 9000)
31254 * @type Number The z-index value
31259 register : function(dlg){
31260 list[dlg.id] = dlg;
31261 accessList.push(dlg);
31265 unregister : function(dlg){
31266 delete list[dlg.id];
31269 if(!accessList.indexOf){
31270 for( i = 0, len = accessList.length; i < len; i++){
31271 if(accessList[i] == dlg){
31272 accessList.splice(i, 1);
31277 i = accessList.indexOf(dlg);
31279 accessList.splice(i, 1);
31285 * Gets a registered dialog by id
31286 * @param {String/Object} id The id of the dialog or a dialog
31287 * @return {Roo.BasicDialog} this
31289 get : function(id){
31290 return typeof id == "object" ? id : list[id];
31294 * Brings the specified dialog to the front
31295 * @param {String/Object} dlg The id of the dialog or a dialog
31296 * @return {Roo.BasicDialog} this
31298 bringToFront : function(dlg){
31299 dlg = this.get(dlg);
31302 dlg._lastAccess = new Date().getTime();
31309 * Sends the specified dialog to the back
31310 * @param {String/Object} dlg The id of the dialog or a dialog
31311 * @return {Roo.BasicDialog} this
31313 sendToBack : function(dlg){
31314 dlg = this.get(dlg);
31315 dlg._lastAccess = -(new Date().getTime());
31321 * Hides all dialogs
31323 hideAll : function(){
31324 for(var id in list){
31325 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31334 * @class Roo.LayoutDialog
31335 * @extends Roo.BasicDialog
31336 * Dialog which provides adjustments for working with a layout in a Dialog.
31337 * Add your necessary layout config options to the dialog's config.<br>
31338 * Example usage (including a nested layout):
31341 dialog = new Roo.LayoutDialog("download-dlg", {
31350 // layout config merges with the dialog config
31352 tabPosition: "top",
31353 alwaysShowTabs: true
31356 dialog.addKeyListener(27, dialog.hide, dialog);
31357 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31358 dialog.addButton("Build It!", this.getDownload, this);
31360 // we can even add nested layouts
31361 var innerLayout = new Roo.BorderLayout("dl-inner", {
31371 innerLayout.beginUpdate();
31372 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31373 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31374 innerLayout.endUpdate(true);
31376 var layout = dialog.getLayout();
31377 layout.beginUpdate();
31378 layout.add("center", new Roo.ContentPanel("standard-panel",
31379 {title: "Download the Source", fitToFrame:true}));
31380 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31381 {title: "Build your own roo.js"}));
31382 layout.getRegion("center").showPanel(sp);
31383 layout.endUpdate();
31387 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31388 * @param {Object} config configuration options
31390 Roo.LayoutDialog = function(el, cfg){
31393 if (typeof(cfg) == 'undefined') {
31394 config = Roo.apply({}, el);
31395 // not sure why we use documentElement here.. - it should always be body.
31396 // IE7 borks horribly if we use documentElement.
31397 // webkit also does not like documentElement - it creates a body element...
31398 el = Roo.get( document.body || document.documentElement ).createChild();
31399 //config.autoCreate = true;
31403 config.autoTabs = false;
31404 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31405 this.body.setStyle({overflow:"hidden", position:"relative"});
31406 this.layout = new Roo.BorderLayout(this.body.dom, config);
31407 this.layout.monitorWindowResize = false;
31408 this.el.addClass("x-dlg-auto-layout");
31409 // fix case when center region overwrites center function
31410 this.center = Roo.BasicDialog.prototype.center;
31411 this.on("show", this.layout.layout, this.layout, true);
31412 if (config.items) {
31413 var xitems = config.items;
31414 delete config.items;
31415 Roo.each(xitems, this.addxtype, this);
31420 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31422 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31425 endUpdate : function(){
31426 this.layout.endUpdate();
31430 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31433 beginUpdate : function(){
31434 this.layout.beginUpdate();
31438 * Get the BorderLayout for this dialog
31439 * @return {Roo.BorderLayout}
31441 getLayout : function(){
31442 return this.layout;
31445 showEl : function(){
31446 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31448 this.layout.layout();
31453 // Use the syncHeightBeforeShow config option to control this automatically
31454 syncBodyHeight : function(){
31455 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31456 if(this.layout){this.layout.layout();}
31460 * Add an xtype element (actually adds to the layout.)
31461 * @return {Object} xdata xtype object data.
31464 addxtype : function(c) {
31465 return this.layout.addxtype(c);
31469 * Ext JS Library 1.1.1
31470 * Copyright(c) 2006-2007, Ext JS, LLC.
31472 * Originally Released Under LGPL - original licence link has changed is not relivant.
31475 * <script type="text/javascript">
31479 * @class Roo.MessageBox
31480 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31484 Roo.Msg.alert('Status', 'Changes saved successfully.');
31486 // Prompt for user data:
31487 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31489 // process text value...
31493 // Show a dialog using config options:
31495 title:'Save Changes?',
31496 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31497 buttons: Roo.Msg.YESNOCANCEL,
31504 Roo.MessageBox = function(){
31505 var dlg, opt, mask, waitTimer;
31506 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31507 var buttons, activeTextEl, bwidth;
31510 var handleButton = function(button){
31512 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31516 var handleHide = function(){
31517 if(opt && opt.cls){
31518 dlg.el.removeClass(opt.cls);
31521 Roo.TaskMgr.stop(waitTimer);
31527 var updateButtons = function(b){
31530 buttons["ok"].hide();
31531 buttons["cancel"].hide();
31532 buttons["yes"].hide();
31533 buttons["no"].hide();
31534 dlg.footer.dom.style.display = 'none';
31537 dlg.footer.dom.style.display = '';
31538 for(var k in buttons){
31539 if(typeof buttons[k] != "function"){
31542 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31543 width += buttons[k].el.getWidth()+15;
31553 var handleEsc = function(d, k, e){
31554 if(opt && opt.closable !== false){
31564 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31565 * @return {Roo.BasicDialog} The BasicDialog element
31567 getDialog : function(){
31569 dlg = new Roo.BasicDialog("x-msg-box", {
31574 constraintoviewport:false,
31576 collapsible : false,
31579 width:400, height:100,
31580 buttonAlign:"center",
31581 closeClick : function(){
31582 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31583 handleButton("no");
31585 handleButton("cancel");
31589 dlg.on("hide", handleHide);
31591 dlg.addKeyListener(27, handleEsc);
31593 var bt = this.buttonText;
31594 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31595 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31596 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31597 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31598 bodyEl = dlg.body.createChild({
31600 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>'
31602 msgEl = bodyEl.dom.firstChild;
31603 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31604 textboxEl.enableDisplayMode();
31605 textboxEl.addKeyListener([10,13], function(){
31606 if(dlg.isVisible() && opt && opt.buttons){
31607 if(opt.buttons.ok){
31608 handleButton("ok");
31609 }else if(opt.buttons.yes){
31610 handleButton("yes");
31614 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31615 textareaEl.enableDisplayMode();
31616 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31617 progressEl.enableDisplayMode();
31618 var pf = progressEl.dom.firstChild;
31620 pp = Roo.get(pf.firstChild);
31621 pp.setHeight(pf.offsetHeight);
31629 * Updates the message box body text
31630 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31631 * the XHTML-compliant non-breaking space character '&#160;')
31632 * @return {Roo.MessageBox} This message box
31634 updateText : function(text){
31635 if(!dlg.isVisible() && !opt.width){
31636 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31638 msgEl.innerHTML = text || ' ';
31640 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31641 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31643 Math.min(opt.width || cw , this.maxWidth),
31644 Math.max(opt.minWidth || this.minWidth, bwidth)
31647 activeTextEl.setWidth(w);
31649 if(dlg.isVisible()){
31650 dlg.fixedcenter = false;
31652 // to big, make it scroll. = But as usual stupid IE does not support
31655 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31656 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31657 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31659 bodyEl.dom.style.height = '';
31660 bodyEl.dom.style.overflowY = '';
31663 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31665 bodyEl.dom.style.overflowX = '';
31668 dlg.setContentSize(w, bodyEl.getHeight());
31669 if(dlg.isVisible()){
31670 dlg.fixedcenter = true;
31676 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31677 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31678 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31679 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31680 * @return {Roo.MessageBox} This message box
31682 updateProgress : function(value, text){
31684 this.updateText(text);
31686 if (pp) { // weird bug on my firefox - for some reason this is not defined
31687 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31693 * Returns true if the message box is currently displayed
31694 * @return {Boolean} True if the message box is visible, else false
31696 isVisible : function(){
31697 return dlg && dlg.isVisible();
31701 * Hides the message box if it is displayed
31704 if(this.isVisible()){
31710 * Displays a new message box, or reinitializes an existing message box, based on the config options
31711 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31712 * The following config object properties are supported:
31714 Property Type Description
31715 ---------- --------------- ------------------------------------------------------------------------------------
31716 animEl String/Element An id or Element from which the message box should animate as it opens and
31717 closes (defaults to undefined)
31718 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31719 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31720 closable Boolean False to hide the top-right close button (defaults to true). Note that
31721 progress and wait dialogs will ignore this property and always hide the
31722 close button as they can only be closed programmatically.
31723 cls String A custom CSS class to apply to the message box element
31724 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31725 displayed (defaults to 75)
31726 fn Function A callback function to execute after closing the dialog. The arguments to the
31727 function will be btn (the name of the button that was clicked, if applicable,
31728 e.g. "ok"), and text (the value of the active text field, if applicable).
31729 Progress and wait dialogs will ignore this option since they do not respond to
31730 user actions and can only be closed programmatically, so any required function
31731 should be called by the same code after it closes the dialog.
31732 icon String A CSS class that provides a background image to be used as an icon for
31733 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31734 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31735 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31736 modal Boolean False to allow user interaction with the page while the message box is
31737 displayed (defaults to true)
31738 msg String A string that will replace the existing message box body text (defaults
31739 to the XHTML-compliant non-breaking space character ' ')
31740 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31741 progress Boolean True to display a progress bar (defaults to false)
31742 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31743 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31744 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31745 title String The title text
31746 value String The string value to set into the active textbox element if displayed
31747 wait Boolean True to display a progress bar (defaults to false)
31748 width Number The width of the dialog in pixels
31755 msg: 'Please enter your address:',
31757 buttons: Roo.MessageBox.OKCANCEL,
31760 animEl: 'addAddressBtn'
31763 * @param {Object} config Configuration options
31764 * @return {Roo.MessageBox} This message box
31766 show : function(options)
31769 // this causes nightmares if you show one dialog after another
31770 // especially on callbacks..
31772 if(this.isVisible()){
31775 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31776 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31777 Roo.log("New Dialog Message:" + options.msg )
31778 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31779 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31782 var d = this.getDialog();
31784 d.setTitle(opt.title || " ");
31785 d.close.setDisplayed(opt.closable !== false);
31786 activeTextEl = textboxEl;
31787 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31792 textareaEl.setHeight(typeof opt.multiline == "number" ?
31793 opt.multiline : this.defaultTextHeight);
31794 activeTextEl = textareaEl;
31803 progressEl.setDisplayed(opt.progress === true);
31804 this.updateProgress(0);
31805 activeTextEl.dom.value = opt.value || "";
31807 dlg.setDefaultButton(activeTextEl);
31809 var bs = opt.buttons;
31812 db = buttons["ok"];
31813 }else if(bs && bs.yes){
31814 db = buttons["yes"];
31816 dlg.setDefaultButton(db);
31818 bwidth = updateButtons(opt.buttons);
31819 this.updateText(opt.msg);
31821 d.el.addClass(opt.cls);
31823 d.proxyDrag = opt.proxyDrag === true;
31824 d.modal = opt.modal !== false;
31825 d.mask = opt.modal !== false ? mask : false;
31826 if(!d.isVisible()){
31827 // force it to the end of the z-index stack so it gets a cursor in FF
31828 document.body.appendChild(dlg.el.dom);
31829 d.animateTarget = null;
31830 d.show(options.animEl);
31836 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31837 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31838 * and closing the message box when the process is complete.
31839 * @param {String} title The title bar text
31840 * @param {String} msg The message box body text
31841 * @return {Roo.MessageBox} This message box
31843 progress : function(title, msg){
31850 minWidth: this.minProgressWidth,
31857 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31858 * If a callback function is passed it will be called after the user clicks the button, and the
31859 * id of the button that was clicked will be passed as the only parameter to the callback
31860 * (could also be the top-right close button).
31861 * @param {String} title The title bar text
31862 * @param {String} msg The message box body text
31863 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31864 * @param {Object} scope (optional) The scope of the callback function
31865 * @return {Roo.MessageBox} This message box
31867 alert : function(title, msg, fn, scope){
31880 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31881 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31882 * You are responsible for closing the message box when the process is complete.
31883 * @param {String} msg The message box body text
31884 * @param {String} title (optional) The title bar text
31885 * @return {Roo.MessageBox} This message box
31887 wait : function(msg, title){
31898 waitTimer = Roo.TaskMgr.start({
31900 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31908 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31909 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31910 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31911 * @param {String} title The title bar text
31912 * @param {String} msg The message box body text
31913 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31914 * @param {Object} scope (optional) The scope of the callback function
31915 * @return {Roo.MessageBox} This message box
31917 confirm : function(title, msg, fn, scope){
31921 buttons: this.YESNO,
31930 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31931 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31932 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31933 * (could also be the top-right close button) and the text that was entered will be passed as the two
31934 * parameters to the callback.
31935 * @param {String} title The title bar text
31936 * @param {String} msg The message box body text
31937 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31938 * @param {Object} scope (optional) The scope of the callback function
31939 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31940 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31941 * @return {Roo.MessageBox} This message box
31943 prompt : function(title, msg, fn, scope, multiline){
31947 buttons: this.OKCANCEL,
31952 multiline: multiline,
31959 * Button config that displays a single OK button
31964 * Button config that displays Yes and No buttons
31967 YESNO : {yes:true, no:true},
31969 * Button config that displays OK and Cancel buttons
31972 OKCANCEL : {ok:true, cancel:true},
31974 * Button config that displays Yes, No and Cancel buttons
31977 YESNOCANCEL : {yes:true, no:true, cancel:true},
31980 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31983 defaultTextHeight : 75,
31985 * The maximum width in pixels of the message box (defaults to 600)
31990 * The minimum width in pixels of the message box (defaults to 100)
31995 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31996 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31999 minProgressWidth : 250,
32001 * An object containing the default button text strings that can be overriden for localized language support.
32002 * Supported properties are: ok, cancel, yes and no.
32003 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
32016 * Shorthand for {@link Roo.MessageBox}
32018 Roo.Msg = Roo.MessageBox;/*
32020 * Ext JS Library 1.1.1
32021 * Copyright(c) 2006-2007, Ext JS, LLC.
32023 * Originally Released Under LGPL - original licence link has changed is not relivant.
32026 * <script type="text/javascript">
32029 * @class Roo.QuickTips
32030 * Provides attractive and customizable tooltips for any element.
32033 Roo.QuickTips = function(){
32034 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
32035 var ce, bd, xy, dd;
32036 var visible = false, disabled = true, inited = false;
32037 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
32039 var onOver = function(e){
32043 var t = e.getTarget();
32044 if(!t || t.nodeType !== 1 || t == document || t == document.body){
32047 if(ce && t == ce.el){
32048 clearTimeout(hideProc);
32051 if(t && tagEls[t.id]){
32052 tagEls[t.id].el = t;
32053 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
32056 var ttp, et = Roo.fly(t);
32057 var ns = cfg.namespace;
32058 if(tm.interceptTitles && t.title){
32061 t.removeAttribute("title");
32062 e.preventDefault();
32064 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
32067 showProc = show.defer(tm.showDelay, tm, [{
32070 width: et.getAttributeNS(ns, cfg.width),
32071 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
32072 title: et.getAttributeNS(ns, cfg.title),
32073 cls: et.getAttributeNS(ns, cfg.cls)
32078 var onOut = function(e){
32079 clearTimeout(showProc);
32080 var t = e.getTarget();
32081 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
32082 hideProc = setTimeout(hide, tm.hideDelay);
32086 var onMove = function(e){
32092 if(tm.trackMouse && ce){
32097 var onDown = function(e){
32098 clearTimeout(showProc);
32099 clearTimeout(hideProc);
32101 if(tm.hideOnClick){
32104 tm.enable.defer(100, tm);
32109 var getPad = function(){
32110 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
32113 var show = function(o){
32117 clearTimeout(dismissProc);
32119 if(removeCls){ // in case manually hidden
32120 el.removeClass(removeCls);
32124 el.addClass(ce.cls);
32125 removeCls = ce.cls;
32128 tipTitle.update(ce.title);
32131 tipTitle.update('');
32134 el.dom.style.width = tm.maxWidth+'px';
32135 //tipBody.dom.style.width = '';
32136 tipBodyText.update(o.text);
32137 var p = getPad(), w = ce.width;
32139 var td = tipBodyText.dom;
32140 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
32141 if(aw > tm.maxWidth){
32143 }else if(aw < tm.minWidth){
32149 //tipBody.setWidth(w);
32150 el.setWidth(parseInt(w, 10) + p);
32151 if(ce.autoHide === false){
32152 close.setDisplayed(true);
32157 close.setDisplayed(false);
32163 el.avoidY = xy[1]-18;
32168 el.setStyle("visibility", "visible");
32169 el.fadeIn({callback: afterShow});
32175 var afterShow = function(){
32179 if(tm.autoDismiss && ce.autoHide !== false){
32180 dismissProc = setTimeout(hide, tm.autoDismissDelay);
32185 var hide = function(noanim){
32186 clearTimeout(dismissProc);
32187 clearTimeout(hideProc);
32189 if(el.isVisible()){
32191 if(noanim !== true && tm.animate){
32192 el.fadeOut({callback: afterHide});
32199 var afterHide = function(){
32202 el.removeClass(removeCls);
32209 * @cfg {Number} minWidth
32210 * The minimum width of the quick tip (defaults to 40)
32214 * @cfg {Number} maxWidth
32215 * The maximum width of the quick tip (defaults to 300)
32219 * @cfg {Boolean} interceptTitles
32220 * True to automatically use the element's DOM title value if available (defaults to false)
32222 interceptTitles : false,
32224 * @cfg {Boolean} trackMouse
32225 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
32227 trackMouse : false,
32229 * @cfg {Boolean} hideOnClick
32230 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32232 hideOnClick : true,
32234 * @cfg {Number} showDelay
32235 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32239 * @cfg {Number} hideDelay
32240 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32244 * @cfg {Boolean} autoHide
32245 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32246 * Used in conjunction with hideDelay.
32251 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32252 * (defaults to true). Used in conjunction with autoDismissDelay.
32254 autoDismiss : true,
32257 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32259 autoDismissDelay : 5000,
32261 * @cfg {Boolean} animate
32262 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32267 * @cfg {String} title
32268 * Title text to display (defaults to ''). This can be any valid HTML markup.
32272 * @cfg {String} text
32273 * Body text to display (defaults to ''). This can be any valid HTML markup.
32277 * @cfg {String} cls
32278 * A CSS class to apply to the base quick tip element (defaults to '').
32282 * @cfg {Number} width
32283 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32284 * minWidth or maxWidth.
32289 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32290 * or display QuickTips in a page.
32293 tm = Roo.QuickTips;
32294 cfg = tm.tagConfig;
32296 if(!Roo.isReady){ // allow calling of init() before onReady
32297 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32300 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32301 el.fxDefaults = {stopFx: true};
32302 // maximum custom styling
32303 //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>');
32304 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>');
32305 tipTitle = el.child('h3');
32306 tipTitle.enableDisplayMode("block");
32307 tipBody = el.child('div.x-tip-bd');
32308 tipBodyText = el.child('div.x-tip-bd-inner');
32309 //bdLeft = el.child('div.x-tip-bd-left');
32310 //bdRight = el.child('div.x-tip-bd-right');
32311 close = el.child('div.x-tip-close');
32312 close.enableDisplayMode("block");
32313 close.on("click", hide);
32314 var d = Roo.get(document);
32315 d.on("mousedown", onDown);
32316 d.on("mouseover", onOver);
32317 d.on("mouseout", onOut);
32318 d.on("mousemove", onMove);
32319 esc = d.addKeyListener(27, hide);
32322 dd = el.initDD("default", null, {
32323 onDrag : function(){
32327 dd.setHandleElId(tipTitle.id);
32336 * Configures a new quick tip instance and assigns it to a target element. The following config options
32339 Property Type Description
32340 ---------- --------------------- ------------------------------------------------------------------------
32341 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32343 * @param {Object} config The config object
32345 register : function(config){
32346 var cs = config instanceof Array ? config : arguments;
32347 for(var i = 0, len = cs.length; i < len; i++) {
32349 var target = c.target;
32351 if(target instanceof Array){
32352 for(var j = 0, jlen = target.length; j < jlen; j++){
32353 tagEls[target[j]] = c;
32356 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32363 * Removes this quick tip from its element and destroys it.
32364 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32366 unregister : function(el){
32367 delete tagEls[Roo.id(el)];
32371 * Enable this quick tip.
32373 enable : function(){
32374 if(inited && disabled){
32376 if(locks.length < 1){
32383 * Disable this quick tip.
32385 disable : function(){
32387 clearTimeout(showProc);
32388 clearTimeout(hideProc);
32389 clearTimeout(dismissProc);
32397 * Returns true if the quick tip is enabled, else false.
32399 isEnabled : function(){
32405 namespace : "roo", // was ext?? this may break..
32406 alt_namespace : "ext",
32407 attribute : "qtip",
32417 // backwards compat
32418 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32420 * Ext JS Library 1.1.1
32421 * Copyright(c) 2006-2007, Ext JS, LLC.
32423 * Originally Released Under LGPL - original licence link has changed is not relivant.
32426 * <script type="text/javascript">
32431 * @class Roo.tree.TreePanel
32432 * @extends Roo.data.Tree
32434 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32435 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32436 * @cfg {Boolean} enableDD true to enable drag and drop
32437 * @cfg {Boolean} enableDrag true to enable just drag
32438 * @cfg {Boolean} enableDrop true to enable just drop
32439 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32440 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32441 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32442 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32443 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32444 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32445 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32446 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32447 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32448 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32449 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32450 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32451 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32452 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32453 * @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>
32454 * @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>
32457 * @param {String/HTMLElement/Element} el The container element
32458 * @param {Object} config
32460 Roo.tree.TreePanel = function(el, config){
32462 var loader = false;
32464 root = config.root;
32465 delete config.root;
32467 if (config.loader) {
32468 loader = config.loader;
32469 delete config.loader;
32472 Roo.apply(this, config);
32473 Roo.tree.TreePanel.superclass.constructor.call(this);
32474 this.el = Roo.get(el);
32475 this.el.addClass('x-tree');
32476 //console.log(root);
32478 this.setRootNode( Roo.factory(root, Roo.tree));
32481 this.loader = Roo.factory(loader, Roo.tree);
32484 * Read-only. The id of the container element becomes this TreePanel's id.
32486 this.id = this.el.id;
32489 * @event beforeload
32490 * Fires before a node is loaded, return false to cancel
32491 * @param {Node} node The node being loaded
32493 "beforeload" : true,
32496 * Fires when a node is loaded
32497 * @param {Node} node The node that was loaded
32501 * @event textchange
32502 * Fires when the text for a node is changed
32503 * @param {Node} node The node
32504 * @param {String} text The new text
32505 * @param {String} oldText The old text
32507 "textchange" : true,
32509 * @event beforeexpand
32510 * Fires before a node is expanded, return false to cancel.
32511 * @param {Node} node The node
32512 * @param {Boolean} deep
32513 * @param {Boolean} anim
32515 "beforeexpand" : true,
32517 * @event beforecollapse
32518 * Fires before a node is collapsed, return false to cancel.
32519 * @param {Node} node The node
32520 * @param {Boolean} deep
32521 * @param {Boolean} anim
32523 "beforecollapse" : true,
32526 * Fires when a node is expanded
32527 * @param {Node} node The node
32531 * @event disabledchange
32532 * Fires when the disabled status of a node changes
32533 * @param {Node} node The node
32534 * @param {Boolean} disabled
32536 "disabledchange" : true,
32539 * Fires when a node is collapsed
32540 * @param {Node} node The node
32544 * @event beforeclick
32545 * Fires before click processing on a node. Return false to cancel the default action.
32546 * @param {Node} node The node
32547 * @param {Roo.EventObject} e The event object
32549 "beforeclick":true,
32551 * @event checkchange
32552 * Fires when a node with a checkbox's checked property changes
32553 * @param {Node} this This node
32554 * @param {Boolean} checked
32556 "checkchange":true,
32559 * Fires when a node is clicked
32560 * @param {Node} node The node
32561 * @param {Roo.EventObject} e The event object
32566 * Fires when a node is double clicked
32567 * @param {Node} node The node
32568 * @param {Roo.EventObject} e The event object
32572 * @event contextmenu
32573 * Fires when a node is right clicked
32574 * @param {Node} node The node
32575 * @param {Roo.EventObject} e The event object
32577 "contextmenu":true,
32579 * @event beforechildrenrendered
32580 * Fires right before the child nodes for a node are rendered
32581 * @param {Node} node The node
32583 "beforechildrenrendered":true,
32586 * Fires when a node starts being dragged
32587 * @param {Roo.tree.TreePanel} this
32588 * @param {Roo.tree.TreeNode} node
32589 * @param {event} e The raw browser event
32591 "startdrag" : true,
32594 * Fires when a drag operation is complete
32595 * @param {Roo.tree.TreePanel} this
32596 * @param {Roo.tree.TreeNode} node
32597 * @param {event} e The raw browser event
32602 * Fires when a dragged node is dropped on a valid DD target
32603 * @param {Roo.tree.TreePanel} this
32604 * @param {Roo.tree.TreeNode} node
32605 * @param {DD} dd The dd it was dropped on
32606 * @param {event} e The raw browser event
32610 * @event beforenodedrop
32611 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32612 * passed to handlers has the following properties:<br />
32613 * <ul style="padding:5px;padding-left:16px;">
32614 * <li>tree - The TreePanel</li>
32615 * <li>target - The node being targeted for the drop</li>
32616 * <li>data - The drag data from the drag source</li>
32617 * <li>point - The point of the drop - append, above or below</li>
32618 * <li>source - The drag source</li>
32619 * <li>rawEvent - Raw mouse event</li>
32620 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32621 * to be inserted by setting them on this object.</li>
32622 * <li>cancel - Set this to true to cancel the drop.</li>
32624 * @param {Object} dropEvent
32626 "beforenodedrop" : true,
32629 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32630 * passed to handlers has the following properties:<br />
32631 * <ul style="padding:5px;padding-left:16px;">
32632 * <li>tree - The TreePanel</li>
32633 * <li>target - The node being targeted for the drop</li>
32634 * <li>data - The drag data from the drag source</li>
32635 * <li>point - The point of the drop - append, above or below</li>
32636 * <li>source - The drag source</li>
32637 * <li>rawEvent - Raw mouse event</li>
32638 * <li>dropNode - Dropped node(s).</li>
32640 * @param {Object} dropEvent
32644 * @event nodedragover
32645 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32646 * passed to handlers has the following properties:<br />
32647 * <ul style="padding:5px;padding-left:16px;">
32648 * <li>tree - The TreePanel</li>
32649 * <li>target - The node being targeted for the drop</li>
32650 * <li>data - The drag data from the drag source</li>
32651 * <li>point - The point of the drop - append, above or below</li>
32652 * <li>source - The drag source</li>
32653 * <li>rawEvent - Raw mouse event</li>
32654 * <li>dropNode - Drop node(s) provided by the source.</li>
32655 * <li>cancel - Set this to true to signal drop not allowed.</li>
32657 * @param {Object} dragOverEvent
32659 "nodedragover" : true
32662 if(this.singleExpand){
32663 this.on("beforeexpand", this.restrictExpand, this);
32666 this.editor.tree = this;
32667 this.editor = Roo.factory(this.editor, Roo.tree);
32670 if (this.selModel) {
32671 this.selModel = Roo.factory(this.selModel, Roo.tree);
32675 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32676 rootVisible : true,
32677 animate: Roo.enableFx,
32680 hlDrop : Roo.enableFx,
32684 rendererTip: false,
32686 restrictExpand : function(node){
32687 var p = node.parentNode;
32689 if(p.expandedChild && p.expandedChild.parentNode == p){
32690 p.expandedChild.collapse();
32692 p.expandedChild = node;
32696 // private override
32697 setRootNode : function(node){
32698 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32699 if(!this.rootVisible){
32700 node.ui = new Roo.tree.RootTreeNodeUI(node);
32706 * Returns the container element for this TreePanel
32708 getEl : function(){
32713 * Returns the default TreeLoader for this TreePanel
32715 getLoader : function(){
32716 return this.loader;
32722 expandAll : function(){
32723 this.root.expand(true);
32727 * Collapse all nodes
32729 collapseAll : function(){
32730 this.root.collapse(true);
32734 * Returns the selection model used by this TreePanel
32736 getSelectionModel : function(){
32737 if(!this.selModel){
32738 this.selModel = new Roo.tree.DefaultSelectionModel();
32740 return this.selModel;
32744 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32745 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32746 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32749 getChecked : function(a, startNode){
32750 startNode = startNode || this.root;
32752 var f = function(){
32753 if(this.attributes.checked){
32754 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32757 startNode.cascade(f);
32762 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32763 * @param {String} path
32764 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32765 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32766 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32768 expandPath : function(path, attr, callback){
32769 attr = attr || "id";
32770 var keys = path.split(this.pathSeparator);
32771 var curNode = this.root;
32772 if(curNode.attributes[attr] != keys[1]){ // invalid root
32774 callback(false, null);
32779 var f = function(){
32780 if(++index == keys.length){
32782 callback(true, curNode);
32786 var c = curNode.findChild(attr, keys[index]);
32789 callback(false, curNode);
32794 c.expand(false, false, f);
32796 curNode.expand(false, false, f);
32800 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32801 * @param {String} path
32802 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32803 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32804 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32806 selectPath : function(path, attr, callback){
32807 attr = attr || "id";
32808 var keys = path.split(this.pathSeparator);
32809 var v = keys.pop();
32810 if(keys.length > 0){
32811 var f = function(success, node){
32812 if(success && node){
32813 var n = node.findChild(attr, v);
32819 }else if(callback){
32820 callback(false, n);
32824 callback(false, n);
32828 this.expandPath(keys.join(this.pathSeparator), attr, f);
32830 this.root.select();
32832 callback(true, this.root);
32837 getTreeEl : function(){
32842 * Trigger rendering of this TreePanel
32844 render : function(){
32845 if (this.innerCt) {
32846 return this; // stop it rendering more than once!!
32849 this.innerCt = this.el.createChild({tag:"ul",
32850 cls:"x-tree-root-ct " +
32851 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32853 if(this.containerScroll){
32854 Roo.dd.ScrollManager.register(this.el);
32856 if((this.enableDD || this.enableDrop) && !this.dropZone){
32858 * The dropZone used by this tree if drop is enabled
32859 * @type Roo.tree.TreeDropZone
32861 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32862 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32865 if((this.enableDD || this.enableDrag) && !this.dragZone){
32867 * The dragZone used by this tree if drag is enabled
32868 * @type Roo.tree.TreeDragZone
32870 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32871 ddGroup: this.ddGroup || "TreeDD",
32872 scroll: this.ddScroll
32875 this.getSelectionModel().init(this);
32877 Roo.log("ROOT not set in tree");
32880 this.root.render();
32881 if(!this.rootVisible){
32882 this.root.renderChildren();
32888 * Ext JS Library 1.1.1
32889 * Copyright(c) 2006-2007, Ext JS, LLC.
32891 * Originally Released Under LGPL - original licence link has changed is not relivant.
32894 * <script type="text/javascript">
32899 * @class Roo.tree.DefaultSelectionModel
32900 * @extends Roo.util.Observable
32901 * The default single selection for a TreePanel.
32902 * @param {Object} cfg Configuration
32904 Roo.tree.DefaultSelectionModel = function(cfg){
32905 this.selNode = null;
32911 * @event selectionchange
32912 * Fires when the selected node changes
32913 * @param {DefaultSelectionModel} this
32914 * @param {TreeNode} node the new selection
32916 "selectionchange" : true,
32919 * @event beforeselect
32920 * Fires before the selected node changes, return false to cancel the change
32921 * @param {DefaultSelectionModel} this
32922 * @param {TreeNode} node the new selection
32923 * @param {TreeNode} node the old selection
32925 "beforeselect" : true
32928 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32931 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32932 init : function(tree){
32934 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32935 tree.on("click", this.onNodeClick, this);
32938 onNodeClick : function(node, e){
32939 if (e.ctrlKey && this.selNode == node) {
32940 this.unselect(node);
32948 * @param {TreeNode} node The node to select
32949 * @return {TreeNode} The selected node
32951 select : function(node){
32952 var last = this.selNode;
32953 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32955 last.ui.onSelectedChange(false);
32957 this.selNode = node;
32958 node.ui.onSelectedChange(true);
32959 this.fireEvent("selectionchange", this, node, last);
32966 * @param {TreeNode} node The node to unselect
32968 unselect : function(node){
32969 if(this.selNode == node){
32970 this.clearSelections();
32975 * Clear all selections
32977 clearSelections : function(){
32978 var n = this.selNode;
32980 n.ui.onSelectedChange(false);
32981 this.selNode = null;
32982 this.fireEvent("selectionchange", this, null);
32988 * Get the selected node
32989 * @return {TreeNode} The selected node
32991 getSelectedNode : function(){
32992 return this.selNode;
32996 * Returns true if the node is selected
32997 * @param {TreeNode} node The node to check
32998 * @return {Boolean}
33000 isSelected : function(node){
33001 return this.selNode == node;
33005 * Selects the node above the selected node in the tree, intelligently walking the nodes
33006 * @return TreeNode The new selection
33008 selectPrevious : function(){
33009 var s = this.selNode || this.lastSelNode;
33013 var ps = s.previousSibling;
33015 if(!ps.isExpanded() || ps.childNodes.length < 1){
33016 return this.select(ps);
33018 var lc = ps.lastChild;
33019 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
33022 return this.select(lc);
33024 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
33025 return this.select(s.parentNode);
33031 * Selects the node above the selected node in the tree, intelligently walking the nodes
33032 * @return TreeNode The new selection
33034 selectNext : function(){
33035 var s = this.selNode || this.lastSelNode;
33039 if(s.firstChild && s.isExpanded()){
33040 return this.select(s.firstChild);
33041 }else if(s.nextSibling){
33042 return this.select(s.nextSibling);
33043 }else if(s.parentNode){
33045 s.parentNode.bubble(function(){
33046 if(this.nextSibling){
33047 newS = this.getOwnerTree().selModel.select(this.nextSibling);
33056 onKeyDown : function(e){
33057 var s = this.selNode || this.lastSelNode;
33058 // undesirable, but required
33063 var k = e.getKey();
33071 this.selectPrevious();
33074 e.preventDefault();
33075 if(s.hasChildNodes()){
33076 if(!s.isExpanded()){
33078 }else if(s.firstChild){
33079 this.select(s.firstChild, e);
33084 e.preventDefault();
33085 if(s.hasChildNodes() && s.isExpanded()){
33087 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
33088 this.select(s.parentNode, e);
33096 * @class Roo.tree.MultiSelectionModel
33097 * @extends Roo.util.Observable
33098 * Multi selection for a TreePanel.
33099 * @param {Object} cfg Configuration
33101 Roo.tree.MultiSelectionModel = function(){
33102 this.selNodes = [];
33106 * @event selectionchange
33107 * Fires when the selected nodes change
33108 * @param {MultiSelectionModel} this
33109 * @param {Array} nodes Array of the selected nodes
33111 "selectionchange" : true
33113 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
33117 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
33118 init : function(tree){
33120 tree.getTreeEl().on("keydown", this.onKeyDown, this);
33121 tree.on("click", this.onNodeClick, this);
33124 onNodeClick : function(node, e){
33125 this.select(node, e, e.ctrlKey);
33130 * @param {TreeNode} node The node to select
33131 * @param {EventObject} e (optional) An event associated with the selection
33132 * @param {Boolean} keepExisting True to retain existing selections
33133 * @return {TreeNode} The selected node
33135 select : function(node, e, keepExisting){
33136 if(keepExisting !== true){
33137 this.clearSelections(true);
33139 if(this.isSelected(node)){
33140 this.lastSelNode = node;
33143 this.selNodes.push(node);
33144 this.selMap[node.id] = node;
33145 this.lastSelNode = node;
33146 node.ui.onSelectedChange(true);
33147 this.fireEvent("selectionchange", this, this.selNodes);
33153 * @param {TreeNode} node The node to unselect
33155 unselect : function(node){
33156 if(this.selMap[node.id]){
33157 node.ui.onSelectedChange(false);
33158 var sn = this.selNodes;
33161 index = sn.indexOf(node);
33163 for(var i = 0, len = sn.length; i < len; i++){
33171 this.selNodes.splice(index, 1);
33173 delete this.selMap[node.id];
33174 this.fireEvent("selectionchange", this, this.selNodes);
33179 * Clear all selections
33181 clearSelections : function(suppressEvent){
33182 var sn = this.selNodes;
33184 for(var i = 0, len = sn.length; i < len; i++){
33185 sn[i].ui.onSelectedChange(false);
33187 this.selNodes = [];
33189 if(suppressEvent !== true){
33190 this.fireEvent("selectionchange", this, this.selNodes);
33196 * Returns true if the node is selected
33197 * @param {TreeNode} node The node to check
33198 * @return {Boolean}
33200 isSelected : function(node){
33201 return this.selMap[node.id] ? true : false;
33205 * Returns an array of the selected nodes
33208 getSelectedNodes : function(){
33209 return this.selNodes;
33212 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
33214 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
33216 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
33219 * Ext JS Library 1.1.1
33220 * Copyright(c) 2006-2007, Ext JS, LLC.
33222 * Originally Released Under LGPL - original licence link has changed is not relivant.
33225 * <script type="text/javascript">
33229 * @class Roo.tree.TreeNode
33230 * @extends Roo.data.Node
33231 * @cfg {String} text The text for this node
33232 * @cfg {Boolean} expanded true to start the node expanded
33233 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33234 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33235 * @cfg {Boolean} disabled true to start the node disabled
33236 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33237 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33238 * @cfg {String} cls A css class to be added to the node
33239 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33240 * @cfg {String} href URL of the link used for the node (defaults to #)
33241 * @cfg {String} hrefTarget target frame for the link
33242 * @cfg {String} qtip An Ext QuickTip for the node
33243 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33244 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33245 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33246 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33247 * (defaults to undefined with no checkbox rendered)
33249 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33251 Roo.tree.TreeNode = function(attributes){
33252 attributes = attributes || {};
33253 if(typeof attributes == "string"){
33254 attributes = {text: attributes};
33256 this.childrenRendered = false;
33257 this.rendered = false;
33258 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33259 this.expanded = attributes.expanded === true;
33260 this.isTarget = attributes.isTarget !== false;
33261 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33262 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33265 * Read-only. The text for this node. To change it use setText().
33268 this.text = attributes.text;
33270 * True if this node is disabled.
33273 this.disabled = attributes.disabled === true;
33277 * @event textchange
33278 * Fires when the text for this node is changed
33279 * @param {Node} this This node
33280 * @param {String} text The new text
33281 * @param {String} oldText The old text
33283 "textchange" : true,
33285 * @event beforeexpand
33286 * Fires before this node is expanded, return false to cancel.
33287 * @param {Node} this This node
33288 * @param {Boolean} deep
33289 * @param {Boolean} anim
33291 "beforeexpand" : true,
33293 * @event beforecollapse
33294 * Fires before this node is collapsed, return false to cancel.
33295 * @param {Node} this This node
33296 * @param {Boolean} deep
33297 * @param {Boolean} anim
33299 "beforecollapse" : true,
33302 * Fires when this node is expanded
33303 * @param {Node} this This node
33307 * @event disabledchange
33308 * Fires when the disabled status of this node changes
33309 * @param {Node} this This node
33310 * @param {Boolean} disabled
33312 "disabledchange" : true,
33315 * Fires when this node is collapsed
33316 * @param {Node} this This node
33320 * @event beforeclick
33321 * Fires before click processing. Return false to cancel the default action.
33322 * @param {Node} this This node
33323 * @param {Roo.EventObject} e The event object
33325 "beforeclick":true,
33327 * @event checkchange
33328 * Fires when a node with a checkbox's checked property changes
33329 * @param {Node} this This node
33330 * @param {Boolean} checked
33332 "checkchange":true,
33335 * Fires when this node is clicked
33336 * @param {Node} this This node
33337 * @param {Roo.EventObject} e The event object
33342 * Fires when this node is double clicked
33343 * @param {Node} this This node
33344 * @param {Roo.EventObject} e The event object
33348 * @event contextmenu
33349 * Fires when this node is right clicked
33350 * @param {Node} this This node
33351 * @param {Roo.EventObject} e The event object
33353 "contextmenu":true,
33355 * @event beforechildrenrendered
33356 * Fires right before the child nodes for this node are rendered
33357 * @param {Node} this This node
33359 "beforechildrenrendered":true
33362 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33365 * Read-only. The UI for this node
33368 this.ui = new uiClass(this);
33370 // finally support items[]
33371 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33376 Roo.each(this.attributes.items, function(c) {
33377 this.appendChild(Roo.factory(c,Roo.Tree));
33379 delete this.attributes.items;
33384 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33385 preventHScroll: true,
33387 * Returns true if this node is expanded
33388 * @return {Boolean}
33390 isExpanded : function(){
33391 return this.expanded;
33395 * Returns the UI object for this node
33396 * @return {TreeNodeUI}
33398 getUI : function(){
33402 // private override
33403 setFirstChild : function(node){
33404 var of = this.firstChild;
33405 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33406 if(this.childrenRendered && of && node != of){
33407 of.renderIndent(true, true);
33410 this.renderIndent(true, true);
33414 // private override
33415 setLastChild : function(node){
33416 var ol = this.lastChild;
33417 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33418 if(this.childrenRendered && ol && node != ol){
33419 ol.renderIndent(true, true);
33422 this.renderIndent(true, true);
33426 // these methods are overridden to provide lazy rendering support
33427 // private override
33428 appendChild : function()
33430 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33431 if(node && this.childrenRendered){
33434 this.ui.updateExpandIcon();
33438 // private override
33439 removeChild : function(node){
33440 this.ownerTree.getSelectionModel().unselect(node);
33441 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33442 // if it's been rendered remove dom node
33443 if(this.childrenRendered){
33446 if(this.childNodes.length < 1){
33447 this.collapse(false, false);
33449 this.ui.updateExpandIcon();
33451 if(!this.firstChild) {
33452 this.childrenRendered = false;
33457 // private override
33458 insertBefore : function(node, refNode){
33459 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33460 if(newNode && refNode && this.childrenRendered){
33463 this.ui.updateExpandIcon();
33468 * Sets the text for this node
33469 * @param {String} text
33471 setText : function(text){
33472 var oldText = this.text;
33474 this.attributes.text = text;
33475 if(this.rendered){ // event without subscribing
33476 this.ui.onTextChange(this, text, oldText);
33478 this.fireEvent("textchange", this, text, oldText);
33482 * Triggers selection of this node
33484 select : function(){
33485 this.getOwnerTree().getSelectionModel().select(this);
33489 * Triggers deselection of this node
33491 unselect : function(){
33492 this.getOwnerTree().getSelectionModel().unselect(this);
33496 * Returns true if this node is selected
33497 * @return {Boolean}
33499 isSelected : function(){
33500 return this.getOwnerTree().getSelectionModel().isSelected(this);
33504 * Expand this node.
33505 * @param {Boolean} deep (optional) True to expand all children as well
33506 * @param {Boolean} anim (optional) false to cancel the default animation
33507 * @param {Function} callback (optional) A callback to be called when
33508 * expanding this node completes (does not wait for deep expand to complete).
33509 * Called with 1 parameter, this node.
33511 expand : function(deep, anim, callback){
33512 if(!this.expanded){
33513 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33516 if(!this.childrenRendered){
33517 this.renderChildren();
33519 this.expanded = true;
33520 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33521 this.ui.animExpand(function(){
33522 this.fireEvent("expand", this);
33523 if(typeof callback == "function"){
33527 this.expandChildNodes(true);
33529 }.createDelegate(this));
33533 this.fireEvent("expand", this);
33534 if(typeof callback == "function"){
33539 if(typeof callback == "function"){
33544 this.expandChildNodes(true);
33548 isHiddenRoot : function(){
33549 return this.isRoot && !this.getOwnerTree().rootVisible;
33553 * Collapse this node.
33554 * @param {Boolean} deep (optional) True to collapse all children as well
33555 * @param {Boolean} anim (optional) false to cancel the default animation
33557 collapse : function(deep, anim){
33558 if(this.expanded && !this.isHiddenRoot()){
33559 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33562 this.expanded = false;
33563 if((this.getOwnerTree().animate && anim !== false) || anim){
33564 this.ui.animCollapse(function(){
33565 this.fireEvent("collapse", this);
33567 this.collapseChildNodes(true);
33569 }.createDelegate(this));
33572 this.ui.collapse();
33573 this.fireEvent("collapse", this);
33577 var cs = this.childNodes;
33578 for(var i = 0, len = cs.length; i < len; i++) {
33579 cs[i].collapse(true, false);
33585 delayedExpand : function(delay){
33586 if(!this.expandProcId){
33587 this.expandProcId = this.expand.defer(delay, this);
33592 cancelExpand : function(){
33593 if(this.expandProcId){
33594 clearTimeout(this.expandProcId);
33596 this.expandProcId = false;
33600 * Toggles expanded/collapsed state of the node
33602 toggle : function(){
33611 * Ensures all parent nodes are expanded
33613 ensureVisible : function(callback){
33614 var tree = this.getOwnerTree();
33615 tree.expandPath(this.parentNode.getPath(), false, function(){
33616 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33617 Roo.callback(callback);
33618 }.createDelegate(this));
33622 * Expand all child nodes
33623 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33625 expandChildNodes : function(deep){
33626 var cs = this.childNodes;
33627 for(var i = 0, len = cs.length; i < len; i++) {
33628 cs[i].expand(deep);
33633 * Collapse all child nodes
33634 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33636 collapseChildNodes : function(deep){
33637 var cs = this.childNodes;
33638 for(var i = 0, len = cs.length; i < len; i++) {
33639 cs[i].collapse(deep);
33644 * Disables this node
33646 disable : function(){
33647 this.disabled = true;
33649 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33650 this.ui.onDisableChange(this, true);
33652 this.fireEvent("disabledchange", this, true);
33656 * Enables this node
33658 enable : function(){
33659 this.disabled = false;
33660 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33661 this.ui.onDisableChange(this, false);
33663 this.fireEvent("disabledchange", this, false);
33667 renderChildren : function(suppressEvent){
33668 if(suppressEvent !== false){
33669 this.fireEvent("beforechildrenrendered", this);
33671 var cs = this.childNodes;
33672 for(var i = 0, len = cs.length; i < len; i++){
33673 cs[i].render(true);
33675 this.childrenRendered = true;
33679 sort : function(fn, scope){
33680 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33681 if(this.childrenRendered){
33682 var cs = this.childNodes;
33683 for(var i = 0, len = cs.length; i < len; i++){
33684 cs[i].render(true);
33690 render : function(bulkRender){
33691 this.ui.render(bulkRender);
33692 if(!this.rendered){
33693 this.rendered = true;
33695 this.expanded = false;
33696 this.expand(false, false);
33702 renderIndent : function(deep, refresh){
33704 this.ui.childIndent = null;
33706 this.ui.renderIndent();
33707 if(deep === true && this.childrenRendered){
33708 var cs = this.childNodes;
33709 for(var i = 0, len = cs.length; i < len; i++){
33710 cs[i].renderIndent(true, refresh);
33716 * Ext JS Library 1.1.1
33717 * Copyright(c) 2006-2007, Ext JS, LLC.
33719 * Originally Released Under LGPL - original licence link has changed is not relivant.
33722 * <script type="text/javascript">
33726 * @class Roo.tree.AsyncTreeNode
33727 * @extends Roo.tree.TreeNode
33728 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33730 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33732 Roo.tree.AsyncTreeNode = function(config){
33733 this.loaded = false;
33734 this.loading = false;
33735 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33737 * @event beforeload
33738 * Fires before this node is loaded, return false to cancel
33739 * @param {Node} this This node
33741 this.addEvents({'beforeload':true, 'load': true});
33744 * Fires when this node is loaded
33745 * @param {Node} this This node
33748 * The loader used by this node (defaults to using the tree's defined loader)
33753 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33754 expand : function(deep, anim, callback){
33755 if(this.loading){ // if an async load is already running, waiting til it's done
33757 var f = function(){
33758 if(!this.loading){ // done loading
33759 clearInterval(timer);
33760 this.expand(deep, anim, callback);
33762 }.createDelegate(this);
33763 timer = setInterval(f, 200);
33767 if(this.fireEvent("beforeload", this) === false){
33770 this.loading = true;
33771 this.ui.beforeLoad(this);
33772 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33774 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33778 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33782 * Returns true if this node is currently loading
33783 * @return {Boolean}
33785 isLoading : function(){
33786 return this.loading;
33789 loadComplete : function(deep, anim, callback){
33790 this.loading = false;
33791 this.loaded = true;
33792 this.ui.afterLoad(this);
33793 this.fireEvent("load", this);
33794 this.expand(deep, anim, callback);
33798 * Returns true if this node has been loaded
33799 * @return {Boolean}
33801 isLoaded : function(){
33802 return this.loaded;
33805 hasChildNodes : function(){
33806 if(!this.isLeaf() && !this.loaded){
33809 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33814 * Trigger a reload for this node
33815 * @param {Function} callback
33817 reload : function(callback){
33818 this.collapse(false, false);
33819 while(this.firstChild){
33820 this.removeChild(this.firstChild);
33822 this.childrenRendered = false;
33823 this.loaded = false;
33824 if(this.isHiddenRoot()){
33825 this.expanded = false;
33827 this.expand(false, false, callback);
33831 * Ext JS Library 1.1.1
33832 * Copyright(c) 2006-2007, Ext JS, LLC.
33834 * Originally Released Under LGPL - original licence link has changed is not relivant.
33837 * <script type="text/javascript">
33841 * @class Roo.tree.TreeNodeUI
33843 * @param {Object} node The node to render
33844 * The TreeNode UI implementation is separate from the
33845 * tree implementation. Unless you are customizing the tree UI,
33846 * you should never have to use this directly.
33848 Roo.tree.TreeNodeUI = function(node){
33850 this.rendered = false;
33851 this.animating = false;
33852 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33855 Roo.tree.TreeNodeUI.prototype = {
33856 removeChild : function(node){
33858 this.ctNode.removeChild(node.ui.getEl());
33862 beforeLoad : function(){
33863 this.addClass("x-tree-node-loading");
33866 afterLoad : function(){
33867 this.removeClass("x-tree-node-loading");
33870 onTextChange : function(node, text, oldText){
33872 this.textNode.innerHTML = text;
33876 onDisableChange : function(node, state){
33877 this.disabled = state;
33879 this.addClass("x-tree-node-disabled");
33881 this.removeClass("x-tree-node-disabled");
33885 onSelectedChange : function(state){
33888 this.addClass("x-tree-selected");
33891 this.removeClass("x-tree-selected");
33895 onMove : function(tree, node, oldParent, newParent, index, refNode){
33896 this.childIndent = null;
33898 var targetNode = newParent.ui.getContainer();
33899 if(!targetNode){//target not rendered
33900 this.holder = document.createElement("div");
33901 this.holder.appendChild(this.wrap);
33904 var insertBefore = refNode ? refNode.ui.getEl() : null;
33906 targetNode.insertBefore(this.wrap, insertBefore);
33908 targetNode.appendChild(this.wrap);
33910 this.node.renderIndent(true);
33914 addClass : function(cls){
33916 Roo.fly(this.elNode).addClass(cls);
33920 removeClass : function(cls){
33922 Roo.fly(this.elNode).removeClass(cls);
33926 remove : function(){
33928 this.holder = document.createElement("div");
33929 this.holder.appendChild(this.wrap);
33933 fireEvent : function(){
33934 return this.node.fireEvent.apply(this.node, arguments);
33937 initEvents : function(){
33938 this.node.on("move", this.onMove, this);
33939 var E = Roo.EventManager;
33940 var a = this.anchor;
33942 var el = Roo.fly(a, '_treeui');
33944 if(Roo.isOpera){ // opera render bug ignores the CSS
33945 el.setStyle("text-decoration", "none");
33948 el.on("click", this.onClick, this);
33949 el.on("dblclick", this.onDblClick, this);
33952 Roo.EventManager.on(this.checkbox,
33953 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33956 el.on("contextmenu", this.onContextMenu, this);
33958 var icon = Roo.fly(this.iconNode);
33959 icon.on("click", this.onClick, this);
33960 icon.on("dblclick", this.onDblClick, this);
33961 icon.on("contextmenu", this.onContextMenu, this);
33962 E.on(this.ecNode, "click", this.ecClick, this, true);
33964 if(this.node.disabled){
33965 this.addClass("x-tree-node-disabled");
33967 if(this.node.hidden){
33968 this.addClass("x-tree-node-disabled");
33970 var ot = this.node.getOwnerTree();
33971 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33972 if(dd && (!this.node.isRoot || ot.rootVisible)){
33973 Roo.dd.Registry.register(this.elNode, {
33975 handles: this.getDDHandles(),
33981 getDDHandles : function(){
33982 return [this.iconNode, this.textNode];
33987 this.wrap.style.display = "none";
33993 this.wrap.style.display = "";
33997 onContextMenu : function(e){
33998 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33999 e.preventDefault();
34001 this.fireEvent("contextmenu", this.node, e);
34005 onClick : function(e){
34010 if(this.fireEvent("beforeclick", this.node, e) !== false){
34011 if(!this.disabled && this.node.attributes.href){
34012 this.fireEvent("click", this.node, e);
34015 e.preventDefault();
34020 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
34021 this.node.toggle();
34024 this.fireEvent("click", this.node, e);
34030 onDblClick : function(e){
34031 e.preventDefault();
34036 this.toggleCheck();
34038 if(!this.animating && this.node.hasChildNodes()){
34039 this.node.toggle();
34041 this.fireEvent("dblclick", this.node, e);
34044 onCheckChange : function(){
34045 var checked = this.checkbox.checked;
34046 this.node.attributes.checked = checked;
34047 this.fireEvent('checkchange', this.node, checked);
34050 ecClick : function(e){
34051 if(!this.animating && this.node.hasChildNodes()){
34052 this.node.toggle();
34056 startDrop : function(){
34057 this.dropping = true;
34060 // delayed drop so the click event doesn't get fired on a drop
34061 endDrop : function(){
34062 setTimeout(function(){
34063 this.dropping = false;
34064 }.createDelegate(this), 50);
34067 expand : function(){
34068 this.updateExpandIcon();
34069 this.ctNode.style.display = "";
34072 focus : function(){
34073 if(!this.node.preventHScroll){
34074 try{this.anchor.focus();
34076 }else if(!Roo.isIE){
34078 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
34079 var l = noscroll.scrollLeft;
34080 this.anchor.focus();
34081 noscroll.scrollLeft = l;
34086 toggleCheck : function(value){
34087 var cb = this.checkbox;
34089 cb.checked = (value === undefined ? !cb.checked : value);
34095 this.anchor.blur();
34099 animExpand : function(callback){
34100 var ct = Roo.get(this.ctNode);
34102 if(!this.node.hasChildNodes()){
34103 this.updateExpandIcon();
34104 this.ctNode.style.display = "";
34105 Roo.callback(callback);
34108 this.animating = true;
34109 this.updateExpandIcon();
34112 callback : function(){
34113 this.animating = false;
34114 Roo.callback(callback);
34117 duration: this.node.ownerTree.duration || .25
34121 highlight : function(){
34122 var tree = this.node.getOwnerTree();
34123 Roo.fly(this.wrap).highlight(
34124 tree.hlColor || "C3DAF9",
34125 {endColor: tree.hlBaseColor}
34129 collapse : function(){
34130 this.updateExpandIcon();
34131 this.ctNode.style.display = "none";
34134 animCollapse : function(callback){
34135 var ct = Roo.get(this.ctNode);
34136 ct.enableDisplayMode('block');
34139 this.animating = true;
34140 this.updateExpandIcon();
34143 callback : function(){
34144 this.animating = false;
34145 Roo.callback(callback);
34148 duration: this.node.ownerTree.duration || .25
34152 getContainer : function(){
34153 return this.ctNode;
34156 getEl : function(){
34160 appendDDGhost : function(ghostNode){
34161 ghostNode.appendChild(this.elNode.cloneNode(true));
34164 getDDRepairXY : function(){
34165 return Roo.lib.Dom.getXY(this.iconNode);
34168 onRender : function(){
34172 render : function(bulkRender){
34173 var n = this.node, a = n.attributes;
34174 var targetNode = n.parentNode ?
34175 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
34177 if(!this.rendered){
34178 this.rendered = true;
34180 this.renderElements(n, a, targetNode, bulkRender);
34183 if(this.textNode.setAttributeNS){
34184 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
34186 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
34189 this.textNode.setAttribute("ext:qtip", a.qtip);
34191 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
34194 }else if(a.qtipCfg){
34195 a.qtipCfg.target = Roo.id(this.textNode);
34196 Roo.QuickTips.register(a.qtipCfg);
34199 if(!this.node.expanded){
34200 this.updateExpandIcon();
34203 if(bulkRender === true) {
34204 targetNode.appendChild(this.wrap);
34209 renderElements : function(n, a, targetNode, bulkRender)
34211 // add some indent caching, this helps performance when rendering a large tree
34212 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34213 var t = n.getOwnerTree();
34214 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
34215 if (typeof(n.attributes.html) != 'undefined') {
34216 txt = n.attributes.html;
34218 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
34219 var cb = typeof a.checked == 'boolean';
34220 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34221 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
34222 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
34223 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
34224 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
34225 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
34226 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
34227 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
34228 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
34229 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34232 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34233 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34234 n.nextSibling.ui.getEl(), buf.join(""));
34236 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34239 this.elNode = this.wrap.childNodes[0];
34240 this.ctNode = this.wrap.childNodes[1];
34241 var cs = this.elNode.childNodes;
34242 this.indentNode = cs[0];
34243 this.ecNode = cs[1];
34244 this.iconNode = cs[2];
34247 this.checkbox = cs[3];
34250 this.anchor = cs[index];
34251 this.textNode = cs[index].firstChild;
34254 getAnchor : function(){
34255 return this.anchor;
34258 getTextEl : function(){
34259 return this.textNode;
34262 getIconEl : function(){
34263 return this.iconNode;
34266 isChecked : function(){
34267 return this.checkbox ? this.checkbox.checked : false;
34270 updateExpandIcon : function(){
34272 var n = this.node, c1, c2;
34273 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34274 var hasChild = n.hasChildNodes();
34278 c1 = "x-tree-node-collapsed";
34279 c2 = "x-tree-node-expanded";
34282 c1 = "x-tree-node-expanded";
34283 c2 = "x-tree-node-collapsed";
34286 this.removeClass("x-tree-node-leaf");
34287 this.wasLeaf = false;
34289 if(this.c1 != c1 || this.c2 != c2){
34290 Roo.fly(this.elNode).replaceClass(c1, c2);
34291 this.c1 = c1; this.c2 = c2;
34294 // this changes non-leafs into leafs if they have no children.
34295 // it's not very rational behaviour..
34297 if(!this.wasLeaf && this.node.leaf){
34298 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34301 this.wasLeaf = true;
34304 var ecc = "x-tree-ec-icon "+cls;
34305 if(this.ecc != ecc){
34306 this.ecNode.className = ecc;
34312 getChildIndent : function(){
34313 if(!this.childIndent){
34317 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34319 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34321 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34326 this.childIndent = buf.join("");
34328 return this.childIndent;
34331 renderIndent : function(){
34334 var p = this.node.parentNode;
34336 indent = p.ui.getChildIndent();
34338 if(this.indentMarkup != indent){ // don't rerender if not required
34339 this.indentNode.innerHTML = indent;
34340 this.indentMarkup = indent;
34342 this.updateExpandIcon();
34347 Roo.tree.RootTreeNodeUI = function(){
34348 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34350 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34351 render : function(){
34352 if(!this.rendered){
34353 var targetNode = this.node.ownerTree.innerCt.dom;
34354 this.node.expanded = true;
34355 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34356 this.wrap = this.ctNode = targetNode.firstChild;
34359 collapse : function(){
34361 expand : function(){
34365 * Ext JS Library 1.1.1
34366 * Copyright(c) 2006-2007, Ext JS, LLC.
34368 * Originally Released Under LGPL - original licence link has changed is not relivant.
34371 * <script type="text/javascript">
34374 * @class Roo.tree.TreeLoader
34375 * @extends Roo.util.Observable
34376 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34377 * nodes from a specified URL. The response must be a javascript Array definition
34378 * who's elements are node definition objects. eg:
34383 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34384 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34391 * The old style respose with just an array is still supported, but not recommended.
34394 * A server request is sent, and child nodes are loaded only when a node is expanded.
34395 * The loading node's id is passed to the server under the parameter name "node" to
34396 * enable the server to produce the correct child nodes.
34398 * To pass extra parameters, an event handler may be attached to the "beforeload"
34399 * event, and the parameters specified in the TreeLoader's baseParams property:
34401 myTreeLoader.on("beforeload", function(treeLoader, node) {
34402 this.baseParams.category = node.attributes.category;
34405 * This would pass an HTTP parameter called "category" to the server containing
34406 * the value of the Node's "category" attribute.
34408 * Creates a new Treeloader.
34409 * @param {Object} config A config object containing config properties.
34411 Roo.tree.TreeLoader = function(config){
34412 this.baseParams = {};
34413 this.requestMethod = "POST";
34414 Roo.apply(this, config);
34419 * @event beforeload
34420 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34421 * @param {Object} This TreeLoader object.
34422 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34423 * @param {Object} callback The callback function specified in the {@link #load} call.
34428 * Fires when the node has been successfuly loaded.
34429 * @param {Object} This TreeLoader object.
34430 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34431 * @param {Object} response The response object containing the data from the server.
34435 * @event loadexception
34436 * Fires if the network request failed.
34437 * @param {Object} This TreeLoader object.
34438 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34439 * @param {Object} response The response object containing the data from the server.
34441 loadexception : true,
34444 * Fires before a node is created, enabling you to return custom Node types
34445 * @param {Object} This TreeLoader object.
34446 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34451 Roo.tree.TreeLoader.superclass.constructor.call(this);
34454 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34456 * @cfg {String} dataUrl The URL from which to request a Json string which
34457 * specifies an array of node definition object representing the child nodes
34461 * @cfg {String} requestMethod either GET or POST
34462 * defaults to POST (due to BC)
34466 * @cfg {Object} baseParams (optional) An object containing properties which
34467 * specify HTTP parameters to be passed to each request for child nodes.
34470 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34471 * created by this loader. If the attributes sent by the server have an attribute in this object,
34472 * they take priority.
34475 * @cfg {Object} uiProviders (optional) An object containing properties which
34477 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34478 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34479 * <i>uiProvider</i> attribute of a returned child node is a string rather
34480 * than a reference to a TreeNodeUI implementation, this that string value
34481 * is used as a property name in the uiProviders object. You can define the provider named
34482 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34487 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34488 * child nodes before loading.
34490 clearOnLoad : true,
34493 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34494 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34495 * Grid query { data : [ .....] }
34500 * @cfg {String} queryParam (optional)
34501 * Name of the query as it will be passed on the querystring (defaults to 'node')
34502 * eg. the request will be ?node=[id]
34509 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34510 * This is called automatically when a node is expanded, but may be used to reload
34511 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34512 * @param {Roo.tree.TreeNode} node
34513 * @param {Function} callback
34515 load : function(node, callback){
34516 if(this.clearOnLoad){
34517 while(node.firstChild){
34518 node.removeChild(node.firstChild);
34521 if(node.attributes.children){ // preloaded json children
34522 var cs = node.attributes.children;
34523 for(var i = 0, len = cs.length; i < len; i++){
34524 node.appendChild(this.createNode(cs[i]));
34526 if(typeof callback == "function"){
34529 }else if(this.dataUrl){
34530 this.requestData(node, callback);
34534 getParams: function(node){
34535 var buf = [], bp = this.baseParams;
34536 for(var key in bp){
34537 if(typeof bp[key] != "function"){
34538 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34541 var n = this.queryParam === false ? 'node' : this.queryParam;
34542 buf.push(n + "=", encodeURIComponent(node.id));
34543 return buf.join("");
34546 requestData : function(node, callback){
34547 if(this.fireEvent("beforeload", this, node, callback) !== false){
34548 this.transId = Roo.Ajax.request({
34549 method:this.requestMethod,
34550 url: this.dataUrl||this.url,
34551 success: this.handleResponse,
34552 failure: this.handleFailure,
34554 argument: {callback: callback, node: node},
34555 params: this.getParams(node)
34558 // if the load is cancelled, make sure we notify
34559 // the node that we are done
34560 if(typeof callback == "function"){
34566 isLoading : function(){
34567 return this.transId ? true : false;
34570 abort : function(){
34571 if(this.isLoading()){
34572 Roo.Ajax.abort(this.transId);
34577 createNode : function(attr)
34579 // apply baseAttrs, nice idea Corey!
34580 if(this.baseAttrs){
34581 Roo.applyIf(attr, this.baseAttrs);
34583 if(this.applyLoader !== false){
34584 attr.loader = this;
34586 // uiProvider = depreciated..
34588 if(typeof(attr.uiProvider) == 'string'){
34589 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34590 /** eval:var:attr */ eval(attr.uiProvider);
34592 if(typeof(this.uiProviders['default']) != 'undefined') {
34593 attr.uiProvider = this.uiProviders['default'];
34596 this.fireEvent('create', this, attr);
34598 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34600 new Roo.tree.TreeNode(attr) :
34601 new Roo.tree.AsyncTreeNode(attr));
34604 processResponse : function(response, node, callback)
34606 var json = response.responseText;
34609 var o = Roo.decode(json);
34611 if (this.root === false && typeof(o.success) != undefined) {
34612 this.root = 'data'; // the default behaviour for list like data..
34615 if (this.root !== false && !o.success) {
34616 // it's a failure condition.
34617 var a = response.argument;
34618 this.fireEvent("loadexception", this, a.node, response);
34619 Roo.log("Load failed - should have a handler really");
34625 if (this.root !== false) {
34629 for(var i = 0, len = o.length; i < len; i++){
34630 var n = this.createNode(o[i]);
34632 node.appendChild(n);
34635 if(typeof callback == "function"){
34636 callback(this, node);
34639 this.handleFailure(response);
34643 handleResponse : function(response){
34644 this.transId = false;
34645 var a = response.argument;
34646 this.processResponse(response, a.node, a.callback);
34647 this.fireEvent("load", this, a.node, response);
34650 handleFailure : function(response)
34652 // should handle failure better..
34653 this.transId = false;
34654 var a = response.argument;
34655 this.fireEvent("loadexception", this, a.node, response);
34656 if(typeof a.callback == "function"){
34657 a.callback(this, a.node);
34662 * Ext JS Library 1.1.1
34663 * Copyright(c) 2006-2007, Ext JS, LLC.
34665 * Originally Released Under LGPL - original licence link has changed is not relivant.
34668 * <script type="text/javascript">
34672 * @class Roo.tree.TreeFilter
34673 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34674 * @param {TreePanel} tree
34675 * @param {Object} config (optional)
34677 Roo.tree.TreeFilter = function(tree, config){
34679 this.filtered = {};
34680 Roo.apply(this, config);
34683 Roo.tree.TreeFilter.prototype = {
34690 * Filter the data by a specific attribute.
34691 * @param {String/RegExp} value Either string that the attribute value
34692 * should start with or a RegExp to test against the attribute
34693 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34694 * @param {TreeNode} startNode (optional) The node to start the filter at.
34696 filter : function(value, attr, startNode){
34697 attr = attr || "text";
34699 if(typeof value == "string"){
34700 var vlen = value.length;
34701 // auto clear empty filter
34702 if(vlen == 0 && this.clearBlank){
34706 value = value.toLowerCase();
34708 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34710 }else if(value.exec){ // regex?
34712 return value.test(n.attributes[attr]);
34715 throw 'Illegal filter type, must be string or regex';
34717 this.filterBy(f, null, startNode);
34721 * Filter by a function. The passed function will be called with each
34722 * node in the tree (or from the startNode). If the function returns true, the node is kept
34723 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34724 * @param {Function} fn The filter function
34725 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34727 filterBy : function(fn, scope, startNode){
34728 startNode = startNode || this.tree.root;
34729 if(this.autoClear){
34732 var af = this.filtered, rv = this.reverse;
34733 var f = function(n){
34734 if(n == startNode){
34740 var m = fn.call(scope || n, n);
34748 startNode.cascade(f);
34751 if(typeof id != "function"){
34753 if(n && n.parentNode){
34754 n.parentNode.removeChild(n);
34762 * Clears the current filter. Note: with the "remove" option
34763 * set a filter cannot be cleared.
34765 clear : function(){
34767 var af = this.filtered;
34769 if(typeof id != "function"){
34776 this.filtered = {};
34781 * Ext JS Library 1.1.1
34782 * Copyright(c) 2006-2007, Ext JS, LLC.
34784 * Originally Released Under LGPL - original licence link has changed is not relivant.
34787 * <script type="text/javascript">
34792 * @class Roo.tree.TreeSorter
34793 * Provides sorting of nodes in a TreePanel
34795 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34796 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34797 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34798 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34799 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34800 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34802 * @param {TreePanel} tree
34803 * @param {Object} config
34805 Roo.tree.TreeSorter = function(tree, config){
34806 Roo.apply(this, config);
34807 tree.on("beforechildrenrendered", this.doSort, this);
34808 tree.on("append", this.updateSort, this);
34809 tree.on("insert", this.updateSort, this);
34811 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34812 var p = this.property || "text";
34813 var sortType = this.sortType;
34814 var fs = this.folderSort;
34815 var cs = this.caseSensitive === true;
34816 var leafAttr = this.leafAttr || 'leaf';
34818 this.sortFn = function(n1, n2){
34820 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34823 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34827 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34828 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34830 return dsc ? +1 : -1;
34832 return dsc ? -1 : +1;
34839 Roo.tree.TreeSorter.prototype = {
34840 doSort : function(node){
34841 node.sort(this.sortFn);
34844 compareNodes : function(n1, n2){
34845 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34848 updateSort : function(tree, node){
34849 if(node.childrenRendered){
34850 this.doSort.defer(1, this, [node]);
34855 * Ext JS Library 1.1.1
34856 * Copyright(c) 2006-2007, Ext JS, LLC.
34858 * Originally Released Under LGPL - original licence link has changed is not relivant.
34861 * <script type="text/javascript">
34864 if(Roo.dd.DropZone){
34866 Roo.tree.TreeDropZone = function(tree, config){
34867 this.allowParentInsert = false;
34868 this.allowContainerDrop = false;
34869 this.appendOnly = false;
34870 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34872 this.lastInsertClass = "x-tree-no-status";
34873 this.dragOverData = {};
34876 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34877 ddGroup : "TreeDD",
34880 expandDelay : 1000,
34882 expandNode : function(node){
34883 if(node.hasChildNodes() && !node.isExpanded()){
34884 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34888 queueExpand : function(node){
34889 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34892 cancelExpand : function(){
34893 if(this.expandProcId){
34894 clearTimeout(this.expandProcId);
34895 this.expandProcId = false;
34899 isValidDropPoint : function(n, pt, dd, e, data){
34900 if(!n || !data){ return false; }
34901 var targetNode = n.node;
34902 var dropNode = data.node;
34903 // default drop rules
34904 if(!(targetNode && targetNode.isTarget && pt)){
34907 if(pt == "append" && targetNode.allowChildren === false){
34910 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34913 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34916 // reuse the object
34917 var overEvent = this.dragOverData;
34918 overEvent.tree = this.tree;
34919 overEvent.target = targetNode;
34920 overEvent.data = data;
34921 overEvent.point = pt;
34922 overEvent.source = dd;
34923 overEvent.rawEvent = e;
34924 overEvent.dropNode = dropNode;
34925 overEvent.cancel = false;
34926 var result = this.tree.fireEvent("nodedragover", overEvent);
34927 return overEvent.cancel === false && result !== false;
34930 getDropPoint : function(e, n, dd)
34934 return tn.allowChildren !== false ? "append" : false; // always append for root
34936 var dragEl = n.ddel;
34937 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34938 var y = Roo.lib.Event.getPageY(e);
34939 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34941 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34942 var noAppend = tn.allowChildren === false;
34943 if(this.appendOnly || tn.parentNode.allowChildren === false){
34944 return noAppend ? false : "append";
34946 var noBelow = false;
34947 if(!this.allowParentInsert){
34948 noBelow = tn.hasChildNodes() && tn.isExpanded();
34950 var q = (b - t) / (noAppend ? 2 : 3);
34951 if(y >= t && y < (t + q)){
34953 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34960 onNodeEnter : function(n, dd, e, data)
34962 this.cancelExpand();
34965 onNodeOver : function(n, dd, e, data)
34968 var pt = this.getDropPoint(e, n, dd);
34971 // auto node expand check
34972 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34973 this.queueExpand(node);
34974 }else if(pt != "append"){
34975 this.cancelExpand();
34978 // set the insert point style on the target node
34979 var returnCls = this.dropNotAllowed;
34980 if(this.isValidDropPoint(n, pt, dd, e, data)){
34985 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34986 cls = "x-tree-drag-insert-above";
34987 }else if(pt == "below"){
34988 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34989 cls = "x-tree-drag-insert-below";
34991 returnCls = "x-tree-drop-ok-append";
34992 cls = "x-tree-drag-append";
34994 if(this.lastInsertClass != cls){
34995 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34996 this.lastInsertClass = cls;
35003 onNodeOut : function(n, dd, e, data){
35005 this.cancelExpand();
35006 this.removeDropIndicators(n);
35009 onNodeDrop : function(n, dd, e, data){
35010 var point = this.getDropPoint(e, n, dd);
35011 var targetNode = n.node;
35012 targetNode.ui.startDrop();
35013 if(!this.isValidDropPoint(n, point, dd, e, data)){
35014 targetNode.ui.endDrop();
35017 // first try to find the drop node
35018 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
35021 target: targetNode,
35026 dropNode: dropNode,
35029 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
35030 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
35031 targetNode.ui.endDrop();
35034 // allow target changing
35035 targetNode = dropEvent.target;
35036 if(point == "append" && !targetNode.isExpanded()){
35037 targetNode.expand(false, null, function(){
35038 this.completeDrop(dropEvent);
35039 }.createDelegate(this));
35041 this.completeDrop(dropEvent);
35046 completeDrop : function(de){
35047 var ns = de.dropNode, p = de.point, t = de.target;
35048 if(!(ns instanceof Array)){
35052 for(var i = 0, len = ns.length; i < len; i++){
35055 t.parentNode.insertBefore(n, t);
35056 }else if(p == "below"){
35057 t.parentNode.insertBefore(n, t.nextSibling);
35063 if(this.tree.hlDrop){
35067 this.tree.fireEvent("nodedrop", de);
35070 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
35071 if(this.tree.hlDrop){
35072 dropNode.ui.focus();
35073 dropNode.ui.highlight();
35075 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
35078 getTree : function(){
35082 removeDropIndicators : function(n){
35085 Roo.fly(el).removeClass([
35086 "x-tree-drag-insert-above",
35087 "x-tree-drag-insert-below",
35088 "x-tree-drag-append"]);
35089 this.lastInsertClass = "_noclass";
35093 beforeDragDrop : function(target, e, id){
35094 this.cancelExpand();
35098 afterRepair : function(data){
35099 if(data && Roo.enableFx){
35100 data.node.ui.highlight();
35110 * Ext JS Library 1.1.1
35111 * Copyright(c) 2006-2007, Ext JS, LLC.
35113 * Originally Released Under LGPL - original licence link has changed is not relivant.
35116 * <script type="text/javascript">
35120 if(Roo.dd.DragZone){
35121 Roo.tree.TreeDragZone = function(tree, config){
35122 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
35126 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
35127 ddGroup : "TreeDD",
35129 onBeforeDrag : function(data, e){
35131 return n && n.draggable && !n.disabled;
35135 onInitDrag : function(e){
35136 var data = this.dragData;
35137 this.tree.getSelectionModel().select(data.node);
35138 this.proxy.update("");
35139 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
35140 this.tree.fireEvent("startdrag", this.tree, data.node, e);
35143 getRepairXY : function(e, data){
35144 return data.node.ui.getDDRepairXY();
35147 onEndDrag : function(data, e){
35148 this.tree.fireEvent("enddrag", this.tree, data.node, e);
35153 onValidDrop : function(dd, e, id){
35154 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
35158 beforeInvalidDrop : function(e, id){
35159 // this scrolls the original position back into view
35160 var sm = this.tree.getSelectionModel();
35161 sm.clearSelections();
35162 sm.select(this.dragData.node);
35167 * Ext JS Library 1.1.1
35168 * Copyright(c) 2006-2007, Ext JS, LLC.
35170 * Originally Released Under LGPL - original licence link has changed is not relivant.
35173 * <script type="text/javascript">
35176 * @class Roo.tree.TreeEditor
35177 * @extends Roo.Editor
35178 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
35179 * as the editor field.
35181 * @param {Object} config (used to be the tree panel.)
35182 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
35184 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
35185 * @cfg {Roo.form.TextField|Object} field The field configuration
35189 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
35192 if (oldconfig) { // old style..
35193 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
35196 tree = config.tree;
35197 config.field = config.field || {};
35198 config.field.xtype = 'TextField';
35199 field = Roo.factory(config.field, Roo.form);
35201 config = config || {};
35206 * @event beforenodeedit
35207 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
35208 * false from the handler of this event.
35209 * @param {Editor} this
35210 * @param {Roo.tree.Node} node
35212 "beforenodeedit" : true
35216 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
35220 tree.on('beforeclick', this.beforeNodeClick, this);
35221 tree.getTreeEl().on('mousedown', this.hide, this);
35222 this.on('complete', this.updateNode, this);
35223 this.on('beforestartedit', this.fitToTree, this);
35224 this.on('startedit', this.bindScroll, this, {delay:10});
35225 this.on('specialkey', this.onSpecialKey, this);
35228 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
35230 * @cfg {String} alignment
35231 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35237 * @cfg {Boolean} hideEl
35238 * True to hide the bound element while the editor is displayed (defaults to false)
35242 * @cfg {String} cls
35243 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35245 cls: "x-small-editor x-tree-editor",
35247 * @cfg {Boolean} shim
35248 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35254 * @cfg {Number} maxWidth
35255 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35256 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35257 * scroll and client offsets into account prior to each edit.
35264 fitToTree : function(ed, el){
35265 var td = this.tree.getTreeEl().dom, nd = el.dom;
35266 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35267 td.scrollLeft = nd.offsetLeft;
35271 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35272 this.setSize(w, '');
35274 return this.fireEvent('beforenodeedit', this, this.editNode);
35279 triggerEdit : function(node){
35280 this.completeEdit();
35281 this.editNode = node;
35282 this.startEdit(node.ui.textNode, node.text);
35286 bindScroll : function(){
35287 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35291 beforeNodeClick : function(node, e){
35292 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35293 this.lastClick = new Date();
35294 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35296 this.triggerEdit(node);
35303 updateNode : function(ed, value){
35304 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35305 this.editNode.setText(value);
35309 onHide : function(){
35310 Roo.tree.TreeEditor.superclass.onHide.call(this);
35312 this.editNode.ui.focus();
35317 onSpecialKey : function(field, e){
35318 var k = e.getKey();
35322 }else if(k == e.ENTER && !e.hasModifier()){
35324 this.completeEdit();
35327 });//<Script type="text/javascript">
35330 * Ext JS Library 1.1.1
35331 * Copyright(c) 2006-2007, Ext JS, LLC.
35333 * Originally Released Under LGPL - original licence link has changed is not relivant.
35336 * <script type="text/javascript">
35340 * Not documented??? - probably should be...
35343 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35344 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35346 renderElements : function(n, a, targetNode, bulkRender){
35347 //consel.log("renderElements?");
35348 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35350 var t = n.getOwnerTree();
35351 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35353 var cols = t.columns;
35354 var bw = t.borderWidth;
35356 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35357 var cb = typeof a.checked == "boolean";
35358 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35359 var colcls = 'x-t-' + tid + '-c0';
35361 '<li class="x-tree-node">',
35364 '<div class="x-tree-node-el ', a.cls,'">',
35366 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35369 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35370 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35371 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35372 (a.icon ? ' x-tree-node-inline-icon' : ''),
35373 (a.iconCls ? ' '+a.iconCls : ''),
35374 '" unselectable="on" />',
35375 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35376 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35378 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35379 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35380 '<span unselectable="on" qtip="' + tx + '">',
35384 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35385 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35387 for(var i = 1, len = cols.length; i < len; i++){
35389 colcls = 'x-t-' + tid + '-c' +i;
35390 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35391 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35392 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35398 '<div class="x-clear"></div></div>',
35399 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35402 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35403 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35404 n.nextSibling.ui.getEl(), buf.join(""));
35406 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35408 var el = this.wrap.firstChild;
35410 this.elNode = el.firstChild;
35411 this.ranchor = el.childNodes[1];
35412 this.ctNode = this.wrap.childNodes[1];
35413 var cs = el.firstChild.childNodes;
35414 this.indentNode = cs[0];
35415 this.ecNode = cs[1];
35416 this.iconNode = cs[2];
35419 this.checkbox = cs[3];
35422 this.anchor = cs[index];
35424 this.textNode = cs[index].firstChild;
35426 //el.on("click", this.onClick, this);
35427 //el.on("dblclick", this.onDblClick, this);
35430 // console.log(this);
35432 initEvents : function(){
35433 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35436 var a = this.ranchor;
35438 var el = Roo.get(a);
35440 if(Roo.isOpera){ // opera render bug ignores the CSS
35441 el.setStyle("text-decoration", "none");
35444 el.on("click", this.onClick, this);
35445 el.on("dblclick", this.onDblClick, this);
35446 el.on("contextmenu", this.onContextMenu, this);
35450 /*onSelectedChange : function(state){
35453 this.addClass("x-tree-selected");
35456 this.removeClass("x-tree-selected");
35459 addClass : function(cls){
35461 Roo.fly(this.elRow).addClass(cls);
35467 removeClass : function(cls){
35469 Roo.fly(this.elRow).removeClass(cls);
35475 });//<Script type="text/javascript">
35479 * Ext JS Library 1.1.1
35480 * Copyright(c) 2006-2007, Ext JS, LLC.
35482 * Originally Released Under LGPL - original licence link has changed is not relivant.
35485 * <script type="text/javascript">
35490 * @class Roo.tree.ColumnTree
35491 * @extends Roo.data.TreePanel
35492 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35493 * @cfg {int} borderWidth compined right/left border allowance
35495 * @param {String/HTMLElement/Element} el The container element
35496 * @param {Object} config
35498 Roo.tree.ColumnTree = function(el, config)
35500 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35504 * Fire this event on a container when it resizes
35505 * @param {int} w Width
35506 * @param {int} h Height
35510 this.on('resize', this.onResize, this);
35513 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35517 borderWidth: Roo.isBorderBox ? 0 : 2,
35520 render : function(){
35521 // add the header.....
35523 Roo.tree.ColumnTree.superclass.render.apply(this);
35525 this.el.addClass('x-column-tree');
35527 this.headers = this.el.createChild(
35528 {cls:'x-tree-headers'},this.innerCt.dom);
35530 var cols = this.columns, c;
35531 var totalWidth = 0;
35533 var len = cols.length;
35534 for(var i = 0; i < len; i++){
35536 totalWidth += c.width;
35537 this.headEls.push(this.headers.createChild({
35538 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35540 cls:'x-tree-hd-text',
35543 style:'width:'+(c.width-this.borderWidth)+'px;'
35546 this.headers.createChild({cls:'x-clear'});
35547 // prevent floats from wrapping when clipped
35548 this.headers.setWidth(totalWidth);
35549 //this.innerCt.setWidth(totalWidth);
35550 this.innerCt.setStyle({ overflow: 'auto' });
35551 this.onResize(this.width, this.height);
35555 onResize : function(w,h)
35560 this.innerCt.setWidth(this.width);
35561 this.innerCt.setHeight(this.height-20);
35564 var cols = this.columns, c;
35565 var totalWidth = 0;
35567 var len = cols.length;
35568 for(var i = 0; i < len; i++){
35570 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35571 // it's the expander..
35572 expEl = this.headEls[i];
35575 totalWidth += c.width;
35579 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35581 this.headers.setWidth(w-20);
35590 * Ext JS Library 1.1.1
35591 * Copyright(c) 2006-2007, Ext JS, LLC.
35593 * Originally Released Under LGPL - original licence link has changed is not relivant.
35596 * <script type="text/javascript">
35600 * @class Roo.menu.Menu
35601 * @extends Roo.util.Observable
35602 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35603 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35605 * Creates a new Menu
35606 * @param {Object} config Configuration options
35608 Roo.menu.Menu = function(config){
35609 Roo.apply(this, config);
35610 this.id = this.id || Roo.id();
35613 * @event beforeshow
35614 * Fires before this menu is displayed
35615 * @param {Roo.menu.Menu} this
35619 * @event beforehide
35620 * Fires before this menu is hidden
35621 * @param {Roo.menu.Menu} this
35626 * Fires after this menu is displayed
35627 * @param {Roo.menu.Menu} this
35632 * Fires after this menu is hidden
35633 * @param {Roo.menu.Menu} this
35638 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35639 * @param {Roo.menu.Menu} this
35640 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35641 * @param {Roo.EventObject} e
35646 * Fires when the mouse is hovering over this menu
35647 * @param {Roo.menu.Menu} this
35648 * @param {Roo.EventObject} e
35649 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35654 * Fires when the mouse exits this menu
35655 * @param {Roo.menu.Menu} this
35656 * @param {Roo.EventObject} e
35657 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35662 * Fires when a menu item contained in this menu is clicked
35663 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35664 * @param {Roo.EventObject} e
35668 if (this.registerMenu) {
35669 Roo.menu.MenuMgr.register(this);
35672 var mis = this.items;
35673 this.items = new Roo.util.MixedCollection();
35675 this.add.apply(this, mis);
35679 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35681 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35685 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35686 * for bottom-right shadow (defaults to "sides")
35690 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35691 * this menu (defaults to "tl-tr?")
35693 subMenuAlign : "tl-tr?",
35695 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35696 * relative to its element of origin (defaults to "tl-bl?")
35698 defaultAlign : "tl-bl?",
35700 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35702 allowOtherMenus : false,
35704 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35706 registerMenu : true,
35711 render : function(){
35715 var el = this.el = new Roo.Layer({
35717 shadow:this.shadow,
35719 parentEl: this.parentEl || document.body,
35723 this.keyNav = new Roo.menu.MenuNav(this);
35726 el.addClass("x-menu-plain");
35729 el.addClass(this.cls);
35731 // generic focus element
35732 this.focusEl = el.createChild({
35733 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35735 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35736 //disabling touch- as it's causing issues ..
35737 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35738 ul.on('click' , this.onClick, this);
35741 ul.on("mouseover", this.onMouseOver, this);
35742 ul.on("mouseout", this.onMouseOut, this);
35743 this.items.each(function(item){
35748 var li = document.createElement("li");
35749 li.className = "x-menu-list-item";
35750 ul.dom.appendChild(li);
35751 item.render(li, this);
35758 autoWidth : function(){
35759 var el = this.el, ul = this.ul;
35763 var w = this.width;
35766 }else if(Roo.isIE){
35767 el.setWidth(this.minWidth);
35768 var t = el.dom.offsetWidth; // force recalc
35769 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35774 delayAutoWidth : function(){
35777 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35779 this.awTask.delay(20);
35784 findTargetItem : function(e){
35785 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35786 if(t && t.menuItemId){
35787 return this.items.get(t.menuItemId);
35792 onClick : function(e){
35793 Roo.log("menu.onClick");
35794 var t = this.findTargetItem(e);
35799 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35800 if(t == this.activeItem && t.shouldDeactivate(e)){
35801 this.activeItem.deactivate();
35802 delete this.activeItem;
35806 this.setActiveItem(t, true);
35814 this.fireEvent("click", this, t, e);
35818 setActiveItem : function(item, autoExpand){
35819 if(item != this.activeItem){
35820 if(this.activeItem){
35821 this.activeItem.deactivate();
35823 this.activeItem = item;
35824 item.activate(autoExpand);
35825 }else if(autoExpand){
35831 tryActivate : function(start, step){
35832 var items = this.items;
35833 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35834 var item = items.get(i);
35835 if(!item.disabled && item.canActivate){
35836 this.setActiveItem(item, false);
35844 onMouseOver : function(e){
35846 if(t = this.findTargetItem(e)){
35847 if(t.canActivate && !t.disabled){
35848 this.setActiveItem(t, true);
35851 this.fireEvent("mouseover", this, e, t);
35855 onMouseOut : function(e){
35857 if(t = this.findTargetItem(e)){
35858 if(t == this.activeItem && t.shouldDeactivate(e)){
35859 this.activeItem.deactivate();
35860 delete this.activeItem;
35863 this.fireEvent("mouseout", this, e, t);
35867 * Read-only. Returns true if the menu is currently displayed, else false.
35870 isVisible : function(){
35871 return this.el && !this.hidden;
35875 * Displays this menu relative to another element
35876 * @param {String/HTMLElement/Roo.Element} element The element to align to
35877 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35878 * the element (defaults to this.defaultAlign)
35879 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35881 show : function(el, pos, parentMenu){
35882 this.parentMenu = parentMenu;
35886 this.fireEvent("beforeshow", this);
35887 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35891 * Displays this menu at a specific xy position
35892 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35893 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35895 showAt : function(xy, parentMenu, /* private: */_e){
35896 this.parentMenu = parentMenu;
35901 this.fireEvent("beforeshow", this);
35902 xy = this.el.adjustForConstraints(xy);
35906 this.hidden = false;
35908 this.fireEvent("show", this);
35911 focus : function(){
35913 this.doFocus.defer(50, this);
35917 doFocus : function(){
35919 this.focusEl.focus();
35924 * Hides this menu and optionally all parent menus
35925 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35927 hide : function(deep){
35928 if(this.el && this.isVisible()){
35929 this.fireEvent("beforehide", this);
35930 if(this.activeItem){
35931 this.activeItem.deactivate();
35932 this.activeItem = null;
35935 this.hidden = true;
35936 this.fireEvent("hide", this);
35938 if(deep === true && this.parentMenu){
35939 this.parentMenu.hide(true);
35944 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35945 * Any of the following are valid:
35947 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35948 * <li>An HTMLElement object which will be converted to a menu item</li>
35949 * <li>A menu item config object that will be created as a new menu item</li>
35950 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35951 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35956 var menu = new Roo.menu.Menu();
35958 // Create a menu item to add by reference
35959 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35961 // Add a bunch of items at once using different methods.
35962 // Only the last item added will be returned.
35963 var item = menu.add(
35964 menuItem, // add existing item by ref
35965 'Dynamic Item', // new TextItem
35966 '-', // new separator
35967 { text: 'Config Item' } // new item by config
35970 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35971 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35974 var a = arguments, l = a.length, item;
35975 for(var i = 0; i < l; i++){
35977 if ((typeof(el) == "object") && el.xtype && el.xns) {
35978 el = Roo.factory(el, Roo.menu);
35981 if(el.render){ // some kind of Item
35982 item = this.addItem(el);
35983 }else if(typeof el == "string"){ // string
35984 if(el == "separator" || el == "-"){
35985 item = this.addSeparator();
35987 item = this.addText(el);
35989 }else if(el.tagName || el.el){ // element
35990 item = this.addElement(el);
35991 }else if(typeof el == "object"){ // must be menu item config?
35992 item = this.addMenuItem(el);
35999 * Returns this menu's underlying {@link Roo.Element} object
36000 * @return {Roo.Element} The element
36002 getEl : function(){
36010 * Adds a separator bar to the menu
36011 * @return {Roo.menu.Item} The menu item that was added
36013 addSeparator : function(){
36014 return this.addItem(new Roo.menu.Separator());
36018 * Adds an {@link Roo.Element} object to the menu
36019 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
36020 * @return {Roo.menu.Item} The menu item that was added
36022 addElement : function(el){
36023 return this.addItem(new Roo.menu.BaseItem(el));
36027 * Adds an existing object based on {@link Roo.menu.Item} to the menu
36028 * @param {Roo.menu.Item} item The menu item to add
36029 * @return {Roo.menu.Item} The menu item that was added
36031 addItem : function(item){
36032 this.items.add(item);
36034 var li = document.createElement("li");
36035 li.className = "x-menu-list-item";
36036 this.ul.dom.appendChild(li);
36037 item.render(li, this);
36038 this.delayAutoWidth();
36044 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
36045 * @param {Object} config A MenuItem config object
36046 * @return {Roo.menu.Item} The menu item that was added
36048 addMenuItem : function(config){
36049 if(!(config instanceof Roo.menu.Item)){
36050 if(typeof config.checked == "boolean"){ // must be check menu item config?
36051 config = new Roo.menu.CheckItem(config);
36053 config = new Roo.menu.Item(config);
36056 return this.addItem(config);
36060 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
36061 * @param {String} text The text to display in the menu item
36062 * @return {Roo.menu.Item} The menu item that was added
36064 addText : function(text){
36065 return this.addItem(new Roo.menu.TextItem({ text : text }));
36069 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
36070 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
36071 * @param {Roo.menu.Item} item The menu item to add
36072 * @return {Roo.menu.Item} The menu item that was added
36074 insert : function(index, item){
36075 this.items.insert(index, item);
36077 var li = document.createElement("li");
36078 li.className = "x-menu-list-item";
36079 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
36080 item.render(li, this);
36081 this.delayAutoWidth();
36087 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
36088 * @param {Roo.menu.Item} item The menu item to remove
36090 remove : function(item){
36091 this.items.removeKey(item.id);
36096 * Removes and destroys all items in the menu
36098 removeAll : function(){
36100 while(f = this.items.first()){
36106 // MenuNav is a private utility class used internally by the Menu
36107 Roo.menu.MenuNav = function(menu){
36108 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
36109 this.scope = this.menu = menu;
36112 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
36113 doRelay : function(e, h){
36114 var k = e.getKey();
36115 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
36116 this.menu.tryActivate(0, 1);
36119 return h.call(this.scope || this, e, this.menu);
36122 up : function(e, m){
36123 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
36124 m.tryActivate(m.items.length-1, -1);
36128 down : function(e, m){
36129 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
36130 m.tryActivate(0, 1);
36134 right : function(e, m){
36136 m.activeItem.expandMenu(true);
36140 left : function(e, m){
36142 if(m.parentMenu && m.parentMenu.activeItem){
36143 m.parentMenu.activeItem.activate();
36147 enter : function(e, m){
36149 e.stopPropagation();
36150 m.activeItem.onClick(e);
36151 m.fireEvent("click", this, m.activeItem);
36157 * Ext JS Library 1.1.1
36158 * Copyright(c) 2006-2007, Ext JS, LLC.
36160 * Originally Released Under LGPL - original licence link has changed is not relivant.
36163 * <script type="text/javascript">
36167 * @class Roo.menu.MenuMgr
36168 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
36171 Roo.menu.MenuMgr = function(){
36172 var menus, active, groups = {}, attached = false, lastShow = new Date();
36174 // private - called when first menu is created
36177 active = new Roo.util.MixedCollection();
36178 Roo.get(document).addKeyListener(27, function(){
36179 if(active.length > 0){
36186 function hideAll(){
36187 if(active && active.length > 0){
36188 var c = active.clone();
36189 c.each(function(m){
36196 function onHide(m){
36198 if(active.length < 1){
36199 Roo.get(document).un("mousedown", onMouseDown);
36205 function onShow(m){
36206 var last = active.last();
36207 lastShow = new Date();
36210 Roo.get(document).on("mousedown", onMouseDown);
36214 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
36215 m.parentMenu.activeChild = m;
36216 }else if(last && last.isVisible()){
36217 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
36222 function onBeforeHide(m){
36224 m.activeChild.hide();
36226 if(m.autoHideTimer){
36227 clearTimeout(m.autoHideTimer);
36228 delete m.autoHideTimer;
36233 function onBeforeShow(m){
36234 var pm = m.parentMenu;
36235 if(!pm && !m.allowOtherMenus){
36237 }else if(pm && pm.activeChild && active != m){
36238 pm.activeChild.hide();
36243 function onMouseDown(e){
36244 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36250 function onBeforeCheck(mi, state){
36252 var g = groups[mi.group];
36253 for(var i = 0, l = g.length; i < l; i++){
36255 g[i].setChecked(false);
36264 * Hides all menus that are currently visible
36266 hideAll : function(){
36271 register : function(menu){
36275 menus[menu.id] = menu;
36276 menu.on("beforehide", onBeforeHide);
36277 menu.on("hide", onHide);
36278 menu.on("beforeshow", onBeforeShow);
36279 menu.on("show", onShow);
36280 var g = menu.group;
36281 if(g && menu.events["checkchange"]){
36285 groups[g].push(menu);
36286 menu.on("checkchange", onCheck);
36291 * Returns a {@link Roo.menu.Menu} object
36292 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36293 * be used to generate and return a new Menu instance.
36295 get : function(menu){
36296 if(typeof menu == "string"){ // menu id
36297 return menus[menu];
36298 }else if(menu.events){ // menu instance
36300 }else if(typeof menu.length == 'number'){ // array of menu items?
36301 return new Roo.menu.Menu({items:menu});
36302 }else{ // otherwise, must be a config
36303 return new Roo.menu.Menu(menu);
36308 unregister : function(menu){
36309 delete menus[menu.id];
36310 menu.un("beforehide", onBeforeHide);
36311 menu.un("hide", onHide);
36312 menu.un("beforeshow", onBeforeShow);
36313 menu.un("show", onShow);
36314 var g = menu.group;
36315 if(g && menu.events["checkchange"]){
36316 groups[g].remove(menu);
36317 menu.un("checkchange", onCheck);
36322 registerCheckable : function(menuItem){
36323 var g = menuItem.group;
36328 groups[g].push(menuItem);
36329 menuItem.on("beforecheckchange", onBeforeCheck);
36334 unregisterCheckable : function(menuItem){
36335 var g = menuItem.group;
36337 groups[g].remove(menuItem);
36338 menuItem.un("beforecheckchange", onBeforeCheck);
36344 * Ext JS Library 1.1.1
36345 * Copyright(c) 2006-2007, Ext JS, LLC.
36347 * Originally Released Under LGPL - original licence link has changed is not relivant.
36350 * <script type="text/javascript">
36355 * @class Roo.menu.BaseItem
36356 * @extends Roo.Component
36357 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36358 * management and base configuration options shared by all menu components.
36360 * Creates a new BaseItem
36361 * @param {Object} config Configuration options
36363 Roo.menu.BaseItem = function(config){
36364 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36369 * Fires when this item is clicked
36370 * @param {Roo.menu.BaseItem} this
36371 * @param {Roo.EventObject} e
36376 * Fires when this item is activated
36377 * @param {Roo.menu.BaseItem} this
36381 * @event deactivate
36382 * Fires when this item is deactivated
36383 * @param {Roo.menu.BaseItem} this
36389 this.on("click", this.handler, this.scope, true);
36393 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36395 * @cfg {Function} handler
36396 * A function that will handle the click event of this menu item (defaults to undefined)
36399 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36401 canActivate : false,
36404 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36409 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36411 activeClass : "x-menu-item-active",
36413 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36415 hideOnClick : true,
36417 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36422 ctype: "Roo.menu.BaseItem",
36425 actionMode : "container",
36428 render : function(container, parentMenu){
36429 this.parentMenu = parentMenu;
36430 Roo.menu.BaseItem.superclass.render.call(this, container);
36431 this.container.menuItemId = this.id;
36435 onRender : function(container, position){
36436 this.el = Roo.get(this.el);
36437 container.dom.appendChild(this.el.dom);
36441 onClick : function(e){
36442 if(!this.disabled && this.fireEvent("click", this, e) !== false
36443 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36444 this.handleClick(e);
36451 activate : function(){
36455 var li = this.container;
36456 li.addClass(this.activeClass);
36457 this.region = li.getRegion().adjust(2, 2, -2, -2);
36458 this.fireEvent("activate", this);
36463 deactivate : function(){
36464 this.container.removeClass(this.activeClass);
36465 this.fireEvent("deactivate", this);
36469 shouldDeactivate : function(e){
36470 return !this.region || !this.region.contains(e.getPoint());
36474 handleClick : function(e){
36475 if(this.hideOnClick){
36476 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36481 expandMenu : function(autoActivate){
36486 hideMenu : function(){
36491 * Ext JS Library 1.1.1
36492 * Copyright(c) 2006-2007, Ext JS, LLC.
36494 * Originally Released Under LGPL - original licence link has changed is not relivant.
36497 * <script type="text/javascript">
36501 * @class Roo.menu.Adapter
36502 * @extends Roo.menu.BaseItem
36503 * 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.
36504 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36506 * Creates a new Adapter
36507 * @param {Object} config Configuration options
36509 Roo.menu.Adapter = function(component, config){
36510 Roo.menu.Adapter.superclass.constructor.call(this, config);
36511 this.component = component;
36513 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36515 canActivate : true,
36518 onRender : function(container, position){
36519 this.component.render(container);
36520 this.el = this.component.getEl();
36524 activate : function(){
36528 this.component.focus();
36529 this.fireEvent("activate", this);
36534 deactivate : function(){
36535 this.fireEvent("deactivate", this);
36539 disable : function(){
36540 this.component.disable();
36541 Roo.menu.Adapter.superclass.disable.call(this);
36545 enable : function(){
36546 this.component.enable();
36547 Roo.menu.Adapter.superclass.enable.call(this);
36551 * Ext JS Library 1.1.1
36552 * Copyright(c) 2006-2007, Ext JS, LLC.
36554 * Originally Released Under LGPL - original licence link has changed is not relivant.
36557 * <script type="text/javascript">
36561 * @class Roo.menu.TextItem
36562 * @extends Roo.menu.BaseItem
36563 * Adds a static text string to a menu, usually used as either a heading or group separator.
36564 * Note: old style constructor with text is still supported.
36567 * Creates a new TextItem
36568 * @param {Object} cfg Configuration
36570 Roo.menu.TextItem = function(cfg){
36571 if (typeof(cfg) == 'string') {
36574 Roo.apply(this,cfg);
36577 Roo.menu.TextItem.superclass.constructor.call(this);
36580 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36582 * @cfg {Boolean} text Text to show on item.
36587 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36589 hideOnClick : false,
36591 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36593 itemCls : "x-menu-text",
36596 onRender : function(){
36597 var s = document.createElement("span");
36598 s.className = this.itemCls;
36599 s.innerHTML = this.text;
36601 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36605 * Ext JS Library 1.1.1
36606 * Copyright(c) 2006-2007, Ext JS, LLC.
36608 * Originally Released Under LGPL - original licence link has changed is not relivant.
36611 * <script type="text/javascript">
36615 * @class Roo.menu.Separator
36616 * @extends Roo.menu.BaseItem
36617 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36618 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36620 * @param {Object} config Configuration options
36622 Roo.menu.Separator = function(config){
36623 Roo.menu.Separator.superclass.constructor.call(this, config);
36626 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36628 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36630 itemCls : "x-menu-sep",
36632 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36634 hideOnClick : false,
36637 onRender : function(li){
36638 var s = document.createElement("span");
36639 s.className = this.itemCls;
36640 s.innerHTML = " ";
36642 li.addClass("x-menu-sep-li");
36643 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36647 * Ext JS Library 1.1.1
36648 * Copyright(c) 2006-2007, Ext JS, LLC.
36650 * Originally Released Under LGPL - original licence link has changed is not relivant.
36653 * <script type="text/javascript">
36656 * @class Roo.menu.Item
36657 * @extends Roo.menu.BaseItem
36658 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36659 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36660 * activation and click handling.
36662 * Creates a new Item
36663 * @param {Object} config Configuration options
36665 Roo.menu.Item = function(config){
36666 Roo.menu.Item.superclass.constructor.call(this, config);
36668 this.menu = Roo.menu.MenuMgr.get(this.menu);
36671 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36674 * @cfg {String} text
36675 * The text to show on the menu item.
36679 * @cfg {String} HTML to render in menu
36680 * The text to show on the menu item (HTML version).
36684 * @cfg {String} icon
36685 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36689 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36691 itemCls : "x-menu-item",
36693 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36695 canActivate : true,
36697 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36700 // doc'd in BaseItem
36704 ctype: "Roo.menu.Item",
36707 onRender : function(container, position){
36708 var el = document.createElement("a");
36709 el.hideFocus = true;
36710 el.unselectable = "on";
36711 el.href = this.href || "#";
36712 if(this.hrefTarget){
36713 el.target = this.hrefTarget;
36715 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36717 var html = this.html.length ? this.html : String.format('{0}',this.text);
36719 el.innerHTML = String.format(
36720 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36721 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36723 Roo.menu.Item.superclass.onRender.call(this, container, position);
36727 * Sets the text to display in this menu item
36728 * @param {String} text The text to display
36729 * @param {Boolean} isHTML true to indicate text is pure html.
36731 setText : function(text, isHTML){
36739 var html = this.html.length ? this.html : String.format('{0}',this.text);
36741 this.el.update(String.format(
36742 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36743 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36744 this.parentMenu.autoWidth();
36749 handleClick : function(e){
36750 if(!this.href){ // if no link defined, stop the event automatically
36753 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36757 activate : function(autoExpand){
36758 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36768 shouldDeactivate : function(e){
36769 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36770 if(this.menu && this.menu.isVisible()){
36771 return !this.menu.getEl().getRegion().contains(e.getPoint());
36779 deactivate : function(){
36780 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36785 expandMenu : function(autoActivate){
36786 if(!this.disabled && this.menu){
36787 clearTimeout(this.hideTimer);
36788 delete this.hideTimer;
36789 if(!this.menu.isVisible() && !this.showTimer){
36790 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36791 }else if (this.menu.isVisible() && autoActivate){
36792 this.menu.tryActivate(0, 1);
36798 deferExpand : function(autoActivate){
36799 delete this.showTimer;
36800 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36802 this.menu.tryActivate(0, 1);
36807 hideMenu : function(){
36808 clearTimeout(this.showTimer);
36809 delete this.showTimer;
36810 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36811 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36816 deferHide : function(){
36817 delete this.hideTimer;
36822 * Ext JS Library 1.1.1
36823 * Copyright(c) 2006-2007, Ext JS, LLC.
36825 * Originally Released Under LGPL - original licence link has changed is not relivant.
36828 * <script type="text/javascript">
36832 * @class Roo.menu.CheckItem
36833 * @extends Roo.menu.Item
36834 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36836 * Creates a new CheckItem
36837 * @param {Object} config Configuration options
36839 Roo.menu.CheckItem = function(config){
36840 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36843 * @event beforecheckchange
36844 * Fires before the checked value is set, providing an opportunity to cancel if needed
36845 * @param {Roo.menu.CheckItem} this
36846 * @param {Boolean} checked The new checked value that will be set
36848 "beforecheckchange" : true,
36850 * @event checkchange
36851 * Fires after the checked value has been set
36852 * @param {Roo.menu.CheckItem} this
36853 * @param {Boolean} checked The checked value that was set
36855 "checkchange" : true
36857 if(this.checkHandler){
36858 this.on('checkchange', this.checkHandler, this.scope);
36861 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36863 * @cfg {String} group
36864 * All check items with the same group name will automatically be grouped into a single-select
36865 * radio button group (defaults to '')
36868 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36870 itemCls : "x-menu-item x-menu-check-item",
36872 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36874 groupClass : "x-menu-group-item",
36877 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36878 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36879 * initialized with checked = true will be rendered as checked.
36884 ctype: "Roo.menu.CheckItem",
36887 onRender : function(c){
36888 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36890 this.el.addClass(this.groupClass);
36892 Roo.menu.MenuMgr.registerCheckable(this);
36894 this.checked = false;
36895 this.setChecked(true, true);
36900 destroy : function(){
36902 Roo.menu.MenuMgr.unregisterCheckable(this);
36904 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36908 * Set the checked state of this item
36909 * @param {Boolean} checked The new checked value
36910 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36912 setChecked : function(state, suppressEvent){
36913 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36914 if(this.container){
36915 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36917 this.checked = state;
36918 if(suppressEvent !== true){
36919 this.fireEvent("checkchange", this, state);
36925 handleClick : function(e){
36926 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36927 this.setChecked(!this.checked);
36929 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36933 * Ext JS Library 1.1.1
36934 * Copyright(c) 2006-2007, Ext JS, LLC.
36936 * Originally Released Under LGPL - original licence link has changed is not relivant.
36939 * <script type="text/javascript">
36943 * @class Roo.menu.DateItem
36944 * @extends Roo.menu.Adapter
36945 * A menu item that wraps the {@link Roo.DatPicker} component.
36947 * Creates a new DateItem
36948 * @param {Object} config Configuration options
36950 Roo.menu.DateItem = function(config){
36951 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36952 /** The Roo.DatePicker object @type Roo.DatePicker */
36953 this.picker = this.component;
36954 this.addEvents({select: true});
36956 this.picker.on("render", function(picker){
36957 picker.getEl().swallowEvent("click");
36958 picker.container.addClass("x-menu-date-item");
36961 this.picker.on("select", this.onSelect, this);
36964 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36966 onSelect : function(picker, date){
36967 this.fireEvent("select", this, date, picker);
36968 Roo.menu.DateItem.superclass.handleClick.call(this);
36972 * Ext JS Library 1.1.1
36973 * Copyright(c) 2006-2007, Ext JS, LLC.
36975 * Originally Released Under LGPL - original licence link has changed is not relivant.
36978 * <script type="text/javascript">
36982 * @class Roo.menu.ColorItem
36983 * @extends Roo.menu.Adapter
36984 * A menu item that wraps the {@link Roo.ColorPalette} component.
36986 * Creates a new ColorItem
36987 * @param {Object} config Configuration options
36989 Roo.menu.ColorItem = function(config){
36990 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36991 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36992 this.palette = this.component;
36993 this.relayEvents(this.palette, ["select"]);
36994 if(this.selectHandler){
36995 this.on('select', this.selectHandler, this.scope);
36998 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
37000 * Ext JS Library 1.1.1
37001 * Copyright(c) 2006-2007, Ext JS, LLC.
37003 * Originally Released Under LGPL - original licence link has changed is not relivant.
37006 * <script type="text/javascript">
37011 * @class Roo.menu.DateMenu
37012 * @extends Roo.menu.Menu
37013 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
37015 * Creates a new DateMenu
37016 * @param {Object} config Configuration options
37018 Roo.menu.DateMenu = function(config){
37019 Roo.menu.DateMenu.superclass.constructor.call(this, config);
37021 var di = new Roo.menu.DateItem(config);
37024 * The {@link Roo.DatePicker} instance for this DateMenu
37027 this.picker = di.picker;
37030 * @param {DatePicker} picker
37031 * @param {Date} date
37033 this.relayEvents(di, ["select"]);
37034 this.on('beforeshow', function(){
37036 this.picker.hideMonthPicker(false);
37040 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
37044 * Ext JS Library 1.1.1
37045 * Copyright(c) 2006-2007, Ext JS, LLC.
37047 * Originally Released Under LGPL - original licence link has changed is not relivant.
37050 * <script type="text/javascript">
37055 * @class Roo.menu.ColorMenu
37056 * @extends Roo.menu.Menu
37057 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
37059 * Creates a new ColorMenu
37060 * @param {Object} config Configuration options
37062 Roo.menu.ColorMenu = function(config){
37063 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
37065 var ci = new Roo.menu.ColorItem(config);
37068 * The {@link Roo.ColorPalette} instance for this ColorMenu
37069 * @type ColorPalette
37071 this.palette = ci.palette;
37074 * @param {ColorPalette} palette
37075 * @param {String} color
37077 this.relayEvents(ci, ["select"]);
37079 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
37081 * Ext JS Library 1.1.1
37082 * Copyright(c) 2006-2007, Ext JS, LLC.
37084 * Originally Released Under LGPL - original licence link has changed is not relivant.
37087 * <script type="text/javascript">
37091 * @class Roo.form.Field
37092 * @extends Roo.BoxComponent
37093 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
37095 * Creates a new Field
37096 * @param {Object} config Configuration options
37098 Roo.form.Field = function(config){
37099 Roo.form.Field.superclass.constructor.call(this, config);
37102 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
37104 * @cfg {String} fieldLabel Label to use when rendering a form.
37107 * @cfg {String} qtip Mouse over tip
37111 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
37113 invalidClass : "x-form-invalid",
37115 * @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")
37117 invalidText : "The value in this field is invalid",
37119 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
37121 focusClass : "x-form-focus",
37123 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
37124 automatic validation (defaults to "keyup").
37126 validationEvent : "keyup",
37128 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
37130 validateOnBlur : true,
37132 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
37134 validationDelay : 250,
37136 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37137 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
37139 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
37141 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
37143 fieldClass : "x-form-field",
37145 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
37148 ----------- ----------------------------------------------------------------------
37149 qtip Display a quick tip when the user hovers over the field
37150 title Display a default browser title attribute popup
37151 under Add a block div beneath the field containing the error text
37152 side Add an error icon to the right of the field with a popup on hover
37153 [element id] Add the error text directly to the innerHTML of the specified element
37156 msgTarget : 'qtip',
37158 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
37163 * @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.
37168 * @cfg {Boolean} disabled True to disable the field (defaults to false).
37173 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
37175 inputType : undefined,
37178 * @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).
37180 tabIndex : undefined,
37183 isFormField : true,
37188 * @property {Roo.Element} fieldEl
37189 * Element Containing the rendered Field (with label etc.)
37192 * @cfg {Mixed} value A value to initialize this field with.
37197 * @cfg {String} name The field's HTML name attribute.
37200 * @cfg {String} cls A CSS class to apply to the field's underlying element.
37203 loadedValue : false,
37207 initComponent : function(){
37208 Roo.form.Field.superclass.initComponent.call(this);
37212 * Fires when this field receives input focus.
37213 * @param {Roo.form.Field} this
37218 * Fires when this field loses input focus.
37219 * @param {Roo.form.Field} this
37223 * @event specialkey
37224 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
37225 * {@link Roo.EventObject#getKey} to determine which key was pressed.
37226 * @param {Roo.form.Field} this
37227 * @param {Roo.EventObject} e The event object
37232 * Fires just before the field blurs if the field value has changed.
37233 * @param {Roo.form.Field} this
37234 * @param {Mixed} newValue The new value
37235 * @param {Mixed} oldValue The original value
37240 * Fires after the field has been marked as invalid.
37241 * @param {Roo.form.Field} this
37242 * @param {String} msg The validation message
37247 * Fires after the field has been validated with no errors.
37248 * @param {Roo.form.Field} this
37253 * Fires after the key up
37254 * @param {Roo.form.Field} this
37255 * @param {Roo.EventObject} e The event Object
37262 * Returns the name attribute of the field if available
37263 * @return {String} name The field name
37265 getName: function(){
37266 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37270 onRender : function(ct, position){
37271 Roo.form.Field.superclass.onRender.call(this, ct, position);
37273 var cfg = this.getAutoCreate();
37275 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37277 if (!cfg.name.length) {
37280 if(this.inputType){
37281 cfg.type = this.inputType;
37283 this.el = ct.createChild(cfg, position);
37285 var type = this.el.dom.type;
37287 if(type == 'password'){
37290 this.el.addClass('x-form-'+type);
37293 this.el.dom.readOnly = true;
37295 if(this.tabIndex !== undefined){
37296 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37299 this.el.addClass([this.fieldClass, this.cls]);
37304 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37305 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37306 * @return {Roo.form.Field} this
37308 applyTo : function(target){
37309 this.allowDomMove = false;
37310 this.el = Roo.get(target);
37311 this.render(this.el.dom.parentNode);
37316 initValue : function(){
37317 if(this.value !== undefined){
37318 this.setValue(this.value);
37319 }else if(this.el.dom.value.length > 0){
37320 this.setValue(this.el.dom.value);
37325 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37326 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
37328 isDirty : function() {
37329 if(this.disabled) {
37332 return String(this.getValue()) !== String(this.originalValue);
37336 * stores the current value in loadedValue
37338 resetHasChanged : function()
37340 this.loadedValue = String(this.getValue());
37343 * checks the current value against the 'loaded' value.
37344 * Note - will return false if 'resetHasChanged' has not been called first.
37346 hasChanged : function()
37348 if(this.disabled || this.readOnly) {
37351 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
37357 afterRender : function(){
37358 Roo.form.Field.superclass.afterRender.call(this);
37363 fireKey : function(e){
37364 //Roo.log('field ' + e.getKey());
37365 if(e.isNavKeyPress()){
37366 this.fireEvent("specialkey", this, e);
37371 * Resets the current field value to the originally loaded value and clears any validation messages
37373 reset : function(){
37374 this.setValue(this.resetValue);
37375 this.clearInvalid();
37379 initEvents : function(){
37380 // safari killled keypress - so keydown is now used..
37381 this.el.on("keydown" , this.fireKey, this);
37382 this.el.on("focus", this.onFocus, this);
37383 this.el.on("blur", this.onBlur, this);
37384 this.el.relayEvent('keyup', this);
37386 // reference to original value for reset
37387 this.originalValue = this.getValue();
37388 this.resetValue = this.getValue();
37392 onFocus : function(){
37393 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37394 this.el.addClass(this.focusClass);
37396 if(!this.hasFocus){
37397 this.hasFocus = true;
37398 this.startValue = this.getValue();
37399 this.fireEvent("focus", this);
37403 beforeBlur : Roo.emptyFn,
37406 onBlur : function(){
37408 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37409 this.el.removeClass(this.focusClass);
37411 this.hasFocus = false;
37412 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37415 var v = this.getValue();
37416 if(String(v) !== String(this.startValue)){
37417 this.fireEvent('change', this, v, this.startValue);
37419 this.fireEvent("blur", this);
37423 * Returns whether or not the field value is currently valid
37424 * @param {Boolean} preventMark True to disable marking the field invalid
37425 * @return {Boolean} True if the value is valid, else false
37427 isValid : function(preventMark){
37431 var restore = this.preventMark;
37432 this.preventMark = preventMark === true;
37433 var v = this.validateValue(this.processValue(this.getRawValue()));
37434 this.preventMark = restore;
37439 * Validates the field value
37440 * @return {Boolean} True if the value is valid, else false
37442 validate : function(){
37443 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37444 this.clearInvalid();
37450 processValue : function(value){
37455 // Subclasses should provide the validation implementation by overriding this
37456 validateValue : function(value){
37461 * Mark this field as invalid
37462 * @param {String} msg The validation message
37464 markInvalid : function(msg){
37465 if(!this.rendered || this.preventMark){ // not rendered
37469 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37471 obj.el.addClass(this.invalidClass);
37472 msg = msg || this.invalidText;
37473 switch(this.msgTarget){
37475 obj.el.dom.qtip = msg;
37476 obj.el.dom.qclass = 'x-form-invalid-tip';
37477 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37478 Roo.QuickTips.enable();
37482 this.el.dom.title = msg;
37486 var elp = this.el.findParent('.x-form-element', 5, true);
37487 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37488 this.errorEl.setWidth(elp.getWidth(true)-20);
37490 this.errorEl.update(msg);
37491 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37494 if(!this.errorIcon){
37495 var elp = this.el.findParent('.x-form-element', 5, true);
37496 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37498 this.alignErrorIcon();
37499 this.errorIcon.dom.qtip = msg;
37500 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37501 this.errorIcon.show();
37502 this.on('resize', this.alignErrorIcon, this);
37505 var t = Roo.getDom(this.msgTarget);
37507 t.style.display = this.msgDisplay;
37510 this.fireEvent('invalid', this, msg);
37514 alignErrorIcon : function(){
37515 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37519 * Clear any invalid styles/messages for this field
37521 clearInvalid : function(){
37522 if(!this.rendered || this.preventMark){ // not rendered
37525 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37527 obj.el.removeClass(this.invalidClass);
37528 switch(this.msgTarget){
37530 obj.el.dom.qtip = '';
37533 this.el.dom.title = '';
37537 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37541 if(this.errorIcon){
37542 this.errorIcon.dom.qtip = '';
37543 this.errorIcon.hide();
37544 this.un('resize', this.alignErrorIcon, this);
37548 var t = Roo.getDom(this.msgTarget);
37550 t.style.display = 'none';
37553 this.fireEvent('valid', this);
37557 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37558 * @return {Mixed} value The field value
37560 getRawValue : function(){
37561 var v = this.el.getValue();
37567 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37568 * @return {Mixed} value The field value
37570 getValue : function(){
37571 var v = this.el.getValue();
37577 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37578 * @param {Mixed} value The value to set
37580 setRawValue : function(v){
37581 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37585 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37586 * @param {Mixed} value The value to set
37588 setValue : function(v){
37591 this.el.dom.value = (v === null || v === undefined ? '' : v);
37596 adjustSize : function(w, h){
37597 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37598 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37602 adjustWidth : function(tag, w){
37603 tag = tag.toLowerCase();
37604 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37605 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37606 if(tag == 'input'){
37609 if(tag == 'textarea'){
37612 }else if(Roo.isOpera){
37613 if(tag == 'input'){
37616 if(tag == 'textarea'){
37626 // anything other than normal should be considered experimental
37627 Roo.form.Field.msgFx = {
37629 show: function(msgEl, f){
37630 msgEl.setDisplayed('block');
37633 hide : function(msgEl, f){
37634 msgEl.setDisplayed(false).update('');
37639 show: function(msgEl, f){
37640 msgEl.slideIn('t', {stopFx:true});
37643 hide : function(msgEl, f){
37644 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37649 show: function(msgEl, f){
37650 msgEl.fixDisplay();
37651 msgEl.alignTo(f.el, 'tl-tr');
37652 msgEl.slideIn('l', {stopFx:true});
37655 hide : function(msgEl, f){
37656 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37661 * Ext JS Library 1.1.1
37662 * Copyright(c) 2006-2007, Ext JS, LLC.
37664 * Originally Released Under LGPL - original licence link has changed is not relivant.
37667 * <script type="text/javascript">
37672 * @class Roo.form.TextField
37673 * @extends Roo.form.Field
37674 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37675 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37677 * Creates a new TextField
37678 * @param {Object} config Configuration options
37680 Roo.form.TextField = function(config){
37681 Roo.form.TextField.superclass.constructor.call(this, config);
37685 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37686 * according to the default logic, but this event provides a hook for the developer to apply additional
37687 * logic at runtime to resize the field if needed.
37688 * @param {Roo.form.Field} this This text field
37689 * @param {Number} width The new field width
37695 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37697 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37701 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37705 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37709 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37713 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37717 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37719 disableKeyFilter : false,
37721 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37725 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37729 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37731 maxLength : Number.MAX_VALUE,
37733 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37735 minLengthText : "The minimum length for this field is {0}",
37737 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37739 maxLengthText : "The maximum length for this field is {0}",
37741 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37743 selectOnFocus : false,
37745 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37747 blankText : "This field is required",
37749 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37750 * If available, this function will be called only after the basic validators all return true, and will be passed the
37751 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37755 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37756 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37757 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37761 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37765 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37771 initEvents : function()
37773 if (this.emptyText) {
37774 this.el.attr('placeholder', this.emptyText);
37777 Roo.form.TextField.superclass.initEvents.call(this);
37778 if(this.validationEvent == 'keyup'){
37779 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37780 this.el.on('keyup', this.filterValidation, this);
37782 else if(this.validationEvent !== false){
37783 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37786 if(this.selectOnFocus){
37787 this.on("focus", this.preFocus, this);
37790 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37791 this.el.on("keypress", this.filterKeys, this);
37794 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37795 this.el.on("click", this.autoSize, this);
37797 if(this.el.is('input[type=password]') && Roo.isSafari){
37798 this.el.on('keydown', this.SafariOnKeyDown, this);
37802 processValue : function(value){
37803 if(this.stripCharsRe){
37804 var newValue = value.replace(this.stripCharsRe, '');
37805 if(newValue !== value){
37806 this.setRawValue(newValue);
37813 filterValidation : function(e){
37814 if(!e.isNavKeyPress()){
37815 this.validationTask.delay(this.validationDelay);
37820 onKeyUp : function(e){
37821 if(!e.isNavKeyPress()){
37827 * Resets the current field value to the originally-loaded value and clears any validation messages.
37830 reset : function(){
37831 Roo.form.TextField.superclass.reset.call(this);
37837 preFocus : function(){
37839 if(this.selectOnFocus){
37840 this.el.dom.select();
37846 filterKeys : function(e){
37847 var k = e.getKey();
37848 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37851 var c = e.getCharCode(), cc = String.fromCharCode(c);
37852 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37855 if(!this.maskRe.test(cc)){
37860 setValue : function(v){
37862 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37868 * Validates a value according to the field's validation rules and marks the field as invalid
37869 * if the validation fails
37870 * @param {Mixed} value The value to validate
37871 * @return {Boolean} True if the value is valid, else false
37873 validateValue : function(value){
37874 if(value.length < 1) { // if it's blank
37875 if(this.allowBlank){
37876 this.clearInvalid();
37879 this.markInvalid(this.blankText);
37883 if(value.length < this.minLength){
37884 this.markInvalid(String.format(this.minLengthText, this.minLength));
37887 if(value.length > this.maxLength){
37888 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37892 var vt = Roo.form.VTypes;
37893 if(!vt[this.vtype](value, this)){
37894 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37898 if(typeof this.validator == "function"){
37899 var msg = this.validator(value);
37901 this.markInvalid(msg);
37905 if(this.regex && !this.regex.test(value)){
37906 this.markInvalid(this.regexText);
37913 * Selects text in this field
37914 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37915 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37917 selectText : function(start, end){
37918 var v = this.getRawValue();
37920 start = start === undefined ? 0 : start;
37921 end = end === undefined ? v.length : end;
37922 var d = this.el.dom;
37923 if(d.setSelectionRange){
37924 d.setSelectionRange(start, end);
37925 }else if(d.createTextRange){
37926 var range = d.createTextRange();
37927 range.moveStart("character", start);
37928 range.moveEnd("character", v.length-end);
37935 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37936 * This only takes effect if grow = true, and fires the autosize event.
37938 autoSize : function(){
37939 if(!this.grow || !this.rendered){
37943 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37946 var v = el.dom.value;
37947 var d = document.createElement('div');
37948 d.appendChild(document.createTextNode(v));
37952 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37953 this.el.setWidth(w);
37954 this.fireEvent("autosize", this, w);
37958 SafariOnKeyDown : function(event)
37960 // this is a workaround for a password hang bug on chrome/ webkit.
37962 var isSelectAll = false;
37964 if(this.el.dom.selectionEnd > 0){
37965 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37967 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37968 event.preventDefault();
37973 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
37975 event.preventDefault();
37976 // this is very hacky as keydown always get's upper case.
37978 var cc = String.fromCharCode(event.getCharCode());
37981 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37989 * Ext JS Library 1.1.1
37990 * Copyright(c) 2006-2007, Ext JS, LLC.
37992 * Originally Released Under LGPL - original licence link has changed is not relivant.
37995 * <script type="text/javascript">
37999 * @class Roo.form.Hidden
38000 * @extends Roo.form.TextField
38001 * Simple Hidden element used on forms
38003 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
38006 * Creates a new Hidden form element.
38007 * @param {Object} config Configuration options
38012 // easy hidden field...
38013 Roo.form.Hidden = function(config){
38014 Roo.form.Hidden.superclass.constructor.call(this, config);
38017 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
38019 inputType: 'hidden',
38022 labelSeparator: '',
38024 itemCls : 'x-form-item-display-none'
38032 * Ext JS Library 1.1.1
38033 * Copyright(c) 2006-2007, Ext JS, LLC.
38035 * Originally Released Under LGPL - original licence link has changed is not relivant.
38038 * <script type="text/javascript">
38042 * @class Roo.form.TriggerField
38043 * @extends Roo.form.TextField
38044 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
38045 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
38046 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
38047 * for which you can provide a custom implementation. For example:
38049 var trigger = new Roo.form.TriggerField();
38050 trigger.onTriggerClick = myTriggerFn;
38051 trigger.applyTo('my-field');
38054 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
38055 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
38056 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
38057 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
38059 * Create a new TriggerField.
38060 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
38061 * to the base TextField)
38063 Roo.form.TriggerField = function(config){
38064 this.mimicing = false;
38065 Roo.form.TriggerField.superclass.constructor.call(this, config);
38068 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
38070 * @cfg {String} triggerClass A CSS class to apply to the trigger
38073 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38074 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
38076 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
38078 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
38082 /** @cfg {Boolean} grow @hide */
38083 /** @cfg {Number} growMin @hide */
38084 /** @cfg {Number} growMax @hide */
38090 autoSize: Roo.emptyFn,
38094 deferHeight : true,
38097 actionMode : 'wrap',
38099 onResize : function(w, h){
38100 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
38101 if(typeof w == 'number'){
38102 var x = w - this.trigger.getWidth();
38103 this.el.setWidth(this.adjustWidth('input', x));
38104 this.trigger.setStyle('left', x+'px');
38109 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38112 getResizeEl : function(){
38117 getPositionEl : function(){
38122 alignErrorIcon : function(){
38123 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
38127 onRender : function(ct, position){
38128 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
38129 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
38130 this.trigger = this.wrap.createChild(this.triggerConfig ||
38131 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
38132 if(this.hideTrigger){
38133 this.trigger.setDisplayed(false);
38135 this.initTrigger();
38137 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
38142 initTrigger : function(){
38143 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
38144 this.trigger.addClassOnOver('x-form-trigger-over');
38145 this.trigger.addClassOnClick('x-form-trigger-click');
38149 onDestroy : function(){
38151 this.trigger.removeAllListeners();
38152 this.trigger.remove();
38155 this.wrap.remove();
38157 Roo.form.TriggerField.superclass.onDestroy.call(this);
38161 onFocus : function(){
38162 Roo.form.TriggerField.superclass.onFocus.call(this);
38163 if(!this.mimicing){
38164 this.wrap.addClass('x-trigger-wrap-focus');
38165 this.mimicing = true;
38166 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
38167 if(this.monitorTab){
38168 this.el.on("keydown", this.checkTab, this);
38174 checkTab : function(e){
38175 if(e.getKey() == e.TAB){
38176 this.triggerBlur();
38181 onBlur : function(){
38186 mimicBlur : function(e, t){
38187 if(!this.wrap.contains(t) && this.validateBlur()){
38188 this.triggerBlur();
38193 triggerBlur : function(){
38194 this.mimicing = false;
38195 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
38196 if(this.monitorTab){
38197 this.el.un("keydown", this.checkTab, this);
38199 this.wrap.removeClass('x-trigger-wrap-focus');
38200 Roo.form.TriggerField.superclass.onBlur.call(this);
38204 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
38205 validateBlur : function(e, t){
38210 onDisable : function(){
38211 Roo.form.TriggerField.superclass.onDisable.call(this);
38213 this.wrap.addClass('x-item-disabled');
38218 onEnable : function(){
38219 Roo.form.TriggerField.superclass.onEnable.call(this);
38221 this.wrap.removeClass('x-item-disabled');
38226 onShow : function(){
38227 var ae = this.getActionEl();
38230 ae.dom.style.display = '';
38231 ae.dom.style.visibility = 'visible';
38237 onHide : function(){
38238 var ae = this.getActionEl();
38239 ae.dom.style.display = 'none';
38243 * The function that should handle the trigger's click event. This method does nothing by default until overridden
38244 * by an implementing function.
38246 * @param {EventObject} e
38248 onTriggerClick : Roo.emptyFn
38251 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
38252 // to be extended by an implementing class. For an example of implementing this class, see the custom
38253 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
38254 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
38255 initComponent : function(){
38256 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
38258 this.triggerConfig = {
38259 tag:'span', cls:'x-form-twin-triggers', cn:[
38260 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38261 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38265 getTrigger : function(index){
38266 return this.triggers[index];
38269 initTrigger : function(){
38270 var ts = this.trigger.select('.x-form-trigger', true);
38271 this.wrap.setStyle('overflow', 'hidden');
38272 var triggerField = this;
38273 ts.each(function(t, all, index){
38274 t.hide = function(){
38275 var w = triggerField.wrap.getWidth();
38276 this.dom.style.display = 'none';
38277 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38279 t.show = function(){
38280 var w = triggerField.wrap.getWidth();
38281 this.dom.style.display = '';
38282 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38284 var triggerIndex = 'Trigger'+(index+1);
38286 if(this['hide'+triggerIndex]){
38287 t.dom.style.display = 'none';
38289 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38290 t.addClassOnOver('x-form-trigger-over');
38291 t.addClassOnClick('x-form-trigger-click');
38293 this.triggers = ts.elements;
38296 onTrigger1Click : Roo.emptyFn,
38297 onTrigger2Click : Roo.emptyFn
38300 * Ext JS Library 1.1.1
38301 * Copyright(c) 2006-2007, Ext JS, LLC.
38303 * Originally Released Under LGPL - original licence link has changed is not relivant.
38306 * <script type="text/javascript">
38310 * @class Roo.form.TextArea
38311 * @extends Roo.form.TextField
38312 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38313 * support for auto-sizing.
38315 * Creates a new TextArea
38316 * @param {Object} config Configuration options
38318 Roo.form.TextArea = function(config){
38319 Roo.form.TextArea.superclass.constructor.call(this, config);
38320 // these are provided exchanges for backwards compat
38321 // minHeight/maxHeight were replaced by growMin/growMax to be
38322 // compatible with TextField growing config values
38323 if(this.minHeight !== undefined){
38324 this.growMin = this.minHeight;
38326 if(this.maxHeight !== undefined){
38327 this.growMax = this.maxHeight;
38331 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38333 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38337 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38341 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38342 * in the field (equivalent to setting overflow: hidden, defaults to false)
38344 preventScrollbars: false,
38346 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38347 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38351 onRender : function(ct, position){
38353 this.defaultAutoCreate = {
38355 style:"width:300px;height:60px;",
38356 autocomplete: "new-password"
38359 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38361 this.textSizeEl = Roo.DomHelper.append(document.body, {
38362 tag: "pre", cls: "x-form-grow-sizer"
38364 if(this.preventScrollbars){
38365 this.el.setStyle("overflow", "hidden");
38367 this.el.setHeight(this.growMin);
38371 onDestroy : function(){
38372 if(this.textSizeEl){
38373 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38375 Roo.form.TextArea.superclass.onDestroy.call(this);
38379 onKeyUp : function(e){
38380 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38386 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38387 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38389 autoSize : function(){
38390 if(!this.grow || !this.textSizeEl){
38394 var v = el.dom.value;
38395 var ts = this.textSizeEl;
38398 ts.appendChild(document.createTextNode(v));
38401 Roo.fly(ts).setWidth(this.el.getWidth());
38403 v = "  ";
38406 v = v.replace(/\n/g, '<p> </p>');
38408 v += " \n ";
38411 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38412 if(h != this.lastHeight){
38413 this.lastHeight = h;
38414 this.el.setHeight(h);
38415 this.fireEvent("autosize", this, h);
38420 * Ext JS Library 1.1.1
38421 * Copyright(c) 2006-2007, Ext JS, LLC.
38423 * Originally Released Under LGPL - original licence link has changed is not relivant.
38426 * <script type="text/javascript">
38431 * @class Roo.form.NumberField
38432 * @extends Roo.form.TextField
38433 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38435 * Creates a new NumberField
38436 * @param {Object} config Configuration options
38438 Roo.form.NumberField = function(config){
38439 Roo.form.NumberField.superclass.constructor.call(this, config);
38442 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38444 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38446 fieldClass: "x-form-field x-form-num-field",
38448 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38450 allowDecimals : true,
38452 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38454 decimalSeparator : ".",
38456 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38458 decimalPrecision : 2,
38460 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38462 allowNegative : true,
38464 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38466 minValue : Number.NEGATIVE_INFINITY,
38468 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38470 maxValue : Number.MAX_VALUE,
38472 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38474 minText : "The minimum value for this field is {0}",
38476 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38478 maxText : "The maximum value for this field is {0}",
38480 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38481 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38483 nanText : "{0} is not a valid number",
38486 initEvents : function(){
38487 Roo.form.NumberField.superclass.initEvents.call(this);
38488 var allowed = "0123456789";
38489 if(this.allowDecimals){
38490 allowed += this.decimalSeparator;
38492 if(this.allowNegative){
38495 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38496 var keyPress = function(e){
38497 var k = e.getKey();
38498 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38501 var c = e.getCharCode();
38502 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38506 this.el.on("keypress", keyPress, this);
38510 validateValue : function(value){
38511 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38514 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38517 var num = this.parseValue(value);
38519 this.markInvalid(String.format(this.nanText, value));
38522 if(num < this.minValue){
38523 this.markInvalid(String.format(this.minText, this.minValue));
38526 if(num > this.maxValue){
38527 this.markInvalid(String.format(this.maxText, this.maxValue));
38533 getValue : function(){
38534 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38538 parseValue : function(value){
38539 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38540 return isNaN(value) ? '' : value;
38544 fixPrecision : function(value){
38545 var nan = isNaN(value);
38546 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38547 return nan ? '' : value;
38549 return parseFloat(value).toFixed(this.decimalPrecision);
38552 setValue : function(v){
38553 v = this.fixPrecision(v);
38554 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38558 decimalPrecisionFcn : function(v){
38559 return Math.floor(v);
38562 beforeBlur : function(){
38563 var v = this.parseValue(this.getRawValue());
38570 * Ext JS Library 1.1.1
38571 * Copyright(c) 2006-2007, Ext JS, LLC.
38573 * Originally Released Under LGPL - original licence link has changed is not relivant.
38576 * <script type="text/javascript">
38580 * @class Roo.form.DateField
38581 * @extends Roo.form.TriggerField
38582 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38584 * Create a new DateField
38585 * @param {Object} config
38587 Roo.form.DateField = function(config){
38588 Roo.form.DateField.superclass.constructor.call(this, config);
38594 * Fires when a date is selected
38595 * @param {Roo.form.DateField} combo This combo box
38596 * @param {Date} date The date selected
38603 if(typeof this.minValue == "string") {
38604 this.minValue = this.parseDate(this.minValue);
38606 if(typeof this.maxValue == "string") {
38607 this.maxValue = this.parseDate(this.maxValue);
38609 this.ddMatch = null;
38610 if(this.disabledDates){
38611 var dd = this.disabledDates;
38613 for(var i = 0; i < dd.length; i++){
38615 if(i != dd.length-1) {
38619 this.ddMatch = new RegExp(re + ")");
38623 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38625 * @cfg {String} format
38626 * The default date format string which can be overriden for localization support. The format must be
38627 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38631 * @cfg {String} altFormats
38632 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38633 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38635 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38637 * @cfg {Array} disabledDays
38638 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38640 disabledDays : null,
38642 * @cfg {String} disabledDaysText
38643 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38645 disabledDaysText : "Disabled",
38647 * @cfg {Array} disabledDates
38648 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38649 * expression so they are very powerful. Some examples:
38651 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38652 * <li>["03/08", "09/16"] would disable those days for every year</li>
38653 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38654 * <li>["03/../2006"] would disable every day in March 2006</li>
38655 * <li>["^03"] would disable every day in every March</li>
38657 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38658 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38660 disabledDates : null,
38662 * @cfg {String} disabledDatesText
38663 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38665 disabledDatesText : "Disabled",
38667 * @cfg {Date/String} minValue
38668 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38669 * valid format (defaults to null).
38673 * @cfg {Date/String} maxValue
38674 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38675 * valid format (defaults to null).
38679 * @cfg {String} minText
38680 * The error text to display when the date in the cell is before minValue (defaults to
38681 * 'The date in this field must be after {minValue}').
38683 minText : "The date in this field must be equal to or after {0}",
38685 * @cfg {String} maxText
38686 * The error text to display when the date in the cell is after maxValue (defaults to
38687 * 'The date in this field must be before {maxValue}').
38689 maxText : "The date in this field must be equal to or before {0}",
38691 * @cfg {String} invalidText
38692 * The error text to display when the date in the field is invalid (defaults to
38693 * '{value} is not a valid date - it must be in the format {format}').
38695 invalidText : "{0} is not a valid date - it must be in the format {1}",
38697 * @cfg {String} triggerClass
38698 * An additional CSS class used to style the trigger button. The trigger will always get the
38699 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38700 * which displays a calendar icon).
38702 triggerClass : 'x-form-date-trigger',
38706 * @cfg {Boolean} useIso
38707 * if enabled, then the date field will use a hidden field to store the
38708 * real value as iso formated date. default (false)
38712 * @cfg {String/Object} autoCreate
38713 * A DomHelper element spec, or true for a default element spec (defaults to
38714 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38717 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38720 hiddenField: false,
38722 onRender : function(ct, position)
38724 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38726 //this.el.dom.removeAttribute('name');
38727 Roo.log("Changing name?");
38728 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38729 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38731 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38732 // prevent input submission
38733 this.hiddenName = this.name;
38740 validateValue : function(value)
38742 value = this.formatDate(value);
38743 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38744 Roo.log('super failed');
38747 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38750 var svalue = value;
38751 value = this.parseDate(value);
38753 Roo.log('parse date failed' + svalue);
38754 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38757 var time = value.getTime();
38758 if(this.minValue && time < this.minValue.getTime()){
38759 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38762 if(this.maxValue && time > this.maxValue.getTime()){
38763 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38766 if(this.disabledDays){
38767 var day = value.getDay();
38768 for(var i = 0; i < this.disabledDays.length; i++) {
38769 if(day === this.disabledDays[i]){
38770 this.markInvalid(this.disabledDaysText);
38775 var fvalue = this.formatDate(value);
38776 if(this.ddMatch && this.ddMatch.test(fvalue)){
38777 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38784 // Provides logic to override the default TriggerField.validateBlur which just returns true
38785 validateBlur : function(){
38786 return !this.menu || !this.menu.isVisible();
38789 getName: function()
38791 // returns hidden if it's set..
38792 if (!this.rendered) {return ''};
38793 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38798 * Returns the current date value of the date field.
38799 * @return {Date} The date value
38801 getValue : function(){
38803 return this.hiddenField ?
38804 this.hiddenField.value :
38805 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38809 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38810 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38811 * (the default format used is "m/d/y").
38814 //All of these calls set the same date value (May 4, 2006)
38816 //Pass a date object:
38817 var dt = new Date('5/4/06');
38818 dateField.setValue(dt);
38820 //Pass a date string (default format):
38821 dateField.setValue('5/4/06');
38823 //Pass a date string (custom format):
38824 dateField.format = 'Y-m-d';
38825 dateField.setValue('2006-5-4');
38827 * @param {String/Date} date The date or valid date string
38829 setValue : function(date){
38830 if (this.hiddenField) {
38831 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38833 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38834 // make sure the value field is always stored as a date..
38835 this.value = this.parseDate(date);
38841 parseDate : function(value){
38842 if(!value || value instanceof Date){
38845 var v = Date.parseDate(value, this.format);
38846 if (!v && this.useIso) {
38847 v = Date.parseDate(value, 'Y-m-d');
38849 if(!v && this.altFormats){
38850 if(!this.altFormatsArray){
38851 this.altFormatsArray = this.altFormats.split("|");
38853 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38854 v = Date.parseDate(value, this.altFormatsArray[i]);
38861 formatDate : function(date, fmt){
38862 return (!date || !(date instanceof Date)) ?
38863 date : date.dateFormat(fmt || this.format);
38868 select: function(m, d){
38871 this.fireEvent('select', this, d);
38873 show : function(){ // retain focus styling
38877 this.focus.defer(10, this);
38878 var ml = this.menuListeners;
38879 this.menu.un("select", ml.select, this);
38880 this.menu.un("show", ml.show, this);
38881 this.menu.un("hide", ml.hide, this);
38886 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38887 onTriggerClick : function(){
38891 if(this.menu == null){
38892 this.menu = new Roo.menu.DateMenu();
38894 Roo.apply(this.menu.picker, {
38895 showClear: this.allowBlank,
38896 minDate : this.minValue,
38897 maxDate : this.maxValue,
38898 disabledDatesRE : this.ddMatch,
38899 disabledDatesText : this.disabledDatesText,
38900 disabledDays : this.disabledDays,
38901 disabledDaysText : this.disabledDaysText,
38902 format : this.useIso ? 'Y-m-d' : this.format,
38903 minText : String.format(this.minText, this.formatDate(this.minValue)),
38904 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38906 this.menu.on(Roo.apply({}, this.menuListeners, {
38909 this.menu.picker.setValue(this.getValue() || new Date());
38910 this.menu.show(this.el, "tl-bl?");
38913 beforeBlur : function(){
38914 var v = this.parseDate(this.getRawValue());
38924 isDirty : function() {
38925 if(this.disabled) {
38929 if(typeof(this.startValue) === 'undefined'){
38933 return String(this.getValue()) !== String(this.startValue);
38938 * Ext JS Library 1.1.1
38939 * Copyright(c) 2006-2007, Ext JS, LLC.
38941 * Originally Released Under LGPL - original licence link has changed is not relivant.
38944 * <script type="text/javascript">
38948 * @class Roo.form.MonthField
38949 * @extends Roo.form.TriggerField
38950 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38952 * Create a new MonthField
38953 * @param {Object} config
38955 Roo.form.MonthField = function(config){
38957 Roo.form.MonthField.superclass.constructor.call(this, config);
38963 * Fires when a date is selected
38964 * @param {Roo.form.MonthFieeld} combo This combo box
38965 * @param {Date} date The date selected
38972 if(typeof this.minValue == "string") {
38973 this.minValue = this.parseDate(this.minValue);
38975 if(typeof this.maxValue == "string") {
38976 this.maxValue = this.parseDate(this.maxValue);
38978 this.ddMatch = null;
38979 if(this.disabledDates){
38980 var dd = this.disabledDates;
38982 for(var i = 0; i < dd.length; i++){
38984 if(i != dd.length-1) {
38988 this.ddMatch = new RegExp(re + ")");
38992 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38994 * @cfg {String} format
38995 * The default date format string which can be overriden for localization support. The format must be
38996 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
39000 * @cfg {String} altFormats
39001 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
39002 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
39004 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
39006 * @cfg {Array} disabledDays
39007 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
39009 disabledDays : [0,1,2,3,4,5,6],
39011 * @cfg {String} disabledDaysText
39012 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
39014 disabledDaysText : "Disabled",
39016 * @cfg {Array} disabledDates
39017 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
39018 * expression so they are very powerful. Some examples:
39020 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
39021 * <li>["03/08", "09/16"] would disable those days for every year</li>
39022 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
39023 * <li>["03/../2006"] would disable every day in March 2006</li>
39024 * <li>["^03"] would disable every day in every March</li>
39026 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
39027 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
39029 disabledDates : null,
39031 * @cfg {String} disabledDatesText
39032 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
39034 disabledDatesText : "Disabled",
39036 * @cfg {Date/String} minValue
39037 * The minimum allowed date. Can be either a Javascript date object or a string date in a
39038 * valid format (defaults to null).
39042 * @cfg {Date/String} maxValue
39043 * The maximum allowed date. Can be either a Javascript date object or a string date in a
39044 * valid format (defaults to null).
39048 * @cfg {String} minText
39049 * The error text to display when the date in the cell is before minValue (defaults to
39050 * 'The date in this field must be after {minValue}').
39052 minText : "The date in this field must be equal to or after {0}",
39054 * @cfg {String} maxTextf
39055 * The error text to display when the date in the cell is after maxValue (defaults to
39056 * 'The date in this field must be before {maxValue}').
39058 maxText : "The date in this field must be equal to or before {0}",
39060 * @cfg {String} invalidText
39061 * The error text to display when the date in the field is invalid (defaults to
39062 * '{value} is not a valid date - it must be in the format {format}').
39064 invalidText : "{0} is not a valid date - it must be in the format {1}",
39066 * @cfg {String} triggerClass
39067 * An additional CSS class used to style the trigger button. The trigger will always get the
39068 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
39069 * which displays a calendar icon).
39071 triggerClass : 'x-form-date-trigger',
39075 * @cfg {Boolean} useIso
39076 * if enabled, then the date field will use a hidden field to store the
39077 * real value as iso formated date. default (true)
39081 * @cfg {String/Object} autoCreate
39082 * A DomHelper element spec, or true for a default element spec (defaults to
39083 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
39086 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
39089 hiddenField: false,
39091 hideMonthPicker : false,
39093 onRender : function(ct, position)
39095 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
39097 this.el.dom.removeAttribute('name');
39098 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
39100 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
39101 // prevent input submission
39102 this.hiddenName = this.name;
39109 validateValue : function(value)
39111 value = this.formatDate(value);
39112 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
39115 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39118 var svalue = value;
39119 value = this.parseDate(value);
39121 this.markInvalid(String.format(this.invalidText, svalue, this.format));
39124 var time = value.getTime();
39125 if(this.minValue && time < this.minValue.getTime()){
39126 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
39129 if(this.maxValue && time > this.maxValue.getTime()){
39130 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
39133 /*if(this.disabledDays){
39134 var day = value.getDay();
39135 for(var i = 0; i < this.disabledDays.length; i++) {
39136 if(day === this.disabledDays[i]){
39137 this.markInvalid(this.disabledDaysText);
39143 var fvalue = this.formatDate(value);
39144 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
39145 this.markInvalid(String.format(this.disabledDatesText, fvalue));
39153 // Provides logic to override the default TriggerField.validateBlur which just returns true
39154 validateBlur : function(){
39155 return !this.menu || !this.menu.isVisible();
39159 * Returns the current date value of the date field.
39160 * @return {Date} The date value
39162 getValue : function(){
39166 return this.hiddenField ?
39167 this.hiddenField.value :
39168 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
39172 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
39173 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
39174 * (the default format used is "m/d/y").
39177 //All of these calls set the same date value (May 4, 2006)
39179 //Pass a date object:
39180 var dt = new Date('5/4/06');
39181 monthField.setValue(dt);
39183 //Pass a date string (default format):
39184 monthField.setValue('5/4/06');
39186 //Pass a date string (custom format):
39187 monthField.format = 'Y-m-d';
39188 monthField.setValue('2006-5-4');
39190 * @param {String/Date} date The date or valid date string
39192 setValue : function(date){
39193 Roo.log('month setValue' + date);
39194 // can only be first of month..
39196 var val = this.parseDate(date);
39198 if (this.hiddenField) {
39199 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
39201 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
39202 this.value = this.parseDate(date);
39206 parseDate : function(value){
39207 if(!value || value instanceof Date){
39208 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
39211 var v = Date.parseDate(value, this.format);
39212 if (!v && this.useIso) {
39213 v = Date.parseDate(value, 'Y-m-d');
39217 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
39221 if(!v && this.altFormats){
39222 if(!this.altFormatsArray){
39223 this.altFormatsArray = this.altFormats.split("|");
39225 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
39226 v = Date.parseDate(value, this.altFormatsArray[i]);
39233 formatDate : function(date, fmt){
39234 return (!date || !(date instanceof Date)) ?
39235 date : date.dateFormat(fmt || this.format);
39240 select: function(m, d){
39242 this.fireEvent('select', this, d);
39244 show : function(){ // retain focus styling
39248 this.focus.defer(10, this);
39249 var ml = this.menuListeners;
39250 this.menu.un("select", ml.select, this);
39251 this.menu.un("show", ml.show, this);
39252 this.menu.un("hide", ml.hide, this);
39256 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
39257 onTriggerClick : function(){
39261 if(this.menu == null){
39262 this.menu = new Roo.menu.DateMenu();
39266 Roo.apply(this.menu.picker, {
39268 showClear: this.allowBlank,
39269 minDate : this.minValue,
39270 maxDate : this.maxValue,
39271 disabledDatesRE : this.ddMatch,
39272 disabledDatesText : this.disabledDatesText,
39274 format : this.useIso ? 'Y-m-d' : this.format,
39275 minText : String.format(this.minText, this.formatDate(this.minValue)),
39276 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39279 this.menu.on(Roo.apply({}, this.menuListeners, {
39287 // hide month picker get's called when we called by 'before hide';
39289 var ignorehide = true;
39290 p.hideMonthPicker = function(disableAnim){
39294 if(this.monthPicker){
39295 Roo.log("hideMonthPicker called");
39296 if(disableAnim === true){
39297 this.monthPicker.hide();
39299 this.monthPicker.slideOut('t', {duration:.2});
39300 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39301 p.fireEvent("select", this, this.value);
39307 Roo.log('picker set value');
39308 Roo.log(this.getValue());
39309 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39310 m.show(this.el, 'tl-bl?');
39311 ignorehide = false;
39312 // this will trigger hideMonthPicker..
39315 // hidden the day picker
39316 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39322 p.showMonthPicker.defer(100, p);
39328 beforeBlur : function(){
39329 var v = this.parseDate(this.getRawValue());
39335 /** @cfg {Boolean} grow @hide */
39336 /** @cfg {Number} growMin @hide */
39337 /** @cfg {Number} growMax @hide */
39344 * Ext JS Library 1.1.1
39345 * Copyright(c) 2006-2007, Ext JS, LLC.
39347 * Originally Released Under LGPL - original licence link has changed is not relivant.
39350 * <script type="text/javascript">
39355 * @class Roo.form.ComboBox
39356 * @extends Roo.form.TriggerField
39357 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39359 * Create a new ComboBox.
39360 * @param {Object} config Configuration options
39362 Roo.form.ComboBox = function(config){
39363 Roo.form.ComboBox.superclass.constructor.call(this, config);
39367 * Fires when the dropdown list is expanded
39368 * @param {Roo.form.ComboBox} combo This combo box
39373 * Fires when the dropdown list is collapsed
39374 * @param {Roo.form.ComboBox} combo This combo box
39378 * @event beforeselect
39379 * Fires before a list item is selected. Return false to cancel the selection.
39380 * @param {Roo.form.ComboBox} combo This combo box
39381 * @param {Roo.data.Record} record The data record returned from the underlying store
39382 * @param {Number} index The index of the selected item in the dropdown list
39384 'beforeselect' : true,
39387 * Fires when a list item is selected
39388 * @param {Roo.form.ComboBox} combo This combo box
39389 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39390 * @param {Number} index The index of the selected item in the dropdown list
39394 * @event beforequery
39395 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39396 * The event object passed has these properties:
39397 * @param {Roo.form.ComboBox} combo This combo box
39398 * @param {String} query The query
39399 * @param {Boolean} forceAll true to force "all" query
39400 * @param {Boolean} cancel true to cancel the query
39401 * @param {Object} e The query event object
39403 'beforequery': true,
39406 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39407 * @param {Roo.form.ComboBox} combo This combo box
39412 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39413 * @param {Roo.form.ComboBox} combo This combo box
39414 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39420 if(this.transform){
39421 this.allowDomMove = false;
39422 var s = Roo.getDom(this.transform);
39423 if(!this.hiddenName){
39424 this.hiddenName = s.name;
39427 this.mode = 'local';
39428 var d = [], opts = s.options;
39429 for(var i = 0, len = opts.length;i < len; i++){
39431 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39433 this.value = value;
39435 d.push([value, o.text]);
39437 this.store = new Roo.data.SimpleStore({
39439 fields: ['value', 'text'],
39442 this.valueField = 'value';
39443 this.displayField = 'text';
39445 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39446 if(!this.lazyRender){
39447 this.target = true;
39448 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39449 s.parentNode.removeChild(s); // remove it
39450 this.render(this.el.parentNode);
39452 s.parentNode.removeChild(s); // remove it
39457 this.store = Roo.factory(this.store, Roo.data);
39460 this.selectedIndex = -1;
39461 if(this.mode == 'local'){
39462 if(config.queryDelay === undefined){
39463 this.queryDelay = 10;
39465 if(config.minChars === undefined){
39471 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39473 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39476 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39477 * rendering into an Roo.Editor, defaults to false)
39480 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39481 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39484 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39487 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39488 * the dropdown list (defaults to undefined, with no header element)
39492 * @cfg {String/Roo.Template} tpl The template to use to render the output
39496 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39498 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39500 listWidth: undefined,
39502 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39503 * mode = 'remote' or 'text' if mode = 'local')
39505 displayField: undefined,
39507 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39508 * mode = 'remote' or 'value' if mode = 'local').
39509 * Note: use of a valueField requires the user make a selection
39510 * in order for a value to be mapped.
39512 valueField: undefined,
39516 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39517 * field's data value (defaults to the underlying DOM element's name)
39519 hiddenName: undefined,
39521 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39525 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39527 selectedClass: 'x-combo-selected',
39529 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39530 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39531 * which displays a downward arrow icon).
39533 triggerClass : 'x-form-arrow-trigger',
39535 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39539 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39540 * anchor positions (defaults to 'tl-bl')
39542 listAlign: 'tl-bl?',
39544 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39548 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39549 * query specified by the allQuery config option (defaults to 'query')
39551 triggerAction: 'query',
39553 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39554 * (defaults to 4, does not apply if editable = false)
39558 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39559 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39563 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39564 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39568 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39569 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39573 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39574 * when editable = true (defaults to false)
39576 selectOnFocus:false,
39578 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39580 queryParam: 'query',
39582 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39583 * when mode = 'remote' (defaults to 'Loading...')
39585 loadingText: 'Loading...',
39587 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39591 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39595 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39596 * traditional select (defaults to true)
39600 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39604 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39608 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39609 * listWidth has a higher value)
39613 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39614 * allow the user to set arbitrary text into the field (defaults to false)
39616 forceSelection:false,
39618 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39619 * if typeAhead = true (defaults to 250)
39621 typeAheadDelay : 250,
39623 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39624 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39626 valueNotFoundText : undefined,
39628 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39630 blockFocus : false,
39633 * @cfg {Boolean} disableClear Disable showing of clear button.
39635 disableClear : false,
39637 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39639 alwaysQuery : false,
39645 // element that contains real text value.. (when hidden is used..)
39648 onRender : function(ct, position){
39649 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39650 if(this.hiddenName){
39651 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39653 this.hiddenField.value =
39654 this.hiddenValue !== undefined ? this.hiddenValue :
39655 this.value !== undefined ? this.value : '';
39657 // prevent input submission
39658 this.el.dom.removeAttribute('name');
39663 this.el.dom.setAttribute('autocomplete', 'off');
39666 var cls = 'x-combo-list';
39668 this.list = new Roo.Layer({
39669 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39672 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39673 this.list.setWidth(lw);
39674 this.list.swallowEvent('mousewheel');
39675 this.assetHeight = 0;
39678 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39679 this.assetHeight += this.header.getHeight();
39682 this.innerList = this.list.createChild({cls:cls+'-inner'});
39683 this.innerList.on('mouseover', this.onViewOver, this);
39684 this.innerList.on('mousemove', this.onViewMove, this);
39685 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39687 if(this.allowBlank && !this.pageSize && !this.disableClear){
39688 this.footer = this.list.createChild({cls:cls+'-ft'});
39689 this.pageTb = new Roo.Toolbar(this.footer);
39693 this.footer = this.list.createChild({cls:cls+'-ft'});
39694 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39695 {pageSize: this.pageSize});
39699 if (this.pageTb && this.allowBlank && !this.disableClear) {
39701 this.pageTb.add(new Roo.Toolbar.Fill(), {
39702 cls: 'x-btn-icon x-btn-clear',
39704 handler: function()
39707 _this.clearValue();
39708 _this.onSelect(false, -1);
39713 this.assetHeight += this.footer.getHeight();
39718 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39721 this.view = new Roo.View(this.innerList, this.tpl, {
39722 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39725 this.view.on('click', this.onViewClick, this);
39727 this.store.on('beforeload', this.onBeforeLoad, this);
39728 this.store.on('load', this.onLoad, this);
39729 this.store.on('loadexception', this.onLoadException, this);
39731 if(this.resizable){
39732 this.resizer = new Roo.Resizable(this.list, {
39733 pinned:true, handles:'se'
39735 this.resizer.on('resize', function(r, w, h){
39736 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39737 this.listWidth = w;
39738 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39739 this.restrictHeight();
39741 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39743 if(!this.editable){
39744 this.editable = true;
39745 this.setEditable(false);
39749 if (typeof(this.events.add.listeners) != 'undefined') {
39751 this.addicon = this.wrap.createChild(
39752 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39754 this.addicon.on('click', function(e) {
39755 this.fireEvent('add', this);
39758 if (typeof(this.events.edit.listeners) != 'undefined') {
39760 this.editicon = this.wrap.createChild(
39761 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39762 if (this.addicon) {
39763 this.editicon.setStyle('margin-left', '40px');
39765 this.editicon.on('click', function(e) {
39767 // we fire even if inothing is selected..
39768 this.fireEvent('edit', this, this.lastData );
39778 initEvents : function(){
39779 Roo.form.ComboBox.superclass.initEvents.call(this);
39781 this.keyNav = new Roo.KeyNav(this.el, {
39782 "up" : function(e){
39783 this.inKeyMode = true;
39787 "down" : function(e){
39788 if(!this.isExpanded()){
39789 this.onTriggerClick();
39791 this.inKeyMode = true;
39796 "enter" : function(e){
39797 this.onViewClick();
39801 "esc" : function(e){
39805 "tab" : function(e){
39806 this.onViewClick(false);
39807 this.fireEvent("specialkey", this, e);
39813 doRelay : function(foo, bar, hname){
39814 if(hname == 'down' || this.scope.isExpanded()){
39815 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39822 this.queryDelay = Math.max(this.queryDelay || 10,
39823 this.mode == 'local' ? 10 : 250);
39824 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39825 if(this.typeAhead){
39826 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39828 if(this.editable !== false){
39829 this.el.on("keyup", this.onKeyUp, this);
39831 if(this.forceSelection){
39832 this.on('blur', this.doForce, this);
39836 onDestroy : function(){
39838 this.view.setStore(null);
39839 this.view.el.removeAllListeners();
39840 this.view.el.remove();
39841 this.view.purgeListeners();
39844 this.list.destroy();
39847 this.store.un('beforeload', this.onBeforeLoad, this);
39848 this.store.un('load', this.onLoad, this);
39849 this.store.un('loadexception', this.onLoadException, this);
39851 Roo.form.ComboBox.superclass.onDestroy.call(this);
39855 fireKey : function(e){
39856 if(e.isNavKeyPress() && !this.list.isVisible()){
39857 this.fireEvent("specialkey", this, e);
39862 onResize: function(w, h){
39863 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39865 if(typeof w != 'number'){
39866 // we do not handle it!?!?
39869 var tw = this.trigger.getWidth();
39870 tw += this.addicon ? this.addicon.getWidth() : 0;
39871 tw += this.editicon ? this.editicon.getWidth() : 0;
39873 this.el.setWidth( this.adjustWidth('input', x));
39875 this.trigger.setStyle('left', x+'px');
39877 if(this.list && this.listWidth === undefined){
39878 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39879 this.list.setWidth(lw);
39880 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39888 * Allow or prevent the user from directly editing the field text. If false is passed,
39889 * the user will only be able to select from the items defined in the dropdown list. This method
39890 * is the runtime equivalent of setting the 'editable' config option at config time.
39891 * @param {Boolean} value True to allow the user to directly edit the field text
39893 setEditable : function(value){
39894 if(value == this.editable){
39897 this.editable = value;
39899 this.el.dom.setAttribute('readOnly', true);
39900 this.el.on('mousedown', this.onTriggerClick, this);
39901 this.el.addClass('x-combo-noedit');
39903 this.el.dom.setAttribute('readOnly', false);
39904 this.el.un('mousedown', this.onTriggerClick, this);
39905 this.el.removeClass('x-combo-noedit');
39910 onBeforeLoad : function(){
39911 if(!this.hasFocus){
39914 this.innerList.update(this.loadingText ?
39915 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39916 this.restrictHeight();
39917 this.selectedIndex = -1;
39921 onLoad : function(){
39922 if(!this.hasFocus){
39925 if(this.store.getCount() > 0){
39927 this.restrictHeight();
39928 if(this.lastQuery == this.allQuery){
39930 this.el.dom.select();
39932 if(!this.selectByValue(this.value, true)){
39933 this.select(0, true);
39937 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39938 this.taTask.delay(this.typeAheadDelay);
39942 this.onEmptyResults();
39947 onLoadException : function()
39950 Roo.log(this.store.reader.jsonData);
39951 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39952 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39958 onTypeAhead : function(){
39959 if(this.store.getCount() > 0){
39960 var r = this.store.getAt(0);
39961 var newValue = r.data[this.displayField];
39962 var len = newValue.length;
39963 var selStart = this.getRawValue().length;
39964 if(selStart != len){
39965 this.setRawValue(newValue);
39966 this.selectText(selStart, newValue.length);
39972 onSelect : function(record, index){
39973 if(this.fireEvent('beforeselect', this, record, index) !== false){
39974 this.setFromData(index > -1 ? record.data : false);
39976 this.fireEvent('select', this, record, index);
39981 * Returns the currently selected field value or empty string if no value is set.
39982 * @return {String} value The selected value
39984 getValue : function(){
39985 if(this.valueField){
39986 return typeof this.value != 'undefined' ? this.value : '';
39988 return Roo.form.ComboBox.superclass.getValue.call(this);
39992 * Clears any text/value currently set in the field
39994 clearValue : function(){
39995 if(this.hiddenField){
39996 this.hiddenField.value = '';
39999 this.setRawValue('');
40000 this.lastSelectionText = '';
40005 * Sets the specified value into the field. If the value finds a match, the corresponding record text
40006 * will be displayed in the field. If the value does not match the data value of an existing item,
40007 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
40008 * Otherwise the field will be blank (although the value will still be set).
40009 * @param {String} value The value to match
40011 setValue : function(v){
40013 if(this.valueField){
40014 var r = this.findRecord(this.valueField, v);
40016 text = r.data[this.displayField];
40017 }else if(this.valueNotFoundText !== undefined){
40018 text = this.valueNotFoundText;
40021 this.lastSelectionText = text;
40022 if(this.hiddenField){
40023 this.hiddenField.value = v;
40025 Roo.form.ComboBox.superclass.setValue.call(this, text);
40029 * @property {Object} the last set data for the element
40034 * Sets the value of the field based on a object which is related to the record format for the store.
40035 * @param {Object} value the value to set as. or false on reset?
40037 setFromData : function(o){
40038 var dv = ''; // display value
40039 var vv = ''; // value value..
40041 if (this.displayField) {
40042 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
40044 // this is an error condition!!!
40045 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
40048 if(this.valueField){
40049 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
40051 if(this.hiddenField){
40052 this.hiddenField.value = vv;
40054 this.lastSelectionText = dv;
40055 Roo.form.ComboBox.superclass.setValue.call(this, dv);
40059 // no hidden field.. - we store the value in 'value', but still display
40060 // display field!!!!
40061 this.lastSelectionText = dv;
40062 Roo.form.ComboBox.superclass.setValue.call(this, dv);
40068 reset : function(){
40069 // overridden so that last data is reset..
40070 this.setValue(this.resetValue);
40071 this.clearInvalid();
40072 this.lastData = false;
40074 this.view.clearSelections();
40078 findRecord : function(prop, value){
40080 if(this.store.getCount() > 0){
40081 this.store.each(function(r){
40082 if(r.data[prop] == value){
40092 getName: function()
40094 // returns hidden if it's set..
40095 if (!this.rendered) {return ''};
40096 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40100 onViewMove : function(e, t){
40101 this.inKeyMode = false;
40105 onViewOver : function(e, t){
40106 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
40109 var item = this.view.findItemFromChild(t);
40111 var index = this.view.indexOf(item);
40112 this.select(index, false);
40117 onViewClick : function(doFocus)
40119 var index = this.view.getSelectedIndexes()[0];
40120 var r = this.store.getAt(index);
40122 this.onSelect(r, index);
40124 if(doFocus !== false && !this.blockFocus){
40130 restrictHeight : function(){
40131 this.innerList.dom.style.height = '';
40132 var inner = this.innerList.dom;
40133 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
40134 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
40135 this.list.beginUpdate();
40136 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
40137 this.list.alignTo(this.el, this.listAlign);
40138 this.list.endUpdate();
40142 onEmptyResults : function(){
40147 * Returns true if the dropdown list is expanded, else false.
40149 isExpanded : function(){
40150 return this.list.isVisible();
40154 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
40155 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40156 * @param {String} value The data value of the item to select
40157 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40158 * selected item if it is not currently in view (defaults to true)
40159 * @return {Boolean} True if the value matched an item in the list, else false
40161 selectByValue : function(v, scrollIntoView){
40162 if(v !== undefined && v !== null){
40163 var r = this.findRecord(this.valueField || this.displayField, v);
40165 this.select(this.store.indexOf(r), scrollIntoView);
40173 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
40174 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40175 * @param {Number} index The zero-based index of the list item to select
40176 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40177 * selected item if it is not currently in view (defaults to true)
40179 select : function(index, scrollIntoView){
40180 this.selectedIndex = index;
40181 this.view.select(index);
40182 if(scrollIntoView !== false){
40183 var el = this.view.getNode(index);
40185 this.innerList.scrollChildIntoView(el, false);
40191 selectNext : function(){
40192 var ct = this.store.getCount();
40194 if(this.selectedIndex == -1){
40196 }else if(this.selectedIndex < ct-1){
40197 this.select(this.selectedIndex+1);
40203 selectPrev : function(){
40204 var ct = this.store.getCount();
40206 if(this.selectedIndex == -1){
40208 }else if(this.selectedIndex != 0){
40209 this.select(this.selectedIndex-1);
40215 onKeyUp : function(e){
40216 if(this.editable !== false && !e.isSpecialKey()){
40217 this.lastKey = e.getKey();
40218 this.dqTask.delay(this.queryDelay);
40223 validateBlur : function(){
40224 return !this.list || !this.list.isVisible();
40228 initQuery : function(){
40229 this.doQuery(this.getRawValue());
40233 doForce : function(){
40234 if(this.el.dom.value.length > 0){
40235 this.el.dom.value =
40236 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
40242 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
40243 * query allowing the query action to be canceled if needed.
40244 * @param {String} query The SQL query to execute
40245 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
40246 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
40247 * saved in the current store (defaults to false)
40249 doQuery : function(q, forceAll){
40250 if(q === undefined || q === null){
40255 forceAll: forceAll,
40259 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
40263 forceAll = qe.forceAll;
40264 if(forceAll === true || (q.length >= this.minChars)){
40265 if(this.lastQuery != q || this.alwaysQuery){
40266 this.lastQuery = q;
40267 if(this.mode == 'local'){
40268 this.selectedIndex = -1;
40270 this.store.clearFilter();
40272 this.store.filter(this.displayField, q);
40276 this.store.baseParams[this.queryParam] = q;
40278 params: this.getParams(q)
40283 this.selectedIndex = -1;
40290 getParams : function(q){
40292 //p[this.queryParam] = q;
40295 p.limit = this.pageSize;
40301 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40303 collapse : function(){
40304 if(!this.isExpanded()){
40308 Roo.get(document).un('mousedown', this.collapseIf, this);
40309 Roo.get(document).un('mousewheel', this.collapseIf, this);
40310 if (!this.editable) {
40311 Roo.get(document).un('keydown', this.listKeyPress, this);
40313 this.fireEvent('collapse', this);
40317 collapseIf : function(e){
40318 if(!e.within(this.wrap) && !e.within(this.list)){
40324 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40326 expand : function(){
40327 if(this.isExpanded() || !this.hasFocus){
40330 this.list.alignTo(this.el, this.listAlign);
40332 Roo.get(document).on('mousedown', this.collapseIf, this);
40333 Roo.get(document).on('mousewheel', this.collapseIf, this);
40334 if (!this.editable) {
40335 Roo.get(document).on('keydown', this.listKeyPress, this);
40338 this.fireEvent('expand', this);
40342 // Implements the default empty TriggerField.onTriggerClick function
40343 onTriggerClick : function(){
40347 if(this.isExpanded()){
40349 if (!this.blockFocus) {
40354 this.hasFocus = true;
40355 if(this.triggerAction == 'all') {
40356 this.doQuery(this.allQuery, true);
40358 this.doQuery(this.getRawValue());
40360 if (!this.blockFocus) {
40365 listKeyPress : function(e)
40367 //Roo.log('listkeypress');
40368 // scroll to first matching element based on key pres..
40369 if (e.isSpecialKey()) {
40372 var k = String.fromCharCode(e.getKey()).toUpperCase();
40375 var csel = this.view.getSelectedNodes();
40376 var cselitem = false;
40378 var ix = this.view.indexOf(csel[0]);
40379 cselitem = this.store.getAt(ix);
40380 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40386 this.store.each(function(v) {
40388 // start at existing selection.
40389 if (cselitem.id == v.id) {
40395 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40396 match = this.store.indexOf(v);
40401 if (match === false) {
40402 return true; // no more action?
40405 this.view.select(match);
40406 var sn = Roo.get(this.view.getSelectedNodes()[0]);
40407 sn.scrollIntoView(sn.dom.parentNode, false);
40411 * @cfg {Boolean} grow
40415 * @cfg {Number} growMin
40419 * @cfg {Number} growMax
40427 * Copyright(c) 2010-2012, Roo J Solutions Limited
40434 * @class Roo.form.ComboBoxArray
40435 * @extends Roo.form.TextField
40436 * A facebook style adder... for lists of email / people / countries etc...
40437 * pick multiple items from a combo box, and shows each one.
40439 * Fred [x] Brian [x] [Pick another |v]
40442 * For this to work: it needs various extra information
40443 * - normal combo problay has
40445 * + displayField, valueField
40447 * For our purpose...
40450 * If we change from 'extends' to wrapping...
40457 * Create a new ComboBoxArray.
40458 * @param {Object} config Configuration options
40462 Roo.form.ComboBoxArray = function(config)
40466 * @event beforeremove
40467 * Fires before remove the value from the list
40468 * @param {Roo.form.ComboBoxArray} _self This combo box array
40469 * @param {Roo.form.ComboBoxArray.Item} item removed item
40471 'beforeremove' : true,
40474 * Fires when remove the value from the list
40475 * @param {Roo.form.ComboBoxArray} _self This combo box array
40476 * @param {Roo.form.ComboBoxArray.Item} item removed item
40483 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40485 this.items = new Roo.util.MixedCollection(false);
40487 // construct the child combo...
40497 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40500 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40505 // behavies liek a hiddne field
40506 inputType: 'hidden',
40508 * @cfg {Number} width The width of the box that displays the selected element
40515 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40519 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40521 hiddenName : false,
40524 // private the array of items that are displayed..
40526 // private - the hidden field el.
40528 // private - the filed el..
40531 //validateValue : function() { return true; }, // all values are ok!
40532 //onAddClick: function() { },
40534 onRender : function(ct, position)
40537 // create the standard hidden element
40538 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40541 // give fake names to child combo;
40542 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40543 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40545 this.combo = Roo.factory(this.combo, Roo.form);
40546 this.combo.onRender(ct, position);
40547 if (typeof(this.combo.width) != 'undefined') {
40548 this.combo.onResize(this.combo.width,0);
40551 this.combo.initEvents();
40553 // assigned so form know we need to do this..
40554 this.store = this.combo.store;
40555 this.valueField = this.combo.valueField;
40556 this.displayField = this.combo.displayField ;
40559 this.combo.wrap.addClass('x-cbarray-grp');
40561 var cbwrap = this.combo.wrap.createChild(
40562 {tag: 'div', cls: 'x-cbarray-cb'},
40567 this.hiddenEl = this.combo.wrap.createChild({
40568 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40570 this.el = this.combo.wrap.createChild({
40571 tag: 'input', type:'hidden' , name: this.name, value : ''
40573 // this.el.dom.removeAttribute("name");
40576 this.outerWrap = this.combo.wrap;
40577 this.wrap = cbwrap;
40579 this.outerWrap.setWidth(this.width);
40580 this.outerWrap.dom.removeChild(this.el.dom);
40582 this.wrap.dom.appendChild(this.el.dom);
40583 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40584 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40586 this.combo.trigger.setStyle('position','relative');
40587 this.combo.trigger.setStyle('left', '0px');
40588 this.combo.trigger.setStyle('top', '2px');
40590 this.combo.el.setStyle('vertical-align', 'text-bottom');
40592 //this.trigger.setStyle('vertical-align', 'top');
40594 // this should use the code from combo really... on('add' ....)
40598 this.adder = this.outerWrap.createChild(
40599 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40601 this.adder.on('click', function(e) {
40602 _t.fireEvent('adderclick', this, e);
40606 //this.adder.on('click', this.onAddClick, _t);
40609 this.combo.on('select', function(cb, rec, ix) {
40610 this.addItem(rec.data);
40613 cb.el.dom.value = '';
40614 //cb.lastData = rec.data;
40623 getName: function()
40625 // returns hidden if it's set..
40626 if (!this.rendered) {return ''};
40627 return this.hiddenName ? this.hiddenName : this.name;
40632 onResize: function(w, h){
40635 // not sure if this is needed..
40636 //this.combo.onResize(w,h);
40638 if(typeof w != 'number'){
40639 // we do not handle it!?!?
40642 var tw = this.combo.trigger.getWidth();
40643 tw += this.addicon ? this.addicon.getWidth() : 0;
40644 tw += this.editicon ? this.editicon.getWidth() : 0;
40646 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40648 this.combo.trigger.setStyle('left', '0px');
40650 if(this.list && this.listWidth === undefined){
40651 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40652 this.list.setWidth(lw);
40653 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40660 addItem: function(rec)
40662 var valueField = this.combo.valueField;
40663 var displayField = this.combo.displayField;
40664 if (this.items.indexOfKey(rec[valueField]) > -1) {
40665 //console.log("GOT " + rec.data.id);
40669 var x = new Roo.form.ComboBoxArray.Item({
40670 //id : rec[this.idField],
40672 displayField : displayField ,
40673 tipField : displayField ,
40677 this.items.add(rec[valueField],x);
40678 // add it before the element..
40679 this.updateHiddenEl();
40680 x.render(this.outerWrap, this.wrap.dom);
40681 // add the image handler..
40684 updateHiddenEl : function()
40687 if (!this.hiddenEl) {
40691 var idField = this.combo.valueField;
40693 this.items.each(function(f) {
40694 ar.push(f.data[idField]);
40697 this.hiddenEl.dom.value = ar.join(',');
40703 this.items.clear();
40705 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
40709 this.el.dom.value = '';
40710 if (this.hiddenEl) {
40711 this.hiddenEl.dom.value = '';
40715 getValue: function()
40717 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40719 setValue: function(v) // not a valid action - must use addItems..
40726 if (this.store.isLocal && (typeof(v) == 'string')) {
40727 // then we can use the store to find the values..
40728 // comma seperated at present.. this needs to allow JSON based encoding..
40729 this.hiddenEl.value = v;
40731 Roo.each(v.split(','), function(k) {
40732 Roo.log("CHECK " + this.valueField + ',' + k);
40733 var li = this.store.query(this.valueField, k);
40738 add[this.valueField] = k;
40739 add[this.displayField] = li.item(0).data[this.displayField];
40745 if (typeof(v) == 'object' ) {
40746 // then let's assume it's an array of objects..
40747 Roo.each(v, function(l) {
40755 setFromData: function(v)
40757 // this recieves an object, if setValues is called.
40759 this.el.dom.value = v[this.displayField];
40760 this.hiddenEl.dom.value = v[this.valueField];
40761 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40764 var kv = v[this.valueField];
40765 var dv = v[this.displayField];
40766 kv = typeof(kv) != 'string' ? '' : kv;
40767 dv = typeof(dv) != 'string' ? '' : dv;
40770 var keys = kv.split(',');
40771 var display = dv.split(',');
40772 for (var i = 0 ; i < keys.length; i++) {
40775 add[this.valueField] = keys[i];
40776 add[this.displayField] = display[i];
40784 * Validates the combox array value
40785 * @return {Boolean} True if the value is valid, else false
40787 validate : function(){
40788 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40789 this.clearInvalid();
40795 validateValue : function(value){
40796 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40804 isDirty : function() {
40805 if(this.disabled) {
40810 var d = Roo.decode(String(this.originalValue));
40812 return String(this.getValue()) !== String(this.originalValue);
40815 var originalValue = [];
40817 for (var i = 0; i < d.length; i++){
40818 originalValue.push(d[i][this.valueField]);
40821 return String(this.getValue()) !== String(originalValue.join(','));
40830 * @class Roo.form.ComboBoxArray.Item
40831 * @extends Roo.BoxComponent
40832 * A selected item in the list
40833 * Fred [x] Brian [x] [Pick another |v]
40836 * Create a new item.
40837 * @param {Object} config Configuration options
40840 Roo.form.ComboBoxArray.Item = function(config) {
40841 config.id = Roo.id();
40842 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40845 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40848 displayField : false,
40852 defaultAutoCreate : {
40854 cls: 'x-cbarray-item',
40861 src : Roo.BLANK_IMAGE_URL ,
40869 onRender : function(ct, position)
40871 Roo.form.Field.superclass.onRender.call(this, ct, position);
40874 var cfg = this.getAutoCreate();
40875 this.el = ct.createChild(cfg, position);
40878 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40880 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40881 this.cb.renderer(this.data) :
40882 String.format('{0}',this.data[this.displayField]);
40885 this.el.child('div').dom.setAttribute('qtip',
40886 String.format('{0}',this.data[this.tipField])
40889 this.el.child('img').on('click', this.remove, this);
40893 remove : function()
40895 if(this.cb.disabled){
40899 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
40900 this.cb.items.remove(this);
40901 this.el.child('img').un('click', this.remove, this);
40903 this.cb.updateHiddenEl();
40905 this.cb.fireEvent('remove', this.cb, this);
40911 * Ext JS Library 1.1.1
40912 * Copyright(c) 2006-2007, Ext JS, LLC.
40914 * Originally Released Under LGPL - original licence link has changed is not relivant.
40917 * <script type="text/javascript">
40920 * @class Roo.form.Checkbox
40921 * @extends Roo.form.Field
40922 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40924 * Creates a new Checkbox
40925 * @param {Object} config Configuration options
40927 Roo.form.Checkbox = function(config){
40928 Roo.form.Checkbox.superclass.constructor.call(this, config);
40932 * Fires when the checkbox is checked or unchecked.
40933 * @param {Roo.form.Checkbox} this This checkbox
40934 * @param {Boolean} checked The new checked value
40940 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40942 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40944 focusClass : undefined,
40946 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40948 fieldClass: "x-form-field",
40950 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40954 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40955 * {tag: "input", type: "checkbox", autocomplete: "off"})
40957 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40959 * @cfg {String} boxLabel The text that appears beside the checkbox
40963 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40967 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40969 valueOff: '0', // value when not checked..
40971 actionMode : 'viewEl',
40974 itemCls : 'x-menu-check-item x-form-item',
40975 groupClass : 'x-menu-group-item',
40976 inputType : 'hidden',
40979 inSetChecked: false, // check that we are not calling self...
40981 inputElement: false, // real input element?
40982 basedOn: false, // ????
40984 isFormField: true, // not sure where this is needed!!!!
40986 onResize : function(){
40987 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40988 if(!this.boxLabel){
40989 this.el.alignTo(this.wrap, 'c-c');
40993 initEvents : function(){
40994 Roo.form.Checkbox.superclass.initEvents.call(this);
40995 this.el.on("click", this.onClick, this);
40996 this.el.on("change", this.onClick, this);
41000 getResizeEl : function(){
41004 getPositionEl : function(){
41009 onRender : function(ct, position){
41010 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
41012 if(this.inputValue !== undefined){
41013 this.el.dom.value = this.inputValue;
41016 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
41017 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
41018 var viewEl = this.wrap.createChild({
41019 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
41020 this.viewEl = viewEl;
41021 this.wrap.on('click', this.onClick, this);
41023 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
41024 this.el.on('propertychange', this.setFromHidden, this); //ie
41029 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
41030 // viewEl.on('click', this.onClick, this);
41032 //if(this.checked){
41033 this.setChecked(this.checked);
41035 //this.checked = this.el.dom;
41041 initValue : Roo.emptyFn,
41044 * Returns the checked state of the checkbox.
41045 * @return {Boolean} True if checked, else false
41047 getValue : function(){
41049 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
41051 return this.valueOff;
41056 onClick : function(){
41057 if (this.disabled) {
41060 this.setChecked(!this.checked);
41062 //if(this.el.dom.checked != this.checked){
41063 // this.setValue(this.el.dom.checked);
41068 * Sets the checked state of the checkbox.
41069 * On is always based on a string comparison between inputValue and the param.
41070 * @param {Boolean/String} value - the value to set
41071 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
41073 setValue : function(v,suppressEvent){
41076 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
41077 //if(this.el && this.el.dom){
41078 // this.el.dom.checked = this.checked;
41079 // this.el.dom.defaultChecked = this.checked;
41081 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
41082 //this.fireEvent("check", this, this.checked);
41085 setChecked : function(state,suppressEvent)
41087 if (this.inSetChecked) {
41088 this.checked = state;
41094 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
41096 this.checked = state;
41097 if(suppressEvent !== true){
41098 this.fireEvent('check', this, state);
41100 this.inSetChecked = true;
41101 this.el.dom.value = state ? this.inputValue : this.valueOff;
41102 this.inSetChecked = false;
41105 // handle setting of hidden value by some other method!!?!?
41106 setFromHidden: function()
41111 //console.log("SET FROM HIDDEN");
41112 //alert('setFrom hidden');
41113 this.setValue(this.el.dom.value);
41116 onDestroy : function()
41119 Roo.get(this.viewEl).remove();
41122 Roo.form.Checkbox.superclass.onDestroy.call(this);
41125 setBoxLabel : function(str)
41127 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
41132 * Ext JS Library 1.1.1
41133 * Copyright(c) 2006-2007, Ext JS, LLC.
41135 * Originally Released Under LGPL - original licence link has changed is not relivant.
41138 * <script type="text/javascript">
41142 * @class Roo.form.Radio
41143 * @extends Roo.form.Checkbox
41144 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
41145 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
41147 * Creates a new Radio
41148 * @param {Object} config Configuration options
41150 Roo.form.Radio = function(){
41151 Roo.form.Radio.superclass.constructor.apply(this, arguments);
41153 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
41154 inputType: 'radio',
41157 * If this radio is part of a group, it will return the selected value
41160 getGroupValue : function(){
41161 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
41165 onRender : function(ct, position){
41166 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
41168 if(this.inputValue !== undefined){
41169 this.el.dom.value = this.inputValue;
41172 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
41173 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
41174 //var viewEl = this.wrap.createChild({
41175 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
41176 //this.viewEl = viewEl;
41177 //this.wrap.on('click', this.onClick, this);
41179 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
41180 //this.el.on('propertychange', this.setFromHidden, this); //ie
41185 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
41186 // viewEl.on('click', this.onClick, this);
41189 this.el.dom.checked = 'checked' ;
41195 });//<script type="text/javascript">
41198 * Based Ext JS Library 1.1.1
41199 * Copyright(c) 2006-2007, Ext JS, LLC.
41205 * @class Roo.HtmlEditorCore
41206 * @extends Roo.Component
41207 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
41209 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
41212 Roo.HtmlEditorCore = function(config){
41215 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
41220 * @event initialize
41221 * Fires when the editor is fully initialized (including the iframe)
41222 * @param {Roo.HtmlEditorCore} this
41227 * Fires when the editor is first receives the focus. Any insertion must wait
41228 * until after this event.
41229 * @param {Roo.HtmlEditorCore} this
41233 * @event beforesync
41234 * Fires before the textarea is updated with content from the editor iframe. Return false
41235 * to cancel the sync.
41236 * @param {Roo.HtmlEditorCore} this
41237 * @param {String} html
41241 * @event beforepush
41242 * Fires before the iframe editor is updated with content from the textarea. Return false
41243 * to cancel the push.
41244 * @param {Roo.HtmlEditorCore} this
41245 * @param {String} html
41250 * Fires when the textarea is updated with content from the editor iframe.
41251 * @param {Roo.HtmlEditorCore} this
41252 * @param {String} html
41257 * Fires when the iframe editor is updated with content from the textarea.
41258 * @param {Roo.HtmlEditorCore} this
41259 * @param {String} html
41264 * @event editorevent
41265 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41266 * @param {Roo.HtmlEditorCore} this
41272 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
41274 // defaults : white / black...
41275 this.applyBlacklists();
41282 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41286 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41292 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41297 * @cfg {Number} height (in pixels)
41301 * @cfg {Number} width (in pixels)
41306 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41309 stylesheets: false,
41314 // private properties
41315 validationEvent : false,
41317 initialized : false,
41319 sourceEditMode : false,
41320 onFocus : Roo.emptyFn,
41322 hideMode:'offsets',
41326 // blacklist + whitelisted elements..
41333 * Protected method that will not generally be called directly. It
41334 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41335 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41337 getDocMarkup : function(){
41341 // inherit styels from page...??
41342 if (this.stylesheets === false) {
41344 Roo.get(document.head).select('style').each(function(node) {
41345 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41348 Roo.get(document.head).select('link').each(function(node) {
41349 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41352 } else if (!this.stylesheets.length) {
41354 st = '<style type="text/css">' +
41355 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41361 st += '<style type="text/css">' +
41362 'IMG { cursor: pointer } ' +
41366 return '<html><head>' + st +
41367 //<style type="text/css">' +
41368 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41370 ' </head><body class="roo-htmleditor-body"></body></html>';
41374 onRender : function(ct, position)
41377 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41378 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41381 this.el.dom.style.border = '0 none';
41382 this.el.dom.setAttribute('tabIndex', -1);
41383 this.el.addClass('x-hidden hide');
41387 if(Roo.isIE){ // fix IE 1px bogus margin
41388 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41392 this.frameId = Roo.id();
41396 var iframe = this.owner.wrap.createChild({
41398 cls: 'form-control', // bootstrap..
41400 name: this.frameId,
41401 frameBorder : 'no',
41402 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41407 this.iframe = iframe.dom;
41409 this.assignDocWin();
41411 this.doc.designMode = 'on';
41414 this.doc.write(this.getDocMarkup());
41418 var task = { // must defer to wait for browser to be ready
41420 //console.log("run task?" + this.doc.readyState);
41421 this.assignDocWin();
41422 if(this.doc.body || this.doc.readyState == 'complete'){
41424 this.doc.designMode="on";
41428 Roo.TaskMgr.stop(task);
41429 this.initEditor.defer(10, this);
41436 Roo.TaskMgr.start(task);
41441 onResize : function(w, h)
41443 Roo.log('resize: ' +w + ',' + h );
41444 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41448 if(typeof w == 'number'){
41450 this.iframe.style.width = w + 'px';
41452 if(typeof h == 'number'){
41454 this.iframe.style.height = h + 'px';
41456 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41463 * Toggles the editor between standard and source edit mode.
41464 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41466 toggleSourceEdit : function(sourceEditMode){
41468 this.sourceEditMode = sourceEditMode === true;
41470 if(this.sourceEditMode){
41472 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41475 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41476 //this.iframe.className = '';
41479 //this.setSize(this.owner.wrap.getSize());
41480 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41487 * Protected method that will not generally be called directly. If you need/want
41488 * custom HTML cleanup, this is the method you should override.
41489 * @param {String} html The HTML to be cleaned
41490 * return {String} The cleaned HTML
41492 cleanHtml : function(html){
41493 html = String(html);
41494 if(html.length > 5){
41495 if(Roo.isSafari){ // strip safari nonsense
41496 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41499 if(html == ' '){
41506 * HTML Editor -> Textarea
41507 * Protected method that will not generally be called directly. Syncs the contents
41508 * of the editor iframe with the textarea.
41510 syncValue : function(){
41511 if(this.initialized){
41512 var bd = (this.doc.body || this.doc.documentElement);
41513 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41514 var html = bd.innerHTML;
41516 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41517 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41519 html = '<div style="'+m[0]+'">' + html + '</div>';
41522 html = this.cleanHtml(html);
41523 // fix up the special chars.. normaly like back quotes in word...
41524 // however we do not want to do this with chinese..
41525 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41526 var cc = b.charCodeAt();
41528 (cc >= 0x4E00 && cc < 0xA000 ) ||
41529 (cc >= 0x3400 && cc < 0x4E00 ) ||
41530 (cc >= 0xf900 && cc < 0xfb00 )
41536 if(this.owner.fireEvent('beforesync', this, html) !== false){
41537 this.el.dom.value = html;
41538 this.owner.fireEvent('sync', this, html);
41544 * Protected method that will not generally be called directly. Pushes the value of the textarea
41545 * into the iframe editor.
41547 pushValue : function(){
41548 if(this.initialized){
41549 var v = this.el.dom.value.trim();
41551 // if(v.length < 1){
41555 if(this.owner.fireEvent('beforepush', this, v) !== false){
41556 var d = (this.doc.body || this.doc.documentElement);
41558 this.cleanUpPaste();
41559 this.el.dom.value = d.innerHTML;
41560 this.owner.fireEvent('push', this, v);
41566 deferFocus : function(){
41567 this.focus.defer(10, this);
41571 focus : function(){
41572 if(this.win && !this.sourceEditMode){
41579 assignDocWin: function()
41581 var iframe = this.iframe;
41584 this.doc = iframe.contentWindow.document;
41585 this.win = iframe.contentWindow;
41587 // if (!Roo.get(this.frameId)) {
41590 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41591 // this.win = Roo.get(this.frameId).dom.contentWindow;
41593 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
41597 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41598 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
41603 initEditor : function(){
41604 //console.log("INIT EDITOR");
41605 this.assignDocWin();
41609 this.doc.designMode="on";
41611 this.doc.write(this.getDocMarkup());
41614 var dbody = (this.doc.body || this.doc.documentElement);
41615 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41616 // this copies styles from the containing element into thsi one..
41617 // not sure why we need all of this..
41618 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41620 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41621 //ss['background-attachment'] = 'fixed'; // w3c
41622 dbody.bgProperties = 'fixed'; // ie
41623 //Roo.DomHelper.applyStyles(dbody, ss);
41624 Roo.EventManager.on(this.doc, {
41625 //'mousedown': this.onEditorEvent,
41626 'mouseup': this.onEditorEvent,
41627 'dblclick': this.onEditorEvent,
41628 'click': this.onEditorEvent,
41629 'keyup': this.onEditorEvent,
41634 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41636 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41637 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41639 this.initialized = true;
41641 this.owner.fireEvent('initialize', this);
41646 onDestroy : function(){
41652 //for (var i =0; i < this.toolbars.length;i++) {
41653 // // fixme - ask toolbars for heights?
41654 // this.toolbars[i].onDestroy();
41657 //this.wrap.dom.innerHTML = '';
41658 //this.wrap.remove();
41663 onFirstFocus : function(){
41665 this.assignDocWin();
41668 this.activated = true;
41671 if(Roo.isGecko){ // prevent silly gecko errors
41673 var s = this.win.getSelection();
41674 if(!s.focusNode || s.focusNode.nodeType != 3){
41675 var r = s.getRangeAt(0);
41676 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41681 this.execCmd('useCSS', true);
41682 this.execCmd('styleWithCSS', false);
41685 this.owner.fireEvent('activate', this);
41689 adjustFont: function(btn){
41690 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41691 //if(Roo.isSafari){ // safari
41694 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41695 if(Roo.isSafari){ // safari
41696 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41697 v = (v < 10) ? 10 : v;
41698 v = (v > 48) ? 48 : v;
41699 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41704 v = Math.max(1, v+adjust);
41706 this.execCmd('FontSize', v );
41709 onEditorEvent : function(e)
41711 this.owner.fireEvent('editorevent', this, e);
41712 // this.updateToolbar();
41713 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41716 insertTag : function(tg)
41718 // could be a bit smarter... -> wrap the current selected tRoo..
41719 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41721 range = this.createRange(this.getSelection());
41722 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41723 wrappingNode.appendChild(range.extractContents());
41724 range.insertNode(wrappingNode);
41731 this.execCmd("formatblock", tg);
41735 insertText : function(txt)
41739 var range = this.createRange();
41740 range.deleteContents();
41741 //alert(Sender.getAttribute('label'));
41743 range.insertNode(this.doc.createTextNode(txt));
41749 * Executes a Midas editor command on the editor document and performs necessary focus and
41750 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41751 * @param {String} cmd The Midas command
41752 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41754 relayCmd : function(cmd, value){
41756 this.execCmd(cmd, value);
41757 this.owner.fireEvent('editorevent', this);
41758 //this.updateToolbar();
41759 this.owner.deferFocus();
41763 * Executes a Midas editor command directly on the editor document.
41764 * For visual commands, you should use {@link #relayCmd} instead.
41765 * <b>This should only be called after the editor is initialized.</b>
41766 * @param {String} cmd The Midas command
41767 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41769 execCmd : function(cmd, value){
41770 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41777 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41779 * @param {String} text | dom node..
41781 insertAtCursor : function(text)
41786 if(!this.activated){
41792 var r = this.doc.selection.createRange();
41803 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41807 // from jquery ui (MIT licenced)
41809 var win = this.win;
41811 if (win.getSelection && win.getSelection().getRangeAt) {
41812 range = win.getSelection().getRangeAt(0);
41813 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41814 range.insertNode(node);
41815 } else if (win.document.selection && win.document.selection.createRange) {
41816 // no firefox support
41817 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41818 win.document.selection.createRange().pasteHTML(txt);
41820 // no firefox support
41821 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41822 this.execCmd('InsertHTML', txt);
41831 mozKeyPress : function(e){
41833 var c = e.getCharCode(), cmd;
41836 c = String.fromCharCode(c).toLowerCase();
41850 this.cleanUpPaste.defer(100, this);
41858 e.preventDefault();
41866 fixKeys : function(){ // load time branching for fastest keydown performance
41868 return function(e){
41869 var k = e.getKey(), r;
41872 r = this.doc.selection.createRange();
41875 r.pasteHTML('    ');
41882 r = this.doc.selection.createRange();
41884 var target = r.parentElement();
41885 if(!target || target.tagName.toLowerCase() != 'li'){
41887 r.pasteHTML('<br />');
41893 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41894 this.cleanUpPaste.defer(100, this);
41900 }else if(Roo.isOpera){
41901 return function(e){
41902 var k = e.getKey();
41906 this.execCmd('InsertHTML','    ');
41909 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41910 this.cleanUpPaste.defer(100, this);
41915 }else if(Roo.isSafari){
41916 return function(e){
41917 var k = e.getKey();
41921 this.execCmd('InsertText','\t');
41925 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41926 this.cleanUpPaste.defer(100, this);
41934 getAllAncestors: function()
41936 var p = this.getSelectedNode();
41939 a.push(p); // push blank onto stack..
41940 p = this.getParentElement();
41944 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41948 a.push(this.doc.body);
41952 lastSelNode : false,
41955 getSelection : function()
41957 this.assignDocWin();
41958 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41961 getSelectedNode: function()
41963 // this may only work on Gecko!!!
41965 // should we cache this!!!!
41970 var range = this.createRange(this.getSelection()).cloneRange();
41973 var parent = range.parentElement();
41975 var testRange = range.duplicate();
41976 testRange.moveToElementText(parent);
41977 if (testRange.inRange(range)) {
41980 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41983 parent = parent.parentElement;
41988 // is ancestor a text element.
41989 var ac = range.commonAncestorContainer;
41990 if (ac.nodeType == 3) {
41991 ac = ac.parentNode;
41994 var ar = ac.childNodes;
41997 var other_nodes = [];
41998 var has_other_nodes = false;
41999 for (var i=0;i<ar.length;i++) {
42000 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
42003 // fullly contained node.
42005 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
42010 // probably selected..
42011 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
42012 other_nodes.push(ar[i]);
42016 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
42021 has_other_nodes = true;
42023 if (!nodes.length && other_nodes.length) {
42024 nodes= other_nodes;
42026 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
42032 createRange: function(sel)
42034 // this has strange effects when using with
42035 // top toolbar - not sure if it's a great idea.
42036 //this.editor.contentWindow.focus();
42037 if (typeof sel != "undefined") {
42039 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
42041 return this.doc.createRange();
42044 return this.doc.createRange();
42047 getParentElement: function()
42050 this.assignDocWin();
42051 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
42053 var range = this.createRange(sel);
42056 var p = range.commonAncestorContainer;
42057 while (p.nodeType == 3) { // text node
42068 * Range intersection.. the hard stuff...
42072 * [ -- selected range --- ]
42076 * if end is before start or hits it. fail.
42077 * if start is after end or hits it fail.
42079 * if either hits (but other is outside. - then it's not
42085 // @see http://www.thismuchiknow.co.uk/?p=64.
42086 rangeIntersectsNode : function(range, node)
42088 var nodeRange = node.ownerDocument.createRange();
42090 nodeRange.selectNode(node);
42092 nodeRange.selectNodeContents(node);
42095 var rangeStartRange = range.cloneRange();
42096 rangeStartRange.collapse(true);
42098 var rangeEndRange = range.cloneRange();
42099 rangeEndRange.collapse(false);
42101 var nodeStartRange = nodeRange.cloneRange();
42102 nodeStartRange.collapse(true);
42104 var nodeEndRange = nodeRange.cloneRange();
42105 nodeEndRange.collapse(false);
42107 return rangeStartRange.compareBoundaryPoints(
42108 Range.START_TO_START, nodeEndRange) == -1 &&
42109 rangeEndRange.compareBoundaryPoints(
42110 Range.START_TO_START, nodeStartRange) == 1;
42114 rangeCompareNode : function(range, node)
42116 var nodeRange = node.ownerDocument.createRange();
42118 nodeRange.selectNode(node);
42120 nodeRange.selectNodeContents(node);
42124 range.collapse(true);
42126 nodeRange.collapse(true);
42128 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
42129 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
42131 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
42133 var nodeIsBefore = ss == 1;
42134 var nodeIsAfter = ee == -1;
42136 if (nodeIsBefore && nodeIsAfter) {
42139 if (!nodeIsBefore && nodeIsAfter) {
42140 return 1; //right trailed.
42143 if (nodeIsBefore && !nodeIsAfter) {
42144 return 2; // left trailed.
42150 // private? - in a new class?
42151 cleanUpPaste : function()
42153 // cleans up the whole document..
42154 Roo.log('cleanuppaste');
42156 this.cleanUpChildren(this.doc.body);
42157 var clean = this.cleanWordChars(this.doc.body.innerHTML);
42158 if (clean != this.doc.body.innerHTML) {
42159 this.doc.body.innerHTML = clean;
42164 cleanWordChars : function(input) {// change the chars to hex code
42165 var he = Roo.HtmlEditorCore;
42167 var output = input;
42168 Roo.each(he.swapCodes, function(sw) {
42169 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
42171 output = output.replace(swapper, sw[1]);
42178 cleanUpChildren : function (n)
42180 if (!n.childNodes.length) {
42183 for (var i = n.childNodes.length-1; i > -1 ; i--) {
42184 this.cleanUpChild(n.childNodes[i]);
42191 cleanUpChild : function (node)
42194 //console.log(node);
42195 if (node.nodeName == "#text") {
42196 // clean up silly Windows -- stuff?
42199 if (node.nodeName == "#comment") {
42200 node.parentNode.removeChild(node);
42201 // clean up silly Windows -- stuff?
42204 var lcname = node.tagName.toLowerCase();
42205 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
42206 // whitelist of tags..
42208 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
42210 node.parentNode.removeChild(node);
42215 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
42217 // remove <a name=....> as rendering on yahoo mailer is borked with this.
42218 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
42220 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
42221 // remove_keep_children = true;
42224 if (remove_keep_children) {
42225 this.cleanUpChildren(node);
42226 // inserts everything just before this node...
42227 while (node.childNodes.length) {
42228 var cn = node.childNodes[0];
42229 node.removeChild(cn);
42230 node.parentNode.insertBefore(cn, node);
42232 node.parentNode.removeChild(node);
42236 if (!node.attributes || !node.attributes.length) {
42237 this.cleanUpChildren(node);
42241 function cleanAttr(n,v)
42244 if (v.match(/^\./) || v.match(/^\//)) {
42247 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
42250 if (v.match(/^#/)) {
42253 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
42254 node.removeAttribute(n);
42258 var cwhite = this.cwhite;
42259 var cblack = this.cblack;
42261 function cleanStyle(n,v)
42263 if (v.match(/expression/)) { //XSS?? should we even bother..
42264 node.removeAttribute(n);
42268 var parts = v.split(/;/);
42271 Roo.each(parts, function(p) {
42272 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42276 var l = p.split(':').shift().replace(/\s+/g,'');
42277 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42279 if ( cwhite.length && cblack.indexOf(l) > -1) {
42280 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42281 //node.removeAttribute(n);
42285 // only allow 'c whitelisted system attributes'
42286 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42287 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42288 //node.removeAttribute(n);
42298 if (clean.length) {
42299 node.setAttribute(n, clean.join(';'));
42301 node.removeAttribute(n);
42307 for (var i = node.attributes.length-1; i > -1 ; i--) {
42308 var a = node.attributes[i];
42311 if (a.name.toLowerCase().substr(0,2)=='on') {
42312 node.removeAttribute(a.name);
42315 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42316 node.removeAttribute(a.name);
42319 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42320 cleanAttr(a.name,a.value); // fixme..
42323 if (a.name == 'style') {
42324 cleanStyle(a.name,a.value);
42327 /// clean up MS crap..
42328 // tecnically this should be a list of valid class'es..
42331 if (a.name == 'class') {
42332 if (a.value.match(/^Mso/)) {
42333 node.className = '';
42336 if (a.value.match(/body/)) {
42337 node.className = '';
42348 this.cleanUpChildren(node);
42354 * Clean up MS wordisms...
42356 cleanWord : function(node)
42361 this.cleanWord(this.doc.body);
42364 if (node.nodeName == "#text") {
42365 // clean up silly Windows -- stuff?
42368 if (node.nodeName == "#comment") {
42369 node.parentNode.removeChild(node);
42370 // clean up silly Windows -- stuff?
42374 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42375 node.parentNode.removeChild(node);
42379 // remove - but keep children..
42380 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42381 while (node.childNodes.length) {
42382 var cn = node.childNodes[0];
42383 node.removeChild(cn);
42384 node.parentNode.insertBefore(cn, node);
42386 node.parentNode.removeChild(node);
42387 this.iterateChildren(node, this.cleanWord);
42391 if (node.className.length) {
42393 var cn = node.className.split(/\W+/);
42395 Roo.each(cn, function(cls) {
42396 if (cls.match(/Mso[a-zA-Z]+/)) {
42401 node.className = cna.length ? cna.join(' ') : '';
42403 node.removeAttribute("class");
42407 if (node.hasAttribute("lang")) {
42408 node.removeAttribute("lang");
42411 if (node.hasAttribute("style")) {
42413 var styles = node.getAttribute("style").split(";");
42415 Roo.each(styles, function(s) {
42416 if (!s.match(/:/)) {
42419 var kv = s.split(":");
42420 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42423 // what ever is left... we allow.
42426 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42427 if (!nstyle.length) {
42428 node.removeAttribute('style');
42431 this.iterateChildren(node, this.cleanWord);
42437 * iterateChildren of a Node, calling fn each time, using this as the scole..
42438 * @param {DomNode} node node to iterate children of.
42439 * @param {Function} fn method of this class to call on each item.
42441 iterateChildren : function(node, fn)
42443 if (!node.childNodes.length) {
42446 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42447 fn.call(this, node.childNodes[i])
42453 * cleanTableWidths.
42455 * Quite often pasting from word etc.. results in tables with column and widths.
42456 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
42459 cleanTableWidths : function(node)
42464 this.cleanTableWidths(this.doc.body);
42469 if (node.nodeName == "#text" || node.nodeName == "#comment") {
42472 Roo.log(node.tagName);
42473 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
42474 this.iterateChildren(node, this.cleanTableWidths);
42477 if (node.hasAttribute('width')) {
42478 node.removeAttribute('width');
42482 if (node.hasAttribute("style")) {
42485 var styles = node.getAttribute("style").split(";");
42487 Roo.each(styles, function(s) {
42488 if (!s.match(/:/)) {
42491 var kv = s.split(":");
42492 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
42495 // what ever is left... we allow.
42498 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42499 if (!nstyle.length) {
42500 node.removeAttribute('style');
42504 this.iterateChildren(node, this.cleanTableWidths);
42512 domToHTML : function(currentElement, depth, nopadtext) {
42514 depth = depth || 0;
42515 nopadtext = nopadtext || false;
42517 if (!currentElement) {
42518 return this.domToHTML(this.doc.body);
42521 //Roo.log(currentElement);
42523 var allText = false;
42524 var nodeName = currentElement.nodeName;
42525 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42527 if (nodeName == '#text') {
42529 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
42534 if (nodeName != 'BODY') {
42537 // Prints the node tagName, such as <A>, <IMG>, etc
42540 for(i = 0; i < currentElement.attributes.length;i++) {
42542 var aname = currentElement.attributes.item(i).name;
42543 if (!currentElement.attributes.item(i).value.length) {
42546 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42549 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42558 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42561 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42566 // Traverse the tree
42568 var currentElementChild = currentElement.childNodes.item(i);
42569 var allText = true;
42570 var innerHTML = '';
42572 while (currentElementChild) {
42573 // Formatting code (indent the tree so it looks nice on the screen)
42574 var nopad = nopadtext;
42575 if (lastnode == 'SPAN') {
42579 if (currentElementChild.nodeName == '#text') {
42580 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42581 toadd = nopadtext ? toadd : toadd.trim();
42582 if (!nopad && toadd.length > 80) {
42583 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42585 innerHTML += toadd;
42588 currentElementChild = currentElement.childNodes.item(i);
42594 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42596 // Recursively traverse the tree structure of the child node
42597 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42598 lastnode = currentElementChild.nodeName;
42600 currentElementChild=currentElement.childNodes.item(i);
42606 // The remaining code is mostly for formatting the tree
42607 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42612 ret+= "</"+tagName+">";
42618 applyBlacklists : function()
42620 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
42621 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
42625 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
42626 if (b.indexOf(tag) > -1) {
42629 this.white.push(tag);
42633 Roo.each(w, function(tag) {
42634 if (b.indexOf(tag) > -1) {
42637 if (this.white.indexOf(tag) > -1) {
42640 this.white.push(tag);
42645 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
42646 if (w.indexOf(tag) > -1) {
42649 this.black.push(tag);
42653 Roo.each(b, function(tag) {
42654 if (w.indexOf(tag) > -1) {
42657 if (this.black.indexOf(tag) > -1) {
42660 this.black.push(tag);
42665 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
42666 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
42670 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
42671 if (b.indexOf(tag) > -1) {
42674 this.cwhite.push(tag);
42678 Roo.each(w, function(tag) {
42679 if (b.indexOf(tag) > -1) {
42682 if (this.cwhite.indexOf(tag) > -1) {
42685 this.cwhite.push(tag);
42690 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
42691 if (w.indexOf(tag) > -1) {
42694 this.cblack.push(tag);
42698 Roo.each(b, function(tag) {
42699 if (w.indexOf(tag) > -1) {
42702 if (this.cblack.indexOf(tag) > -1) {
42705 this.cblack.push(tag);
42710 setStylesheets : function(stylesheets)
42712 if(typeof(stylesheets) == 'string'){
42713 Roo.get(this.iframe.contentDocument.head).createChild({
42715 rel : 'stylesheet',
42724 Roo.each(stylesheets, function(s) {
42729 Roo.get(_this.iframe.contentDocument.head).createChild({
42731 rel : 'stylesheet',
42740 removeStylesheets : function()
42744 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
42749 // hide stuff that is not compatible
42763 * @event specialkey
42767 * @cfg {String} fieldClass @hide
42770 * @cfg {String} focusClass @hide
42773 * @cfg {String} autoCreate @hide
42776 * @cfg {String} inputType @hide
42779 * @cfg {String} invalidClass @hide
42782 * @cfg {String} invalidText @hide
42785 * @cfg {String} msgFx @hide
42788 * @cfg {String} validateOnBlur @hide
42792 Roo.HtmlEditorCore.white = [
42793 'area', 'br', 'img', 'input', 'hr', 'wbr',
42795 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42796 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42797 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42798 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42799 'table', 'ul', 'xmp',
42801 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42804 'dir', 'menu', 'ol', 'ul', 'dl',
42810 Roo.HtmlEditorCore.black = [
42811 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42813 'base', 'basefont', 'bgsound', 'blink', 'body',
42814 'frame', 'frameset', 'head', 'html', 'ilayer',
42815 'iframe', 'layer', 'link', 'meta', 'object',
42816 'script', 'style' ,'title', 'xml' // clean later..
42818 Roo.HtmlEditorCore.clean = [
42819 'script', 'style', 'title', 'xml'
42821 Roo.HtmlEditorCore.remove = [
42826 Roo.HtmlEditorCore.ablack = [
42830 Roo.HtmlEditorCore.aclean = [
42831 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42835 Roo.HtmlEditorCore.pwhite= [
42836 'http', 'https', 'mailto'
42839 // white listed style attributes.
42840 Roo.HtmlEditorCore.cwhite= [
42841 // 'text-align', /// default is to allow most things..
42847 // black listed style attributes.
42848 Roo.HtmlEditorCore.cblack= [
42849 // 'font-size' -- this can be set by the project
42853 Roo.HtmlEditorCore.swapCodes =[
42864 //<script type="text/javascript">
42867 * Ext JS Library 1.1.1
42868 * Copyright(c) 2006-2007, Ext JS, LLC.
42874 Roo.form.HtmlEditor = function(config){
42878 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42880 if (!this.toolbars) {
42881 this.toolbars = [];
42883 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42889 * @class Roo.form.HtmlEditor
42890 * @extends Roo.form.Field
42891 * Provides a lightweight HTML Editor component.
42893 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42895 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42896 * supported by this editor.</b><br/><br/>
42897 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42898 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42900 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42902 * @cfg {Boolean} clearUp
42906 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42911 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42916 * @cfg {Number} height (in pixels)
42920 * @cfg {Number} width (in pixels)
42925 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42928 stylesheets: false,
42932 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
42937 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
42943 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
42948 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
42956 // private properties
42957 validationEvent : false,
42959 initialized : false,
42962 onFocus : Roo.emptyFn,
42964 hideMode:'offsets',
42966 actionMode : 'container', // defaults to hiding it...
42968 defaultAutoCreate : { // modified by initCompnoent..
42970 style:"width:500px;height:300px;",
42971 autocomplete: "new-password"
42975 initComponent : function(){
42978 * @event initialize
42979 * Fires when the editor is fully initialized (including the iframe)
42980 * @param {HtmlEditor} this
42985 * Fires when the editor is first receives the focus. Any insertion must wait
42986 * until after this event.
42987 * @param {HtmlEditor} this
42991 * @event beforesync
42992 * Fires before the textarea is updated with content from the editor iframe. Return false
42993 * to cancel the sync.
42994 * @param {HtmlEditor} this
42995 * @param {String} html
42999 * @event beforepush
43000 * Fires before the iframe editor is updated with content from the textarea. Return false
43001 * to cancel the push.
43002 * @param {HtmlEditor} this
43003 * @param {String} html
43008 * Fires when the textarea is updated with content from the editor iframe.
43009 * @param {HtmlEditor} this
43010 * @param {String} html
43015 * Fires when the iframe editor is updated with content from the textarea.
43016 * @param {HtmlEditor} this
43017 * @param {String} html
43021 * @event editmodechange
43022 * Fires when the editor switches edit modes
43023 * @param {HtmlEditor} this
43024 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
43026 editmodechange: true,
43028 * @event editorevent
43029 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
43030 * @param {HtmlEditor} this
43034 * @event firstfocus
43035 * Fires when on first focus - needed by toolbars..
43036 * @param {HtmlEditor} this
43041 * Auto save the htmlEditor value as a file into Events
43042 * @param {HtmlEditor} this
43046 * @event savedpreview
43047 * preview the saved version of htmlEditor
43048 * @param {HtmlEditor} this
43050 savedpreview: true,
43053 * @event stylesheetsclick
43054 * Fires when press the Sytlesheets button
43055 * @param {Roo.HtmlEditorCore} this
43057 stylesheetsclick: true
43059 this.defaultAutoCreate = {
43061 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
43062 autocomplete: "new-password"
43067 * Protected method that will not generally be called directly. It
43068 * is called when the editor creates its toolbar. Override this method if you need to
43069 * add custom toolbar buttons.
43070 * @param {HtmlEditor} editor
43072 createToolbar : function(editor){
43073 Roo.log("create toolbars");
43074 if (!editor.toolbars || !editor.toolbars.length) {
43075 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
43078 for (var i =0 ; i < editor.toolbars.length;i++) {
43079 editor.toolbars[i] = Roo.factory(
43080 typeof(editor.toolbars[i]) == 'string' ?
43081 { xtype: editor.toolbars[i]} : editor.toolbars[i],
43082 Roo.form.HtmlEditor);
43083 editor.toolbars[i].init(editor);
43091 onRender : function(ct, position)
43094 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
43096 this.wrap = this.el.wrap({
43097 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
43100 this.editorcore.onRender(ct, position);
43102 if (this.resizable) {
43103 this.resizeEl = new Roo.Resizable(this.wrap, {
43107 minHeight : this.height,
43108 height: this.height,
43109 handles : this.resizable,
43112 resize : function(r, w, h) {
43113 _t.onResize(w,h); // -something
43119 this.createToolbar(this);
43123 this.setSize(this.wrap.getSize());
43125 if (this.resizeEl) {
43126 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
43127 // should trigger onReize..
43130 this.keyNav = new Roo.KeyNav(this.el, {
43132 "tab" : function(e){
43133 e.preventDefault();
43135 var value = this.getValue();
43137 var start = this.el.dom.selectionStart;
43138 var end = this.el.dom.selectionEnd;
43142 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
43143 this.el.dom.setSelectionRange(end + 1, end + 1);
43147 var f = value.substring(0, start).split("\t");
43149 if(f.pop().length != 0){
43153 this.setValue(f.join("\t") + value.substring(end));
43154 this.el.dom.setSelectionRange(start - 1, start - 1);
43158 "home" : function(e){
43159 e.preventDefault();
43161 var curr = this.el.dom.selectionStart;
43162 var lines = this.getValue().split("\n");
43169 this.el.dom.setSelectionRange(0, 0);
43175 for (var i = 0; i < lines.length;i++) {
43176 pos += lines[i].length;
43186 pos -= lines[i].length;
43192 this.el.dom.setSelectionRange(pos, pos);
43196 this.el.dom.selectionStart = pos;
43197 this.el.dom.selectionEnd = curr;
43200 "end" : function(e){
43201 e.preventDefault();
43203 var curr = this.el.dom.selectionStart;
43204 var lines = this.getValue().split("\n");
43211 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
43217 for (var i = 0; i < lines.length;i++) {
43219 pos += lines[i].length;
43233 this.el.dom.setSelectionRange(pos, pos);
43237 this.el.dom.selectionStart = curr;
43238 this.el.dom.selectionEnd = pos;
43243 doRelay : function(foo, bar, hname){
43244 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
43250 // if(this.autosave && this.w){
43251 // this.autoSaveFn = setInterval(this.autosave, 1000);
43256 onResize : function(w, h)
43258 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
43263 if(typeof w == 'number'){
43264 var aw = w - this.wrap.getFrameWidth('lr');
43265 this.el.setWidth(this.adjustWidth('textarea', aw));
43268 if(typeof h == 'number'){
43270 for (var i =0; i < this.toolbars.length;i++) {
43271 // fixme - ask toolbars for heights?
43272 tbh += this.toolbars[i].tb.el.getHeight();
43273 if (this.toolbars[i].footer) {
43274 tbh += this.toolbars[i].footer.el.getHeight();
43281 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
43282 ah -= 5; // knock a few pixes off for look..
43284 this.el.setHeight(this.adjustWidth('textarea', ah));
43288 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
43289 this.editorcore.onResize(ew,eh);
43294 * Toggles the editor between standard and source edit mode.
43295 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43297 toggleSourceEdit : function(sourceEditMode)
43299 this.editorcore.toggleSourceEdit(sourceEditMode);
43301 if(this.editorcore.sourceEditMode){
43302 Roo.log('editor - showing textarea');
43305 // Roo.log(this.syncValue());
43306 this.editorcore.syncValue();
43307 this.el.removeClass('x-hidden');
43308 this.el.dom.removeAttribute('tabIndex');
43311 for (var i = 0; i < this.toolbars.length; i++) {
43312 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43313 this.toolbars[i].tb.hide();
43314 this.toolbars[i].footer.hide();
43319 Roo.log('editor - hiding textarea');
43321 // Roo.log(this.pushValue());
43322 this.editorcore.pushValue();
43324 this.el.addClass('x-hidden');
43325 this.el.dom.setAttribute('tabIndex', -1);
43327 for (var i = 0; i < this.toolbars.length; i++) {
43328 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43329 this.toolbars[i].tb.show();
43330 this.toolbars[i].footer.show();
43334 //this.deferFocus();
43337 this.setSize(this.wrap.getSize());
43338 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
43340 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
43343 // private (for BoxComponent)
43344 adjustSize : Roo.BoxComponent.prototype.adjustSize,
43346 // private (for BoxComponent)
43347 getResizeEl : function(){
43351 // private (for BoxComponent)
43352 getPositionEl : function(){
43357 initEvents : function(){
43358 this.originalValue = this.getValue();
43362 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43365 markInvalid : Roo.emptyFn,
43367 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43370 clearInvalid : Roo.emptyFn,
43372 setValue : function(v){
43373 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
43374 this.editorcore.pushValue();
43379 deferFocus : function(){
43380 this.focus.defer(10, this);
43384 focus : function(){
43385 this.editorcore.focus();
43391 onDestroy : function(){
43397 for (var i =0; i < this.toolbars.length;i++) {
43398 // fixme - ask toolbars for heights?
43399 this.toolbars[i].onDestroy();
43402 this.wrap.dom.innerHTML = '';
43403 this.wrap.remove();
43408 onFirstFocus : function(){
43409 //Roo.log("onFirstFocus");
43410 this.editorcore.onFirstFocus();
43411 for (var i =0; i < this.toolbars.length;i++) {
43412 this.toolbars[i].onFirstFocus();
43418 syncValue : function()
43420 this.editorcore.syncValue();
43423 pushValue : function()
43425 this.editorcore.pushValue();
43428 setStylesheets : function(stylesheets)
43430 this.editorcore.setStylesheets(stylesheets);
43433 removeStylesheets : function()
43435 this.editorcore.removeStylesheets();
43439 // hide stuff that is not compatible
43453 * @event specialkey
43457 * @cfg {String} fieldClass @hide
43460 * @cfg {String} focusClass @hide
43463 * @cfg {String} autoCreate @hide
43466 * @cfg {String} inputType @hide
43469 * @cfg {String} invalidClass @hide
43472 * @cfg {String} invalidText @hide
43475 * @cfg {String} msgFx @hide
43478 * @cfg {String} validateOnBlur @hide
43482 // <script type="text/javascript">
43485 * Ext JS Library 1.1.1
43486 * Copyright(c) 2006-2007, Ext JS, LLC.
43492 * @class Roo.form.HtmlEditorToolbar1
43497 new Roo.form.HtmlEditor({
43500 new Roo.form.HtmlEditorToolbar1({
43501 disable : { fonts: 1 , format: 1, ..., ... , ...],
43507 * @cfg {Object} disable List of elements to disable..
43508 * @cfg {Array} btns List of additional buttons.
43512 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
43515 Roo.form.HtmlEditor.ToolbarStandard = function(config)
43518 Roo.apply(this, config);
43520 // default disabled, based on 'good practice'..
43521 this.disable = this.disable || {};
43522 Roo.applyIf(this.disable, {
43525 specialElements : true
43529 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43530 // dont call parent... till later.
43533 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
43540 editorcore : false,
43542 * @cfg {Object} disable List of toolbar elements to disable
43549 * @cfg {String} createLinkText The default text for the create link prompt
43551 createLinkText : 'Please enter the URL for the link:',
43553 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
43555 defaultLinkValue : 'http:/'+'/',
43559 * @cfg {Array} fontFamilies An array of available font families
43577 // "á" , ?? a acute?
43582 "°" // , // degrees
43584 // "é" , // e ecute
43585 // "ú" , // u ecute?
43588 specialElements : [
43590 text: "Insert Table",
43593 ihtml : '<table><tr><td>Cell</td></tr></table>'
43597 text: "Insert Image",
43600 ihtml : '<img src="about:blank"/>'
43609 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
43610 "input:submit", "input:button", "select", "textarea", "label" ],
43613 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
43615 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
43623 * @cfg {String} defaultFont default font to use.
43625 defaultFont: 'tahoma',
43627 fontSelect : false,
43630 formatCombo : false,
43632 init : function(editor)
43634 this.editor = editor;
43635 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43636 var editorcore = this.editorcore;
43640 var fid = editorcore.frameId;
43642 function btn(id, toggle, handler){
43643 var xid = fid + '-'+ id ;
43647 cls : 'x-btn-icon x-edit-'+id,
43648 enableToggle:toggle !== false,
43649 scope: _t, // was editor...
43650 handler:handler||_t.relayBtnCmd,
43651 clickEvent:'mousedown',
43652 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43659 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43661 // stop form submits
43662 tb.el.on('click', function(e){
43663 e.preventDefault(); // what does this do?
43666 if(!this.disable.font) { // && !Roo.isSafari){
43667 /* why no safari for fonts
43668 editor.fontSelect = tb.el.createChild({
43671 cls:'x-font-select',
43672 html: this.createFontOptions()
43675 editor.fontSelect.on('change', function(){
43676 var font = editor.fontSelect.dom.value;
43677 editor.relayCmd('fontname', font);
43678 editor.deferFocus();
43682 editor.fontSelect.dom,
43688 if(!this.disable.formats){
43689 this.formatCombo = new Roo.form.ComboBox({
43690 store: new Roo.data.SimpleStore({
43693 data : this.formats // from states.js
43697 //autoCreate : {tag: "div", size: "20"},
43698 displayField:'tag',
43702 triggerAction: 'all',
43703 emptyText:'Add tag',
43704 selectOnFocus:true,
43707 'select': function(c, r, i) {
43708 editorcore.insertTag(r.get('tag'));
43714 tb.addField(this.formatCombo);
43718 if(!this.disable.format){
43723 btn('strikethrough')
43726 if(!this.disable.fontSize){
43731 btn('increasefontsize', false, editorcore.adjustFont),
43732 btn('decreasefontsize', false, editorcore.adjustFont)
43737 if(!this.disable.colors){
43740 id:editorcore.frameId +'-forecolor',
43741 cls:'x-btn-icon x-edit-forecolor',
43742 clickEvent:'mousedown',
43743 tooltip: this.buttonTips['forecolor'] || undefined,
43745 menu : new Roo.menu.ColorMenu({
43746 allowReselect: true,
43747 focus: Roo.emptyFn,
43750 selectHandler: function(cp, color){
43751 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43752 editor.deferFocus();
43755 clickEvent:'mousedown'
43758 id:editorcore.frameId +'backcolor',
43759 cls:'x-btn-icon x-edit-backcolor',
43760 clickEvent:'mousedown',
43761 tooltip: this.buttonTips['backcolor'] || undefined,
43763 menu : new Roo.menu.ColorMenu({
43764 focus: Roo.emptyFn,
43767 allowReselect: true,
43768 selectHandler: function(cp, color){
43770 editorcore.execCmd('useCSS', false);
43771 editorcore.execCmd('hilitecolor', color);
43772 editorcore.execCmd('useCSS', true);
43773 editor.deferFocus();
43775 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43776 Roo.isSafari || Roo.isIE ? '#'+color : color);
43777 editor.deferFocus();
43781 clickEvent:'mousedown'
43786 // now add all the items...
43789 if(!this.disable.alignments){
43792 btn('justifyleft'),
43793 btn('justifycenter'),
43794 btn('justifyright')
43798 //if(!Roo.isSafari){
43799 if(!this.disable.links){
43802 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43806 if(!this.disable.lists){
43809 btn('insertorderedlist'),
43810 btn('insertunorderedlist')
43813 if(!this.disable.sourceEdit){
43816 btn('sourceedit', true, function(btn){
43817 this.toggleSourceEdit(btn.pressed);
43824 // special menu.. - needs to be tidied up..
43825 if (!this.disable.special) {
43828 cls: 'x-edit-none',
43834 for (var i =0; i < this.specialChars.length; i++) {
43835 smenu.menu.items.push({
43837 html: this.specialChars[i],
43838 handler: function(a,b) {
43839 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43840 //editor.insertAtCursor(a.html);
43854 if (!this.disable.cleanStyles) {
43856 cls: 'x-btn-icon x-btn-clear',
43862 for (var i =0; i < this.cleanStyles.length; i++) {
43863 cmenu.menu.items.push({
43864 actiontype : this.cleanStyles[i],
43865 html: 'Remove ' + this.cleanStyles[i],
43866 handler: function(a,b) {
43869 var c = Roo.get(editorcore.doc.body);
43870 c.select('[style]').each(function(s) {
43871 s.dom.style.removeProperty(a.actiontype);
43873 editorcore.syncValue();
43878 cmenu.menu.items.push({
43879 actiontype : 'tablewidths',
43880 html: 'Remove Table Widths',
43881 handler: function(a,b) {
43882 editorcore.cleanTableWidths();
43883 editorcore.syncValue();
43887 cmenu.menu.items.push({
43888 actiontype : 'word',
43889 html: 'Remove MS Word Formating',
43890 handler: function(a,b) {
43891 editorcore.cleanWord();
43892 editorcore.syncValue();
43897 cmenu.menu.items.push({
43898 actiontype : 'all',
43899 html: 'Remove All Styles',
43900 handler: function(a,b) {
43902 var c = Roo.get(editorcore.doc.body);
43903 c.select('[style]').each(function(s) {
43904 s.dom.removeAttribute('style');
43906 editorcore.syncValue();
43911 cmenu.menu.items.push({
43912 actiontype : 'all',
43913 html: 'Remove All CSS Classes',
43914 handler: function(a,b) {
43916 var c = Roo.get(editorcore.doc.body);
43917 c.select('[class]').each(function(s) {
43918 s.dom.className = '';
43920 editorcore.syncValue();
43925 cmenu.menu.items.push({
43926 actiontype : 'tidy',
43927 html: 'Tidy HTML Source',
43928 handler: function(a,b) {
43929 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43930 editorcore.syncValue();
43939 if (!this.disable.specialElements) {
43942 cls: 'x-edit-none',
43947 for (var i =0; i < this.specialElements.length; i++) {
43948 semenu.menu.items.push(
43950 handler: function(a,b) {
43951 editor.insertAtCursor(this.ihtml);
43953 }, this.specialElements[i])
43965 for(var i =0; i< this.btns.length;i++) {
43966 var b = Roo.factory(this.btns[i],Roo.form);
43967 b.cls = 'x-edit-none';
43969 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
43970 b.cls += ' x-init-enable';
43973 b.scope = editorcore;
43981 // disable everything...
43983 this.tb.items.each(function(item){
43986 item.id != editorcore.frameId+ '-sourceedit' &&
43987 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
43993 this.rendered = true;
43995 // the all the btns;
43996 editor.on('editorevent', this.updateToolbar, this);
43997 // other toolbars need to implement this..
43998 //editor.on('editmodechange', this.updateToolbar, this);
44002 relayBtnCmd : function(btn) {
44003 this.editorcore.relayCmd(btn.cmd);
44005 // private used internally
44006 createLink : function(){
44007 Roo.log("create link?");
44008 var url = prompt(this.createLinkText, this.defaultLinkValue);
44009 if(url && url != 'http:/'+'/'){
44010 this.editorcore.relayCmd('createlink', url);
44016 * Protected method that will not generally be called directly. It triggers
44017 * a toolbar update by reading the markup state of the current selection in the editor.
44019 updateToolbar: function(){
44021 if(!this.editorcore.activated){
44022 this.editor.onFirstFocus();
44026 var btns = this.tb.items.map,
44027 doc = this.editorcore.doc,
44028 frameId = this.editorcore.frameId;
44030 if(!this.disable.font && !Roo.isSafari){
44032 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
44033 if(name != this.fontSelect.dom.value){
44034 this.fontSelect.dom.value = name;
44038 if(!this.disable.format){
44039 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
44040 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
44041 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
44042 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
44044 if(!this.disable.alignments){
44045 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
44046 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
44047 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
44049 if(!Roo.isSafari && !this.disable.lists){
44050 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
44051 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
44054 var ans = this.editorcore.getAllAncestors();
44055 if (this.formatCombo) {
44058 var store = this.formatCombo.store;
44059 this.formatCombo.setValue("");
44060 for (var i =0; i < ans.length;i++) {
44061 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
44063 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
44071 // hides menus... - so this cant be on a menu...
44072 Roo.menu.MenuMgr.hideAll();
44074 //this.editorsyncValue();
44078 createFontOptions : function(){
44079 var buf = [], fs = this.fontFamilies, ff, lc;
44083 for(var i = 0, len = fs.length; i< len; i++){
44085 lc = ff.toLowerCase();
44087 '<option value="',lc,'" style="font-family:',ff,';"',
44088 (this.defaultFont == lc ? ' selected="true">' : '>'),
44093 return buf.join('');
44096 toggleSourceEdit : function(sourceEditMode){
44098 Roo.log("toolbar toogle");
44099 if(sourceEditMode === undefined){
44100 sourceEditMode = !this.sourceEditMode;
44102 this.sourceEditMode = sourceEditMode === true;
44103 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
44104 // just toggle the button?
44105 if(btn.pressed !== this.sourceEditMode){
44106 btn.toggle(this.sourceEditMode);
44110 if(sourceEditMode){
44111 Roo.log("disabling buttons");
44112 this.tb.items.each(function(item){
44113 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
44119 Roo.log("enabling buttons");
44120 if(this.editorcore.initialized){
44121 this.tb.items.each(function(item){
44127 Roo.log("calling toggole on editor");
44128 // tell the editor that it's been pressed..
44129 this.editor.toggleSourceEdit(sourceEditMode);
44133 * Object collection of toolbar tooltips for the buttons in the editor. The key
44134 * is the command id associated with that button and the value is a valid QuickTips object.
44139 title: 'Bold (Ctrl+B)',
44140 text: 'Make the selected text bold.',
44141 cls: 'x-html-editor-tip'
44144 title: 'Italic (Ctrl+I)',
44145 text: 'Make the selected text italic.',
44146 cls: 'x-html-editor-tip'
44154 title: 'Bold (Ctrl+B)',
44155 text: 'Make the selected text bold.',
44156 cls: 'x-html-editor-tip'
44159 title: 'Italic (Ctrl+I)',
44160 text: 'Make the selected text italic.',
44161 cls: 'x-html-editor-tip'
44164 title: 'Underline (Ctrl+U)',
44165 text: 'Underline the selected text.',
44166 cls: 'x-html-editor-tip'
44169 title: 'Strikethrough',
44170 text: 'Strikethrough the selected text.',
44171 cls: 'x-html-editor-tip'
44173 increasefontsize : {
44174 title: 'Grow Text',
44175 text: 'Increase the font size.',
44176 cls: 'x-html-editor-tip'
44178 decreasefontsize : {
44179 title: 'Shrink Text',
44180 text: 'Decrease the font size.',
44181 cls: 'x-html-editor-tip'
44184 title: 'Text Highlight Color',
44185 text: 'Change the background color of the selected text.',
44186 cls: 'x-html-editor-tip'
44189 title: 'Font Color',
44190 text: 'Change the color of the selected text.',
44191 cls: 'x-html-editor-tip'
44194 title: 'Align Text Left',
44195 text: 'Align text to the left.',
44196 cls: 'x-html-editor-tip'
44199 title: 'Center Text',
44200 text: 'Center text in the editor.',
44201 cls: 'x-html-editor-tip'
44204 title: 'Align Text Right',
44205 text: 'Align text to the right.',
44206 cls: 'x-html-editor-tip'
44208 insertunorderedlist : {
44209 title: 'Bullet List',
44210 text: 'Start a bulleted list.',
44211 cls: 'x-html-editor-tip'
44213 insertorderedlist : {
44214 title: 'Numbered List',
44215 text: 'Start a numbered list.',
44216 cls: 'x-html-editor-tip'
44219 title: 'Hyperlink',
44220 text: 'Make the selected text a hyperlink.',
44221 cls: 'x-html-editor-tip'
44224 title: 'Source Edit',
44225 text: 'Switch to source editing mode.',
44226 cls: 'x-html-editor-tip'
44230 onDestroy : function(){
44233 this.tb.items.each(function(item){
44235 item.menu.removeAll();
44237 item.menu.el.destroy();
44245 onFirstFocus: function() {
44246 this.tb.items.each(function(item){
44255 // <script type="text/javascript">
44258 * Ext JS Library 1.1.1
44259 * Copyright(c) 2006-2007, Ext JS, LLC.
44266 * @class Roo.form.HtmlEditor.ToolbarContext
44271 new Roo.form.HtmlEditor({
44274 { xtype: 'ToolbarStandard', styles : {} }
44275 { xtype: 'ToolbarContext', disable : {} }
44281 * @config : {Object} disable List of elements to disable.. (not done yet.)
44282 * @config : {Object} styles Map of styles available.
44286 Roo.form.HtmlEditor.ToolbarContext = function(config)
44289 Roo.apply(this, config);
44290 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44291 // dont call parent... till later.
44292 this.styles = this.styles || {};
44297 Roo.form.HtmlEditor.ToolbarContext.types = {
44309 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
44375 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
44380 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
44390 style : 'fontFamily',
44391 displayField: 'display',
44392 optname : 'font-family',
44441 // should we really allow this??
44442 // should this just be
44453 style : 'fontFamily',
44454 displayField: 'display',
44455 optname : 'font-family',
44462 style : 'fontFamily',
44463 displayField: 'display',
44464 optname : 'font-family',
44471 style : 'fontFamily',
44472 displayField: 'display',
44473 optname : 'font-family',
44484 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
44485 Roo.form.HtmlEditor.ToolbarContext.stores = false;
44487 Roo.form.HtmlEditor.ToolbarContext.options = {
44489 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
44490 [ 'Courier New', 'Courier New'],
44491 [ 'Tahoma', 'Tahoma'],
44492 [ 'Times New Roman,serif', 'Times'],
44493 [ 'Verdana','Verdana' ]
44497 // fixme - these need to be configurable..
44500 //Roo.form.HtmlEditor.ToolbarContext.types
44503 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
44510 editorcore : false,
44512 * @cfg {Object} disable List of toolbar elements to disable
44517 * @cfg {Object} styles List of styles
44518 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
44520 * These must be defined in the page, so they get rendered correctly..
44531 init : function(editor)
44533 this.editor = editor;
44534 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44535 var editorcore = this.editorcore;
44537 var fid = editorcore.frameId;
44539 function btn(id, toggle, handler){
44540 var xid = fid + '-'+ id ;
44544 cls : 'x-btn-icon x-edit-'+id,
44545 enableToggle:toggle !== false,
44546 scope: editorcore, // was editor...
44547 handler:handler||editorcore.relayBtnCmd,
44548 clickEvent:'mousedown',
44549 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44553 // create a new element.
44554 var wdiv = editor.wrap.createChild({
44556 }, editor.wrap.dom.firstChild.nextSibling, true);
44558 // can we do this more than once??
44560 // stop form submits
44563 // disable everything...
44564 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44565 this.toolbars = {};
44567 for (var i in ty) {
44569 this.toolbars[i] = this.buildToolbar(ty[i],i);
44571 this.tb = this.toolbars.BODY;
44573 this.buildFooter();
44574 this.footer.show();
44575 editor.on('hide', function( ) { this.footer.hide() }, this);
44576 editor.on('show', function( ) { this.footer.show() }, this);
44579 this.rendered = true;
44581 // the all the btns;
44582 editor.on('editorevent', this.updateToolbar, this);
44583 // other toolbars need to implement this..
44584 //editor.on('editmodechange', this.updateToolbar, this);
44590 * Protected method that will not generally be called directly. It triggers
44591 * a toolbar update by reading the markup state of the current selection in the editor.
44593 * Note you can force an update by calling on('editorevent', scope, false)
44595 updateToolbar: function(editor,ev,sel){
44598 // capture mouse up - this is handy for selecting images..
44599 // perhaps should go somewhere else...
44600 if(!this.editorcore.activated){
44601 this.editor.onFirstFocus();
44607 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
44608 // selectNode - might want to handle IE?
44610 (ev.type == 'mouseup' || ev.type == 'click' ) &&
44611 ev.target && ev.target.tagName == 'IMG') {
44612 // they have click on an image...
44613 // let's see if we can change the selection...
44616 var nodeRange = sel.ownerDocument.createRange();
44618 nodeRange.selectNode(sel);
44620 nodeRange.selectNodeContents(sel);
44622 //nodeRange.collapse(true);
44623 var s = this.editorcore.win.getSelection();
44624 s.removeAllRanges();
44625 s.addRange(nodeRange);
44629 var updateFooter = sel ? false : true;
44632 var ans = this.editorcore.getAllAncestors();
44635 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44638 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
44639 sel = sel ? sel : this.editorcore.doc.body;
44640 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
44643 // pick a menu that exists..
44644 var tn = sel.tagName.toUpperCase();
44645 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
44647 tn = sel.tagName.toUpperCase();
44649 var lastSel = this.tb.selectedNode;
44651 this.tb.selectedNode = sel;
44653 // if current menu does not match..
44655 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
44658 ///console.log("show: " + tn);
44659 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
44662 this.tb.items.first().el.innerHTML = tn + ': ';
44665 // update attributes
44666 if (this.tb.fields) {
44667 this.tb.fields.each(function(e) {
44669 e.setValue(sel.style[e.stylename]);
44672 e.setValue(sel.getAttribute(e.attrname));
44676 var hasStyles = false;
44677 for(var i in this.styles) {
44684 var st = this.tb.fields.item(0);
44686 st.store.removeAll();
44689 var cn = sel.className.split(/\s+/);
44692 if (this.styles['*']) {
44694 Roo.each(this.styles['*'], function(v) {
44695 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44698 if (this.styles[tn]) {
44699 Roo.each(this.styles[tn], function(v) {
44700 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44704 st.store.loadData(avs);
44708 // flag our selected Node.
44709 this.tb.selectedNode = sel;
44712 Roo.menu.MenuMgr.hideAll();
44716 if (!updateFooter) {
44717 //this.footDisp.dom.innerHTML = '';
44720 // update the footer
44724 this.footerEls = ans.reverse();
44725 Roo.each(this.footerEls, function(a,i) {
44726 if (!a) { return; }
44727 html += html.length ? ' > ' : '';
44729 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44734 var sz = this.footDisp.up('td').getSize();
44735 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44736 this.footDisp.dom.style.marginLeft = '5px';
44738 this.footDisp.dom.style.overflow = 'hidden';
44740 this.footDisp.dom.innerHTML = html;
44742 //this.editorsyncValue();
44749 onDestroy : function(){
44752 this.tb.items.each(function(item){
44754 item.menu.removeAll();
44756 item.menu.el.destroy();
44764 onFirstFocus: function() {
44765 // need to do this for all the toolbars..
44766 this.tb.items.each(function(item){
44770 buildToolbar: function(tlist, nm)
44772 var editor = this.editor;
44773 var editorcore = this.editorcore;
44774 // create a new element.
44775 var wdiv = editor.wrap.createChild({
44777 }, editor.wrap.dom.firstChild.nextSibling, true);
44780 var tb = new Roo.Toolbar(wdiv);
44783 tb.add(nm+ ": ");
44786 for(var i in this.styles) {
44791 if (styles && styles.length) {
44793 // this needs a multi-select checkbox...
44794 tb.addField( new Roo.form.ComboBox({
44795 store: new Roo.data.SimpleStore({
44797 fields: ['val', 'selected'],
44800 name : '-roo-edit-className',
44801 attrname : 'className',
44802 displayField: 'val',
44806 triggerAction: 'all',
44807 emptyText:'Select Style',
44808 selectOnFocus:true,
44811 'select': function(c, r, i) {
44812 // initial support only for on class per el..
44813 tb.selectedNode.className = r ? r.get('val') : '';
44814 editorcore.syncValue();
44821 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44822 var tbops = tbc.options;
44824 for (var i in tlist) {
44826 var item = tlist[i];
44827 tb.add(item.title + ": ");
44830 //optname == used so you can configure the options available..
44831 var opts = item.opts ? item.opts : false;
44832 if (item.optname) {
44833 opts = tbops[item.optname];
44838 // opts == pulldown..
44839 tb.addField( new Roo.form.ComboBox({
44840 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44842 fields: ['val', 'display'],
44845 name : '-roo-edit-' + i,
44847 stylename : item.style ? item.style : false,
44848 displayField: item.displayField ? item.displayField : 'val',
44849 valueField : 'val',
44851 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44853 triggerAction: 'all',
44854 emptyText:'Select',
44855 selectOnFocus:true,
44856 width: item.width ? item.width : 130,
44858 'select': function(c, r, i) {
44860 tb.selectedNode.style[c.stylename] = r.get('val');
44863 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44872 tb.addField( new Roo.form.TextField({
44875 //allowBlank:false,
44880 tb.addField( new Roo.form.TextField({
44881 name: '-roo-edit-' + i,
44888 'change' : function(f, nv, ov) {
44889 tb.selectedNode.setAttribute(f.attrname, nv);
44902 text: 'Stylesheets',
44905 click : function ()
44907 _this.editor.fireEvent('stylesheetsclick', _this.editor);
44915 text: 'Remove Tag',
44918 click : function ()
44921 // undo does not work.
44923 var sn = tb.selectedNode;
44925 var pn = sn.parentNode;
44927 var stn = sn.childNodes[0];
44928 var en = sn.childNodes[sn.childNodes.length - 1 ];
44929 while (sn.childNodes.length) {
44930 var node = sn.childNodes[0];
44931 sn.removeChild(node);
44933 pn.insertBefore(node, sn);
44936 pn.removeChild(sn);
44937 var range = editorcore.createRange();
44939 range.setStart(stn,0);
44940 range.setEnd(en,0); //????
44941 //range.selectNode(sel);
44944 var selection = editorcore.getSelection();
44945 selection.removeAllRanges();
44946 selection.addRange(range);
44950 //_this.updateToolbar(null, null, pn);
44951 _this.updateToolbar(null, null, null);
44952 _this.footDisp.dom.innerHTML = '';
44962 tb.el.on('click', function(e){
44963 e.preventDefault(); // what does this do?
44965 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44968 // dont need to disable them... as they will get hidden
44973 buildFooter : function()
44976 var fel = this.editor.wrap.createChild();
44977 this.footer = new Roo.Toolbar(fel);
44978 // toolbar has scrolly on left / right?
44979 var footDisp= new Roo.Toolbar.Fill();
44985 handler : function() {
44986 _t.footDisp.scrollTo('left',0,true)
44990 this.footer.add( footDisp );
44995 handler : function() {
44997 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
45001 var fel = Roo.get(footDisp.el);
45002 fel.addClass('x-editor-context');
45003 this.footDispWrap = fel;
45004 this.footDispWrap.overflow = 'hidden';
45006 this.footDisp = fel.createChild();
45007 this.footDispWrap.on('click', this.onContextClick, this)
45011 onContextClick : function (ev,dom)
45013 ev.preventDefault();
45014 var cn = dom.className;
45016 if (!cn.match(/x-ed-loc-/)) {
45019 var n = cn.split('-').pop();
45020 var ans = this.footerEls;
45024 var range = this.editorcore.createRange();
45026 range.selectNodeContents(sel);
45027 //range.selectNode(sel);
45030 var selection = this.editorcore.getSelection();
45031 selection.removeAllRanges();
45032 selection.addRange(range);
45036 this.updateToolbar(null, null, sel);
45053 * Ext JS Library 1.1.1
45054 * Copyright(c) 2006-2007, Ext JS, LLC.
45056 * Originally Released Under LGPL - original licence link has changed is not relivant.
45059 * <script type="text/javascript">
45063 * @class Roo.form.BasicForm
45064 * @extends Roo.util.Observable
45065 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
45067 * @param {String/HTMLElement/Roo.Element} el The form element or its id
45068 * @param {Object} config Configuration options
45070 Roo.form.BasicForm = function(el, config){
45071 this.allItems = [];
45072 this.childForms = [];
45073 Roo.apply(this, config);
45075 * The Roo.form.Field items in this form.
45076 * @type MixedCollection
45080 this.items = new Roo.util.MixedCollection(false, function(o){
45081 return o.id || (o.id = Roo.id());
45085 * @event beforeaction
45086 * Fires before any action is performed. Return false to cancel the action.
45087 * @param {Form} this
45088 * @param {Action} action The action to be performed
45090 beforeaction: true,
45092 * @event actionfailed
45093 * Fires when an action fails.
45094 * @param {Form} this
45095 * @param {Action} action The action that failed
45097 actionfailed : true,
45099 * @event actioncomplete
45100 * Fires when an action is completed.
45101 * @param {Form} this
45102 * @param {Action} action The action that completed
45104 actioncomplete : true
45109 Roo.form.BasicForm.superclass.constructor.call(this);
45112 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
45114 * @cfg {String} method
45115 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
45118 * @cfg {DataReader} reader
45119 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
45120 * This is optional as there is built-in support for processing JSON.
45123 * @cfg {DataReader} errorReader
45124 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
45125 * This is completely optional as there is built-in support for processing JSON.
45128 * @cfg {String} url
45129 * The URL to use for form actions if one isn't supplied in the action options.
45132 * @cfg {Boolean} fileUpload
45133 * Set to true if this form is a file upload.
45137 * @cfg {Object} baseParams
45138 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
45143 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
45148 activeAction : null,
45151 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
45152 * or setValues() data instead of when the form was first created.
45154 trackResetOnLoad : false,
45158 * childForms - used for multi-tab forms
45161 childForms : false,
45164 * allItems - full list of fields.
45170 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
45171 * element by passing it or its id or mask the form itself by passing in true.
45174 waitMsgTarget : false,
45177 initEl : function(el){
45178 this.el = Roo.get(el);
45179 this.id = this.el.id || Roo.id();
45180 this.el.on('submit', this.onSubmit, this);
45181 this.el.addClass('x-form');
45185 onSubmit : function(e){
45190 * Returns true if client-side validation on the form is successful.
45193 isValid : function(){
45195 this.items.each(function(f){
45204 * DEPRICATED Returns true if any fields in this form have changed since their original load.
45207 isDirty : function(){
45209 this.items.each(function(f){
45219 * Returns true if any fields in this form have changed since their original load. (New version)
45223 hasChanged : function()
45226 this.items.each(function(f){
45227 if(f.hasChanged()){
45236 * Resets all hasChanged to 'false' -
45237 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
45238 * So hasChanged storage is only to be used for this purpose
45241 resetHasChanged : function()
45243 this.items.each(function(f){
45244 f.resetHasChanged();
45251 * Performs a predefined action (submit or load) or custom actions you define on this form.
45252 * @param {String} actionName The name of the action type
45253 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
45254 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
45255 * accept other config options):
45257 Property Type Description
45258 ---------------- --------------- ----------------------------------------------------------------------------------
45259 url String The url for the action (defaults to the form's url)
45260 method String The form method to use (defaults to the form's method, or POST if not defined)
45261 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
45262 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
45263 validate the form on the client (defaults to false)
45265 * @return {BasicForm} this
45267 doAction : function(action, options){
45268 if(typeof action == 'string'){
45269 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
45271 if(this.fireEvent('beforeaction', this, action) !== false){
45272 this.beforeAction(action);
45273 action.run.defer(100, action);
45279 * Shortcut to do a submit action.
45280 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45281 * @return {BasicForm} this
45283 submit : function(options){
45284 this.doAction('submit', options);
45289 * Shortcut to do a load action.
45290 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45291 * @return {BasicForm} this
45293 load : function(options){
45294 this.doAction('load', options);
45299 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
45300 * @param {Record} record The record to edit
45301 * @return {BasicForm} this
45303 updateRecord : function(record){
45304 record.beginEdit();
45305 var fs = record.fields;
45306 fs.each(function(f){
45307 var field = this.findField(f.name);
45309 record.set(f.name, field.getValue());
45317 * Loads an Roo.data.Record into this form.
45318 * @param {Record} record The record to load
45319 * @return {BasicForm} this
45321 loadRecord : function(record){
45322 this.setValues(record.data);
45327 beforeAction : function(action){
45328 var o = action.options;
45331 if(this.waitMsgTarget === true){
45332 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
45333 }else if(this.waitMsgTarget){
45334 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
45335 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
45337 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
45343 afterAction : function(action, success){
45344 this.activeAction = null;
45345 var o = action.options;
45347 if(this.waitMsgTarget === true){
45349 }else if(this.waitMsgTarget){
45350 this.waitMsgTarget.unmask();
45352 Roo.MessageBox.updateProgress(1);
45353 Roo.MessageBox.hide();
45360 Roo.callback(o.success, o.scope, [this, action]);
45361 this.fireEvent('actioncomplete', this, action);
45365 // failure condition..
45366 // we have a scenario where updates need confirming.
45367 // eg. if a locking scenario exists..
45368 // we look for { errors : { needs_confirm : true }} in the response.
45370 (typeof(action.result) != 'undefined') &&
45371 (typeof(action.result.errors) != 'undefined') &&
45372 (typeof(action.result.errors.needs_confirm) != 'undefined')
45375 Roo.MessageBox.confirm(
45376 "Change requires confirmation",
45377 action.result.errorMsg,
45382 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
45392 Roo.callback(o.failure, o.scope, [this, action]);
45393 // show an error message if no failed handler is set..
45394 if (!this.hasListener('actionfailed')) {
45395 Roo.MessageBox.alert("Error",
45396 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
45397 action.result.errorMsg :
45398 "Saving Failed, please check your entries or try again"
45402 this.fireEvent('actionfailed', this, action);
45408 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
45409 * @param {String} id The value to search for
45412 findField : function(id){
45413 var field = this.items.get(id);
45415 this.items.each(function(f){
45416 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
45422 return field || null;
45426 * Add a secondary form to this one,
45427 * Used to provide tabbed forms. One form is primary, with hidden values
45428 * which mirror the elements from the other forms.
45430 * @param {Roo.form.Form} form to add.
45433 addForm : function(form)
45436 if (this.childForms.indexOf(form) > -1) {
45440 this.childForms.push(form);
45442 Roo.each(form.allItems, function (fe) {
45444 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
45445 if (this.findField(n)) { // already added..
45448 var add = new Roo.form.Hidden({
45451 add.render(this.el);
45458 * Mark fields in this form invalid in bulk.
45459 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
45460 * @return {BasicForm} this
45462 markInvalid : function(errors){
45463 if(errors instanceof Array){
45464 for(var i = 0, len = errors.length; i < len; i++){
45465 var fieldError = errors[i];
45466 var f = this.findField(fieldError.id);
45468 f.markInvalid(fieldError.msg);
45474 if(typeof errors[id] != 'function' && (field = this.findField(id))){
45475 field.markInvalid(errors[id]);
45479 Roo.each(this.childForms || [], function (f) {
45480 f.markInvalid(errors);
45487 * Set values for fields in this form in bulk.
45488 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
45489 * @return {BasicForm} this
45491 setValues : function(values){
45492 if(values instanceof Array){ // array of objects
45493 for(var i = 0, len = values.length; i < len; i++){
45495 var f = this.findField(v.id);
45497 f.setValue(v.value);
45498 if(this.trackResetOnLoad){
45499 f.originalValue = f.getValue();
45503 }else{ // object hash
45506 if(typeof values[id] != 'function' && (field = this.findField(id))){
45508 if (field.setFromData &&
45509 field.valueField &&
45510 field.displayField &&
45511 // combos' with local stores can
45512 // be queried via setValue()
45513 // to set their value..
45514 (field.store && !field.store.isLocal)
45518 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
45519 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
45520 field.setFromData(sd);
45523 field.setValue(values[id]);
45527 if(this.trackResetOnLoad){
45528 field.originalValue = field.getValue();
45533 this.resetHasChanged();
45536 Roo.each(this.childForms || [], function (f) {
45537 f.setValues(values);
45538 f.resetHasChanged();
45545 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
45546 * they are returned as an array.
45547 * @param {Boolean} asString
45550 getValues : function(asString){
45551 if (this.childForms) {
45552 // copy values from the child forms
45553 Roo.each(this.childForms, function (f) {
45554 this.setValues(f.getValues());
45560 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
45561 if(asString === true){
45564 return Roo.urlDecode(fs);
45568 * Returns the fields in this form as an object with key/value pairs.
45569 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
45572 getFieldValues : function(with_hidden)
45574 if (this.childForms) {
45575 // copy values from the child forms
45576 // should this call getFieldValues - probably not as we do not currently copy
45577 // hidden fields when we generate..
45578 Roo.each(this.childForms, function (f) {
45579 this.setValues(f.getValues());
45584 this.items.each(function(f){
45585 if (!f.getName()) {
45588 var v = f.getValue();
45589 if (f.inputType =='radio') {
45590 if (typeof(ret[f.getName()]) == 'undefined') {
45591 ret[f.getName()] = ''; // empty..
45594 if (!f.el.dom.checked) {
45598 v = f.el.dom.value;
45602 // not sure if this supported any more..
45603 if ((typeof(v) == 'object') && f.getRawValue) {
45604 v = f.getRawValue() ; // dates..
45606 // combo boxes where name != hiddenName...
45607 if (f.name != f.getName()) {
45608 ret[f.name] = f.getRawValue();
45610 ret[f.getName()] = v;
45617 * Clears all invalid messages in this form.
45618 * @return {BasicForm} this
45620 clearInvalid : function(){
45621 this.items.each(function(f){
45625 Roo.each(this.childForms || [], function (f) {
45634 * Resets this form.
45635 * @return {BasicForm} this
45637 reset : function(){
45638 this.items.each(function(f){
45642 Roo.each(this.childForms || [], function (f) {
45645 this.resetHasChanged();
45651 * Add Roo.form components to this form.
45652 * @param {Field} field1
45653 * @param {Field} field2 (optional)
45654 * @param {Field} etc (optional)
45655 * @return {BasicForm} this
45658 this.items.addAll(Array.prototype.slice.call(arguments, 0));
45664 * Removes a field from the items collection (does NOT remove its markup).
45665 * @param {Field} field
45666 * @return {BasicForm} this
45668 remove : function(field){
45669 this.items.remove(field);
45674 * Looks at the fields in this form, checks them for an id attribute,
45675 * and calls applyTo on the existing dom element with that id.
45676 * @return {BasicForm} this
45678 render : function(){
45679 this.items.each(function(f){
45680 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
45688 * Calls {@link Ext#apply} for all fields in this form with the passed object.
45689 * @param {Object} values
45690 * @return {BasicForm} this
45692 applyToFields : function(o){
45693 this.items.each(function(f){
45700 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
45701 * @param {Object} values
45702 * @return {BasicForm} this
45704 applyIfToFields : function(o){
45705 this.items.each(function(f){
45713 Roo.BasicForm = Roo.form.BasicForm;/*
45715 * Ext JS Library 1.1.1
45716 * Copyright(c) 2006-2007, Ext JS, LLC.
45718 * Originally Released Under LGPL - original licence link has changed is not relivant.
45721 * <script type="text/javascript">
45725 * @class Roo.form.Form
45726 * @extends Roo.form.BasicForm
45727 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
45729 * @param {Object} config Configuration options
45731 Roo.form.Form = function(config){
45733 if (config.items) {
45734 xitems = config.items;
45735 delete config.items;
45739 Roo.form.Form.superclass.constructor.call(this, null, config);
45740 this.url = this.url || this.action;
45742 this.root = new Roo.form.Layout(Roo.applyIf({
45746 this.active = this.root;
45748 * Array of all the buttons that have been added to this form via {@link addButton}
45752 this.allItems = [];
45755 * @event clientvalidation
45756 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45757 * @param {Form} this
45758 * @param {Boolean} valid true if the form has passed client-side validation
45760 clientvalidation: true,
45763 * Fires when the form is rendered
45764 * @param {Roo.form.Form} form
45769 if (this.progressUrl) {
45770 // push a hidden field onto the list of fields..
45774 name : 'UPLOAD_IDENTIFIER'
45779 Roo.each(xitems, this.addxtype, this);
45785 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45787 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45790 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45793 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45795 buttonAlign:'center',
45798 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45803 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45804 * This property cascades to child containers if not set.
45809 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45810 * fires a looping event with that state. This is required to bind buttons to the valid
45811 * state using the config value formBind:true on the button.
45813 monitorValid : false,
45816 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45821 * @cfg {String} progressUrl - Url to return progress data
45824 progressUrl : false,
45827 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45828 * fields are added and the column is closed. If no fields are passed the column remains open
45829 * until end() is called.
45830 * @param {Object} config The config to pass to the column
45831 * @param {Field} field1 (optional)
45832 * @param {Field} field2 (optional)
45833 * @param {Field} etc (optional)
45834 * @return Column The column container object
45836 column : function(c){
45837 var col = new Roo.form.Column(c);
45839 if(arguments.length > 1){ // duplicate code required because of Opera
45840 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45847 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45848 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45849 * until end() is called.
45850 * @param {Object} config The config to pass to the fieldset
45851 * @param {Field} field1 (optional)
45852 * @param {Field} field2 (optional)
45853 * @param {Field} etc (optional)
45854 * @return FieldSet The fieldset container object
45856 fieldset : function(c){
45857 var fs = new Roo.form.FieldSet(c);
45859 if(arguments.length > 1){ // duplicate code required because of Opera
45860 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45867 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45868 * fields are added and the container is closed. If no fields are passed the container remains open
45869 * until end() is called.
45870 * @param {Object} config The config to pass to the Layout
45871 * @param {Field} field1 (optional)
45872 * @param {Field} field2 (optional)
45873 * @param {Field} etc (optional)
45874 * @return Layout The container object
45876 container : function(c){
45877 var l = new Roo.form.Layout(c);
45879 if(arguments.length > 1){ // duplicate code required because of Opera
45880 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45887 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45888 * @param {Object} container A Roo.form.Layout or subclass of Layout
45889 * @return {Form} this
45891 start : function(c){
45892 // cascade label info
45893 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45894 this.active.stack.push(c);
45895 c.ownerCt = this.active;
45901 * Closes the current open container
45902 * @return {Form} this
45905 if(this.active == this.root){
45908 this.active = this.active.ownerCt;
45913 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45914 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45915 * as the label of the field.
45916 * @param {Field} field1
45917 * @param {Field} field2 (optional)
45918 * @param {Field} etc. (optional)
45919 * @return {Form} this
45922 this.active.stack.push.apply(this.active.stack, arguments);
45923 this.allItems.push.apply(this.allItems,arguments);
45925 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45926 if(a[i].isFormField){
45931 Roo.form.Form.superclass.add.apply(this, r);
45941 * Find any element that has been added to a form, using it's ID or name
45942 * This can include framesets, columns etc. along with regular fields..
45943 * @param {String} id - id or name to find.
45945 * @return {Element} e - or false if nothing found.
45947 findbyId : function(id)
45953 Roo.each(this.allItems, function(f){
45954 if (f.id == id || f.name == id ){
45965 * Render this form into the passed container. This should only be called once!
45966 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45967 * @return {Form} this
45969 render : function(ct)
45975 var o = this.autoCreate || {
45977 method : this.method || 'POST',
45978 id : this.id || Roo.id()
45980 this.initEl(ct.createChild(o));
45982 this.root.render(this.el);
45986 this.items.each(function(f){
45987 f.render('x-form-el-'+f.id);
45990 if(this.buttons.length > 0){
45991 // tables are required to maintain order and for correct IE layout
45992 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45993 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45994 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45996 var tr = tb.getElementsByTagName('tr')[0];
45997 for(var i = 0, len = this.buttons.length; i < len; i++) {
45998 var b = this.buttons[i];
45999 var td = document.createElement('td');
46000 td.className = 'x-form-btn-td';
46001 b.render(tr.appendChild(td));
46004 if(this.monitorValid){ // initialize after render
46005 this.startMonitoring();
46007 this.fireEvent('rendered', this);
46012 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
46013 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
46014 * object or a valid Roo.DomHelper element config
46015 * @param {Function} handler The function called when the button is clicked
46016 * @param {Object} scope (optional) The scope of the handler function
46017 * @return {Roo.Button}
46019 addButton : function(config, handler, scope){
46023 minWidth: this.minButtonWidth,
46026 if(typeof config == "string"){
46029 Roo.apply(bc, config);
46031 var btn = new Roo.Button(null, bc);
46032 this.buttons.push(btn);
46037 * Adds a series of form elements (using the xtype property as the factory method.
46038 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
46039 * @param {Object} config
46042 addxtype : function()
46044 var ar = Array.prototype.slice.call(arguments, 0);
46046 for(var i = 0; i < ar.length; i++) {
46048 continue; // skip -- if this happends something invalid got sent, we
46049 // should ignore it, as basically that interface element will not show up
46050 // and that should be pretty obvious!!
46053 if (Roo.form[ar[i].xtype]) {
46055 var fe = Roo.factory(ar[i], Roo.form);
46061 fe.store.form = this;
46066 this.allItems.push(fe);
46067 if (fe.items && fe.addxtype) {
46068 fe.addxtype.apply(fe, fe.items);
46078 // console.log('adding ' + ar[i].xtype);
46080 if (ar[i].xtype == 'Button') {
46081 //console.log('adding button');
46082 //console.log(ar[i]);
46083 this.addButton(ar[i]);
46084 this.allItems.push(fe);
46088 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
46089 alert('end is not supported on xtype any more, use items');
46091 // //console.log('adding end');
46099 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
46100 * option "monitorValid"
46102 startMonitoring : function(){
46105 Roo.TaskMgr.start({
46106 run : this.bindHandler,
46107 interval : this.monitorPoll || 200,
46114 * Stops monitoring of the valid state of this form
46116 stopMonitoring : function(){
46117 this.bound = false;
46121 bindHandler : function(){
46123 return false; // stops binding
46126 this.items.each(function(f){
46127 if(!f.isValid(true)){
46132 for(var i = 0, len = this.buttons.length; i < len; i++){
46133 var btn = this.buttons[i];
46134 if(btn.formBind === true && btn.disabled === valid){
46135 btn.setDisabled(!valid);
46138 this.fireEvent('clientvalidation', this, valid);
46152 Roo.Form = Roo.form.Form;
46155 * Ext JS Library 1.1.1
46156 * Copyright(c) 2006-2007, Ext JS, LLC.
46158 * Originally Released Under LGPL - original licence link has changed is not relivant.
46161 * <script type="text/javascript">
46164 // as we use this in bootstrap.
46165 Roo.namespace('Roo.form');
46167 * @class Roo.form.Action
46168 * Internal Class used to handle form actions
46170 * @param {Roo.form.BasicForm} el The form element or its id
46171 * @param {Object} config Configuration options
46176 // define the action interface
46177 Roo.form.Action = function(form, options){
46179 this.options = options || {};
46182 * Client Validation Failed
46185 Roo.form.Action.CLIENT_INVALID = 'client';
46187 * Server Validation Failed
46190 Roo.form.Action.SERVER_INVALID = 'server';
46192 * Connect to Server Failed
46195 Roo.form.Action.CONNECT_FAILURE = 'connect';
46197 * Reading Data from Server Failed
46200 Roo.form.Action.LOAD_FAILURE = 'load';
46202 Roo.form.Action.prototype = {
46204 failureType : undefined,
46205 response : undefined,
46206 result : undefined,
46208 // interface method
46209 run : function(options){
46213 // interface method
46214 success : function(response){
46218 // interface method
46219 handleResponse : function(response){
46223 // default connection failure
46224 failure : function(response){
46226 this.response = response;
46227 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46228 this.form.afterAction(this, false);
46231 processResponse : function(response){
46232 this.response = response;
46233 if(!response.responseText){
46236 this.result = this.handleResponse(response);
46237 return this.result;
46240 // utility functions used internally
46241 getUrl : function(appendParams){
46242 var url = this.options.url || this.form.url || this.form.el.dom.action;
46244 var p = this.getParams();
46246 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
46252 getMethod : function(){
46253 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
46256 getParams : function(){
46257 var bp = this.form.baseParams;
46258 var p = this.options.params;
46260 if(typeof p == "object"){
46261 p = Roo.urlEncode(Roo.applyIf(p, bp));
46262 }else if(typeof p == 'string' && bp){
46263 p += '&' + Roo.urlEncode(bp);
46266 p = Roo.urlEncode(bp);
46271 createCallback : function(){
46273 success: this.success,
46274 failure: this.failure,
46276 timeout: (this.form.timeout*1000),
46277 upload: this.form.fileUpload ? this.success : undefined
46282 Roo.form.Action.Submit = function(form, options){
46283 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
46286 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
46289 haveProgress : false,
46290 uploadComplete : false,
46292 // uploadProgress indicator.
46293 uploadProgress : function()
46295 if (!this.form.progressUrl) {
46299 if (!this.haveProgress) {
46300 Roo.MessageBox.progress("Uploading", "Uploading");
46302 if (this.uploadComplete) {
46303 Roo.MessageBox.hide();
46307 this.haveProgress = true;
46309 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
46311 var c = new Roo.data.Connection();
46313 url : this.form.progressUrl,
46318 success : function(req){
46319 //console.log(data);
46323 rdata = Roo.decode(req.responseText)
46325 Roo.log("Invalid data from server..");
46329 if (!rdata || !rdata.success) {
46331 Roo.MessageBox.alert(Roo.encode(rdata));
46334 var data = rdata.data;
46336 if (this.uploadComplete) {
46337 Roo.MessageBox.hide();
46342 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
46343 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
46346 this.uploadProgress.defer(2000,this);
46349 failure: function(data) {
46350 Roo.log('progress url failed ');
46361 // run get Values on the form, so it syncs any secondary forms.
46362 this.form.getValues();
46364 var o = this.options;
46365 var method = this.getMethod();
46366 var isPost = method == 'POST';
46367 if(o.clientValidation === false || this.form.isValid()){
46369 if (this.form.progressUrl) {
46370 this.form.findField('UPLOAD_IDENTIFIER').setValue(
46371 (new Date() * 1) + '' + Math.random());
46376 Roo.Ajax.request(Roo.apply(this.createCallback(), {
46377 form:this.form.el.dom,
46378 url:this.getUrl(!isPost),
46380 params:isPost ? this.getParams() : null,
46381 isUpload: this.form.fileUpload
46384 this.uploadProgress();
46386 }else if (o.clientValidation !== false){ // client validation failed
46387 this.failureType = Roo.form.Action.CLIENT_INVALID;
46388 this.form.afterAction(this, false);
46392 success : function(response)
46394 this.uploadComplete= true;
46395 if (this.haveProgress) {
46396 Roo.MessageBox.hide();
46400 var result = this.processResponse(response);
46401 if(result === true || result.success){
46402 this.form.afterAction(this, true);
46406 this.form.markInvalid(result.errors);
46407 this.failureType = Roo.form.Action.SERVER_INVALID;
46409 this.form.afterAction(this, false);
46411 failure : function(response)
46413 this.uploadComplete= true;
46414 if (this.haveProgress) {
46415 Roo.MessageBox.hide();
46418 this.response = response;
46419 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46420 this.form.afterAction(this, false);
46423 handleResponse : function(response){
46424 if(this.form.errorReader){
46425 var rs = this.form.errorReader.read(response);
46428 for(var i = 0, len = rs.records.length; i < len; i++) {
46429 var r = rs.records[i];
46430 errors[i] = r.data;
46433 if(errors.length < 1){
46437 success : rs.success,
46443 ret = Roo.decode(response.responseText);
46447 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
46457 Roo.form.Action.Load = function(form, options){
46458 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
46459 this.reader = this.form.reader;
46462 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
46467 Roo.Ajax.request(Roo.apply(
46468 this.createCallback(), {
46469 method:this.getMethod(),
46470 url:this.getUrl(false),
46471 params:this.getParams()
46475 success : function(response){
46477 var result = this.processResponse(response);
46478 if(result === true || !result.success || !result.data){
46479 this.failureType = Roo.form.Action.LOAD_FAILURE;
46480 this.form.afterAction(this, false);
46483 this.form.clearInvalid();
46484 this.form.setValues(result.data);
46485 this.form.afterAction(this, true);
46488 handleResponse : function(response){
46489 if(this.form.reader){
46490 var rs = this.form.reader.read(response);
46491 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
46493 success : rs.success,
46497 return Roo.decode(response.responseText);
46501 Roo.form.Action.ACTION_TYPES = {
46502 'load' : Roo.form.Action.Load,
46503 'submit' : Roo.form.Action.Submit
46506 * Ext JS Library 1.1.1
46507 * Copyright(c) 2006-2007, Ext JS, LLC.
46509 * Originally Released Under LGPL - original licence link has changed is not relivant.
46512 * <script type="text/javascript">
46516 * @class Roo.form.Layout
46517 * @extends Roo.Component
46518 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
46520 * @param {Object} config Configuration options
46522 Roo.form.Layout = function(config){
46524 if (config.items) {
46525 xitems = config.items;
46526 delete config.items;
46528 Roo.form.Layout.superclass.constructor.call(this, config);
46530 Roo.each(xitems, this.addxtype, this);
46534 Roo.extend(Roo.form.Layout, Roo.Component, {
46536 * @cfg {String/Object} autoCreate
46537 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
46540 * @cfg {String/Object/Function} style
46541 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
46542 * a function which returns such a specification.
46545 * @cfg {String} labelAlign
46546 * Valid values are "left," "top" and "right" (defaults to "left")
46549 * @cfg {Number} labelWidth
46550 * Fixed width in pixels of all field labels (defaults to undefined)
46553 * @cfg {Boolean} clear
46554 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
46558 * @cfg {String} labelSeparator
46559 * The separator to use after field labels (defaults to ':')
46561 labelSeparator : ':',
46563 * @cfg {Boolean} hideLabels
46564 * True to suppress the display of field labels in this layout (defaults to false)
46566 hideLabels : false,
46569 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
46574 onRender : function(ct, position){
46575 if(this.el){ // from markup
46576 this.el = Roo.get(this.el);
46577 }else { // generate
46578 var cfg = this.getAutoCreate();
46579 this.el = ct.createChild(cfg, position);
46582 this.el.applyStyles(this.style);
46584 if(this.labelAlign){
46585 this.el.addClass('x-form-label-'+this.labelAlign);
46587 if(this.hideLabels){
46588 this.labelStyle = "display:none";
46589 this.elementStyle = "padding-left:0;";
46591 if(typeof this.labelWidth == 'number'){
46592 this.labelStyle = "width:"+this.labelWidth+"px;";
46593 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
46595 if(this.labelAlign == 'top'){
46596 this.labelStyle = "width:auto;";
46597 this.elementStyle = "padding-left:0;";
46600 var stack = this.stack;
46601 var slen = stack.length;
46603 if(!this.fieldTpl){
46604 var t = new Roo.Template(
46605 '<div class="x-form-item {5}">',
46606 '<label for="{0}" style="{2}">{1}{4}</label>',
46607 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46609 '</div><div class="x-form-clear-left"></div>'
46611 t.disableFormats = true;
46613 Roo.form.Layout.prototype.fieldTpl = t;
46615 for(var i = 0; i < slen; i++) {
46616 if(stack[i].isFormField){
46617 this.renderField(stack[i]);
46619 this.renderComponent(stack[i]);
46624 this.el.createChild({cls:'x-form-clear'});
46629 renderField : function(f){
46630 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
46633 f.labelStyle||this.labelStyle||'', //2
46634 this.elementStyle||'', //3
46635 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
46636 f.itemCls||this.itemCls||'' //5
46637 ], true).getPrevSibling());
46641 renderComponent : function(c){
46642 c.render(c.isLayout ? this.el : this.el.createChild());
46645 * Adds a object form elements (using the xtype property as the factory method.)
46646 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
46647 * @param {Object} config
46649 addxtype : function(o)
46651 // create the lement.
46652 o.form = this.form;
46653 var fe = Roo.factory(o, Roo.form);
46654 this.form.allItems.push(fe);
46655 this.stack.push(fe);
46657 if (fe.isFormField) {
46658 this.form.items.add(fe);
46666 * @class Roo.form.Column
46667 * @extends Roo.form.Layout
46668 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
46670 * @param {Object} config Configuration options
46672 Roo.form.Column = function(config){
46673 Roo.form.Column.superclass.constructor.call(this, config);
46676 Roo.extend(Roo.form.Column, Roo.form.Layout, {
46678 * @cfg {Number/String} width
46679 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46682 * @cfg {String/Object} autoCreate
46683 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
46687 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
46690 onRender : function(ct, position){
46691 Roo.form.Column.superclass.onRender.call(this, ct, position);
46693 this.el.setWidth(this.width);
46700 * @class Roo.form.Row
46701 * @extends Roo.form.Layout
46702 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
46704 * @param {Object} config Configuration options
46708 Roo.form.Row = function(config){
46709 Roo.form.Row.superclass.constructor.call(this, config);
46712 Roo.extend(Roo.form.Row, Roo.form.Layout, {
46714 * @cfg {Number/String} width
46715 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46718 * @cfg {Number/String} height
46719 * The fixed height of the column in pixels or CSS value (defaults to "auto")
46721 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
46725 onRender : function(ct, position){
46726 //console.log('row render');
46728 var t = new Roo.Template(
46729 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
46730 '<label for="{0}" style="{2}">{1}{4}</label>',
46731 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46735 t.disableFormats = true;
46737 Roo.form.Layout.prototype.rowTpl = t;
46739 this.fieldTpl = this.rowTpl;
46741 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46742 var labelWidth = 100;
46744 if ((this.labelAlign != 'top')) {
46745 if (typeof this.labelWidth == 'number') {
46746 labelWidth = this.labelWidth
46748 this.padWidth = 20 + labelWidth;
46752 Roo.form.Column.superclass.onRender.call(this, ct, position);
46754 this.el.setWidth(this.width);
46757 this.el.setHeight(this.height);
46762 renderField : function(f){
46763 f.fieldEl = this.fieldTpl.append(this.el, [
46764 f.id, f.fieldLabel,
46765 f.labelStyle||this.labelStyle||'',
46766 this.elementStyle||'',
46767 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46768 f.itemCls||this.itemCls||'',
46769 f.width ? f.width + this.padWidth : 160 + this.padWidth
46776 * @class Roo.form.FieldSet
46777 * @extends Roo.form.Layout
46778 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46780 * @param {Object} config Configuration options
46782 Roo.form.FieldSet = function(config){
46783 Roo.form.FieldSet.superclass.constructor.call(this, config);
46786 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46788 * @cfg {String} legend
46789 * The text to display as the legend for the FieldSet (defaults to '')
46792 * @cfg {String/Object} autoCreate
46793 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46797 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46800 onRender : function(ct, position){
46801 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46803 this.setLegend(this.legend);
46808 setLegend : function(text){
46810 this.el.child('legend').update(text);
46815 * Ext JS Library 1.1.1
46816 * Copyright(c) 2006-2007, Ext JS, LLC.
46818 * Originally Released Under LGPL - original licence link has changed is not relivant.
46821 * <script type="text/javascript">
46824 * @class Roo.form.VTypes
46825 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46828 Roo.form.VTypes = function(){
46829 // closure these in so they are only created once.
46830 var alpha = /^[a-zA-Z_]+$/;
46831 var alphanum = /^[a-zA-Z0-9_]+$/;
46832 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
46833 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46835 // All these messages and functions are configurable
46838 * The function used to validate email addresses
46839 * @param {String} value The email address
46841 'email' : function(v){
46842 return email.test(v);
46845 * The error text to display when the email validation function returns false
46848 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46850 * The keystroke filter mask to be applied on email input
46853 'emailMask' : /[a-z0-9_\.\-@]/i,
46856 * The function used to validate URLs
46857 * @param {String} value The URL
46859 'url' : function(v){
46860 return url.test(v);
46863 * The error text to display when the url validation function returns false
46866 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46869 * The function used to validate alpha values
46870 * @param {String} value The value
46872 'alpha' : function(v){
46873 return alpha.test(v);
46876 * The error text to display when the alpha validation function returns false
46879 'alphaText' : 'This field should only contain letters and _',
46881 * The keystroke filter mask to be applied on alpha input
46884 'alphaMask' : /[a-z_]/i,
46887 * The function used to validate alphanumeric values
46888 * @param {String} value The value
46890 'alphanum' : function(v){
46891 return alphanum.test(v);
46894 * The error text to display when the alphanumeric validation function returns false
46897 'alphanumText' : 'This field should only contain letters, numbers and _',
46899 * The keystroke filter mask to be applied on alphanumeric input
46902 'alphanumMask' : /[a-z0-9_]/i
46904 }();//<script type="text/javascript">
46907 * @class Roo.form.FCKeditor
46908 * @extends Roo.form.TextArea
46909 * Wrapper around the FCKEditor http://www.fckeditor.net
46911 * Creates a new FCKeditor
46912 * @param {Object} config Configuration options
46914 Roo.form.FCKeditor = function(config){
46915 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46918 * @event editorinit
46919 * Fired when the editor is initialized - you can add extra handlers here..
46920 * @param {FCKeditor} this
46921 * @param {Object} the FCK object.
46928 Roo.form.FCKeditor.editors = { };
46929 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46931 //defaultAutoCreate : {
46932 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46936 * @cfg {Object} fck options - see fck manual for details.
46941 * @cfg {Object} fck toolbar set (Basic or Default)
46943 toolbarSet : 'Basic',
46945 * @cfg {Object} fck BasePath
46947 basePath : '/fckeditor/',
46955 onRender : function(ct, position)
46958 this.defaultAutoCreate = {
46960 style:"width:300px;height:60px;",
46961 autocomplete: "new-password"
46964 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46967 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46968 if(this.preventScrollbars){
46969 this.el.setStyle("overflow", "hidden");
46971 this.el.setHeight(this.growMin);
46974 //console.log('onrender' + this.getId() );
46975 Roo.form.FCKeditor.editors[this.getId()] = this;
46978 this.replaceTextarea() ;
46982 getEditor : function() {
46983 return this.fckEditor;
46986 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46987 * @param {Mixed} value The value to set
46991 setValue : function(value)
46993 //console.log('setValue: ' + value);
46995 if(typeof(value) == 'undefined') { // not sure why this is happending...
46998 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
47000 //if(!this.el || !this.getEditor()) {
47001 // this.value = value;
47002 //this.setValue.defer(100,this,[value]);
47006 if(!this.getEditor()) {
47010 this.getEditor().SetData(value);
47017 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
47018 * @return {Mixed} value The field value
47020 getValue : function()
47023 if (this.frame && this.frame.dom.style.display == 'none') {
47024 return Roo.form.FCKeditor.superclass.getValue.call(this);
47027 if(!this.el || !this.getEditor()) {
47029 // this.getValue.defer(100,this);
47034 var value=this.getEditor().GetData();
47035 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
47036 return Roo.form.FCKeditor.superclass.getValue.call(this);
47042 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
47043 * @return {Mixed} value The field value
47045 getRawValue : function()
47047 if (this.frame && this.frame.dom.style.display == 'none') {
47048 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
47051 if(!this.el || !this.getEditor()) {
47052 //this.getRawValue.defer(100,this);
47059 var value=this.getEditor().GetData();
47060 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
47061 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
47065 setSize : function(w,h) {
47069 //if (this.frame && this.frame.dom.style.display == 'none') {
47070 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
47073 //if(!this.el || !this.getEditor()) {
47074 // this.setSize.defer(100,this, [w,h]);
47080 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
47082 this.frame.dom.setAttribute('width', w);
47083 this.frame.dom.setAttribute('height', h);
47084 this.frame.setSize(w,h);
47088 toggleSourceEdit : function(value) {
47092 this.el.dom.style.display = value ? '' : 'none';
47093 this.frame.dom.style.display = value ? 'none' : '';
47098 focus: function(tag)
47100 if (this.frame.dom.style.display == 'none') {
47101 return Roo.form.FCKeditor.superclass.focus.call(this);
47103 if(!this.el || !this.getEditor()) {
47104 this.focus.defer(100,this, [tag]);
47111 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
47112 this.getEditor().Focus();
47114 if (!this.getEditor().Selection.GetSelection()) {
47115 this.focus.defer(100,this, [tag]);
47120 var r = this.getEditor().EditorDocument.createRange();
47121 r.setStart(tgs[0],0);
47122 r.setEnd(tgs[0],0);
47123 this.getEditor().Selection.GetSelection().removeAllRanges();
47124 this.getEditor().Selection.GetSelection().addRange(r);
47125 this.getEditor().Focus();
47132 replaceTextarea : function()
47134 if ( document.getElementById( this.getId() + '___Frame' ) ) {
47137 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
47139 // We must check the elements firstly using the Id and then the name.
47140 var oTextarea = document.getElementById( this.getId() );
47142 var colElementsByName = document.getElementsByName( this.getId() ) ;
47144 oTextarea.style.display = 'none' ;
47146 if ( oTextarea.tabIndex ) {
47147 this.TabIndex = oTextarea.tabIndex ;
47150 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
47151 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
47152 this.frame = Roo.get(this.getId() + '___Frame')
47155 _getConfigHtml : function()
47159 for ( var o in this.fckconfig ) {
47160 sConfig += sConfig.length > 0 ? '&' : '';
47161 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
47164 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
47168 _getIFrameHtml : function()
47170 var sFile = 'fckeditor.html' ;
47171 /* no idea what this is about..
47174 if ( (/fcksource=true/i).test( window.top.location.search ) )
47175 sFile = 'fckeditor.original.html' ;
47180 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
47181 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
47184 var html = '<iframe id="' + this.getId() +
47185 '___Frame" src="' + sLink +
47186 '" width="' + this.width +
47187 '" height="' + this.height + '"' +
47188 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
47189 ' frameborder="0" scrolling="no"></iframe>' ;
47194 _insertHtmlBefore : function( html, element )
47196 if ( element.insertAdjacentHTML ) {
47198 element.insertAdjacentHTML( 'beforeBegin', html ) ;
47200 var oRange = document.createRange() ;
47201 oRange.setStartBefore( element ) ;
47202 var oFragment = oRange.createContextualFragment( html );
47203 element.parentNode.insertBefore( oFragment, element ) ;
47216 //Roo.reg('fckeditor', Roo.form.FCKeditor);
47218 function FCKeditor_OnComplete(editorInstance){
47219 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
47220 f.fckEditor = editorInstance;
47221 //console.log("loaded");
47222 f.fireEvent('editorinit', f, editorInstance);
47242 //<script type="text/javascript">
47244 * @class Roo.form.GridField
47245 * @extends Roo.form.Field
47246 * Embed a grid (or editable grid into a form)
47249 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
47251 * xgrid.store = Roo.data.Store
47252 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
47253 * xgrid.store.reader = Roo.data.JsonReader
47257 * Creates a new GridField
47258 * @param {Object} config Configuration options
47260 Roo.form.GridField = function(config){
47261 Roo.form.GridField.superclass.constructor.call(this, config);
47265 Roo.extend(Roo.form.GridField, Roo.form.Field, {
47267 * @cfg {Number} width - used to restrict width of grid..
47271 * @cfg {Number} height - used to restrict height of grid..
47275 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
47281 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47282 * {tag: "input", type: "checkbox", autocomplete: "off"})
47284 // defaultAutoCreate : { tag: 'div' },
47285 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
47287 * @cfg {String} addTitle Text to include for adding a title.
47291 onResize : function(){
47292 Roo.form.Field.superclass.onResize.apply(this, arguments);
47295 initEvents : function(){
47296 // Roo.form.Checkbox.superclass.initEvents.call(this);
47297 // has no events...
47302 getResizeEl : function(){
47306 getPositionEl : function(){
47311 onRender : function(ct, position){
47313 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
47314 var style = this.style;
47317 Roo.form.GridField.superclass.onRender.call(this, ct, position);
47318 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
47319 this.viewEl = this.wrap.createChild({ tag: 'div' });
47321 this.viewEl.applyStyles(style);
47324 this.viewEl.setWidth(this.width);
47327 this.viewEl.setHeight(this.height);
47329 //if(this.inputValue !== undefined){
47330 //this.setValue(this.value);
47333 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
47336 this.grid.render();
47337 this.grid.getDataSource().on('remove', this.refreshValue, this);
47338 this.grid.getDataSource().on('update', this.refreshValue, this);
47339 this.grid.on('afteredit', this.refreshValue, this);
47345 * Sets the value of the item.
47346 * @param {String} either an object or a string..
47348 setValue : function(v){
47350 v = v || []; // empty set..
47351 // this does not seem smart - it really only affects memoryproxy grids..
47352 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
47353 var ds = this.grid.getDataSource();
47354 // assumes a json reader..
47356 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
47357 ds.loadData( data);
47359 // clear selection so it does not get stale.
47360 if (this.grid.sm) {
47361 this.grid.sm.clearSelections();
47364 Roo.form.GridField.superclass.setValue.call(this, v);
47365 this.refreshValue();
47366 // should load data in the grid really....
47370 refreshValue: function() {
47372 this.grid.getDataSource().each(function(r) {
47375 this.el.dom.value = Roo.encode(val);
47383 * Ext JS Library 1.1.1
47384 * Copyright(c) 2006-2007, Ext JS, LLC.
47386 * Originally Released Under LGPL - original licence link has changed is not relivant.
47389 * <script type="text/javascript">
47392 * @class Roo.form.DisplayField
47393 * @extends Roo.form.Field
47394 * A generic Field to display non-editable data.
47395 * @cfg {Boolean} closable (true|false) default false
47397 * Creates a new Display Field item.
47398 * @param {Object} config Configuration options
47400 Roo.form.DisplayField = function(config){
47401 Roo.form.DisplayField.superclass.constructor.call(this, config);
47406 * Fires after the click the close btn
47407 * @param {Roo.form.DisplayField} this
47413 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
47414 inputType: 'hidden',
47420 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47422 focusClass : undefined,
47424 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47426 fieldClass: 'x-form-field',
47429 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
47431 valueRenderer: undefined,
47435 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47436 * {tag: "input", type: "checkbox", autocomplete: "off"})
47439 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
47443 onResize : function(){
47444 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
47448 initEvents : function(){
47449 // Roo.form.Checkbox.superclass.initEvents.call(this);
47450 // has no events...
47453 this.closeEl.on('click', this.onClose, this);
47459 getResizeEl : function(){
47463 getPositionEl : function(){
47468 onRender : function(ct, position){
47470 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
47471 //if(this.inputValue !== undefined){
47472 this.wrap = this.el.wrap();
47474 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
47477 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
47480 if (this.bodyStyle) {
47481 this.viewEl.applyStyles(this.bodyStyle);
47483 //this.viewEl.setStyle('padding', '2px');
47485 this.setValue(this.value);
47490 initValue : Roo.emptyFn,
47495 onClick : function(){
47500 * Sets the checked state of the checkbox.
47501 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
47503 setValue : function(v){
47505 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
47506 // this might be called before we have a dom element..
47507 if (!this.viewEl) {
47510 this.viewEl.dom.innerHTML = html;
47511 Roo.form.DisplayField.superclass.setValue.call(this, v);
47515 onClose : function(e)
47517 e.preventDefault();
47519 this.fireEvent('close', this);
47528 * @class Roo.form.DayPicker
47529 * @extends Roo.form.Field
47530 * A Day picker show [M] [T] [W] ....
47532 * Creates a new Day Picker
47533 * @param {Object} config Configuration options
47535 Roo.form.DayPicker= function(config){
47536 Roo.form.DayPicker.superclass.constructor.call(this, config);
47540 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
47542 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47544 focusClass : undefined,
47546 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47548 fieldClass: "x-form-field",
47551 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47552 * {tag: "input", type: "checkbox", autocomplete: "off"})
47554 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
47557 actionMode : 'viewEl',
47561 inputType : 'hidden',
47564 inputElement: false, // real input element?
47565 basedOn: false, // ????
47567 isFormField: true, // not sure where this is needed!!!!
47569 onResize : function(){
47570 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
47571 if(!this.boxLabel){
47572 this.el.alignTo(this.wrap, 'c-c');
47576 initEvents : function(){
47577 Roo.form.Checkbox.superclass.initEvents.call(this);
47578 this.el.on("click", this.onClick, this);
47579 this.el.on("change", this.onClick, this);
47583 getResizeEl : function(){
47587 getPositionEl : function(){
47593 onRender : function(ct, position){
47594 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
47596 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
47598 var r1 = '<table><tr>';
47599 var r2 = '<tr class="x-form-daypick-icons">';
47600 for (var i=0; i < 7; i++) {
47601 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
47602 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
47605 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
47606 viewEl.select('img').on('click', this.onClick, this);
47607 this.viewEl = viewEl;
47610 // this will not work on Chrome!!!
47611 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
47612 this.el.on('propertychange', this.setFromHidden, this); //ie
47620 initValue : Roo.emptyFn,
47623 * Returns the checked state of the checkbox.
47624 * @return {Boolean} True if checked, else false
47626 getValue : function(){
47627 return this.el.dom.value;
47632 onClick : function(e){
47633 //this.setChecked(!this.checked);
47634 Roo.get(e.target).toggleClass('x-menu-item-checked');
47635 this.refreshValue();
47636 //if(this.el.dom.checked != this.checked){
47637 // this.setValue(this.el.dom.checked);
47642 refreshValue : function()
47645 this.viewEl.select('img',true).each(function(e,i,n) {
47646 val += e.is(".x-menu-item-checked") ? String(n) : '';
47648 this.setValue(val, true);
47652 * Sets the checked state of the checkbox.
47653 * On is always based on a string comparison between inputValue and the param.
47654 * @param {Boolean/String} value - the value to set
47655 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
47657 setValue : function(v,suppressEvent){
47658 if (!this.el.dom) {
47661 var old = this.el.dom.value ;
47662 this.el.dom.value = v;
47663 if (suppressEvent) {
47667 // update display..
47668 this.viewEl.select('img',true).each(function(e,i,n) {
47670 var on = e.is(".x-menu-item-checked");
47671 var newv = v.indexOf(String(n)) > -1;
47673 e.toggleClass('x-menu-item-checked');
47679 this.fireEvent('change', this, v, old);
47684 // handle setting of hidden value by some other method!!?!?
47685 setFromHidden: function()
47690 //console.log("SET FROM HIDDEN");
47691 //alert('setFrom hidden');
47692 this.setValue(this.el.dom.value);
47695 onDestroy : function()
47698 Roo.get(this.viewEl).remove();
47701 Roo.form.DayPicker.superclass.onDestroy.call(this);
47705 * RooJS Library 1.1.1
47706 * Copyright(c) 2008-2011 Alan Knowles
47713 * @class Roo.form.ComboCheck
47714 * @extends Roo.form.ComboBox
47715 * A combobox for multiple select items.
47717 * FIXME - could do with a reset button..
47720 * Create a new ComboCheck
47721 * @param {Object} config Configuration options
47723 Roo.form.ComboCheck = function(config){
47724 Roo.form.ComboCheck.superclass.constructor.call(this, config);
47725 // should verify some data...
47727 // hiddenName = required..
47728 // displayField = required
47729 // valudField == required
47730 var req= [ 'hiddenName', 'displayField', 'valueField' ];
47732 Roo.each(req, function(e) {
47733 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
47734 throw "Roo.form.ComboCheck : missing value for: " + e;
47741 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
47746 selectedClass: 'x-menu-item-checked',
47749 onRender : function(ct, position){
47755 var cls = 'x-combo-list';
47758 this.tpl = new Roo.Template({
47759 html : '<div class="'+cls+'-item x-menu-check-item">' +
47760 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47761 '<span>{' + this.displayField + '}</span>' +
47768 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47769 this.view.singleSelect = false;
47770 this.view.multiSelect = true;
47771 this.view.toggleSelect = true;
47772 this.pageTb.add(new Roo.Toolbar.Fill(), {
47775 handler: function()
47782 onViewOver : function(e, t){
47788 onViewClick : function(doFocus,index){
47792 select: function () {
47793 //Roo.log("SELECT CALLED");
47796 selectByValue : function(xv, scrollIntoView){
47797 var ar = this.getValueArray();
47800 Roo.each(ar, function(v) {
47801 if(v === undefined || v === null){
47804 var r = this.findRecord(this.valueField, v);
47806 sels.push(this.store.indexOf(r))
47810 this.view.select(sels);
47816 onSelect : function(record, index){
47817 // Roo.log("onselect Called");
47818 // this is only called by the clear button now..
47819 this.view.clearSelections();
47820 this.setValue('[]');
47821 if (this.value != this.valueBefore) {
47822 this.fireEvent('change', this, this.value, this.valueBefore);
47823 this.valueBefore = this.value;
47826 getValueArray : function()
47831 //Roo.log(this.value);
47832 if (typeof(this.value) == 'undefined') {
47835 var ar = Roo.decode(this.value);
47836 return ar instanceof Array ? ar : []; //?? valid?
47839 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47844 expand : function ()
47847 Roo.form.ComboCheck.superclass.expand.call(this);
47848 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47849 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47854 collapse : function(){
47855 Roo.form.ComboCheck.superclass.collapse.call(this);
47856 var sl = this.view.getSelectedIndexes();
47857 var st = this.store;
47861 Roo.each(sl, function(i) {
47863 nv.push(r.get(this.valueField));
47865 this.setValue(Roo.encode(nv));
47866 if (this.value != this.valueBefore) {
47868 this.fireEvent('change', this, this.value, this.valueBefore);
47869 this.valueBefore = this.value;
47874 setValue : function(v){
47878 var vals = this.getValueArray();
47880 Roo.each(vals, function(k) {
47881 var r = this.findRecord(this.valueField, k);
47883 tv.push(r.data[this.displayField]);
47884 }else if(this.valueNotFoundText !== undefined){
47885 tv.push( this.valueNotFoundText );
47890 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47891 this.hiddenField.value = v;
47897 * Ext JS Library 1.1.1
47898 * Copyright(c) 2006-2007, Ext JS, LLC.
47900 * Originally Released Under LGPL - original licence link has changed is not relivant.
47903 * <script type="text/javascript">
47907 * @class Roo.form.Signature
47908 * @extends Roo.form.Field
47912 * @param {Object} config Configuration options
47915 Roo.form.Signature = function(config){
47916 Roo.form.Signature.superclass.constructor.call(this, config);
47918 this.addEvents({// not in used??
47921 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47922 * @param {Roo.form.Signature} combo This combo box
47927 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47928 * @param {Roo.form.ComboBox} combo This combo box
47929 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47935 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47937 * @cfg {Object} labels Label to use when rendering a form.
47941 * confirm : "Confirm"
47946 confirm : "Confirm"
47949 * @cfg {Number} width The signature panel width (defaults to 300)
47953 * @cfg {Number} height The signature panel height (defaults to 100)
47957 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47959 allowBlank : false,
47962 // {Object} signPanel The signature SVG panel element (defaults to {})
47964 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47965 isMouseDown : false,
47966 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47967 isConfirmed : false,
47968 // {String} signatureTmp SVG mapping string (defaults to empty string)
47972 defaultAutoCreate : { // modified by initCompnoent..
47978 onRender : function(ct, position){
47980 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47982 this.wrap = this.el.wrap({
47983 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47986 this.createToolbar(this);
47987 this.signPanel = this.wrap.createChild({
47989 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47993 this.svgID = Roo.id();
47994 this.svgEl = this.signPanel.createChild({
47995 xmlns : 'http://www.w3.org/2000/svg',
47997 id : this.svgID + "-svg",
47999 height: this.height,
48000 viewBox: '0 0 '+this.width+' '+this.height,
48004 id: this.svgID + "-svg-r",
48006 height: this.height,
48011 id: this.svgID + "-svg-l",
48013 y1: (this.height*0.8), // start set the line in 80% of height
48014 x2: this.width, // end
48015 y2: (this.height*0.8), // end set the line in 80% of height
48017 'stroke-width': "1",
48018 'stroke-dasharray': "3",
48019 'shape-rendering': "crispEdges",
48020 'pointer-events': "none"
48024 id: this.svgID + "-svg-p",
48026 'stroke-width': "3",
48028 'pointer-events': 'none'
48033 this.svgBox = this.svgEl.dom.getScreenCTM();
48035 createSVG : function(){
48036 var svg = this.signPanel;
48037 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
48040 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
48041 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
48042 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
48043 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
48044 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
48045 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
48046 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
48049 isTouchEvent : function(e){
48050 return e.type.match(/^touch/);
48052 getCoords : function (e) {
48053 var pt = this.svgEl.dom.createSVGPoint();
48056 if (this.isTouchEvent(e)) {
48057 pt.x = e.targetTouches[0].clientX;
48058 pt.y = e.targetTouches[0].clientY;
48060 var a = this.svgEl.dom.getScreenCTM();
48061 var b = a.inverse();
48062 var mx = pt.matrixTransform(b);
48063 return mx.x + ',' + mx.y;
48065 //mouse event headler
48066 down : function (e) {
48067 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
48068 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
48070 this.isMouseDown = true;
48072 e.preventDefault();
48074 move : function (e) {
48075 if (this.isMouseDown) {
48076 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
48077 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
48080 e.preventDefault();
48082 up : function (e) {
48083 this.isMouseDown = false;
48084 var sp = this.signatureTmp.split(' ');
48087 if(!sp[sp.length-2].match(/^L/)){
48091 this.signatureTmp = sp.join(" ");
48094 if(this.getValue() != this.signatureTmp){
48095 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48096 this.isConfirmed = false;
48098 e.preventDefault();
48102 * Protected method that will not generally be called directly. It
48103 * is called when the editor creates its toolbar. Override this method if you need to
48104 * add custom toolbar buttons.
48105 * @param {HtmlEditor} editor
48107 createToolbar : function(editor){
48108 function btn(id, toggle, handler){
48109 var xid = fid + '-'+ id ;
48113 cls : 'x-btn-icon x-edit-'+id,
48114 enableToggle:toggle !== false,
48115 scope: editor, // was editor...
48116 handler:handler||editor.relayBtnCmd,
48117 clickEvent:'mousedown',
48118 tooltip: etb.buttonTips[id] || undefined, ///tips ???
48124 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
48128 cls : ' x-signature-btn x-signature-'+id,
48129 scope: editor, // was editor...
48130 handler: this.reset,
48131 clickEvent:'mousedown',
48132 text: this.labels.clear
48139 cls : ' x-signature-btn x-signature-'+id,
48140 scope: editor, // was editor...
48141 handler: this.confirmHandler,
48142 clickEvent:'mousedown',
48143 text: this.labels.confirm
48150 * when user is clicked confirm then show this image.....
48152 * @return {String} Image Data URI
48154 getImageDataURI : function(){
48155 var svg = this.svgEl.dom.parentNode.innerHTML;
48156 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
48161 * @return {Boolean} this.isConfirmed
48163 getConfirmed : function(){
48164 return this.isConfirmed;
48168 * @return {Number} this.width
48170 getWidth : function(){
48175 * @return {Number} this.height
48177 getHeight : function(){
48178 return this.height;
48181 getSignature : function(){
48182 return this.signatureTmp;
48185 reset : function(){
48186 this.signatureTmp = '';
48187 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48188 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
48189 this.isConfirmed = false;
48190 Roo.form.Signature.superclass.reset.call(this);
48192 setSignature : function(s){
48193 this.signatureTmp = s;
48194 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48195 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
48197 this.isConfirmed = false;
48198 Roo.form.Signature.superclass.reset.call(this);
48201 // Roo.log(this.signPanel.dom.contentWindow.up())
48204 setConfirmed : function(){
48208 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
48211 confirmHandler : function(){
48212 if(!this.getSignature()){
48216 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
48217 this.setValue(this.getSignature());
48218 this.isConfirmed = true;
48220 this.fireEvent('confirm', this);
48223 // Subclasses should provide the validation implementation by overriding this
48224 validateValue : function(value){
48225 if(this.allowBlank){
48229 if(this.isConfirmed){
48236 * Ext JS Library 1.1.1
48237 * Copyright(c) 2006-2007, Ext JS, LLC.
48239 * Originally Released Under LGPL - original licence link has changed is not relivant.
48242 * <script type="text/javascript">
48247 * @class Roo.form.ComboBox
48248 * @extends Roo.form.TriggerField
48249 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
48251 * Create a new ComboBox.
48252 * @param {Object} config Configuration options
48254 Roo.form.Select = function(config){
48255 Roo.form.Select.superclass.constructor.call(this, config);
48259 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
48261 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
48264 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
48265 * rendering into an Roo.Editor, defaults to false)
48268 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
48269 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
48272 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
48275 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
48276 * the dropdown list (defaults to undefined, with no header element)
48280 * @cfg {String/Roo.Template} tpl The template to use to render the output
48284 defaultAutoCreate : {tag: "select" },
48286 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
48288 listWidth: undefined,
48290 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
48291 * mode = 'remote' or 'text' if mode = 'local')
48293 displayField: undefined,
48295 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
48296 * mode = 'remote' or 'value' if mode = 'local').
48297 * Note: use of a valueField requires the user make a selection
48298 * in order for a value to be mapped.
48300 valueField: undefined,
48304 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
48305 * field's data value (defaults to the underlying DOM element's name)
48307 hiddenName: undefined,
48309 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
48313 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
48315 selectedClass: 'x-combo-selected',
48317 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
48318 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
48319 * which displays a downward arrow icon).
48321 triggerClass : 'x-form-arrow-trigger',
48323 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
48327 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
48328 * anchor positions (defaults to 'tl-bl')
48330 listAlign: 'tl-bl?',
48332 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
48336 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
48337 * query specified by the allQuery config option (defaults to 'query')
48339 triggerAction: 'query',
48341 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
48342 * (defaults to 4, does not apply if editable = false)
48346 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
48347 * delay (typeAheadDelay) if it matches a known value (defaults to false)
48351 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
48352 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
48356 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
48357 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
48361 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
48362 * when editable = true (defaults to false)
48364 selectOnFocus:false,
48366 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
48368 queryParam: 'query',
48370 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
48371 * when mode = 'remote' (defaults to 'Loading...')
48373 loadingText: 'Loading...',
48375 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
48379 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
48383 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
48384 * traditional select (defaults to true)
48388 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
48392 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
48396 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
48397 * listWidth has a higher value)
48401 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
48402 * allow the user to set arbitrary text into the field (defaults to false)
48404 forceSelection:false,
48406 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
48407 * if typeAhead = true (defaults to 250)
48409 typeAheadDelay : 250,
48411 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
48412 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
48414 valueNotFoundText : undefined,
48417 * @cfg {String} defaultValue The value displayed after loading the store.
48422 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
48424 blockFocus : false,
48427 * @cfg {Boolean} disableClear Disable showing of clear button.
48429 disableClear : false,
48431 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
48433 alwaysQuery : false,
48439 // element that contains real text value.. (when hidden is used..)
48442 onRender : function(ct, position){
48443 Roo.form.Field.prototype.onRender.call(this, ct, position);
48446 this.store.on('beforeload', this.onBeforeLoad, this);
48447 this.store.on('load', this.onLoad, this);
48448 this.store.on('loadexception', this.onLoadException, this);
48449 this.store.load({});
48457 initEvents : function(){
48458 //Roo.form.ComboBox.superclass.initEvents.call(this);
48462 onDestroy : function(){
48465 this.store.un('beforeload', this.onBeforeLoad, this);
48466 this.store.un('load', this.onLoad, this);
48467 this.store.un('loadexception', this.onLoadException, this);
48469 //Roo.form.ComboBox.superclass.onDestroy.call(this);
48473 fireKey : function(e){
48474 if(e.isNavKeyPress() && !this.list.isVisible()){
48475 this.fireEvent("specialkey", this, e);
48480 onResize: function(w, h){
48488 * Allow or prevent the user from directly editing the field text. If false is passed,
48489 * the user will only be able to select from the items defined in the dropdown list. This method
48490 * is the runtime equivalent of setting the 'editable' config option at config time.
48491 * @param {Boolean} value True to allow the user to directly edit the field text
48493 setEditable : function(value){
48498 onBeforeLoad : function(){
48500 Roo.log("Select before load");
48503 this.innerList.update(this.loadingText ?
48504 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
48505 //this.restrictHeight();
48506 this.selectedIndex = -1;
48510 onLoad : function(){
48513 var dom = this.el.dom;
48514 dom.innerHTML = '';
48515 var od = dom.ownerDocument;
48517 if (this.emptyText) {
48518 var op = od.createElement('option');
48519 op.setAttribute('value', '');
48520 op.innerHTML = String.format('{0}', this.emptyText);
48521 dom.appendChild(op);
48523 if(this.store.getCount() > 0){
48525 var vf = this.valueField;
48526 var df = this.displayField;
48527 this.store.data.each(function(r) {
48528 // which colmsn to use... testing - cdoe / title..
48529 var op = od.createElement('option');
48530 op.setAttribute('value', r.data[vf]);
48531 op.innerHTML = String.format('{0}', r.data[df]);
48532 dom.appendChild(op);
48534 if (typeof(this.defaultValue != 'undefined')) {
48535 this.setValue(this.defaultValue);
48540 //this.onEmptyResults();
48545 onLoadException : function()
48547 dom.innerHTML = '';
48549 Roo.log("Select on load exception");
48553 Roo.log(this.store.reader.jsonData);
48554 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
48555 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
48561 onTypeAhead : function(){
48566 onSelect : function(record, index){
48567 Roo.log('on select?');
48569 if(this.fireEvent('beforeselect', this, record, index) !== false){
48570 this.setFromData(index > -1 ? record.data : false);
48572 this.fireEvent('select', this, record, index);
48577 * Returns the currently selected field value or empty string if no value is set.
48578 * @return {String} value The selected value
48580 getValue : function(){
48581 var dom = this.el.dom;
48582 this.value = dom.options[dom.selectedIndex].value;
48588 * Clears any text/value currently set in the field
48590 clearValue : function(){
48592 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
48597 * Sets the specified value into the field. If the value finds a match, the corresponding record text
48598 * will be displayed in the field. If the value does not match the data value of an existing item,
48599 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
48600 * Otherwise the field will be blank (although the value will still be set).
48601 * @param {String} value The value to match
48603 setValue : function(v){
48604 var d = this.el.dom;
48605 for (var i =0; i < d.options.length;i++) {
48606 if (v == d.options[i].value) {
48607 d.selectedIndex = i;
48615 * @property {Object} the last set data for the element
48620 * Sets the value of the field based on a object which is related to the record format for the store.
48621 * @param {Object} value the value to set as. or false on reset?
48623 setFromData : function(o){
48624 Roo.log('setfrom data?');
48630 reset : function(){
48634 findRecord : function(prop, value){
48639 if(this.store.getCount() > 0){
48640 this.store.each(function(r){
48641 if(r.data[prop] == value){
48651 getName: function()
48653 // returns hidden if it's set..
48654 if (!this.rendered) {return ''};
48655 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
48663 onEmptyResults : function(){
48664 Roo.log('empty results');
48669 * Returns true if the dropdown list is expanded, else false.
48671 isExpanded : function(){
48676 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
48677 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48678 * @param {String} value The data value of the item to select
48679 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48680 * selected item if it is not currently in view (defaults to true)
48681 * @return {Boolean} True if the value matched an item in the list, else false
48683 selectByValue : function(v, scrollIntoView){
48684 Roo.log('select By Value');
48687 if(v !== undefined && v !== null){
48688 var r = this.findRecord(this.valueField || this.displayField, v);
48690 this.select(this.store.indexOf(r), scrollIntoView);
48698 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
48699 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48700 * @param {Number} index The zero-based index of the list item to select
48701 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48702 * selected item if it is not currently in view (defaults to true)
48704 select : function(index, scrollIntoView){
48705 Roo.log('select ');
48708 this.selectedIndex = index;
48709 this.view.select(index);
48710 if(scrollIntoView !== false){
48711 var el = this.view.getNode(index);
48713 this.innerList.scrollChildIntoView(el, false);
48721 validateBlur : function(){
48728 initQuery : function(){
48729 this.doQuery(this.getRawValue());
48733 doForce : function(){
48734 if(this.el.dom.value.length > 0){
48735 this.el.dom.value =
48736 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
48742 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
48743 * query allowing the query action to be canceled if needed.
48744 * @param {String} query The SQL query to execute
48745 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
48746 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
48747 * saved in the current store (defaults to false)
48749 doQuery : function(q, forceAll){
48751 Roo.log('doQuery?');
48752 if(q === undefined || q === null){
48757 forceAll: forceAll,
48761 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48765 forceAll = qe.forceAll;
48766 if(forceAll === true || (q.length >= this.minChars)){
48767 if(this.lastQuery != q || this.alwaysQuery){
48768 this.lastQuery = q;
48769 if(this.mode == 'local'){
48770 this.selectedIndex = -1;
48772 this.store.clearFilter();
48774 this.store.filter(this.displayField, q);
48778 this.store.baseParams[this.queryParam] = q;
48780 params: this.getParams(q)
48785 this.selectedIndex = -1;
48792 getParams : function(q){
48794 //p[this.queryParam] = q;
48797 p.limit = this.pageSize;
48803 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48805 collapse : function(){
48810 collapseIf : function(e){
48815 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48817 expand : function(){
48825 * @cfg {Boolean} grow
48829 * @cfg {Number} growMin
48833 * @cfg {Number} growMax
48841 setWidth : function()
48845 getResizeEl : function(){
48848 });//<script type="text/javasscript">
48852 * @class Roo.DDView
48853 * A DnD enabled version of Roo.View.
48854 * @param {Element/String} container The Element in which to create the View.
48855 * @param {String} tpl The template string used to create the markup for each element of the View
48856 * @param {Object} config The configuration properties. These include all the config options of
48857 * {@link Roo.View} plus some specific to this class.<br>
48859 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48860 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48862 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48863 .x-view-drag-insert-above {
48864 border-top:1px dotted #3366cc;
48866 .x-view-drag-insert-below {
48867 border-bottom:1px dotted #3366cc;
48873 Roo.DDView = function(container, tpl, config) {
48874 Roo.DDView.superclass.constructor.apply(this, arguments);
48875 this.getEl().setStyle("outline", "0px none");
48876 this.getEl().unselectable();
48877 if (this.dragGroup) {
48878 this.setDraggable(this.dragGroup.split(","));
48880 if (this.dropGroup) {
48881 this.setDroppable(this.dropGroup.split(","));
48883 if (this.deletable) {
48884 this.setDeletable();
48886 this.isDirtyFlag = false;
48892 Roo.extend(Roo.DDView, Roo.View, {
48893 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48894 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48895 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48896 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48900 reset: Roo.emptyFn,
48902 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48904 validate: function() {
48908 destroy: function() {
48909 this.purgeListeners();
48910 this.getEl.removeAllListeners();
48911 this.getEl().remove();
48912 if (this.dragZone) {
48913 if (this.dragZone.destroy) {
48914 this.dragZone.destroy();
48917 if (this.dropZone) {
48918 if (this.dropZone.destroy) {
48919 this.dropZone.destroy();
48924 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48925 getName: function() {
48929 /** Loads the View from a JSON string representing the Records to put into the Store. */
48930 setValue: function(v) {
48932 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48935 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48936 this.store.proxy = new Roo.data.MemoryProxy(data);
48940 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48941 getValue: function() {
48943 this.store.each(function(rec) {
48944 result += rec.id + ',';
48946 return result.substr(0, result.length - 1) + ')';
48949 getIds: function() {
48950 var i = 0, result = new Array(this.store.getCount());
48951 this.store.each(function(rec) {
48952 result[i++] = rec.id;
48957 isDirty: function() {
48958 return this.isDirtyFlag;
48962 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48963 * whole Element becomes the target, and this causes the drop gesture to append.
48965 getTargetFromEvent : function(e) {
48966 var target = e.getTarget();
48967 while ((target !== null) && (target.parentNode != this.el.dom)) {
48968 target = target.parentNode;
48971 target = this.el.dom.lastChild || this.el.dom;
48977 * Create the drag data which consists of an object which has the property "ddel" as
48978 * the drag proxy element.
48980 getDragData : function(e) {
48981 var target = this.findItemFromChild(e.getTarget());
48983 this.handleSelection(e);
48984 var selNodes = this.getSelectedNodes();
48987 copy: this.copy || (this.allowCopy && e.ctrlKey),
48991 var selectedIndices = this.getSelectedIndexes();
48992 for (var i = 0; i < selectedIndices.length; i++) {
48993 dragData.records.push(this.store.getAt(selectedIndices[i]));
48995 if (selNodes.length == 1) {
48996 dragData.ddel = target.cloneNode(true); // the div element
48998 var div = document.createElement('div'); // create the multi element drag "ghost"
48999 div.className = 'multi-proxy';
49000 for (var i = 0, len = selNodes.length; i < len; i++) {
49001 div.appendChild(selNodes[i].cloneNode(true));
49003 dragData.ddel = div;
49005 //console.log(dragData)
49006 //console.log(dragData.ddel.innerHTML)
49009 //console.log('nodragData')
49013 /** Specify to which ddGroup items in this DDView may be dragged. */
49014 setDraggable: function(ddGroup) {
49015 if (ddGroup instanceof Array) {
49016 Roo.each(ddGroup, this.setDraggable, this);
49019 if (this.dragZone) {
49020 this.dragZone.addToGroup(ddGroup);
49022 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
49023 containerScroll: true,
49027 // Draggability implies selection. DragZone's mousedown selects the element.
49028 if (!this.multiSelect) { this.singleSelect = true; }
49030 // Wire the DragZone's handlers up to methods in *this*
49031 this.dragZone.getDragData = this.getDragData.createDelegate(this);
49035 /** Specify from which ddGroup this DDView accepts drops. */
49036 setDroppable: function(ddGroup) {
49037 if (ddGroup instanceof Array) {
49038 Roo.each(ddGroup, this.setDroppable, this);
49041 if (this.dropZone) {
49042 this.dropZone.addToGroup(ddGroup);
49044 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
49045 containerScroll: true,
49049 // Wire the DropZone's handlers up to methods in *this*
49050 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
49051 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
49052 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
49053 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
49054 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
49058 /** Decide whether to drop above or below a View node. */
49059 getDropPoint : function(e, n, dd){
49060 if (n == this.el.dom) { return "above"; }
49061 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
49062 var c = t + (b - t) / 2;
49063 var y = Roo.lib.Event.getPageY(e);
49071 onNodeEnter : function(n, dd, e, data){
49075 onNodeOver : function(n, dd, e, data){
49076 var pt = this.getDropPoint(e, n, dd);
49077 // set the insert point style on the target node
49078 var dragElClass = this.dropNotAllowed;
49081 if (pt == "above"){
49082 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
49083 targetElClass = "x-view-drag-insert-above";
49085 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
49086 targetElClass = "x-view-drag-insert-below";
49088 if (this.lastInsertClass != targetElClass){
49089 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
49090 this.lastInsertClass = targetElClass;
49093 return dragElClass;
49096 onNodeOut : function(n, dd, e, data){
49097 this.removeDropIndicators(n);
49100 onNodeDrop : function(n, dd, e, data){
49101 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
49104 var pt = this.getDropPoint(e, n, dd);
49105 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
49106 if (pt == "below") { insertAt++; }
49107 for (var i = 0; i < data.records.length; i++) {
49108 var r = data.records[i];
49109 var dup = this.store.getById(r.id);
49110 if (dup && (dd != this.dragZone)) {
49111 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
49114 this.store.insert(insertAt++, r.copy());
49116 data.source.isDirtyFlag = true;
49118 this.store.insert(insertAt++, r);
49120 this.isDirtyFlag = true;
49123 this.dragZone.cachedTarget = null;
49127 removeDropIndicators : function(n){
49129 Roo.fly(n).removeClass([
49130 "x-view-drag-insert-above",
49131 "x-view-drag-insert-below"]);
49132 this.lastInsertClass = "_noclass";
49137 * Utility method. Add a delete option to the DDView's context menu.
49138 * @param {String} imageUrl The URL of the "delete" icon image.
49140 setDeletable: function(imageUrl) {
49141 if (!this.singleSelect && !this.multiSelect) {
49142 this.singleSelect = true;
49144 var c = this.getContextMenu();
49145 this.contextMenu.on("itemclick", function(item) {
49148 this.remove(this.getSelectedIndexes());
49152 this.contextMenu.add({
49159 /** Return the context menu for this DDView. */
49160 getContextMenu: function() {
49161 if (!this.contextMenu) {
49162 // Create the View's context menu
49163 this.contextMenu = new Roo.menu.Menu({
49164 id: this.id + "-contextmenu"
49166 this.el.on("contextmenu", this.showContextMenu, this);
49168 return this.contextMenu;
49171 disableContextMenu: function() {
49172 if (this.contextMenu) {
49173 this.el.un("contextmenu", this.showContextMenu, this);
49177 showContextMenu: function(e, item) {
49178 item = this.findItemFromChild(e.getTarget());
49181 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
49182 this.contextMenu.showAt(e.getXY());
49187 * Remove {@link Roo.data.Record}s at the specified indices.
49188 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
49190 remove: function(selectedIndices) {
49191 selectedIndices = [].concat(selectedIndices);
49192 for (var i = 0; i < selectedIndices.length; i++) {
49193 var rec = this.store.getAt(selectedIndices[i]);
49194 this.store.remove(rec);
49199 * Double click fires the event, but also, if this is draggable, and there is only one other
49200 * related DropZone, it transfers the selected node.
49202 onDblClick : function(e){
49203 var item = this.findItemFromChild(e.getTarget());
49205 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
49208 if (this.dragGroup) {
49209 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
49210 while (targets.indexOf(this.dropZone) > -1) {
49211 targets.remove(this.dropZone);
49213 if (targets.length == 1) {
49214 this.dragZone.cachedTarget = null;
49215 var el = Roo.get(targets[0].getEl());
49216 var box = el.getBox(true);
49217 targets[0].onNodeDrop(el.dom, {
49219 xy: [box.x, box.y + box.height - 1]
49220 }, null, this.getDragData(e));
49226 handleSelection: function(e) {
49227 this.dragZone.cachedTarget = null;
49228 var item = this.findItemFromChild(e.getTarget());
49230 this.clearSelections(true);
49233 if (item && (this.multiSelect || this.singleSelect)){
49234 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
49235 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
49236 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
49237 this.unselect(item);
49239 this.select(item, this.multiSelect && e.ctrlKey);
49240 this.lastSelection = item;
49245 onItemClick : function(item, index, e){
49246 if(this.fireEvent("beforeclick", this, index, item, e) === false){
49252 unselect : function(nodeInfo, suppressEvent){
49253 var node = this.getNode(nodeInfo);
49254 if(node && this.isSelected(node)){
49255 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
49256 Roo.fly(node).removeClass(this.selectedClass);
49257 this.selections.remove(node);
49258 if(!suppressEvent){
49259 this.fireEvent("selectionchange", this, this.selections);
49267 * Ext JS Library 1.1.1
49268 * Copyright(c) 2006-2007, Ext JS, LLC.
49270 * Originally Released Under LGPL - original licence link has changed is not relivant.
49273 * <script type="text/javascript">
49277 * @class Roo.LayoutManager
49278 * @extends Roo.util.Observable
49279 * Base class for layout managers.
49281 Roo.LayoutManager = function(container, config){
49282 Roo.LayoutManager.superclass.constructor.call(this);
49283 this.el = Roo.get(container);
49284 // ie scrollbar fix
49285 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
49286 document.body.scroll = "no";
49287 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
49288 this.el.position('relative');
49290 this.id = this.el.id;
49291 this.el.addClass("x-layout-container");
49292 /** false to disable window resize monitoring @type Boolean */
49293 this.monitorWindowResize = true;
49298 * Fires when a layout is performed.
49299 * @param {Roo.LayoutManager} this
49303 * @event regionresized
49304 * Fires when the user resizes a region.
49305 * @param {Roo.LayoutRegion} region The resized region
49306 * @param {Number} newSize The new size (width for east/west, height for north/south)
49308 "regionresized" : true,
49310 * @event regioncollapsed
49311 * Fires when a region is collapsed.
49312 * @param {Roo.LayoutRegion} region The collapsed region
49314 "regioncollapsed" : true,
49316 * @event regionexpanded
49317 * Fires when a region is expanded.
49318 * @param {Roo.LayoutRegion} region The expanded region
49320 "regionexpanded" : true
49322 this.updating = false;
49323 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
49326 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
49328 * Returns true if this layout is currently being updated
49329 * @return {Boolean}
49331 isUpdating : function(){
49332 return this.updating;
49336 * Suspend the LayoutManager from doing auto-layouts while
49337 * making multiple add or remove calls
49339 beginUpdate : function(){
49340 this.updating = true;
49344 * Restore auto-layouts and optionally disable the manager from performing a layout
49345 * @param {Boolean} noLayout true to disable a layout update
49347 endUpdate : function(noLayout){
49348 this.updating = false;
49354 layout: function(){
49358 onRegionResized : function(region, newSize){
49359 this.fireEvent("regionresized", region, newSize);
49363 onRegionCollapsed : function(region){
49364 this.fireEvent("regioncollapsed", region);
49367 onRegionExpanded : function(region){
49368 this.fireEvent("regionexpanded", region);
49372 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
49373 * performs box-model adjustments.
49374 * @return {Object} The size as an object {width: (the width), height: (the height)}
49376 getViewSize : function(){
49378 if(this.el.dom != document.body){
49379 size = this.el.getSize();
49381 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
49383 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
49384 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
49389 * Returns the Element this layout is bound to.
49390 * @return {Roo.Element}
49392 getEl : function(){
49397 * Returns the specified region.
49398 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
49399 * @return {Roo.LayoutRegion}
49401 getRegion : function(target){
49402 return this.regions[target.toLowerCase()];
49405 onWindowResize : function(){
49406 if(this.monitorWindowResize){
49412 * Ext JS Library 1.1.1
49413 * Copyright(c) 2006-2007, Ext JS, LLC.
49415 * Originally Released Under LGPL - original licence link has changed is not relivant.
49418 * <script type="text/javascript">
49421 * @class Roo.BorderLayout
49422 * @extends Roo.LayoutManager
49423 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
49424 * please see: <br><br>
49425 * <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>
49426 * <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>
49429 var layout = new Roo.BorderLayout(document.body, {
49463 preferredTabWidth: 150
49468 var CP = Roo.ContentPanel;
49470 layout.beginUpdate();
49471 layout.add("north", new CP("north", "North"));
49472 layout.add("south", new CP("south", {title: "South", closable: true}));
49473 layout.add("west", new CP("west", {title: "West"}));
49474 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
49475 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
49476 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
49477 layout.getRegion("center").showPanel("center1");
49478 layout.endUpdate();
49481 <b>The container the layout is rendered into can be either the body element or any other element.
49482 If it is not the body element, the container needs to either be an absolute positioned element,
49483 or you will need to add "position:relative" to the css of the container. You will also need to specify
49484 the container size if it is not the body element.</b>
49487 * Create a new BorderLayout
49488 * @param {String/HTMLElement/Element} container The container this layout is bound to
49489 * @param {Object} config Configuration options
49491 Roo.BorderLayout = function(container, config){
49492 config = config || {};
49493 Roo.BorderLayout.superclass.constructor.call(this, container, config);
49494 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
49495 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
49496 var target = this.factory.validRegions[i];
49497 if(config[target]){
49498 this.addRegion(target, config[target]);
49503 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
49505 * Creates and adds a new region if it doesn't already exist.
49506 * @param {String} target The target region key (north, south, east, west or center).
49507 * @param {Object} config The regions config object
49508 * @return {BorderLayoutRegion} The new region
49510 addRegion : function(target, config){
49511 if(!this.regions[target]){
49512 var r = this.factory.create(target, this, config);
49513 this.bindRegion(target, r);
49515 return this.regions[target];
49519 bindRegion : function(name, r){
49520 this.regions[name] = r;
49521 r.on("visibilitychange", this.layout, this);
49522 r.on("paneladded", this.layout, this);
49523 r.on("panelremoved", this.layout, this);
49524 r.on("invalidated", this.layout, this);
49525 r.on("resized", this.onRegionResized, this);
49526 r.on("collapsed", this.onRegionCollapsed, this);
49527 r.on("expanded", this.onRegionExpanded, this);
49531 * Performs a layout update.
49533 layout : function(){
49534 if(this.updating) {
49537 var size = this.getViewSize();
49538 var w = size.width;
49539 var h = size.height;
49544 //var x = 0, y = 0;
49546 var rs = this.regions;
49547 var north = rs["north"];
49548 var south = rs["south"];
49549 var west = rs["west"];
49550 var east = rs["east"];
49551 var center = rs["center"];
49552 //if(this.hideOnLayout){ // not supported anymore
49553 //c.el.setStyle("display", "none");
49555 if(north && north.isVisible()){
49556 var b = north.getBox();
49557 var m = north.getMargins();
49558 b.width = w - (m.left+m.right);
49561 centerY = b.height + b.y + m.bottom;
49562 centerH -= centerY;
49563 north.updateBox(this.safeBox(b));
49565 if(south && south.isVisible()){
49566 var b = south.getBox();
49567 var m = south.getMargins();
49568 b.width = w - (m.left+m.right);
49570 var totalHeight = (b.height + m.top + m.bottom);
49571 b.y = h - totalHeight + m.top;
49572 centerH -= totalHeight;
49573 south.updateBox(this.safeBox(b));
49575 if(west && west.isVisible()){
49576 var b = west.getBox();
49577 var m = west.getMargins();
49578 b.height = centerH - (m.top+m.bottom);
49580 b.y = centerY + m.top;
49581 var totalWidth = (b.width + m.left + m.right);
49582 centerX += totalWidth;
49583 centerW -= totalWidth;
49584 west.updateBox(this.safeBox(b));
49586 if(east && east.isVisible()){
49587 var b = east.getBox();
49588 var m = east.getMargins();
49589 b.height = centerH - (m.top+m.bottom);
49590 var totalWidth = (b.width + m.left + m.right);
49591 b.x = w - totalWidth + m.left;
49592 b.y = centerY + m.top;
49593 centerW -= totalWidth;
49594 east.updateBox(this.safeBox(b));
49597 var m = center.getMargins();
49599 x: centerX + m.left,
49600 y: centerY + m.top,
49601 width: centerW - (m.left+m.right),
49602 height: centerH - (m.top+m.bottom)
49604 //if(this.hideOnLayout){
49605 //center.el.setStyle("display", "block");
49607 center.updateBox(this.safeBox(centerBox));
49610 this.fireEvent("layout", this);
49614 safeBox : function(box){
49615 box.width = Math.max(0, box.width);
49616 box.height = Math.max(0, box.height);
49621 * Adds a ContentPanel (or subclass) to this layout.
49622 * @param {String} target The target region key (north, south, east, west or center).
49623 * @param {Roo.ContentPanel} panel The panel to add
49624 * @return {Roo.ContentPanel} The added panel
49626 add : function(target, panel){
49628 target = target.toLowerCase();
49629 return this.regions[target].add(panel);
49633 * Remove a ContentPanel (or subclass) to this layout.
49634 * @param {String} target The target region key (north, south, east, west or center).
49635 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
49636 * @return {Roo.ContentPanel} The removed panel
49638 remove : function(target, panel){
49639 target = target.toLowerCase();
49640 return this.regions[target].remove(panel);
49644 * Searches all regions for a panel with the specified id
49645 * @param {String} panelId
49646 * @return {Roo.ContentPanel} The panel or null if it wasn't found
49648 findPanel : function(panelId){
49649 var rs = this.regions;
49650 for(var target in rs){
49651 if(typeof rs[target] != "function"){
49652 var p = rs[target].getPanel(panelId);
49662 * Searches all regions for a panel with the specified id and activates (shows) it.
49663 * @param {String/ContentPanel} panelId The panels id or the panel itself
49664 * @return {Roo.ContentPanel} The shown panel or null
49666 showPanel : function(panelId) {
49667 var rs = this.regions;
49668 for(var target in rs){
49669 var r = rs[target];
49670 if(typeof r != "function"){
49671 if(r.hasPanel(panelId)){
49672 return r.showPanel(panelId);
49680 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
49681 * @param {Roo.state.Provider} provider (optional) An alternate state provider
49683 restoreState : function(provider){
49685 provider = Roo.state.Manager;
49687 var sm = new Roo.LayoutStateManager();
49688 sm.init(this, provider);
49692 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
49693 * object should contain properties for each region to add ContentPanels to, and each property's value should be
49694 * a valid ContentPanel config object. Example:
49696 // Create the main layout
49697 var layout = new Roo.BorderLayout('main-ct', {
49708 // Create and add multiple ContentPanels at once via configs
49711 id: 'source-files',
49713 title:'Ext Source Files',
49726 * @param {Object} regions An object containing ContentPanel configs by region name
49728 batchAdd : function(regions){
49729 this.beginUpdate();
49730 for(var rname in regions){
49731 var lr = this.regions[rname];
49733 this.addTypedPanels(lr, regions[rname]);
49740 addTypedPanels : function(lr, ps){
49741 if(typeof ps == 'string'){
49742 lr.add(new Roo.ContentPanel(ps));
49744 else if(ps instanceof Array){
49745 for(var i =0, len = ps.length; i < len; i++){
49746 this.addTypedPanels(lr, ps[i]);
49749 else if(!ps.events){ // raw config?
49751 delete ps.el; // prevent conflict
49752 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
49754 else { // panel object assumed!
49759 * Adds a xtype elements to the layout.
49763 xtype : 'ContentPanel',
49770 xtype : 'NestedLayoutPanel',
49776 items : [ ... list of content panels or nested layout panels.. ]
49780 * @param {Object} cfg Xtype definition of item to add.
49782 addxtype : function(cfg)
49784 // basically accepts a pannel...
49785 // can accept a layout region..!?!?
49786 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49788 if (!cfg.xtype.match(/Panel$/)) {
49793 if (typeof(cfg.region) == 'undefined') {
49794 Roo.log("Failed to add Panel, region was not set");
49798 var region = cfg.region;
49804 xitems = cfg.items;
49811 case 'ContentPanel': // ContentPanel (el, cfg)
49812 case 'ScrollPanel': // ContentPanel (el, cfg)
49814 if(cfg.autoCreate) {
49815 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49817 var el = this.el.createChild();
49818 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49821 this.add(region, ret);
49825 case 'TreePanel': // our new panel!
49826 cfg.el = this.el.createChild();
49827 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49828 this.add(region, ret);
49831 case 'NestedLayoutPanel':
49832 // create a new Layout (which is a Border Layout...
49833 var el = this.el.createChild();
49834 var clayout = cfg.layout;
49836 clayout.items = clayout.items || [];
49837 // replace this exitems with the clayout ones..
49838 xitems = clayout.items;
49841 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49842 cfg.background = false;
49844 var layout = new Roo.BorderLayout(el, clayout);
49846 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49847 //console.log('adding nested layout panel ' + cfg.toSource());
49848 this.add(region, ret);
49849 nb = {}; /// find first...
49854 // needs grid and region
49856 //var el = this.getRegion(region).el.createChild();
49857 var el = this.el.createChild();
49858 // create the grid first...
49860 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49862 if (region == 'center' && this.active ) {
49863 cfg.background = false;
49865 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49867 this.add(region, ret);
49868 if (cfg.background) {
49869 ret.on('activate', function(gp) {
49870 if (!gp.grid.rendered) {
49885 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49887 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49888 this.add(region, ret);
49891 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49895 // GridPanel (grid, cfg)
49898 this.beginUpdate();
49902 Roo.each(xitems, function(i) {
49903 region = nb && i.region ? i.region : false;
49905 var add = ret.addxtype(i);
49908 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49909 if (!i.background) {
49910 abn[region] = nb[region] ;
49917 // make the last non-background panel active..
49918 //if (nb) { Roo.log(abn); }
49921 for(var r in abn) {
49922 region = this.getRegion(r);
49924 // tried using nb[r], but it does not work..
49926 region.showPanel(abn[r]);
49937 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49938 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49939 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49940 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49943 var CP = Roo.ContentPanel;
49945 var layout = Roo.BorderLayout.create({
49949 panels: [new CP("north", "North")]
49958 panels: [new CP("west", {title: "West"})]
49967 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49976 panels: [new CP("south", {title: "South", closable: true})]
49983 preferredTabWidth: 150,
49985 new CP("center1", {title: "Close Me", closable: true}),
49986 new CP("center2", {title: "Center Panel", closable: false})
49991 layout.getRegion("center").showPanel("center1");
49996 Roo.BorderLayout.create = function(config, targetEl){
49997 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49998 layout.beginUpdate();
49999 var regions = Roo.BorderLayout.RegionFactory.validRegions;
50000 for(var j = 0, jlen = regions.length; j < jlen; j++){
50001 var lr = regions[j];
50002 if(layout.regions[lr] && config[lr].panels){
50003 var r = layout.regions[lr];
50004 var ps = config[lr].panels;
50005 layout.addTypedPanels(r, ps);
50008 layout.endUpdate();
50013 Roo.BorderLayout.RegionFactory = {
50015 validRegions : ["north","south","east","west","center"],
50018 create : function(target, mgr, config){
50019 target = target.toLowerCase();
50020 if(config.lightweight || config.basic){
50021 return new Roo.BasicLayoutRegion(mgr, config, target);
50025 return new Roo.NorthLayoutRegion(mgr, config);
50027 return new Roo.SouthLayoutRegion(mgr, config);
50029 return new Roo.EastLayoutRegion(mgr, config);
50031 return new Roo.WestLayoutRegion(mgr, config);
50033 return new Roo.CenterLayoutRegion(mgr, config);
50035 throw 'Layout region "'+target+'" not supported.';
50039 * Ext JS Library 1.1.1
50040 * Copyright(c) 2006-2007, Ext JS, LLC.
50042 * Originally Released Under LGPL - original licence link has changed is not relivant.
50045 * <script type="text/javascript">
50049 * @class Roo.BasicLayoutRegion
50050 * @extends Roo.util.Observable
50051 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
50052 * and does not have a titlebar, tabs or any other features. All it does is size and position
50053 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
50055 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
50057 this.position = pos;
50060 * @scope Roo.BasicLayoutRegion
50064 * @event beforeremove
50065 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
50066 * @param {Roo.LayoutRegion} this
50067 * @param {Roo.ContentPanel} panel The panel
50068 * @param {Object} e The cancel event object
50070 "beforeremove" : true,
50072 * @event invalidated
50073 * Fires when the layout for this region is changed.
50074 * @param {Roo.LayoutRegion} this
50076 "invalidated" : true,
50078 * @event visibilitychange
50079 * Fires when this region is shown or hidden
50080 * @param {Roo.LayoutRegion} this
50081 * @param {Boolean} visibility true or false
50083 "visibilitychange" : true,
50085 * @event paneladded
50086 * Fires when a panel is added.
50087 * @param {Roo.LayoutRegion} this
50088 * @param {Roo.ContentPanel} panel The panel
50090 "paneladded" : true,
50092 * @event panelremoved
50093 * Fires when a panel is removed.
50094 * @param {Roo.LayoutRegion} this
50095 * @param {Roo.ContentPanel} panel The panel
50097 "panelremoved" : true,
50100 * Fires when this region is collapsed.
50101 * @param {Roo.LayoutRegion} this
50103 "collapsed" : true,
50106 * Fires when this region is expanded.
50107 * @param {Roo.LayoutRegion} this
50112 * Fires when this region is slid into view.
50113 * @param {Roo.LayoutRegion} this
50115 "slideshow" : true,
50118 * Fires when this region slides out of view.
50119 * @param {Roo.LayoutRegion} this
50121 "slidehide" : true,
50123 * @event panelactivated
50124 * Fires when a panel is activated.
50125 * @param {Roo.LayoutRegion} this
50126 * @param {Roo.ContentPanel} panel The activated panel
50128 "panelactivated" : true,
50131 * Fires when the user resizes this region.
50132 * @param {Roo.LayoutRegion} this
50133 * @param {Number} newSize The new size (width for east/west, height for north/south)
50137 /** A collection of panels in this region. @type Roo.util.MixedCollection */
50138 this.panels = new Roo.util.MixedCollection();
50139 this.panels.getKey = this.getPanelId.createDelegate(this);
50141 this.activePanel = null;
50142 // ensure listeners are added...
50144 if (config.listeners || config.events) {
50145 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
50146 listeners : config.listeners || {},
50147 events : config.events || {}
50151 if(skipConfig !== true){
50152 this.applyConfig(config);
50156 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
50157 getPanelId : function(p){
50161 applyConfig : function(config){
50162 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50163 this.config = config;
50168 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
50169 * the width, for horizontal (north, south) the height.
50170 * @param {Number} newSize The new width or height
50172 resizeTo : function(newSize){
50173 var el = this.el ? this.el :
50174 (this.activePanel ? this.activePanel.getEl() : null);
50176 switch(this.position){
50179 el.setWidth(newSize);
50180 this.fireEvent("resized", this, newSize);
50184 el.setHeight(newSize);
50185 this.fireEvent("resized", this, newSize);
50191 getBox : function(){
50192 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
50195 getMargins : function(){
50196 return this.margins;
50199 updateBox : function(box){
50201 var el = this.activePanel.getEl();
50202 el.dom.style.left = box.x + "px";
50203 el.dom.style.top = box.y + "px";
50204 this.activePanel.setSize(box.width, box.height);
50208 * Returns the container element for this region.
50209 * @return {Roo.Element}
50211 getEl : function(){
50212 return this.activePanel;
50216 * Returns true if this region is currently visible.
50217 * @return {Boolean}
50219 isVisible : function(){
50220 return this.activePanel ? true : false;
50223 setActivePanel : function(panel){
50224 panel = this.getPanel(panel);
50225 if(this.activePanel && this.activePanel != panel){
50226 this.activePanel.setActiveState(false);
50227 this.activePanel.getEl().setLeftTop(-10000,-10000);
50229 this.activePanel = panel;
50230 panel.setActiveState(true);
50232 panel.setSize(this.box.width, this.box.height);
50234 this.fireEvent("panelactivated", this, panel);
50235 this.fireEvent("invalidated");
50239 * Show the specified panel.
50240 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
50241 * @return {Roo.ContentPanel} The shown panel or null
50243 showPanel : function(panel){
50244 if(panel = this.getPanel(panel)){
50245 this.setActivePanel(panel);
50251 * Get the active panel for this region.
50252 * @return {Roo.ContentPanel} The active panel or null
50254 getActivePanel : function(){
50255 return this.activePanel;
50259 * Add the passed ContentPanel(s)
50260 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50261 * @return {Roo.ContentPanel} The panel added (if only one was added)
50263 add : function(panel){
50264 if(arguments.length > 1){
50265 for(var i = 0, len = arguments.length; i < len; i++) {
50266 this.add(arguments[i]);
50270 if(this.hasPanel(panel)){
50271 this.showPanel(panel);
50274 var el = panel.getEl();
50275 if(el.dom.parentNode != this.mgr.el.dom){
50276 this.mgr.el.dom.appendChild(el.dom);
50278 if(panel.setRegion){
50279 panel.setRegion(this);
50281 this.panels.add(panel);
50282 el.setStyle("position", "absolute");
50283 if(!panel.background){
50284 this.setActivePanel(panel);
50285 if(this.config.initialSize && this.panels.getCount()==1){
50286 this.resizeTo(this.config.initialSize);
50289 this.fireEvent("paneladded", this, panel);
50294 * Returns true if the panel is in this region.
50295 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50296 * @return {Boolean}
50298 hasPanel : function(panel){
50299 if(typeof panel == "object"){ // must be panel obj
50300 panel = panel.getId();
50302 return this.getPanel(panel) ? true : false;
50306 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50307 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50308 * @param {Boolean} preservePanel Overrides the config preservePanel option
50309 * @return {Roo.ContentPanel} The panel that was removed
50311 remove : function(panel, preservePanel){
50312 panel = this.getPanel(panel);
50317 this.fireEvent("beforeremove", this, panel, e);
50318 if(e.cancel === true){
50321 var panelId = panel.getId();
50322 this.panels.removeKey(panelId);
50327 * Returns the panel specified or null if it's not in this region.
50328 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50329 * @return {Roo.ContentPanel}
50331 getPanel : function(id){
50332 if(typeof id == "object"){ // must be panel obj
50335 return this.panels.get(id);
50339 * Returns this regions position (north/south/east/west/center).
50342 getPosition: function(){
50343 return this.position;
50347 * Ext JS Library 1.1.1
50348 * Copyright(c) 2006-2007, Ext JS, LLC.
50350 * Originally Released Under LGPL - original licence link has changed is not relivant.
50353 * <script type="text/javascript">
50357 * @class Roo.LayoutRegion
50358 * @extends Roo.BasicLayoutRegion
50359 * This class represents a region in a layout manager.
50360 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
50361 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
50362 * @cfg {Boolean} floatable False to disable floating (defaults to true)
50363 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
50364 * @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})
50365 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
50366 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
50367 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
50368 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
50369 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
50370 * @cfg {String} title The title for the region (overrides panel titles)
50371 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
50372 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
50373 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
50374 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
50375 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
50376 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
50377 * the space available, similar to FireFox 1.5 tabs (defaults to false)
50378 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
50379 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
50380 * @cfg {Boolean} showPin True to show a pin button
50381 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
50382 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
50383 * @cfg {Boolean} disableTabTips True to disable tab tooltips
50384 * @cfg {Number} width For East/West panels
50385 * @cfg {Number} height For North/South panels
50386 * @cfg {Boolean} split To show the splitter
50387 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
50389 Roo.LayoutRegion = function(mgr, config, pos){
50390 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
50391 var dh = Roo.DomHelper;
50392 /** This region's container element
50393 * @type Roo.Element */
50394 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
50395 /** This region's title element
50396 * @type Roo.Element */
50398 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
50399 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
50400 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
50402 this.titleEl.enableDisplayMode();
50403 /** This region's title text element
50404 * @type HTMLElement */
50405 this.titleTextEl = this.titleEl.dom.firstChild;
50406 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
50407 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
50408 this.closeBtn.enableDisplayMode();
50409 this.closeBtn.on("click", this.closeClicked, this);
50410 this.closeBtn.hide();
50412 this.createBody(config);
50413 this.visible = true;
50414 this.collapsed = false;
50416 if(config.hideWhenEmpty){
50418 this.on("paneladded", this.validateVisibility, this);
50419 this.on("panelremoved", this.validateVisibility, this);
50421 this.applyConfig(config);
50424 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
50426 createBody : function(){
50427 /** This region's body element
50428 * @type Roo.Element */
50429 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
50432 applyConfig : function(c){
50433 if(c.collapsible && this.position != "center" && !this.collapsedEl){
50434 var dh = Roo.DomHelper;
50435 if(c.titlebar !== false){
50436 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
50437 this.collapseBtn.on("click", this.collapse, this);
50438 this.collapseBtn.enableDisplayMode();
50440 if(c.showPin === true || this.showPin){
50441 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
50442 this.stickBtn.enableDisplayMode();
50443 this.stickBtn.on("click", this.expand, this);
50444 this.stickBtn.hide();
50447 /** This region's collapsed element
50448 * @type Roo.Element */
50449 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
50450 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
50452 if(c.floatable !== false){
50453 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
50454 this.collapsedEl.on("click", this.collapseClick, this);
50457 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
50458 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
50459 id: "message", unselectable: "on", style:{"float":"left"}});
50460 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
50462 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
50463 this.expandBtn.on("click", this.expand, this);
50465 if(this.collapseBtn){
50466 this.collapseBtn.setVisible(c.collapsible == true);
50468 this.cmargins = c.cmargins || this.cmargins ||
50469 (this.position == "west" || this.position == "east" ?
50470 {top: 0, left: 2, right:2, bottom: 0} :
50471 {top: 2, left: 0, right:0, bottom: 2});
50472 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50473 this.bottomTabs = c.tabPosition != "top";
50474 this.autoScroll = c.autoScroll || false;
50475 if(this.autoScroll){
50476 this.bodyEl.setStyle("overflow", "auto");
50478 this.bodyEl.setStyle("overflow", "hidden");
50480 //if(c.titlebar !== false){
50481 if((!c.titlebar && !c.title) || c.titlebar === false){
50482 this.titleEl.hide();
50484 this.titleEl.show();
50486 this.titleTextEl.innerHTML = c.title;
50490 this.duration = c.duration || .30;
50491 this.slideDuration = c.slideDuration || .45;
50494 this.collapse(true);
50501 * Returns true if this region is currently visible.
50502 * @return {Boolean}
50504 isVisible : function(){
50505 return this.visible;
50509 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
50510 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
50512 setCollapsedTitle : function(title){
50513 title = title || " ";
50514 if(this.collapsedTitleTextEl){
50515 this.collapsedTitleTextEl.innerHTML = title;
50519 getBox : function(){
50521 if(!this.collapsed){
50522 b = this.el.getBox(false, true);
50524 b = this.collapsedEl.getBox(false, true);
50529 getMargins : function(){
50530 return this.collapsed ? this.cmargins : this.margins;
50533 highlight : function(){
50534 this.el.addClass("x-layout-panel-dragover");
50537 unhighlight : function(){
50538 this.el.removeClass("x-layout-panel-dragover");
50541 updateBox : function(box){
50543 if(!this.collapsed){
50544 this.el.dom.style.left = box.x + "px";
50545 this.el.dom.style.top = box.y + "px";
50546 this.updateBody(box.width, box.height);
50548 this.collapsedEl.dom.style.left = box.x + "px";
50549 this.collapsedEl.dom.style.top = box.y + "px";
50550 this.collapsedEl.setSize(box.width, box.height);
50553 this.tabs.autoSizeTabs();
50557 updateBody : function(w, h){
50559 this.el.setWidth(w);
50560 w -= this.el.getBorderWidth("rl");
50561 if(this.config.adjustments){
50562 w += this.config.adjustments[0];
50566 this.el.setHeight(h);
50567 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
50568 h -= this.el.getBorderWidth("tb");
50569 if(this.config.adjustments){
50570 h += this.config.adjustments[1];
50572 this.bodyEl.setHeight(h);
50574 h = this.tabs.syncHeight(h);
50577 if(this.panelSize){
50578 w = w !== null ? w : this.panelSize.width;
50579 h = h !== null ? h : this.panelSize.height;
50581 if(this.activePanel){
50582 var el = this.activePanel.getEl();
50583 w = w !== null ? w : el.getWidth();
50584 h = h !== null ? h : el.getHeight();
50585 this.panelSize = {width: w, height: h};
50586 this.activePanel.setSize(w, h);
50588 if(Roo.isIE && this.tabs){
50589 this.tabs.el.repaint();
50594 * Returns the container element for this region.
50595 * @return {Roo.Element}
50597 getEl : function(){
50602 * Hides this region.
50605 if(!this.collapsed){
50606 this.el.dom.style.left = "-2000px";
50609 this.collapsedEl.dom.style.left = "-2000px";
50610 this.collapsedEl.hide();
50612 this.visible = false;
50613 this.fireEvent("visibilitychange", this, false);
50617 * Shows this region if it was previously hidden.
50620 if(!this.collapsed){
50623 this.collapsedEl.show();
50625 this.visible = true;
50626 this.fireEvent("visibilitychange", this, true);
50629 closeClicked : function(){
50630 if(this.activePanel){
50631 this.remove(this.activePanel);
50635 collapseClick : function(e){
50637 e.stopPropagation();
50640 e.stopPropagation();
50646 * Collapses this region.
50647 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
50649 collapse : function(skipAnim){
50650 if(this.collapsed) {
50653 this.collapsed = true;
50655 this.split.el.hide();
50657 if(this.config.animate && skipAnim !== true){
50658 this.fireEvent("invalidated", this);
50659 this.animateCollapse();
50661 this.el.setLocation(-20000,-20000);
50663 this.collapsedEl.show();
50664 this.fireEvent("collapsed", this);
50665 this.fireEvent("invalidated", this);
50669 animateCollapse : function(){
50674 * Expands this region if it was previously collapsed.
50675 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
50676 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
50678 expand : function(e, skipAnim){
50680 e.stopPropagation();
50682 if(!this.collapsed || this.el.hasActiveFx()) {
50686 this.afterSlideIn();
50689 this.collapsed = false;
50690 if(this.config.animate && skipAnim !== true){
50691 this.animateExpand();
50695 this.split.el.show();
50697 this.collapsedEl.setLocation(-2000,-2000);
50698 this.collapsedEl.hide();
50699 this.fireEvent("invalidated", this);
50700 this.fireEvent("expanded", this);
50704 animateExpand : function(){
50708 initTabs : function()
50710 this.bodyEl.setStyle("overflow", "hidden");
50711 var ts = new Roo.TabPanel(
50714 tabPosition: this.bottomTabs ? 'bottom' : 'top',
50715 disableTooltips: this.config.disableTabTips,
50716 toolbar : this.config.toolbar
50719 if(this.config.hideTabs){
50720 ts.stripWrap.setDisplayed(false);
50723 ts.resizeTabs = this.config.resizeTabs === true;
50724 ts.minTabWidth = this.config.minTabWidth || 40;
50725 ts.maxTabWidth = this.config.maxTabWidth || 250;
50726 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
50727 ts.monitorResize = false;
50728 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50729 ts.bodyEl.addClass('x-layout-tabs-body');
50730 this.panels.each(this.initPanelAsTab, this);
50733 initPanelAsTab : function(panel){
50734 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
50735 this.config.closeOnTab && panel.isClosable());
50736 if(panel.tabTip !== undefined){
50737 ti.setTooltip(panel.tabTip);
50739 ti.on("activate", function(){
50740 this.setActivePanel(panel);
50742 if(this.config.closeOnTab){
50743 ti.on("beforeclose", function(t, e){
50745 this.remove(panel);
50751 updatePanelTitle : function(panel, title){
50752 if(this.activePanel == panel){
50753 this.updateTitle(title);
50756 var ti = this.tabs.getTab(panel.getEl().id);
50758 if(panel.tabTip !== undefined){
50759 ti.setTooltip(panel.tabTip);
50764 updateTitle : function(title){
50765 if(this.titleTextEl && !this.config.title){
50766 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50770 setActivePanel : function(panel){
50771 panel = this.getPanel(panel);
50772 if(this.activePanel && this.activePanel != panel){
50773 this.activePanel.setActiveState(false);
50775 this.activePanel = panel;
50776 panel.setActiveState(true);
50777 if(this.panelSize){
50778 panel.setSize(this.panelSize.width, this.panelSize.height);
50781 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50783 this.updateTitle(panel.getTitle());
50785 this.fireEvent("invalidated", this);
50787 this.fireEvent("panelactivated", this, panel);
50791 * Shows the specified panel.
50792 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50793 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50795 showPanel : function(panel)
50797 panel = this.getPanel(panel);
50800 var tab = this.tabs.getTab(panel.getEl().id);
50801 if(tab.isHidden()){
50802 this.tabs.unhideTab(tab.id);
50806 this.setActivePanel(panel);
50813 * Get the active panel for this region.
50814 * @return {Roo.ContentPanel} The active panel or null
50816 getActivePanel : function(){
50817 return this.activePanel;
50820 validateVisibility : function(){
50821 if(this.panels.getCount() < 1){
50822 this.updateTitle(" ");
50823 this.closeBtn.hide();
50826 if(!this.isVisible()){
50833 * Adds the passed ContentPanel(s) to this region.
50834 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50835 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50837 add : function(panel){
50838 if(arguments.length > 1){
50839 for(var i = 0, len = arguments.length; i < len; i++) {
50840 this.add(arguments[i]);
50844 if(this.hasPanel(panel)){
50845 this.showPanel(panel);
50848 panel.setRegion(this);
50849 this.panels.add(panel);
50850 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50851 this.bodyEl.dom.appendChild(panel.getEl().dom);
50852 if(panel.background !== true){
50853 this.setActivePanel(panel);
50855 this.fireEvent("paneladded", this, panel);
50861 this.initPanelAsTab(panel);
50863 if(panel.background !== true){
50864 this.tabs.activate(panel.getEl().id);
50866 this.fireEvent("paneladded", this, panel);
50871 * Hides the tab for the specified panel.
50872 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50874 hidePanel : function(panel){
50875 if(this.tabs && (panel = this.getPanel(panel))){
50876 this.tabs.hideTab(panel.getEl().id);
50881 * Unhides the tab for a previously hidden panel.
50882 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50884 unhidePanel : function(panel){
50885 if(this.tabs && (panel = this.getPanel(panel))){
50886 this.tabs.unhideTab(panel.getEl().id);
50890 clearPanels : function(){
50891 while(this.panels.getCount() > 0){
50892 this.remove(this.panels.first());
50897 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50898 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50899 * @param {Boolean} preservePanel Overrides the config preservePanel option
50900 * @return {Roo.ContentPanel} The panel that was removed
50902 remove : function(panel, preservePanel){
50903 panel = this.getPanel(panel);
50908 this.fireEvent("beforeremove", this, panel, e);
50909 if(e.cancel === true){
50912 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50913 var panelId = panel.getId();
50914 this.panels.removeKey(panelId);
50916 document.body.appendChild(panel.getEl().dom);
50919 this.tabs.removeTab(panel.getEl().id);
50920 }else if (!preservePanel){
50921 this.bodyEl.dom.removeChild(panel.getEl().dom);
50923 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50924 var p = this.panels.first();
50925 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50926 tempEl.appendChild(p.getEl().dom);
50927 this.bodyEl.update("");
50928 this.bodyEl.dom.appendChild(p.getEl().dom);
50930 this.updateTitle(p.getTitle());
50932 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50933 this.setActivePanel(p);
50935 panel.setRegion(null);
50936 if(this.activePanel == panel){
50937 this.activePanel = null;
50939 if(this.config.autoDestroy !== false && preservePanel !== true){
50940 try{panel.destroy();}catch(e){}
50942 this.fireEvent("panelremoved", this, panel);
50947 * Returns the TabPanel component used by this region
50948 * @return {Roo.TabPanel}
50950 getTabs : function(){
50954 createTool : function(parentEl, className){
50955 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50956 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50957 btn.addClassOnOver("x-layout-tools-button-over");
50962 * Ext JS Library 1.1.1
50963 * Copyright(c) 2006-2007, Ext JS, LLC.
50965 * Originally Released Under LGPL - original licence link has changed is not relivant.
50968 * <script type="text/javascript">
50974 * @class Roo.SplitLayoutRegion
50975 * @extends Roo.LayoutRegion
50976 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50978 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50979 this.cursor = cursor;
50980 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50983 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50984 splitTip : "Drag to resize.",
50985 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50986 useSplitTips : false,
50988 applyConfig : function(config){
50989 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50992 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50993 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50994 /** The SplitBar for this region
50995 * @type Roo.SplitBar */
50996 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50997 this.split.on("moved", this.onSplitMove, this);
50998 this.split.useShim = config.useShim === true;
50999 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
51000 if(this.useSplitTips){
51001 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
51003 if(config.collapsible){
51004 this.split.el.on("dblclick", this.collapse, this);
51007 if(typeof config.minSize != "undefined"){
51008 this.split.minSize = config.minSize;
51010 if(typeof config.maxSize != "undefined"){
51011 this.split.maxSize = config.maxSize;
51013 if(config.hideWhenEmpty || config.hidden || config.collapsed){
51014 this.hideSplitter();
51019 getHMaxSize : function(){
51020 var cmax = this.config.maxSize || 10000;
51021 var center = this.mgr.getRegion("center");
51022 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
51025 getVMaxSize : function(){
51026 var cmax = this.config.maxSize || 10000;
51027 var center = this.mgr.getRegion("center");
51028 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
51031 onSplitMove : function(split, newSize){
51032 this.fireEvent("resized", this, newSize);
51036 * Returns the {@link Roo.SplitBar} for this region.
51037 * @return {Roo.SplitBar}
51039 getSplitBar : function(){
51044 this.hideSplitter();
51045 Roo.SplitLayoutRegion.superclass.hide.call(this);
51048 hideSplitter : function(){
51050 this.split.el.setLocation(-2000,-2000);
51051 this.split.el.hide();
51057 this.split.el.show();
51059 Roo.SplitLayoutRegion.superclass.show.call(this);
51062 beforeSlide: function(){
51063 if(Roo.isGecko){// firefox overflow auto bug workaround
51064 this.bodyEl.clip();
51066 this.tabs.bodyEl.clip();
51068 if(this.activePanel){
51069 this.activePanel.getEl().clip();
51071 if(this.activePanel.beforeSlide){
51072 this.activePanel.beforeSlide();
51078 afterSlide : function(){
51079 if(Roo.isGecko){// firefox overflow auto bug workaround
51080 this.bodyEl.unclip();
51082 this.tabs.bodyEl.unclip();
51084 if(this.activePanel){
51085 this.activePanel.getEl().unclip();
51086 if(this.activePanel.afterSlide){
51087 this.activePanel.afterSlide();
51093 initAutoHide : function(){
51094 if(this.autoHide !== false){
51095 if(!this.autoHideHd){
51096 var st = new Roo.util.DelayedTask(this.slideIn, this);
51097 this.autoHideHd = {
51098 "mouseout": function(e){
51099 if(!e.within(this.el, true)){
51103 "mouseover" : function(e){
51109 this.el.on(this.autoHideHd);
51113 clearAutoHide : function(){
51114 if(this.autoHide !== false){
51115 this.el.un("mouseout", this.autoHideHd.mouseout);
51116 this.el.un("mouseover", this.autoHideHd.mouseover);
51120 clearMonitor : function(){
51121 Roo.get(document).un("click", this.slideInIf, this);
51124 // these names are backwards but not changed for compat
51125 slideOut : function(){
51126 if(this.isSlid || this.el.hasActiveFx()){
51129 this.isSlid = true;
51130 if(this.collapseBtn){
51131 this.collapseBtn.hide();
51133 this.closeBtnState = this.closeBtn.getStyle('display');
51134 this.closeBtn.hide();
51136 this.stickBtn.show();
51139 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
51140 this.beforeSlide();
51141 this.el.setStyle("z-index", 10001);
51142 this.el.slideIn(this.getSlideAnchor(), {
51143 callback: function(){
51145 this.initAutoHide();
51146 Roo.get(document).on("click", this.slideInIf, this);
51147 this.fireEvent("slideshow", this);
51154 afterSlideIn : function(){
51155 this.clearAutoHide();
51156 this.isSlid = false;
51157 this.clearMonitor();
51158 this.el.setStyle("z-index", "");
51159 if(this.collapseBtn){
51160 this.collapseBtn.show();
51162 this.closeBtn.setStyle('display', this.closeBtnState);
51164 this.stickBtn.hide();
51166 this.fireEvent("slidehide", this);
51169 slideIn : function(cb){
51170 if(!this.isSlid || this.el.hasActiveFx()){
51174 this.isSlid = false;
51175 this.beforeSlide();
51176 this.el.slideOut(this.getSlideAnchor(), {
51177 callback: function(){
51178 this.el.setLeftTop(-10000, -10000);
51180 this.afterSlideIn();
51188 slideInIf : function(e){
51189 if(!e.within(this.el)){
51194 animateCollapse : function(){
51195 this.beforeSlide();
51196 this.el.setStyle("z-index", 20000);
51197 var anchor = this.getSlideAnchor();
51198 this.el.slideOut(anchor, {
51199 callback : function(){
51200 this.el.setStyle("z-index", "");
51201 this.collapsedEl.slideIn(anchor, {duration:.3});
51203 this.el.setLocation(-10000,-10000);
51205 this.fireEvent("collapsed", this);
51212 animateExpand : function(){
51213 this.beforeSlide();
51214 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
51215 this.el.setStyle("z-index", 20000);
51216 this.collapsedEl.hide({
51219 this.el.slideIn(this.getSlideAnchor(), {
51220 callback : function(){
51221 this.el.setStyle("z-index", "");
51224 this.split.el.show();
51226 this.fireEvent("invalidated", this);
51227 this.fireEvent("expanded", this);
51255 getAnchor : function(){
51256 return this.anchors[this.position];
51259 getCollapseAnchor : function(){
51260 return this.canchors[this.position];
51263 getSlideAnchor : function(){
51264 return this.sanchors[this.position];
51267 getAlignAdj : function(){
51268 var cm = this.cmargins;
51269 switch(this.position){
51285 getExpandAdj : function(){
51286 var c = this.collapsedEl, cm = this.cmargins;
51287 switch(this.position){
51289 return [-(cm.right+c.getWidth()+cm.left), 0];
51292 return [cm.right+c.getWidth()+cm.left, 0];
51295 return [0, -(cm.top+cm.bottom+c.getHeight())];
51298 return [0, cm.top+cm.bottom+c.getHeight()];
51304 * Ext JS Library 1.1.1
51305 * Copyright(c) 2006-2007, Ext JS, LLC.
51307 * Originally Released Under LGPL - original licence link has changed is not relivant.
51310 * <script type="text/javascript">
51313 * These classes are private internal classes
51315 Roo.CenterLayoutRegion = function(mgr, config){
51316 Roo.LayoutRegion.call(this, mgr, config, "center");
51317 this.visible = true;
51318 this.minWidth = config.minWidth || 20;
51319 this.minHeight = config.minHeight || 20;
51322 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
51324 // center panel can't be hidden
51328 // center panel can't be hidden
51331 getMinWidth: function(){
51332 return this.minWidth;
51335 getMinHeight: function(){
51336 return this.minHeight;
51341 Roo.NorthLayoutRegion = function(mgr, config){
51342 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
51344 this.split.placement = Roo.SplitBar.TOP;
51345 this.split.orientation = Roo.SplitBar.VERTICAL;
51346 this.split.el.addClass("x-layout-split-v");
51348 var size = config.initialSize || config.height;
51349 if(typeof size != "undefined"){
51350 this.el.setHeight(size);
51353 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
51354 orientation: Roo.SplitBar.VERTICAL,
51355 getBox : function(){
51356 if(this.collapsed){
51357 return this.collapsedEl.getBox();
51359 var box = this.el.getBox();
51361 box.height += this.split.el.getHeight();
51366 updateBox : function(box){
51367 if(this.split && !this.collapsed){
51368 box.height -= this.split.el.getHeight();
51369 this.split.el.setLeft(box.x);
51370 this.split.el.setTop(box.y+box.height);
51371 this.split.el.setWidth(box.width);
51373 if(this.collapsed){
51374 this.updateBody(box.width, null);
51376 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51380 Roo.SouthLayoutRegion = function(mgr, config){
51381 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
51383 this.split.placement = Roo.SplitBar.BOTTOM;
51384 this.split.orientation = Roo.SplitBar.VERTICAL;
51385 this.split.el.addClass("x-layout-split-v");
51387 var size = config.initialSize || config.height;
51388 if(typeof size != "undefined"){
51389 this.el.setHeight(size);
51392 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
51393 orientation: Roo.SplitBar.VERTICAL,
51394 getBox : function(){
51395 if(this.collapsed){
51396 return this.collapsedEl.getBox();
51398 var box = this.el.getBox();
51400 var sh = this.split.el.getHeight();
51407 updateBox : function(box){
51408 if(this.split && !this.collapsed){
51409 var sh = this.split.el.getHeight();
51412 this.split.el.setLeft(box.x);
51413 this.split.el.setTop(box.y-sh);
51414 this.split.el.setWidth(box.width);
51416 if(this.collapsed){
51417 this.updateBody(box.width, null);
51419 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51423 Roo.EastLayoutRegion = function(mgr, config){
51424 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
51426 this.split.placement = Roo.SplitBar.RIGHT;
51427 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51428 this.split.el.addClass("x-layout-split-h");
51430 var size = config.initialSize || config.width;
51431 if(typeof size != "undefined"){
51432 this.el.setWidth(size);
51435 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
51436 orientation: Roo.SplitBar.HORIZONTAL,
51437 getBox : function(){
51438 if(this.collapsed){
51439 return this.collapsedEl.getBox();
51441 var box = this.el.getBox();
51443 var sw = this.split.el.getWidth();
51450 updateBox : function(box){
51451 if(this.split && !this.collapsed){
51452 var sw = this.split.el.getWidth();
51454 this.split.el.setLeft(box.x);
51455 this.split.el.setTop(box.y);
51456 this.split.el.setHeight(box.height);
51459 if(this.collapsed){
51460 this.updateBody(null, box.height);
51462 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51466 Roo.WestLayoutRegion = function(mgr, config){
51467 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
51469 this.split.placement = Roo.SplitBar.LEFT;
51470 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51471 this.split.el.addClass("x-layout-split-h");
51473 var size = config.initialSize || config.width;
51474 if(typeof size != "undefined"){
51475 this.el.setWidth(size);
51478 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
51479 orientation: Roo.SplitBar.HORIZONTAL,
51480 getBox : function(){
51481 if(this.collapsed){
51482 return this.collapsedEl.getBox();
51484 var box = this.el.getBox();
51486 box.width += this.split.el.getWidth();
51491 updateBox : function(box){
51492 if(this.split && !this.collapsed){
51493 var sw = this.split.el.getWidth();
51495 this.split.el.setLeft(box.x+box.width);
51496 this.split.el.setTop(box.y);
51497 this.split.el.setHeight(box.height);
51499 if(this.collapsed){
51500 this.updateBody(null, box.height);
51502 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51507 * Ext JS Library 1.1.1
51508 * Copyright(c) 2006-2007, Ext JS, LLC.
51510 * Originally Released Under LGPL - original licence link has changed is not relivant.
51513 * <script type="text/javascript">
51518 * Private internal class for reading and applying state
51520 Roo.LayoutStateManager = function(layout){
51521 // default empty state
51530 Roo.LayoutStateManager.prototype = {
51531 init : function(layout, provider){
51532 this.provider = provider;
51533 var state = provider.get(layout.id+"-layout-state");
51535 var wasUpdating = layout.isUpdating();
51537 layout.beginUpdate();
51539 for(var key in state){
51540 if(typeof state[key] != "function"){
51541 var rstate = state[key];
51542 var r = layout.getRegion(key);
51545 r.resizeTo(rstate.size);
51547 if(rstate.collapsed == true){
51550 r.expand(null, true);
51556 layout.endUpdate();
51558 this.state = state;
51560 this.layout = layout;
51561 layout.on("regionresized", this.onRegionResized, this);
51562 layout.on("regioncollapsed", this.onRegionCollapsed, this);
51563 layout.on("regionexpanded", this.onRegionExpanded, this);
51566 storeState : function(){
51567 this.provider.set(this.layout.id+"-layout-state", this.state);
51570 onRegionResized : function(region, newSize){
51571 this.state[region.getPosition()].size = newSize;
51575 onRegionCollapsed : function(region){
51576 this.state[region.getPosition()].collapsed = true;
51580 onRegionExpanded : function(region){
51581 this.state[region.getPosition()].collapsed = false;
51586 * Ext JS Library 1.1.1
51587 * Copyright(c) 2006-2007, Ext JS, LLC.
51589 * Originally Released Under LGPL - original licence link has changed is not relivant.
51592 * <script type="text/javascript">
51595 * @class Roo.ContentPanel
51596 * @extends Roo.util.Observable
51597 * A basic ContentPanel element.
51598 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
51599 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
51600 * @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
51601 * @cfg {Boolean} closable True if the panel can be closed/removed
51602 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
51603 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
51604 * @cfg {Toolbar} toolbar A toolbar for this panel
51605 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
51606 * @cfg {String} title The title for this panel
51607 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
51608 * @cfg {String} url Calls {@link #setUrl} with this value
51609 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
51610 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
51611 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
51612 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
51615 * Create a new ContentPanel.
51616 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
51617 * @param {String/Object} config A string to set only the title or a config object
51618 * @param {String} content (optional) Set the HTML content for this panel
51619 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
51621 Roo.ContentPanel = function(el, config, content){
51625 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
51629 if (config && config.parentLayout) {
51630 el = config.parentLayout.el.createChild();
51633 if(el.autoCreate){ // xtype is available if this is called from factory
51637 this.el = Roo.get(el);
51638 if(!this.el && config && config.autoCreate){
51639 if(typeof config.autoCreate == "object"){
51640 if(!config.autoCreate.id){
51641 config.autoCreate.id = config.id||el;
51643 this.el = Roo.DomHelper.append(document.body,
51644 config.autoCreate, true);
51646 this.el = Roo.DomHelper.append(document.body,
51647 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
51650 this.closable = false;
51651 this.loaded = false;
51652 this.active = false;
51653 if(typeof config == "string"){
51654 this.title = config;
51656 Roo.apply(this, config);
51659 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
51660 this.wrapEl = this.el.wrap();
51661 this.toolbar.container = this.el.insertSibling(false, 'before');
51662 this.toolbar = new Roo.Toolbar(this.toolbar);
51665 // xtype created footer. - not sure if will work as we normally have to render first..
51666 if (this.footer && !this.footer.el && this.footer.xtype) {
51667 if (!this.wrapEl) {
51668 this.wrapEl = this.el.wrap();
51671 this.footer.container = this.wrapEl.createChild();
51673 this.footer = Roo.factory(this.footer, Roo);
51678 this.resizeEl = Roo.get(this.resizeEl, true);
51680 this.resizeEl = this.el;
51682 // handle view.xtype
51690 * Fires when this panel is activated.
51691 * @param {Roo.ContentPanel} this
51695 * @event deactivate
51696 * Fires when this panel is activated.
51697 * @param {Roo.ContentPanel} this
51699 "deactivate" : true,
51703 * Fires when this panel is resized if fitToFrame is true.
51704 * @param {Roo.ContentPanel} this
51705 * @param {Number} width The width after any component adjustments
51706 * @param {Number} height The height after any component adjustments
51712 * Fires when this tab is created
51713 * @param {Roo.ContentPanel} this
51724 if(this.autoScroll){
51725 this.resizeEl.setStyle("overflow", "auto");
51727 // fix randome scrolling
51728 this.el.on('scroll', function() {
51729 Roo.log('fix random scolling');
51730 this.scrollTo('top',0);
51733 content = content || this.content;
51735 this.setContent(content);
51737 if(config && config.url){
51738 this.setUrl(this.url, this.params, this.loadOnce);
51743 Roo.ContentPanel.superclass.constructor.call(this);
51745 if (this.view && typeof(this.view.xtype) != 'undefined') {
51746 this.view.el = this.el.appendChild(document.createElement("div"));
51747 this.view = Roo.factory(this.view);
51748 this.view.render && this.view.render(false, '');
51752 this.fireEvent('render', this);
51755 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
51757 setRegion : function(region){
51758 this.region = region;
51760 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
51762 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
51767 * Returns the toolbar for this Panel if one was configured.
51768 * @return {Roo.Toolbar}
51770 getToolbar : function(){
51771 return this.toolbar;
51774 setActiveState : function(active){
51775 this.active = active;
51777 this.fireEvent("deactivate", this);
51779 this.fireEvent("activate", this);
51783 * Updates this panel's element
51784 * @param {String} content The new content
51785 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51787 setContent : function(content, loadScripts){
51788 this.el.update(content, loadScripts);
51791 ignoreResize : function(w, h){
51792 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51795 this.lastSize = {width: w, height: h};
51800 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51801 * @return {Roo.UpdateManager} The UpdateManager
51803 getUpdateManager : function(){
51804 return this.el.getUpdateManager();
51807 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51808 * @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:
51811 url: "your-url.php",
51812 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51813 callback: yourFunction,
51814 scope: yourObject, //(optional scope)
51817 text: "Loading...",
51822 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51823 * 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.
51824 * @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}
51825 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51826 * @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.
51827 * @return {Roo.ContentPanel} this
51830 var um = this.el.getUpdateManager();
51831 um.update.apply(um, arguments);
51837 * 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.
51838 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51839 * @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)
51840 * @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)
51841 * @return {Roo.UpdateManager} The UpdateManager
51843 setUrl : function(url, params, loadOnce){
51844 if(this.refreshDelegate){
51845 this.removeListener("activate", this.refreshDelegate);
51847 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51848 this.on("activate", this.refreshDelegate);
51849 return this.el.getUpdateManager();
51852 _handleRefresh : function(url, params, loadOnce){
51853 if(!loadOnce || !this.loaded){
51854 var updater = this.el.getUpdateManager();
51855 updater.update(url, params, this._setLoaded.createDelegate(this));
51859 _setLoaded : function(){
51860 this.loaded = true;
51864 * Returns this panel's id
51867 getId : function(){
51872 * Returns this panel's element - used by regiosn to add.
51873 * @return {Roo.Element}
51875 getEl : function(){
51876 return this.wrapEl || this.el;
51879 adjustForComponents : function(width, height)
51881 //Roo.log('adjustForComponents ');
51882 if(this.resizeEl != this.el){
51883 width -= this.el.getFrameWidth('lr');
51884 height -= this.el.getFrameWidth('tb');
51887 var te = this.toolbar.getEl();
51888 height -= te.getHeight();
51889 te.setWidth(width);
51892 var te = this.footer.getEl();
51893 Roo.log("footer:" + te.getHeight());
51895 height -= te.getHeight();
51896 te.setWidth(width);
51900 if(this.adjustments){
51901 width += this.adjustments[0];
51902 height += this.adjustments[1];
51904 return {"width": width, "height": height};
51907 setSize : function(width, height){
51908 if(this.fitToFrame && !this.ignoreResize(width, height)){
51909 if(this.fitContainer && this.resizeEl != this.el){
51910 this.el.setSize(width, height);
51912 var size = this.adjustForComponents(width, height);
51913 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51914 this.fireEvent('resize', this, size.width, size.height);
51919 * Returns this panel's title
51922 getTitle : function(){
51927 * Set this panel's title
51928 * @param {String} title
51930 setTitle : function(title){
51931 this.title = title;
51933 this.region.updatePanelTitle(this, title);
51938 * Returns true is this panel was configured to be closable
51939 * @return {Boolean}
51941 isClosable : function(){
51942 return this.closable;
51945 beforeSlide : function(){
51947 this.resizeEl.clip();
51950 afterSlide : function(){
51952 this.resizeEl.unclip();
51956 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51957 * Will fail silently if the {@link #setUrl} method has not been called.
51958 * This does not activate the panel, just updates its content.
51960 refresh : function(){
51961 if(this.refreshDelegate){
51962 this.loaded = false;
51963 this.refreshDelegate();
51968 * Destroys this panel
51970 destroy : function(){
51971 this.el.removeAllListeners();
51972 var tempEl = document.createElement("span");
51973 tempEl.appendChild(this.el.dom);
51974 tempEl.innerHTML = "";
51980 * form - if the content panel contains a form - this is a reference to it.
51981 * @type {Roo.form.Form}
51985 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51986 * This contains a reference to it.
51992 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
52002 * @param {Object} cfg Xtype definition of item to add.
52005 addxtype : function(cfg) {
52007 if (cfg.xtype.match(/^Form$/)) {
52010 //if (this.footer) {
52011 // el = this.footer.container.insertSibling(false, 'before');
52013 el = this.el.createChild();
52016 this.form = new Roo.form.Form(cfg);
52019 if ( this.form.allItems.length) {
52020 this.form.render(el.dom);
52024 // should only have one of theses..
52025 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
52026 // views.. should not be just added - used named prop 'view''
52028 cfg.el = this.el.appendChild(document.createElement("div"));
52031 var ret = new Roo.factory(cfg);
52033 ret.render && ret.render(false, ''); // render blank..
52042 * @class Roo.GridPanel
52043 * @extends Roo.ContentPanel
52045 * Create a new GridPanel.
52046 * @param {Roo.grid.Grid} grid The grid for this panel
52047 * @param {String/Object} config A string to set only the panel's title, or a config object
52049 Roo.GridPanel = function(grid, config){
52052 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
52053 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
52055 this.wrapper.dom.appendChild(grid.getGridEl().dom);
52057 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
52060 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
52062 // xtype created footer. - not sure if will work as we normally have to render first..
52063 if (this.footer && !this.footer.el && this.footer.xtype) {
52065 this.footer.container = this.grid.getView().getFooterPanel(true);
52066 this.footer.dataSource = this.grid.dataSource;
52067 this.footer = Roo.factory(this.footer, Roo);
52071 grid.monitorWindowResize = false; // turn off autosizing
52072 grid.autoHeight = false;
52073 grid.autoWidth = false;
52075 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
52078 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
52079 getId : function(){
52080 return this.grid.id;
52084 * Returns the grid for this panel
52085 * @return {Roo.grid.Grid}
52087 getGrid : function(){
52091 setSize : function(width, height){
52092 if(!this.ignoreResize(width, height)){
52093 var grid = this.grid;
52094 var size = this.adjustForComponents(width, height);
52095 grid.getGridEl().setSize(size.width, size.height);
52100 beforeSlide : function(){
52101 this.grid.getView().scroller.clip();
52104 afterSlide : function(){
52105 this.grid.getView().scroller.unclip();
52108 destroy : function(){
52109 this.grid.destroy();
52111 Roo.GridPanel.superclass.destroy.call(this);
52117 * @class Roo.NestedLayoutPanel
52118 * @extends Roo.ContentPanel
52120 * Create a new NestedLayoutPanel.
52123 * @param {Roo.BorderLayout} layout The layout for this panel
52124 * @param {String/Object} config A string to set only the title or a config object
52126 Roo.NestedLayoutPanel = function(layout, config)
52128 // construct with only one argument..
52129 /* FIXME - implement nicer consturctors
52130 if (layout.layout) {
52132 layout = config.layout;
52133 delete config.layout;
52135 if (layout.xtype && !layout.getEl) {
52136 // then layout needs constructing..
52137 layout = Roo.factory(layout, Roo);
52142 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
52144 layout.monitorWindowResize = false; // turn off autosizing
52145 this.layout = layout;
52146 this.layout.getEl().addClass("x-layout-nested-layout");
52153 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
52155 setSize : function(width, height){
52156 if(!this.ignoreResize(width, height)){
52157 var size = this.adjustForComponents(width, height);
52158 var el = this.layout.getEl();
52159 el.setSize(size.width, size.height);
52160 var touch = el.dom.offsetWidth;
52161 this.layout.layout();
52162 // ie requires a double layout on the first pass
52163 if(Roo.isIE && !this.initialized){
52164 this.initialized = true;
52165 this.layout.layout();
52170 // activate all subpanels if not currently active..
52172 setActiveState : function(active){
52173 this.active = active;
52175 this.fireEvent("deactivate", this);
52179 this.fireEvent("activate", this);
52180 // not sure if this should happen before or after..
52181 if (!this.layout) {
52182 return; // should not happen..
52185 for (var r in this.layout.regions) {
52186 reg = this.layout.getRegion(r);
52187 if (reg.getActivePanel()) {
52188 //reg.showPanel(reg.getActivePanel()); // force it to activate..
52189 reg.setActivePanel(reg.getActivePanel());
52192 if (!reg.panels.length) {
52195 reg.showPanel(reg.getPanel(0));
52204 * Returns the nested BorderLayout for this panel
52205 * @return {Roo.BorderLayout}
52207 getLayout : function(){
52208 return this.layout;
52212 * Adds a xtype elements to the layout of the nested panel
52216 xtype : 'ContentPanel',
52223 xtype : 'NestedLayoutPanel',
52229 items : [ ... list of content panels or nested layout panels.. ]
52233 * @param {Object} cfg Xtype definition of item to add.
52235 addxtype : function(cfg) {
52236 return this.layout.addxtype(cfg);
52241 Roo.ScrollPanel = function(el, config, content){
52242 config = config || {};
52243 config.fitToFrame = true;
52244 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
52246 this.el.dom.style.overflow = "hidden";
52247 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
52248 this.el.removeClass("x-layout-inactive-content");
52249 this.el.on("mousewheel", this.onWheel, this);
52251 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
52252 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
52253 up.unselectable(); down.unselectable();
52254 up.on("click", this.scrollUp, this);
52255 down.on("click", this.scrollDown, this);
52256 up.addClassOnOver("x-scroller-btn-over");
52257 down.addClassOnOver("x-scroller-btn-over");
52258 up.addClassOnClick("x-scroller-btn-click");
52259 down.addClassOnClick("x-scroller-btn-click");
52260 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
52262 this.resizeEl = this.el;
52263 this.el = wrap; this.up = up; this.down = down;
52266 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
52268 wheelIncrement : 5,
52269 scrollUp : function(){
52270 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
52273 scrollDown : function(){
52274 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
52277 afterScroll : function(){
52278 var el = this.resizeEl;
52279 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
52280 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52281 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52284 setSize : function(){
52285 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
52286 this.afterScroll();
52289 onWheel : function(e){
52290 var d = e.getWheelDelta();
52291 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
52292 this.afterScroll();
52296 setContent : function(content, loadScripts){
52297 this.resizeEl.update(content, loadScripts);
52311 * @class Roo.TreePanel
52312 * @extends Roo.ContentPanel
52314 * Create a new TreePanel. - defaults to fit/scoll contents.
52315 * @param {String/Object} config A string to set only the panel's title, or a config object
52316 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
52318 Roo.TreePanel = function(config){
52319 var el = config.el;
52320 var tree = config.tree;
52321 delete config.tree;
52322 delete config.el; // hopefull!
52324 // wrapper for IE7 strict & safari scroll issue
52326 var treeEl = el.createChild();
52327 config.resizeEl = treeEl;
52331 Roo.TreePanel.superclass.constructor.call(this, el, config);
52334 this.tree = new Roo.tree.TreePanel(treeEl , tree);
52335 //console.log(tree);
52336 this.on('activate', function()
52338 if (this.tree.rendered) {
52341 //console.log('render tree');
52342 this.tree.render();
52344 // this should not be needed.. - it's actually the 'el' that resizes?
52345 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
52347 //this.on('resize', function (cp, w, h) {
52348 // this.tree.innerCt.setWidth(w);
52349 // this.tree.innerCt.setHeight(h);
52350 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
52357 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
52374 * Ext JS Library 1.1.1
52375 * Copyright(c) 2006-2007, Ext JS, LLC.
52377 * Originally Released Under LGPL - original licence link has changed is not relivant.
52380 * <script type="text/javascript">
52385 * @class Roo.ReaderLayout
52386 * @extends Roo.BorderLayout
52387 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
52388 * center region containing two nested regions (a top one for a list view and one for item preview below),
52389 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
52390 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
52391 * expedites the setup of the overall layout and regions for this common application style.
52394 var reader = new Roo.ReaderLayout();
52395 var CP = Roo.ContentPanel; // shortcut for adding
52397 reader.beginUpdate();
52398 reader.add("north", new CP("north", "North"));
52399 reader.add("west", new CP("west", {title: "West"}));
52400 reader.add("east", new CP("east", {title: "East"}));
52402 reader.regions.listView.add(new CP("listView", "List"));
52403 reader.regions.preview.add(new CP("preview", "Preview"));
52404 reader.endUpdate();
52407 * Create a new ReaderLayout
52408 * @param {Object} config Configuration options
52409 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
52410 * document.body if omitted)
52412 Roo.ReaderLayout = function(config, renderTo){
52413 var c = config || {size:{}};
52414 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
52415 north: c.north !== false ? Roo.apply({
52419 }, c.north) : false,
52420 west: c.west !== false ? Roo.apply({
52428 margins:{left:5,right:0,bottom:5,top:5},
52429 cmargins:{left:5,right:5,bottom:5,top:5}
52430 }, c.west) : false,
52431 east: c.east !== false ? Roo.apply({
52439 margins:{left:0,right:5,bottom:5,top:5},
52440 cmargins:{left:5,right:5,bottom:5,top:5}
52441 }, c.east) : false,
52442 center: Roo.apply({
52443 tabPosition: 'top',
52447 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
52451 this.el.addClass('x-reader');
52453 this.beginUpdate();
52455 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
52456 south: c.preview !== false ? Roo.apply({
52463 cmargins:{top:5,left:0, right:0, bottom:0}
52464 }, c.preview) : false,
52465 center: Roo.apply({
52471 this.add('center', new Roo.NestedLayoutPanel(inner,
52472 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
52476 this.regions.preview = inner.getRegion('south');
52477 this.regions.listView = inner.getRegion('center');
52480 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
52482 * Ext JS Library 1.1.1
52483 * Copyright(c) 2006-2007, Ext JS, LLC.
52485 * Originally Released Under LGPL - original licence link has changed is not relivant.
52488 * <script type="text/javascript">
52492 * @class Roo.grid.Grid
52493 * @extends Roo.util.Observable
52494 * This class represents the primary interface of a component based grid control.
52495 * <br><br>Usage:<pre><code>
52496 var grid = new Roo.grid.Grid("my-container-id", {
52499 selModel: mySelectionModel,
52500 autoSizeColumns: true,
52501 monitorWindowResize: false,
52502 trackMouseOver: true
52507 * <b>Common Problems:</b><br/>
52508 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
52509 * element will correct this<br/>
52510 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
52511 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
52512 * are unpredictable.<br/>
52513 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
52514 * grid to calculate dimensions/offsets.<br/>
52516 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
52517 * The container MUST have some type of size defined for the grid to fill. The container will be
52518 * automatically set to position relative if it isn't already.
52519 * @param {Object} config A config object that sets properties on this grid.
52521 Roo.grid.Grid = function(container, config){
52522 // initialize the container
52523 this.container = Roo.get(container);
52524 this.container.update("");
52525 this.container.setStyle("overflow", "hidden");
52526 this.container.addClass('x-grid-container');
52528 this.id = this.container.id;
52530 Roo.apply(this, config);
52531 // check and correct shorthanded configs
52533 this.dataSource = this.ds;
52537 this.colModel = this.cm;
52541 this.selModel = this.sm;
52545 if (this.selModel) {
52546 this.selModel = Roo.factory(this.selModel, Roo.grid);
52547 this.sm = this.selModel;
52548 this.sm.xmodule = this.xmodule || false;
52550 if (typeof(this.colModel.config) == 'undefined') {
52551 this.colModel = new Roo.grid.ColumnModel(this.colModel);
52552 this.cm = this.colModel;
52553 this.cm.xmodule = this.xmodule || false;
52555 if (this.dataSource) {
52556 this.dataSource= Roo.factory(this.dataSource, Roo.data);
52557 this.ds = this.dataSource;
52558 this.ds.xmodule = this.xmodule || false;
52565 this.container.setWidth(this.width);
52569 this.container.setHeight(this.height);
52576 * The raw click event for the entire grid.
52577 * @param {Roo.EventObject} e
52582 * The raw dblclick event for the entire grid.
52583 * @param {Roo.EventObject} e
52587 * @event contextmenu
52588 * The raw contextmenu event for the entire grid.
52589 * @param {Roo.EventObject} e
52591 "contextmenu" : true,
52594 * The raw mousedown event for the entire grid.
52595 * @param {Roo.EventObject} e
52597 "mousedown" : true,
52600 * The raw mouseup event for the entire grid.
52601 * @param {Roo.EventObject} e
52606 * The raw mouseover event for the entire grid.
52607 * @param {Roo.EventObject} e
52609 "mouseover" : true,
52612 * The raw mouseout event for the entire grid.
52613 * @param {Roo.EventObject} e
52618 * The raw keypress event for the entire grid.
52619 * @param {Roo.EventObject} e
52624 * The raw keydown event for the entire grid.
52625 * @param {Roo.EventObject} e
52633 * Fires when a cell is clicked
52634 * @param {Grid} this
52635 * @param {Number} rowIndex
52636 * @param {Number} columnIndex
52637 * @param {Roo.EventObject} e
52639 "cellclick" : true,
52641 * @event celldblclick
52642 * Fires when a cell is double clicked
52643 * @param {Grid} this
52644 * @param {Number} rowIndex
52645 * @param {Number} columnIndex
52646 * @param {Roo.EventObject} e
52648 "celldblclick" : true,
52651 * Fires when a row is clicked
52652 * @param {Grid} this
52653 * @param {Number} rowIndex
52654 * @param {Roo.EventObject} e
52658 * @event rowdblclick
52659 * Fires when a row is double clicked
52660 * @param {Grid} this
52661 * @param {Number} rowIndex
52662 * @param {Roo.EventObject} e
52664 "rowdblclick" : true,
52666 * @event headerclick
52667 * Fires when a header is clicked
52668 * @param {Grid} this
52669 * @param {Number} columnIndex
52670 * @param {Roo.EventObject} e
52672 "headerclick" : true,
52674 * @event headerdblclick
52675 * Fires when a header cell is double clicked
52676 * @param {Grid} this
52677 * @param {Number} columnIndex
52678 * @param {Roo.EventObject} e
52680 "headerdblclick" : true,
52682 * @event rowcontextmenu
52683 * Fires when a row is right clicked
52684 * @param {Grid} this
52685 * @param {Number} rowIndex
52686 * @param {Roo.EventObject} e
52688 "rowcontextmenu" : true,
52690 * @event cellcontextmenu
52691 * Fires when a cell is right clicked
52692 * @param {Grid} this
52693 * @param {Number} rowIndex
52694 * @param {Number} cellIndex
52695 * @param {Roo.EventObject} e
52697 "cellcontextmenu" : true,
52699 * @event headercontextmenu
52700 * Fires when a header is right clicked
52701 * @param {Grid} this
52702 * @param {Number} columnIndex
52703 * @param {Roo.EventObject} e
52705 "headercontextmenu" : true,
52707 * @event bodyscroll
52708 * Fires when the body element is scrolled
52709 * @param {Number} scrollLeft
52710 * @param {Number} scrollTop
52712 "bodyscroll" : true,
52714 * @event columnresize
52715 * Fires when the user resizes a column
52716 * @param {Number} columnIndex
52717 * @param {Number} newSize
52719 "columnresize" : true,
52721 * @event columnmove
52722 * Fires when the user moves a column
52723 * @param {Number} oldIndex
52724 * @param {Number} newIndex
52726 "columnmove" : true,
52729 * Fires when row(s) start being dragged
52730 * @param {Grid} this
52731 * @param {Roo.GridDD} dd The drag drop object
52732 * @param {event} e The raw browser event
52734 "startdrag" : true,
52737 * Fires when a drag operation is complete
52738 * @param {Grid} this
52739 * @param {Roo.GridDD} dd The drag drop object
52740 * @param {event} e The raw browser event
52745 * Fires when dragged row(s) are dropped on a valid DD target
52746 * @param {Grid} this
52747 * @param {Roo.GridDD} dd The drag drop object
52748 * @param {String} targetId The target drag drop object
52749 * @param {event} e The raw browser event
52754 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
52755 * @param {Grid} this
52756 * @param {Roo.GridDD} dd The drag drop object
52757 * @param {String} targetId The target drag drop object
52758 * @param {event} e The raw browser event
52763 * Fires when the dragged row(s) first cross another DD target while being dragged
52764 * @param {Grid} this
52765 * @param {Roo.GridDD} dd The drag drop object
52766 * @param {String} targetId The target drag drop object
52767 * @param {event} e The raw browser event
52769 "dragenter" : true,
52772 * Fires when the dragged row(s) leave another DD target while being dragged
52773 * @param {Grid} this
52774 * @param {Roo.GridDD} dd The drag drop object
52775 * @param {String} targetId The target drag drop object
52776 * @param {event} e The raw browser event
52781 * Fires when a row is rendered, so you can change add a style to it.
52782 * @param {GridView} gridview The grid view
52783 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52789 * Fires when the grid is rendered
52790 * @param {Grid} grid
52795 Roo.grid.Grid.superclass.constructor.call(this);
52797 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52800 * @cfg {String} ddGroup - drag drop group.
52804 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52806 minColumnWidth : 25,
52809 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52810 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52811 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52813 autoSizeColumns : false,
52816 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52818 autoSizeHeaders : true,
52821 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52823 monitorWindowResize : true,
52826 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52827 * rows measured to get a columns size. Default is 0 (all rows).
52829 maxRowsToMeasure : 0,
52832 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52834 trackMouseOver : true,
52837 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52841 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52843 enableDragDrop : false,
52846 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52848 enableColumnMove : true,
52851 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52853 enableColumnHide : true,
52856 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52858 enableRowHeightSync : false,
52861 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52866 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52868 autoHeight : false,
52871 * @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.
52873 autoExpandColumn : false,
52876 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52879 autoExpandMin : 50,
52882 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52884 autoExpandMax : 1000,
52887 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52892 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52896 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52906 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52907 * of a fixed width. Default is false.
52910 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52913 * Called once after all setup has been completed and the grid is ready to be rendered.
52914 * @return {Roo.grid.Grid} this
52916 render : function()
52918 var c = this.container;
52919 // try to detect autoHeight/width mode
52920 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52921 this.autoHeight = true;
52923 var view = this.getView();
52926 c.on("click", this.onClick, this);
52927 c.on("dblclick", this.onDblClick, this);
52928 c.on("contextmenu", this.onContextMenu, this);
52929 c.on("keydown", this.onKeyDown, this);
52931 c.on("touchstart", this.onTouchStart, this);
52934 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52936 this.getSelectionModel().init(this);
52941 this.loadMask = new Roo.LoadMask(this.container,
52942 Roo.apply({store:this.dataSource}, this.loadMask));
52946 if (this.toolbar && this.toolbar.xtype) {
52947 this.toolbar.container = this.getView().getHeaderPanel(true);
52948 this.toolbar = new Roo.Toolbar(this.toolbar);
52950 if (this.footer && this.footer.xtype) {
52951 this.footer.dataSource = this.getDataSource();
52952 this.footer.container = this.getView().getFooterPanel(true);
52953 this.footer = Roo.factory(this.footer, Roo);
52955 if (this.dropTarget && this.dropTarget.xtype) {
52956 delete this.dropTarget.xtype;
52957 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52961 this.rendered = true;
52962 this.fireEvent('render', this);
52967 * Reconfigures the grid to use a different Store and Column Model.
52968 * The View will be bound to the new objects and refreshed.
52969 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52970 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52972 reconfigure : function(dataSource, colModel){
52974 this.loadMask.destroy();
52975 this.loadMask = new Roo.LoadMask(this.container,
52976 Roo.apply({store:dataSource}, this.loadMask));
52978 this.view.bind(dataSource, colModel);
52979 this.dataSource = dataSource;
52980 this.colModel = colModel;
52981 this.view.refresh(true);
52985 onKeyDown : function(e){
52986 this.fireEvent("keydown", e);
52990 * Destroy this grid.
52991 * @param {Boolean} removeEl True to remove the element
52993 destroy : function(removeEl, keepListeners){
52995 this.loadMask.destroy();
52997 var c = this.container;
52998 c.removeAllListeners();
52999 this.view.destroy();
53000 this.colModel.purgeListeners();
53001 if(!keepListeners){
53002 this.purgeListeners();
53005 if(removeEl === true){
53011 processEvent : function(name, e){
53012 // does this fire select???
53013 //Roo.log('grid:processEvent ' + name);
53015 if (name != 'touchstart' ) {
53016 this.fireEvent(name, e);
53019 var t = e.getTarget();
53021 var header = v.findHeaderIndex(t);
53022 if(header !== false){
53023 var ename = name == 'touchstart' ? 'click' : name;
53025 this.fireEvent("header" + ename, this, header, e);
53027 var row = v.findRowIndex(t);
53028 var cell = v.findCellIndex(t);
53029 if (name == 'touchstart') {
53030 // first touch is always a click.
53031 // hopefull this happens after selection is updated.?
53034 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
53035 var cs = this.selModel.getSelectedCell();
53036 if (row == cs[0] && cell == cs[1]){
53040 if (typeof(this.selModel.getSelections) != 'undefined') {
53041 var cs = this.selModel.getSelections();
53042 var ds = this.dataSource;
53043 if (cs.length == 1 && ds.getAt(row) == cs[0]){
53054 this.fireEvent("row" + name, this, row, e);
53055 if(cell !== false){
53056 this.fireEvent("cell" + name, this, row, cell, e);
53063 onClick : function(e){
53064 this.processEvent("click", e);
53067 onTouchStart : function(e){
53068 this.processEvent("touchstart", e);
53072 onContextMenu : function(e, t){
53073 this.processEvent("contextmenu", e);
53077 onDblClick : function(e){
53078 this.processEvent("dblclick", e);
53082 walkCells : function(row, col, step, fn, scope){
53083 var cm = this.colModel, clen = cm.getColumnCount();
53084 var ds = this.dataSource, rlen = ds.getCount(), first = true;
53096 if(fn.call(scope || this, row, col, cm) === true){
53114 if(fn.call(scope || this, row, col, cm) === true){
53126 getSelections : function(){
53127 return this.selModel.getSelections();
53131 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
53132 * but if manual update is required this method will initiate it.
53134 autoSize : function(){
53136 this.view.layout();
53137 if(this.view.adjustForScroll){
53138 this.view.adjustForScroll();
53144 * Returns the grid's underlying element.
53145 * @return {Element} The element
53147 getGridEl : function(){
53148 return this.container;
53151 // private for compatibility, overridden by editor grid
53152 stopEditing : function(){},
53155 * Returns the grid's SelectionModel.
53156 * @return {SelectionModel}
53158 getSelectionModel : function(){
53159 if(!this.selModel){
53160 this.selModel = new Roo.grid.RowSelectionModel();
53162 return this.selModel;
53166 * Returns the grid's DataSource.
53167 * @return {DataSource}
53169 getDataSource : function(){
53170 return this.dataSource;
53174 * Returns the grid's ColumnModel.
53175 * @return {ColumnModel}
53177 getColumnModel : function(){
53178 return this.colModel;
53182 * Returns the grid's GridView object.
53183 * @return {GridView}
53185 getView : function(){
53187 this.view = new Roo.grid.GridView(this.viewConfig);
53192 * Called to get grid's drag proxy text, by default returns this.ddText.
53195 getDragDropText : function(){
53196 var count = this.selModel.getCount();
53197 return String.format(this.ddText, count, count == 1 ? '' : 's');
53201 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
53202 * %0 is replaced with the number of selected rows.
53205 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
53207 * Ext JS Library 1.1.1
53208 * Copyright(c) 2006-2007, Ext JS, LLC.
53210 * Originally Released Under LGPL - original licence link has changed is not relivant.
53213 * <script type="text/javascript">
53216 Roo.grid.AbstractGridView = function(){
53220 "beforerowremoved" : true,
53221 "beforerowsinserted" : true,
53222 "beforerefresh" : true,
53223 "rowremoved" : true,
53224 "rowsinserted" : true,
53225 "rowupdated" : true,
53228 Roo.grid.AbstractGridView.superclass.constructor.call(this);
53231 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
53232 rowClass : "x-grid-row",
53233 cellClass : "x-grid-cell",
53234 tdClass : "x-grid-td",
53235 hdClass : "x-grid-hd",
53236 splitClass : "x-grid-hd-split",
53238 init: function(grid){
53240 var cid = this.grid.getGridEl().id;
53241 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
53242 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
53243 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
53244 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
53247 getColumnRenderers : function(){
53248 var renderers = [];
53249 var cm = this.grid.colModel;
53250 var colCount = cm.getColumnCount();
53251 for(var i = 0; i < colCount; i++){
53252 renderers[i] = cm.getRenderer(i);
53257 getColumnIds : function(){
53259 var cm = this.grid.colModel;
53260 var colCount = cm.getColumnCount();
53261 for(var i = 0; i < colCount; i++){
53262 ids[i] = cm.getColumnId(i);
53267 getDataIndexes : function(){
53268 if(!this.indexMap){
53269 this.indexMap = this.buildIndexMap();
53271 return this.indexMap.colToData;
53274 getColumnIndexByDataIndex : function(dataIndex){
53275 if(!this.indexMap){
53276 this.indexMap = this.buildIndexMap();
53278 return this.indexMap.dataToCol[dataIndex];
53282 * Set a css style for a column dynamically.
53283 * @param {Number} colIndex The index of the column
53284 * @param {String} name The css property name
53285 * @param {String} value The css value
53287 setCSSStyle : function(colIndex, name, value){
53288 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
53289 Roo.util.CSS.updateRule(selector, name, value);
53292 generateRules : function(cm){
53293 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
53294 Roo.util.CSS.removeStyleSheet(rulesId);
53295 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53296 var cid = cm.getColumnId(i);
53297 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
53298 this.tdSelector, cid, " {\n}\n",
53299 this.hdSelector, cid, " {\n}\n",
53300 this.splitSelector, cid, " {\n}\n");
53302 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53306 * Ext JS Library 1.1.1
53307 * Copyright(c) 2006-2007, Ext JS, LLC.
53309 * Originally Released Under LGPL - original licence link has changed is not relivant.
53312 * <script type="text/javascript">
53316 // This is a support class used internally by the Grid components
53317 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
53319 this.view = grid.getView();
53320 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53321 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
53323 this.setHandleElId(Roo.id(hd));
53324 this.setOuterHandleElId(Roo.id(hd2));
53326 this.scroll = false;
53328 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
53330 getDragData : function(e){
53331 var t = Roo.lib.Event.getTarget(e);
53332 var h = this.view.findHeaderCell(t);
53334 return {ddel: h.firstChild, header:h};
53339 onInitDrag : function(e){
53340 this.view.headersDisabled = true;
53341 var clone = this.dragData.ddel.cloneNode(true);
53342 clone.id = Roo.id();
53343 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
53344 this.proxy.update(clone);
53348 afterValidDrop : function(){
53350 setTimeout(function(){
53351 v.headersDisabled = false;
53355 afterInvalidDrop : function(){
53357 setTimeout(function(){
53358 v.headersDisabled = false;
53364 * Ext JS Library 1.1.1
53365 * Copyright(c) 2006-2007, Ext JS, LLC.
53367 * Originally Released Under LGPL - original licence link has changed is not relivant.
53370 * <script type="text/javascript">
53373 // This is a support class used internally by the Grid components
53374 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
53376 this.view = grid.getView();
53377 // split the proxies so they don't interfere with mouse events
53378 this.proxyTop = Roo.DomHelper.append(document.body, {
53379 cls:"col-move-top", html:" "
53381 this.proxyBottom = Roo.DomHelper.append(document.body, {
53382 cls:"col-move-bottom", html:" "
53384 this.proxyTop.hide = this.proxyBottom.hide = function(){
53385 this.setLeftTop(-100,-100);
53386 this.setStyle("visibility", "hidden");
53388 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53389 // temporarily disabled
53390 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
53391 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
53393 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
53394 proxyOffsets : [-4, -9],
53395 fly: Roo.Element.fly,
53397 getTargetFromEvent : function(e){
53398 var t = Roo.lib.Event.getTarget(e);
53399 var cindex = this.view.findCellIndex(t);
53400 if(cindex !== false){
53401 return this.view.getHeaderCell(cindex);
53406 nextVisible : function(h){
53407 var v = this.view, cm = this.grid.colModel;
53410 if(!cm.isHidden(v.getCellIndex(h))){
53418 prevVisible : function(h){
53419 var v = this.view, cm = this.grid.colModel;
53422 if(!cm.isHidden(v.getCellIndex(h))){
53430 positionIndicator : function(h, n, e){
53431 var x = Roo.lib.Event.getPageX(e);
53432 var r = Roo.lib.Dom.getRegion(n.firstChild);
53433 var px, pt, py = r.top + this.proxyOffsets[1];
53434 if((r.right - x) <= (r.right-r.left)/2){
53435 px = r.right+this.view.borderWidth;
53441 var oldIndex = this.view.getCellIndex(h);
53442 var newIndex = this.view.getCellIndex(n);
53444 if(this.grid.colModel.isFixed(newIndex)){
53448 var locked = this.grid.colModel.isLocked(newIndex);
53453 if(oldIndex < newIndex){
53456 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
53459 px += this.proxyOffsets[0];
53460 this.proxyTop.setLeftTop(px, py);
53461 this.proxyTop.show();
53462 if(!this.bottomOffset){
53463 this.bottomOffset = this.view.mainHd.getHeight();
53465 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
53466 this.proxyBottom.show();
53470 onNodeEnter : function(n, dd, e, data){
53471 if(data.header != n){
53472 this.positionIndicator(data.header, n, e);
53476 onNodeOver : function(n, dd, e, data){
53477 var result = false;
53478 if(data.header != n){
53479 result = this.positionIndicator(data.header, n, e);
53482 this.proxyTop.hide();
53483 this.proxyBottom.hide();
53485 return result ? this.dropAllowed : this.dropNotAllowed;
53488 onNodeOut : function(n, dd, e, data){
53489 this.proxyTop.hide();
53490 this.proxyBottom.hide();
53493 onNodeDrop : function(n, dd, e, data){
53494 var h = data.header;
53496 var cm = this.grid.colModel;
53497 var x = Roo.lib.Event.getPageX(e);
53498 var r = Roo.lib.Dom.getRegion(n.firstChild);
53499 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
53500 var oldIndex = this.view.getCellIndex(h);
53501 var newIndex = this.view.getCellIndex(n);
53502 var locked = cm.isLocked(newIndex);
53506 if(oldIndex < newIndex){
53509 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
53512 cm.setLocked(oldIndex, locked, true);
53513 cm.moveColumn(oldIndex, newIndex);
53514 this.grid.fireEvent("columnmove", oldIndex, newIndex);
53522 * Ext JS Library 1.1.1
53523 * Copyright(c) 2006-2007, Ext JS, LLC.
53525 * Originally Released Under LGPL - original licence link has changed is not relivant.
53528 * <script type="text/javascript">
53532 * @class Roo.grid.GridView
53533 * @extends Roo.util.Observable
53536 * @param {Object} config
53538 Roo.grid.GridView = function(config){
53539 Roo.grid.GridView.superclass.constructor.call(this);
53542 Roo.apply(this, config);
53545 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
53547 unselectable : 'unselectable="on"',
53548 unselectableCls : 'x-unselectable',
53551 rowClass : "x-grid-row",
53553 cellClass : "x-grid-col",
53555 tdClass : "x-grid-td",
53557 hdClass : "x-grid-hd",
53559 splitClass : "x-grid-split",
53561 sortClasses : ["sort-asc", "sort-desc"],
53563 enableMoveAnim : false,
53567 dh : Roo.DomHelper,
53569 fly : Roo.Element.fly,
53571 css : Roo.util.CSS,
53577 scrollIncrement : 22,
53579 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
53581 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
53583 bind : function(ds, cm){
53585 this.ds.un("load", this.onLoad, this);
53586 this.ds.un("datachanged", this.onDataChange, this);
53587 this.ds.un("add", this.onAdd, this);
53588 this.ds.un("remove", this.onRemove, this);
53589 this.ds.un("update", this.onUpdate, this);
53590 this.ds.un("clear", this.onClear, this);
53593 ds.on("load", this.onLoad, this);
53594 ds.on("datachanged", this.onDataChange, this);
53595 ds.on("add", this.onAdd, this);
53596 ds.on("remove", this.onRemove, this);
53597 ds.on("update", this.onUpdate, this);
53598 ds.on("clear", this.onClear, this);
53603 this.cm.un("widthchange", this.onColWidthChange, this);
53604 this.cm.un("headerchange", this.onHeaderChange, this);
53605 this.cm.un("hiddenchange", this.onHiddenChange, this);
53606 this.cm.un("columnmoved", this.onColumnMove, this);
53607 this.cm.un("columnlockchange", this.onColumnLock, this);
53610 this.generateRules(cm);
53611 cm.on("widthchange", this.onColWidthChange, this);
53612 cm.on("headerchange", this.onHeaderChange, this);
53613 cm.on("hiddenchange", this.onHiddenChange, this);
53614 cm.on("columnmoved", this.onColumnMove, this);
53615 cm.on("columnlockchange", this.onColumnLock, this);
53620 init: function(grid){
53621 Roo.grid.GridView.superclass.init.call(this, grid);
53623 this.bind(grid.dataSource, grid.colModel);
53625 grid.on("headerclick", this.handleHeaderClick, this);
53627 if(grid.trackMouseOver){
53628 grid.on("mouseover", this.onRowOver, this);
53629 grid.on("mouseout", this.onRowOut, this);
53631 grid.cancelTextSelection = function(){};
53632 this.gridId = grid.id;
53634 var tpls = this.templates || {};
53637 tpls.master = new Roo.Template(
53638 '<div class="x-grid" hidefocus="true">',
53639 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
53640 '<div class="x-grid-topbar"></div>',
53641 '<div class="x-grid-scroller"><div></div></div>',
53642 '<div class="x-grid-locked">',
53643 '<div class="x-grid-header">{lockedHeader}</div>',
53644 '<div class="x-grid-body">{lockedBody}</div>',
53646 '<div class="x-grid-viewport">',
53647 '<div class="x-grid-header">{header}</div>',
53648 '<div class="x-grid-body">{body}</div>',
53650 '<div class="x-grid-bottombar"></div>',
53652 '<div class="x-grid-resize-proxy"> </div>',
53655 tpls.master.disableformats = true;
53659 tpls.header = new Roo.Template(
53660 '<table border="0" cellspacing="0" cellpadding="0">',
53661 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
53664 tpls.header.disableformats = true;
53666 tpls.header.compile();
53669 tpls.hcell = new Roo.Template(
53670 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
53671 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
53674 tpls.hcell.disableFormats = true;
53676 tpls.hcell.compile();
53679 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
53680 this.unselectableCls + '" ' + this.unselectable +'> </div>');
53681 tpls.hsplit.disableFormats = true;
53683 tpls.hsplit.compile();
53686 tpls.body = new Roo.Template(
53687 '<table border="0" cellspacing="0" cellpadding="0">',
53688 "<tbody>{rows}</tbody>",
53691 tpls.body.disableFormats = true;
53693 tpls.body.compile();
53696 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
53697 tpls.row.disableFormats = true;
53699 tpls.row.compile();
53702 tpls.cell = new Roo.Template(
53703 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
53704 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
53705 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
53708 tpls.cell.disableFormats = true;
53710 tpls.cell.compile();
53712 this.templates = tpls;
53715 // remap these for backwards compat
53716 onColWidthChange : function(){
53717 this.updateColumns.apply(this, arguments);
53719 onHeaderChange : function(){
53720 this.updateHeaders.apply(this, arguments);
53722 onHiddenChange : function(){
53723 this.handleHiddenChange.apply(this, arguments);
53725 onColumnMove : function(){
53726 this.handleColumnMove.apply(this, arguments);
53728 onColumnLock : function(){
53729 this.handleLockChange.apply(this, arguments);
53732 onDataChange : function(){
53734 this.updateHeaderSortState();
53737 onClear : function(){
53741 onUpdate : function(ds, record){
53742 this.refreshRow(record);
53745 refreshRow : function(record){
53746 var ds = this.ds, index;
53747 if(typeof record == 'number'){
53749 record = ds.getAt(index);
53751 index = ds.indexOf(record);
53753 this.insertRows(ds, index, index, true);
53754 this.onRemove(ds, record, index+1, true);
53755 this.syncRowHeights(index, index);
53757 this.fireEvent("rowupdated", this, index, record);
53760 onAdd : function(ds, records, index){
53761 this.insertRows(ds, index, index + (records.length-1));
53764 onRemove : function(ds, record, index, isUpdate){
53765 if(isUpdate !== true){
53766 this.fireEvent("beforerowremoved", this, index, record);
53768 var bt = this.getBodyTable(), lt = this.getLockedTable();
53769 if(bt.rows[index]){
53770 bt.firstChild.removeChild(bt.rows[index]);
53772 if(lt.rows[index]){
53773 lt.firstChild.removeChild(lt.rows[index]);
53775 if(isUpdate !== true){
53776 this.stripeRows(index);
53777 this.syncRowHeights(index, index);
53779 this.fireEvent("rowremoved", this, index, record);
53783 onLoad : function(){
53784 this.scrollToTop();
53788 * Scrolls the grid to the top
53790 scrollToTop : function(){
53792 this.scroller.dom.scrollTop = 0;
53798 * Gets a panel in the header of the grid that can be used for toolbars etc.
53799 * After modifying the contents of this panel a call to grid.autoSize() may be
53800 * required to register any changes in size.
53801 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
53802 * @return Roo.Element
53804 getHeaderPanel : function(doShow){
53806 this.headerPanel.show();
53808 return this.headerPanel;
53812 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53813 * After modifying the contents of this panel a call to grid.autoSize() may be
53814 * required to register any changes in size.
53815 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53816 * @return Roo.Element
53818 getFooterPanel : function(doShow){
53820 this.footerPanel.show();
53822 return this.footerPanel;
53825 initElements : function(){
53826 var E = Roo.Element;
53827 var el = this.grid.getGridEl().dom.firstChild;
53828 var cs = el.childNodes;
53830 this.el = new E(el);
53832 this.focusEl = new E(el.firstChild);
53833 this.focusEl.swallowEvent("click", true);
53835 this.headerPanel = new E(cs[1]);
53836 this.headerPanel.enableDisplayMode("block");
53838 this.scroller = new E(cs[2]);
53839 this.scrollSizer = new E(this.scroller.dom.firstChild);
53841 this.lockedWrap = new E(cs[3]);
53842 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53843 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53845 this.mainWrap = new E(cs[4]);
53846 this.mainHd = new E(this.mainWrap.dom.firstChild);
53847 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53849 this.footerPanel = new E(cs[5]);
53850 this.footerPanel.enableDisplayMode("block");
53852 this.resizeProxy = new E(cs[6]);
53854 this.headerSelector = String.format(
53855 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53856 this.lockedHd.id, this.mainHd.id
53859 this.splitterSelector = String.format(
53860 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53861 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53864 idToCssName : function(s)
53866 return s.replace(/[^a-z0-9]+/ig, '-');
53869 getHeaderCell : function(index){
53870 return Roo.DomQuery.select(this.headerSelector)[index];
53873 getHeaderCellMeasure : function(index){
53874 return this.getHeaderCell(index).firstChild;
53877 getHeaderCellText : function(index){
53878 return this.getHeaderCell(index).firstChild.firstChild;
53881 getLockedTable : function(){
53882 return this.lockedBody.dom.firstChild;
53885 getBodyTable : function(){
53886 return this.mainBody.dom.firstChild;
53889 getLockedRow : function(index){
53890 return this.getLockedTable().rows[index];
53893 getRow : function(index){
53894 return this.getBodyTable().rows[index];
53897 getRowComposite : function(index){
53899 this.rowEl = new Roo.CompositeElementLite();
53901 var els = [], lrow, mrow;
53902 if(lrow = this.getLockedRow(index)){
53905 if(mrow = this.getRow(index)){
53908 this.rowEl.elements = els;
53912 * Gets the 'td' of the cell
53914 * @param {Integer} rowIndex row to select
53915 * @param {Integer} colIndex column to select
53919 getCell : function(rowIndex, colIndex){
53920 var locked = this.cm.getLockedCount();
53922 if(colIndex < locked){
53923 source = this.lockedBody.dom.firstChild;
53925 source = this.mainBody.dom.firstChild;
53926 colIndex -= locked;
53928 return source.rows[rowIndex].childNodes[colIndex];
53931 getCellText : function(rowIndex, colIndex){
53932 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53935 getCellBox : function(cell){
53936 var b = this.fly(cell).getBox();
53937 if(Roo.isOpera){ // opera fails to report the Y
53938 b.y = cell.offsetTop + this.mainBody.getY();
53943 getCellIndex : function(cell){
53944 var id = String(cell.className).match(this.cellRE);
53946 return parseInt(id[1], 10);
53951 findHeaderIndex : function(n){
53952 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53953 return r ? this.getCellIndex(r) : false;
53956 findHeaderCell : function(n){
53957 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53958 return r ? r : false;
53961 findRowIndex : function(n){
53965 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53966 return r ? r.rowIndex : false;
53969 findCellIndex : function(node){
53970 var stop = this.el.dom;
53971 while(node && node != stop){
53972 if(this.findRE.test(node.className)){
53973 return this.getCellIndex(node);
53975 node = node.parentNode;
53980 getColumnId : function(index){
53981 return this.cm.getColumnId(index);
53984 getSplitters : function()
53986 if(this.splitterSelector){
53987 return Roo.DomQuery.select(this.splitterSelector);
53993 getSplitter : function(index){
53994 return this.getSplitters()[index];
53997 onRowOver : function(e, t){
53999 if((row = this.findRowIndex(t)) !== false){
54000 this.getRowComposite(row).addClass("x-grid-row-over");
54004 onRowOut : function(e, t){
54006 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
54007 this.getRowComposite(row).removeClass("x-grid-row-over");
54011 renderHeaders : function(){
54013 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
54014 var cb = [], lb = [], sb = [], lsb = [], p = {};
54015 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54016 p.cellId = "x-grid-hd-0-" + i;
54017 p.splitId = "x-grid-csplit-0-" + i;
54018 p.id = cm.getColumnId(i);
54019 p.value = cm.getColumnHeader(i) || "";
54020 p.title = cm.getColumnTooltip(i) || p.value.match(/\</) ? '' : p.value || "";
54021 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
54022 if(!cm.isLocked(i)){
54023 cb[cb.length] = ct.apply(p);
54024 sb[sb.length] = st.apply(p);
54026 lb[lb.length] = ct.apply(p);
54027 lsb[lsb.length] = st.apply(p);
54030 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
54031 ht.apply({cells: cb.join(""), splits:sb.join("")})];
54034 updateHeaders : function(){
54035 var html = this.renderHeaders();
54036 this.lockedHd.update(html[0]);
54037 this.mainHd.update(html[1]);
54041 * Focuses the specified row.
54042 * @param {Number} row The row index
54044 focusRow : function(row)
54046 //Roo.log('GridView.focusRow');
54047 var x = this.scroller.dom.scrollLeft;
54048 this.focusCell(row, 0, false);
54049 this.scroller.dom.scrollLeft = x;
54053 * Focuses the specified cell.
54054 * @param {Number} row The row index
54055 * @param {Number} col The column index
54056 * @param {Boolean} hscroll false to disable horizontal scrolling
54058 focusCell : function(row, col, hscroll)
54060 //Roo.log('GridView.focusCell');
54061 var el = this.ensureVisible(row, col, hscroll);
54062 this.focusEl.alignTo(el, "tl-tl");
54064 this.focusEl.focus();
54066 this.focusEl.focus.defer(1, this.focusEl);
54071 * Scrolls the specified cell into view
54072 * @param {Number} row The row index
54073 * @param {Number} col The column index
54074 * @param {Boolean} hscroll false to disable horizontal scrolling
54076 ensureVisible : function(row, col, hscroll)
54078 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
54079 //return null; //disable for testing.
54080 if(typeof row != "number"){
54081 row = row.rowIndex;
54083 if(row < 0 && row >= this.ds.getCount()){
54086 col = (col !== undefined ? col : 0);
54087 var cm = this.grid.colModel;
54088 while(cm.isHidden(col)){
54092 var el = this.getCell(row, col);
54096 var c = this.scroller.dom;
54098 var ctop = parseInt(el.offsetTop, 10);
54099 var cleft = parseInt(el.offsetLeft, 10);
54100 var cbot = ctop + el.offsetHeight;
54101 var cright = cleft + el.offsetWidth;
54103 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
54104 var stop = parseInt(c.scrollTop, 10);
54105 var sleft = parseInt(c.scrollLeft, 10);
54106 var sbot = stop + ch;
54107 var sright = sleft + c.clientWidth;
54109 Roo.log('GridView.ensureVisible:' +
54111 ' c.clientHeight:' + c.clientHeight +
54112 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
54120 c.scrollTop = ctop;
54121 //Roo.log("set scrolltop to ctop DISABLE?");
54122 }else if(cbot > sbot){
54123 //Roo.log("set scrolltop to cbot-ch");
54124 c.scrollTop = cbot-ch;
54127 if(hscroll !== false){
54129 c.scrollLeft = cleft;
54130 }else if(cright > sright){
54131 c.scrollLeft = cright-c.clientWidth;
54138 updateColumns : function(){
54139 this.grid.stopEditing();
54140 var cm = this.grid.colModel, colIds = this.getColumnIds();
54141 //var totalWidth = cm.getTotalWidth();
54143 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54144 //if(cm.isHidden(i)) continue;
54145 var w = cm.getColumnWidth(i);
54146 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
54147 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
54149 this.updateSplitters();
54152 generateRules : function(cm){
54153 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
54154 Roo.util.CSS.removeStyleSheet(rulesId);
54155 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54156 var cid = cm.getColumnId(i);
54158 if(cm.config[i].align){
54159 align = 'text-align:'+cm.config[i].align+';';
54162 if(cm.isHidden(i)){
54163 hidden = 'display:none;';
54165 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
54167 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
54168 this.hdSelector, cid, " {\n", align, width, "}\n",
54169 this.tdSelector, cid, " {\n",hidden,"\n}\n",
54170 this.splitSelector, cid, " {\n", hidden , "\n}\n");
54172 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54175 updateSplitters : function(){
54176 var cm = this.cm, s = this.getSplitters();
54177 if(s){ // splitters not created yet
54178 var pos = 0, locked = true;
54179 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54180 if(cm.isHidden(i)) {
54183 var w = cm.getColumnWidth(i); // make sure it's a number
54184 if(!cm.isLocked(i) && locked){
54189 s[i].style.left = (pos-this.splitOffset) + "px";
54194 handleHiddenChange : function(colModel, colIndex, hidden){
54196 this.hideColumn(colIndex);
54198 this.unhideColumn(colIndex);
54202 hideColumn : function(colIndex){
54203 var cid = this.getColumnId(colIndex);
54204 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
54205 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
54207 this.updateHeaders();
54209 this.updateSplitters();
54213 unhideColumn : function(colIndex){
54214 var cid = this.getColumnId(colIndex);
54215 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
54216 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
54219 this.updateHeaders();
54221 this.updateSplitters();
54225 insertRows : function(dm, firstRow, lastRow, isUpdate){
54226 if(firstRow == 0 && lastRow == dm.getCount()-1){
54230 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
54232 var s = this.getScrollState();
54233 var markup = this.renderRows(firstRow, lastRow);
54234 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
54235 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
54236 this.restoreScroll(s);
54238 this.fireEvent("rowsinserted", this, firstRow, lastRow);
54239 this.syncRowHeights(firstRow, lastRow);
54240 this.stripeRows(firstRow);
54246 bufferRows : function(markup, target, index){
54247 var before = null, trows = target.rows, tbody = target.tBodies[0];
54248 if(index < trows.length){
54249 before = trows[index];
54251 var b = document.createElement("div");
54252 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
54253 var rows = b.firstChild.rows;
54254 for(var i = 0, len = rows.length; i < len; i++){
54256 tbody.insertBefore(rows[0], before);
54258 tbody.appendChild(rows[0]);
54265 deleteRows : function(dm, firstRow, lastRow){
54266 if(dm.getRowCount()<1){
54267 this.fireEvent("beforerefresh", this);
54268 this.mainBody.update("");
54269 this.lockedBody.update("");
54270 this.fireEvent("refresh", this);
54272 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
54273 var bt = this.getBodyTable();
54274 var tbody = bt.firstChild;
54275 var rows = bt.rows;
54276 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
54277 tbody.removeChild(rows[firstRow]);
54279 this.stripeRows(firstRow);
54280 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
54284 updateRows : function(dataSource, firstRow, lastRow){
54285 var s = this.getScrollState();
54287 this.restoreScroll(s);
54290 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
54294 this.updateHeaderSortState();
54297 getScrollState : function(){
54299 var sb = this.scroller.dom;
54300 return {left: sb.scrollLeft, top: sb.scrollTop};
54303 stripeRows : function(startRow){
54304 if(!this.grid.stripeRows || this.ds.getCount() < 1){
54307 startRow = startRow || 0;
54308 var rows = this.getBodyTable().rows;
54309 var lrows = this.getLockedTable().rows;
54310 var cls = ' x-grid-row-alt ';
54311 for(var i = startRow, len = rows.length; i < len; i++){
54312 var row = rows[i], lrow = lrows[i];
54313 var isAlt = ((i+1) % 2 == 0);
54314 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
54315 if(isAlt == hasAlt){
54319 row.className += " x-grid-row-alt";
54321 row.className = row.className.replace("x-grid-row-alt", "");
54324 lrow.className = row.className;
54329 restoreScroll : function(state){
54330 //Roo.log('GridView.restoreScroll');
54331 var sb = this.scroller.dom;
54332 sb.scrollLeft = state.left;
54333 sb.scrollTop = state.top;
54337 syncScroll : function(){
54338 //Roo.log('GridView.syncScroll');
54339 var sb = this.scroller.dom;
54340 var sh = this.mainHd.dom;
54341 var bs = this.mainBody.dom;
54342 var lv = this.lockedBody.dom;
54343 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
54344 lv.scrollTop = bs.scrollTop = sb.scrollTop;
54347 handleScroll : function(e){
54349 var sb = this.scroller.dom;
54350 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
54354 handleWheel : function(e){
54355 var d = e.getWheelDelta();
54356 this.scroller.dom.scrollTop -= d*22;
54357 // set this here to prevent jumpy scrolling on large tables
54358 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
54362 renderRows : function(startRow, endRow){
54363 // pull in all the crap needed to render rows
54364 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
54365 var colCount = cm.getColumnCount();
54367 if(ds.getCount() < 1){
54371 // build a map for all the columns
54373 for(var i = 0; i < colCount; i++){
54374 var name = cm.getDataIndex(i);
54376 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
54377 renderer : cm.getRenderer(i),
54378 id : cm.getColumnId(i),
54379 locked : cm.isLocked(i),
54380 has_editor : cm.isCellEditable(i)
54384 startRow = startRow || 0;
54385 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
54387 // records to render
54388 var rs = ds.getRange(startRow, endRow);
54390 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
54393 // As much as I hate to duplicate code, this was branched because FireFox really hates
54394 // [].join("") on strings. The performance difference was substantial enough to
54395 // branch this function
54396 doRender : Roo.isGecko ?
54397 function(cs, rs, ds, startRow, colCount, stripe){
54398 var ts = this.templates, ct = ts.cell, rt = ts.row;
54400 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54402 var hasListener = this.grid.hasListener('rowclass');
54404 for(var j = 0, len = rs.length; j < len; j++){
54405 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
54406 for(var i = 0; i < colCount; i++){
54408 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54410 p.css = p.attr = "";
54411 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54412 if(p.value == undefined || p.value === "") {
54413 p.value = " ";
54416 p.css += ' x-grid-editable-cell';
54418 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
54419 p.css += ' x-grid-dirty-cell';
54421 var markup = ct.apply(p);
54429 if(stripe && ((rowIndex+1) % 2 == 0)){
54430 alt.push("x-grid-row-alt")
54433 alt.push( " x-grid-dirty-row");
54436 if(this.getRowClass){
54437 alt.push(this.getRowClass(r, rowIndex));
54443 rowIndex : rowIndex,
54446 this.grid.fireEvent('rowclass', this, rowcfg);
54447 alt.push(rowcfg.rowClass);
54449 rp.alt = alt.join(" ");
54450 lbuf+= rt.apply(rp);
54452 buf+= rt.apply(rp);
54454 return [lbuf, buf];
54456 function(cs, rs, ds, startRow, colCount, stripe){
54457 var ts = this.templates, ct = ts.cell, rt = ts.row;
54459 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54460 var hasListener = this.grid.hasListener('rowclass');
54463 for(var j = 0, len = rs.length; j < len; j++){
54464 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
54465 for(var i = 0; i < colCount; i++){
54467 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54469 p.css = p.attr = "";
54470 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54471 if(p.value == undefined || p.value === "") {
54472 p.value = " ";
54476 p.css += ' x-grid-editable-cell';
54478 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54479 p.css += ' x-grid-dirty-cell'
54482 var markup = ct.apply(p);
54484 cb[cb.length] = markup;
54486 lcb[lcb.length] = markup;
54490 if(stripe && ((rowIndex+1) % 2 == 0)){
54491 alt.push( "x-grid-row-alt");
54494 alt.push(" x-grid-dirty-row");
54497 if(this.getRowClass){
54498 alt.push( this.getRowClass(r, rowIndex));
54504 rowIndex : rowIndex,
54507 this.grid.fireEvent('rowclass', this, rowcfg);
54508 alt.push(rowcfg.rowClass);
54511 rp.alt = alt.join(" ");
54512 rp.cells = lcb.join("");
54513 lbuf[lbuf.length] = rt.apply(rp);
54514 rp.cells = cb.join("");
54515 buf[buf.length] = rt.apply(rp);
54517 return [lbuf.join(""), buf.join("")];
54520 renderBody : function(){
54521 var markup = this.renderRows();
54522 var bt = this.templates.body;
54523 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
54527 * Refreshes the grid
54528 * @param {Boolean} headersToo
54530 refresh : function(headersToo){
54531 this.fireEvent("beforerefresh", this);
54532 this.grid.stopEditing();
54533 var result = this.renderBody();
54534 this.lockedBody.update(result[0]);
54535 this.mainBody.update(result[1]);
54536 if(headersToo === true){
54537 this.updateHeaders();
54538 this.updateColumns();
54539 this.updateSplitters();
54540 this.updateHeaderSortState();
54542 this.syncRowHeights();
54544 this.fireEvent("refresh", this);
54547 handleColumnMove : function(cm, oldIndex, newIndex){
54548 this.indexMap = null;
54549 var s = this.getScrollState();
54550 this.refresh(true);
54551 this.restoreScroll(s);
54552 this.afterMove(newIndex);
54555 afterMove : function(colIndex){
54556 if(this.enableMoveAnim && Roo.enableFx){
54557 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
54559 // if multisort - fix sortOrder, and reload..
54560 if (this.grid.dataSource.multiSort) {
54561 // the we can call sort again..
54562 var dm = this.grid.dataSource;
54563 var cm = this.grid.colModel;
54565 for(var i = 0; i < cm.config.length; i++ ) {
54567 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
54568 continue; // dont' bother, it's not in sort list or being set.
54571 so.push(cm.config[i].dataIndex);
54574 dm.load(dm.lastOptions);
54581 updateCell : function(dm, rowIndex, dataIndex){
54582 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
54583 if(typeof colIndex == "undefined"){ // not present in grid
54586 var cm = this.grid.colModel;
54587 var cell = this.getCell(rowIndex, colIndex);
54588 var cellText = this.getCellText(rowIndex, colIndex);
54591 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
54592 id : cm.getColumnId(colIndex),
54593 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
54595 var renderer = cm.getRenderer(colIndex);
54596 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
54597 if(typeof val == "undefined" || val === "") {
54600 cellText.innerHTML = val;
54601 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
54602 this.syncRowHeights(rowIndex, rowIndex);
54605 calcColumnWidth : function(colIndex, maxRowsToMeasure){
54607 if(this.grid.autoSizeHeaders){
54608 var h = this.getHeaderCellMeasure(colIndex);
54609 maxWidth = Math.max(maxWidth, h.scrollWidth);
54612 if(this.cm.isLocked(colIndex)){
54613 tb = this.getLockedTable();
54616 tb = this.getBodyTable();
54617 index = colIndex - this.cm.getLockedCount();
54620 var rows = tb.rows;
54621 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
54622 for(var i = 0; i < stopIndex; i++){
54623 var cell = rows[i].childNodes[index].firstChild;
54624 maxWidth = Math.max(maxWidth, cell.scrollWidth);
54627 return maxWidth + /*margin for error in IE*/ 5;
54630 * Autofit a column to its content.
54631 * @param {Number} colIndex
54632 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
54634 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
54635 if(this.cm.isHidden(colIndex)){
54636 return; // can't calc a hidden column
54639 var cid = this.cm.getColumnId(colIndex);
54640 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
54641 if(this.grid.autoSizeHeaders){
54642 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
54645 var newWidth = this.calcColumnWidth(colIndex);
54646 this.cm.setColumnWidth(colIndex,
54647 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
54648 if(!suppressEvent){
54649 this.grid.fireEvent("columnresize", colIndex, newWidth);
54654 * Autofits all columns to their content and then expands to fit any extra space in the grid
54656 autoSizeColumns : function(){
54657 var cm = this.grid.colModel;
54658 var colCount = cm.getColumnCount();
54659 for(var i = 0; i < colCount; i++){
54660 this.autoSizeColumn(i, true, true);
54662 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
54665 this.updateColumns();
54671 * Autofits all columns to the grid's width proportionate with their current size
54672 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
54674 fitColumns : function(reserveScrollSpace){
54675 var cm = this.grid.colModel;
54676 var colCount = cm.getColumnCount();
54680 for (i = 0; i < colCount; i++){
54681 if(!cm.isHidden(i) && !cm.isFixed(i)){
54682 w = cm.getColumnWidth(i);
54688 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
54689 if(reserveScrollSpace){
54692 var frac = (avail - cm.getTotalWidth())/width;
54693 while (cols.length){
54696 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
54698 this.updateColumns();
54702 onRowSelect : function(rowIndex){
54703 var row = this.getRowComposite(rowIndex);
54704 row.addClass("x-grid-row-selected");
54707 onRowDeselect : function(rowIndex){
54708 var row = this.getRowComposite(rowIndex);
54709 row.removeClass("x-grid-row-selected");
54712 onCellSelect : function(row, col){
54713 var cell = this.getCell(row, col);
54715 Roo.fly(cell).addClass("x-grid-cell-selected");
54719 onCellDeselect : function(row, col){
54720 var cell = this.getCell(row, col);
54722 Roo.fly(cell).removeClass("x-grid-cell-selected");
54726 updateHeaderSortState : function(){
54728 // sort state can be single { field: xxx, direction : yyy}
54729 // or { xxx=>ASC , yyy : DESC ..... }
54732 if (!this.ds.multiSort) {
54733 var state = this.ds.getSortState();
54737 mstate[state.field] = state.direction;
54738 // FIXME... - this is not used here.. but might be elsewhere..
54739 this.sortState = state;
54742 mstate = this.ds.sortToggle;
54744 //remove existing sort classes..
54746 var sc = this.sortClasses;
54747 var hds = this.el.select(this.headerSelector).removeClass(sc);
54749 for(var f in mstate) {
54751 var sortColumn = this.cm.findColumnIndex(f);
54753 if(sortColumn != -1){
54754 var sortDir = mstate[f];
54755 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
54764 handleHeaderClick : function(g, index,e){
54766 Roo.log("header click");
54769 // touch events on header are handled by context
54770 this.handleHdCtx(g,index,e);
54775 if(this.headersDisabled){
54778 var dm = g.dataSource, cm = g.colModel;
54779 if(!cm.isSortable(index)){
54784 if (dm.multiSort) {
54785 // update the sortOrder
54787 for(var i = 0; i < cm.config.length; i++ ) {
54789 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
54790 continue; // dont' bother, it's not in sort list or being set.
54793 so.push(cm.config[i].dataIndex);
54799 dm.sort(cm.getDataIndex(index));
54803 destroy : function(){
54805 this.colMenu.removeAll();
54806 Roo.menu.MenuMgr.unregister(this.colMenu);
54807 this.colMenu.getEl().remove();
54808 delete this.colMenu;
54811 this.hmenu.removeAll();
54812 Roo.menu.MenuMgr.unregister(this.hmenu);
54813 this.hmenu.getEl().remove();
54816 if(this.grid.enableColumnMove){
54817 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54819 for(var dd in dds){
54820 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54821 var elid = dds[dd].dragElId;
54823 Roo.get(elid).remove();
54824 } else if(dds[dd].config.isTarget){
54825 dds[dd].proxyTop.remove();
54826 dds[dd].proxyBottom.remove();
54829 if(Roo.dd.DDM.locationCache[dd]){
54830 delete Roo.dd.DDM.locationCache[dd];
54833 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54836 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54837 this.bind(null, null);
54838 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54841 handleLockChange : function(){
54842 this.refresh(true);
54845 onDenyColumnLock : function(){
54849 onDenyColumnHide : function(){
54853 handleHdMenuClick : function(item){
54854 var index = this.hdCtxIndex;
54855 var cm = this.cm, ds = this.ds;
54858 ds.sort(cm.getDataIndex(index), "ASC");
54861 ds.sort(cm.getDataIndex(index), "DESC");
54864 var lc = cm.getLockedCount();
54865 if(cm.getColumnCount(true) <= lc+1){
54866 this.onDenyColumnLock();
54870 cm.setLocked(index, true, true);
54871 cm.moveColumn(index, lc);
54872 this.grid.fireEvent("columnmove", index, lc);
54874 cm.setLocked(index, true);
54878 var lc = cm.getLockedCount();
54879 if((lc-1) != index){
54880 cm.setLocked(index, false, true);
54881 cm.moveColumn(index, lc-1);
54882 this.grid.fireEvent("columnmove", index, lc-1);
54884 cm.setLocked(index, false);
54887 case 'wider': // used to expand cols on touch..
54889 var cw = cm.getColumnWidth(index);
54890 cw += (item.id == 'wider' ? 1 : -1) * 50;
54891 cw = Math.max(0, cw);
54892 cw = Math.min(cw,4000);
54893 cm.setColumnWidth(index, cw);
54897 index = cm.getIndexById(item.id.substr(4));
54899 if(item.checked && cm.getColumnCount(true) <= 1){
54900 this.onDenyColumnHide();
54903 cm.setHidden(index, item.checked);
54909 beforeColMenuShow : function(){
54910 var cm = this.cm, colCount = cm.getColumnCount();
54911 this.colMenu.removeAll();
54912 for(var i = 0; i < colCount; i++){
54913 this.colMenu.add(new Roo.menu.CheckItem({
54914 id: "col-"+cm.getColumnId(i),
54915 text: cm.getColumnHeader(i),
54916 checked: !cm.isHidden(i),
54922 handleHdCtx : function(g, index, e){
54924 var hd = this.getHeaderCell(index);
54925 this.hdCtxIndex = index;
54926 var ms = this.hmenu.items, cm = this.cm;
54927 ms.get("asc").setDisabled(!cm.isSortable(index));
54928 ms.get("desc").setDisabled(!cm.isSortable(index));
54929 if(this.grid.enableColLock !== false){
54930 ms.get("lock").setDisabled(cm.isLocked(index));
54931 ms.get("unlock").setDisabled(!cm.isLocked(index));
54933 this.hmenu.show(hd, "tl-bl");
54936 handleHdOver : function(e){
54937 var hd = this.findHeaderCell(e.getTarget());
54938 if(hd && !this.headersDisabled){
54939 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54940 this.fly(hd).addClass("x-grid-hd-over");
54945 handleHdOut : function(e){
54946 var hd = this.findHeaderCell(e.getTarget());
54948 this.fly(hd).removeClass("x-grid-hd-over");
54952 handleSplitDblClick : function(e, t){
54953 var i = this.getCellIndex(t);
54954 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54955 this.autoSizeColumn(i, true);
54960 render : function(){
54963 var colCount = cm.getColumnCount();
54965 if(this.grid.monitorWindowResize === true){
54966 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54968 var header = this.renderHeaders();
54969 var body = this.templates.body.apply({rows:""});
54970 var html = this.templates.master.apply({
54973 lockedHeader: header[0],
54977 //this.updateColumns();
54979 this.grid.getGridEl().dom.innerHTML = html;
54981 this.initElements();
54983 // a kludge to fix the random scolling effect in webkit
54984 this.el.on("scroll", function() {
54985 this.el.dom.scrollTop=0; // hopefully not recursive..
54988 this.scroller.on("scroll", this.handleScroll, this);
54989 this.lockedBody.on("mousewheel", this.handleWheel, this);
54990 this.mainBody.on("mousewheel", this.handleWheel, this);
54992 this.mainHd.on("mouseover", this.handleHdOver, this);
54993 this.mainHd.on("mouseout", this.handleHdOut, this);
54994 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54995 {delegate: "."+this.splitClass});
54997 this.lockedHd.on("mouseover", this.handleHdOver, this);
54998 this.lockedHd.on("mouseout", this.handleHdOut, this);
54999 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
55000 {delegate: "."+this.splitClass});
55002 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
55003 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
55006 this.updateSplitters();
55008 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
55009 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
55010 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
55013 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
55014 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
55016 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
55017 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
55019 if(this.grid.enableColLock !== false){
55020 this.hmenu.add('-',
55021 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
55022 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
55026 this.hmenu.add('-',
55027 {id:"wider", text: this.columnsWiderText},
55028 {id:"narrow", text: this.columnsNarrowText }
55034 if(this.grid.enableColumnHide !== false){
55036 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
55037 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
55038 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
55040 this.hmenu.add('-',
55041 {id:"columns", text: this.columnsText, menu: this.colMenu}
55044 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
55046 this.grid.on("headercontextmenu", this.handleHdCtx, this);
55049 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
55050 this.dd = new Roo.grid.GridDragZone(this.grid, {
55051 ddGroup : this.grid.ddGroup || 'GridDD'
55057 for(var i = 0; i < colCount; i++){
55058 if(cm.isHidden(i)){
55059 this.hideColumn(i);
55061 if(cm.config[i].align){
55062 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
55063 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
55067 this.updateHeaderSortState();
55069 this.beforeInitialResize();
55072 // two part rendering gives faster view to the user
55073 this.renderPhase2.defer(1, this);
55076 renderPhase2 : function(){
55077 // render the rows now
55079 if(this.grid.autoSizeColumns){
55080 this.autoSizeColumns();
55084 beforeInitialResize : function(){
55088 onColumnSplitterMoved : function(i, w){
55089 this.userResized = true;
55090 var cm = this.grid.colModel;
55091 cm.setColumnWidth(i, w, true);
55092 var cid = cm.getColumnId(i);
55093 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
55094 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
55095 this.updateSplitters();
55097 this.grid.fireEvent("columnresize", i, w);
55100 syncRowHeights : function(startIndex, endIndex){
55101 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
55102 startIndex = startIndex || 0;
55103 var mrows = this.getBodyTable().rows;
55104 var lrows = this.getLockedTable().rows;
55105 var len = mrows.length-1;
55106 endIndex = Math.min(endIndex || len, len);
55107 for(var i = startIndex; i <= endIndex; i++){
55108 var m = mrows[i], l = lrows[i];
55109 var h = Math.max(m.offsetHeight, l.offsetHeight);
55110 m.style.height = l.style.height = h + "px";
55115 layout : function(initialRender, is2ndPass){
55117 var auto = g.autoHeight;
55118 var scrollOffset = 16;
55119 var c = g.getGridEl(), cm = this.cm,
55120 expandCol = g.autoExpandColumn,
55122 //c.beginMeasure();
55124 if(!c.dom.offsetWidth){ // display:none?
55126 this.lockedWrap.show();
55127 this.mainWrap.show();
55132 var hasLock = this.cm.isLocked(0);
55134 var tbh = this.headerPanel.getHeight();
55135 var bbh = this.footerPanel.getHeight();
55138 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
55139 var newHeight = ch + c.getBorderWidth("tb");
55141 newHeight = Math.min(g.maxHeight, newHeight);
55143 c.setHeight(newHeight);
55147 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
55150 var s = this.scroller;
55152 var csize = c.getSize(true);
55154 this.el.setSize(csize.width, csize.height);
55156 this.headerPanel.setWidth(csize.width);
55157 this.footerPanel.setWidth(csize.width);
55159 var hdHeight = this.mainHd.getHeight();
55160 var vw = csize.width;
55161 var vh = csize.height - (tbh + bbh);
55165 var bt = this.getBodyTable();
55167 if(cm.getLockedCount() == cm.config.length){
55168 bt = this.getLockedTable();
55171 var ltWidth = hasLock ?
55172 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
55174 var scrollHeight = bt.offsetHeight;
55175 var scrollWidth = ltWidth + bt.offsetWidth;
55176 var vscroll = false, hscroll = false;
55178 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
55180 var lw = this.lockedWrap, mw = this.mainWrap;
55181 var lb = this.lockedBody, mb = this.mainBody;
55183 setTimeout(function(){
55184 var t = s.dom.offsetTop;
55185 var w = s.dom.clientWidth,
55186 h = s.dom.clientHeight;
55189 lw.setSize(ltWidth, h);
55191 mw.setLeftTop(ltWidth, t);
55192 mw.setSize(w-ltWidth, h);
55194 lb.setHeight(h-hdHeight);
55195 mb.setHeight(h-hdHeight);
55197 if(is2ndPass !== true && !gv.userResized && expandCol){
55198 // high speed resize without full column calculation
55200 var ci = cm.getIndexById(expandCol);
55202 ci = cm.findColumnIndex(expandCol);
55204 ci = Math.max(0, ci); // make sure it's got at least the first col.
55205 var expandId = cm.getColumnId(ci);
55206 var tw = cm.getTotalWidth(false);
55207 var currentWidth = cm.getColumnWidth(ci);
55208 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
55209 if(currentWidth != cw){
55210 cm.setColumnWidth(ci, cw, true);
55211 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
55212 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
55213 gv.updateSplitters();
55214 gv.layout(false, true);
55226 onWindowResize : function(){
55227 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
55233 appendFooter : function(parentEl){
55237 sortAscText : "Sort Ascending",
55238 sortDescText : "Sort Descending",
55239 lockText : "Lock Column",
55240 unlockText : "Unlock Column",
55241 columnsText : "Columns",
55243 columnsWiderText : "Wider",
55244 columnsNarrowText : "Thinner"
55248 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
55249 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
55250 this.proxy.el.addClass('x-grid3-col-dd');
55253 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
55254 handleMouseDown : function(e){
55258 callHandleMouseDown : function(e){
55259 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
55264 * Ext JS Library 1.1.1
55265 * Copyright(c) 2006-2007, Ext JS, LLC.
55267 * Originally Released Under LGPL - original licence link has changed is not relivant.
55270 * <script type="text/javascript">
55274 // This is a support class used internally by the Grid components
55275 Roo.grid.SplitDragZone = function(grid, hd, hd2){
55277 this.view = grid.getView();
55278 this.proxy = this.view.resizeProxy;
55279 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
55280 "gridSplitters" + this.grid.getGridEl().id, {
55281 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
55283 this.setHandleElId(Roo.id(hd));
55284 this.setOuterHandleElId(Roo.id(hd2));
55285 this.scroll = false;
55287 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
55288 fly: Roo.Element.fly,
55290 b4StartDrag : function(x, y){
55291 this.view.headersDisabled = true;
55292 this.proxy.setHeight(this.view.mainWrap.getHeight());
55293 var w = this.cm.getColumnWidth(this.cellIndex);
55294 var minw = Math.max(w-this.grid.minColumnWidth, 0);
55295 this.resetConstraints();
55296 this.setXConstraint(minw, 1000);
55297 this.setYConstraint(0, 0);
55298 this.minX = x - minw;
55299 this.maxX = x + 1000;
55301 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
55305 handleMouseDown : function(e){
55306 ev = Roo.EventObject.setEvent(e);
55307 var t = this.fly(ev.getTarget());
55308 if(t.hasClass("x-grid-split")){
55309 this.cellIndex = this.view.getCellIndex(t.dom);
55310 this.split = t.dom;
55311 this.cm = this.grid.colModel;
55312 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
55313 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
55318 endDrag : function(e){
55319 this.view.headersDisabled = false;
55320 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
55321 var diff = endX - this.startPos;
55322 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
55325 autoOffset : function(){
55326 this.setDelta(0,0);
55330 * Ext JS Library 1.1.1
55331 * Copyright(c) 2006-2007, Ext JS, LLC.
55333 * Originally Released Under LGPL - original licence link has changed is not relivant.
55336 * <script type="text/javascript">
55340 // This is a support class used internally by the Grid components
55341 Roo.grid.GridDragZone = function(grid, config){
55342 this.view = grid.getView();
55343 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
55344 if(this.view.lockedBody){
55345 this.setHandleElId(Roo.id(this.view.mainBody.dom));
55346 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
55348 this.scroll = false;
55350 this.ddel = document.createElement('div');
55351 this.ddel.className = 'x-grid-dd-wrap';
55354 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
55355 ddGroup : "GridDD",
55357 getDragData : function(e){
55358 var t = Roo.lib.Event.getTarget(e);
55359 var rowIndex = this.view.findRowIndex(t);
55360 var sm = this.grid.selModel;
55362 //Roo.log(rowIndex);
55364 if (sm.getSelectedCell) {
55365 // cell selection..
55366 if (!sm.getSelectedCell()) {
55369 if (rowIndex != sm.getSelectedCell()[0]) {
55375 if(rowIndex !== false){
55380 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
55382 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
55385 if (e.hasModifier()){
55386 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
55389 Roo.log("getDragData");
55394 rowIndex: rowIndex,
55395 selections:sm.getSelections ? sm.getSelections() : (
55396 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
55403 onInitDrag : function(e){
55404 var data = this.dragData;
55405 this.ddel.innerHTML = this.grid.getDragDropText();
55406 this.proxy.update(this.ddel);
55407 // fire start drag?
55410 afterRepair : function(){
55411 this.dragging = false;
55414 getRepairXY : function(e, data){
55418 onEndDrag : function(data, e){
55422 onValidDrop : function(dd, e, id){
55427 beforeInvalidDrop : function(e, id){
55432 * Ext JS Library 1.1.1
55433 * Copyright(c) 2006-2007, Ext JS, LLC.
55435 * Originally Released Under LGPL - original licence link has changed is not relivant.
55438 * <script type="text/javascript">
55443 * @class Roo.grid.ColumnModel
55444 * @extends Roo.util.Observable
55445 * This is the default implementation of a ColumnModel used by the Grid. It defines
55446 * the columns in the grid.
55449 var colModel = new Roo.grid.ColumnModel([
55450 {header: "Ticker", width: 60, sortable: true, locked: true},
55451 {header: "Company Name", width: 150, sortable: true},
55452 {header: "Market Cap.", width: 100, sortable: true},
55453 {header: "$ Sales", width: 100, sortable: true, renderer: money},
55454 {header: "Employees", width: 100, sortable: true, resizable: false}
55459 * The config options listed for this class are options which may appear in each
55460 * individual column definition.
55461 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
55463 * @param {Object} config An Array of column config objects. See this class's
55464 * config objects for details.
55466 Roo.grid.ColumnModel = function(config){
55468 * The config passed into the constructor
55470 this.config = config;
55473 // if no id, create one
55474 // if the column does not have a dataIndex mapping,
55475 // map it to the order it is in the config
55476 for(var i = 0, len = config.length; i < len; i++){
55478 if(typeof c.dataIndex == "undefined"){
55481 if(typeof c.renderer == "string"){
55482 c.renderer = Roo.util.Format[c.renderer];
55484 if(typeof c.id == "undefined"){
55487 if(c.editor && c.editor.xtype){
55488 c.editor = Roo.factory(c.editor, Roo.grid);
55490 if(c.editor && c.editor.isFormField){
55491 c.editor = new Roo.grid.GridEditor(c.editor);
55493 this.lookup[c.id] = c;
55497 * The width of columns which have no width specified (defaults to 100)
55500 this.defaultWidth = 100;
55503 * Default sortable of columns which have no sortable specified (defaults to false)
55506 this.defaultSortable = false;
55510 * @event widthchange
55511 * Fires when the width of a column changes.
55512 * @param {ColumnModel} this
55513 * @param {Number} columnIndex The column index
55514 * @param {Number} newWidth The new width
55516 "widthchange": true,
55518 * @event headerchange
55519 * Fires when the text of a header changes.
55520 * @param {ColumnModel} this
55521 * @param {Number} columnIndex The column index
55522 * @param {Number} newText The new header text
55524 "headerchange": true,
55526 * @event hiddenchange
55527 * Fires when a column is hidden or "unhidden".
55528 * @param {ColumnModel} this
55529 * @param {Number} columnIndex The column index
55530 * @param {Boolean} hidden true if hidden, false otherwise
55532 "hiddenchange": true,
55534 * @event columnmoved
55535 * Fires when a column is moved.
55536 * @param {ColumnModel} this
55537 * @param {Number} oldIndex
55538 * @param {Number} newIndex
55540 "columnmoved" : true,
55542 * @event columlockchange
55543 * Fires when a column's locked state is changed
55544 * @param {ColumnModel} this
55545 * @param {Number} colIndex
55546 * @param {Boolean} locked true if locked
55548 "columnlockchange" : true
55550 Roo.grid.ColumnModel.superclass.constructor.call(this);
55552 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
55554 * @cfg {String} header The header text to display in the Grid view.
55557 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
55558 * {@link Roo.data.Record} definition from which to draw the column's value. If not
55559 * specified, the column's index is used as an index into the Record's data Array.
55562 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
55563 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
55566 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
55567 * Defaults to the value of the {@link #defaultSortable} property.
55568 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
55571 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
55574 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
55577 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
55580 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
55583 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
55584 * given the cell's data value. See {@link #setRenderer}. If not specified, the
55585 * default renderer uses the raw data value. If an object is returned (bootstrap only)
55586 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
55589 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
55592 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
55595 * @cfg {String} cursor (Optional)
55598 * @cfg {String} tooltip (Optional)
55601 * @cfg {Number} xs (Optional)
55604 * @cfg {Number} sm (Optional)
55607 * @cfg {Number} md (Optional)
55610 * @cfg {Number} lg (Optional)
55613 * Returns the id of the column at the specified index.
55614 * @param {Number} index The column index
55615 * @return {String} the id
55617 getColumnId : function(index){
55618 return this.config[index].id;
55622 * Returns the column for a specified id.
55623 * @param {String} id The column id
55624 * @return {Object} the column
55626 getColumnById : function(id){
55627 return this.lookup[id];
55632 * Returns the column for a specified dataIndex.
55633 * @param {String} dataIndex The column dataIndex
55634 * @return {Object|Boolean} the column or false if not found
55636 getColumnByDataIndex: function(dataIndex){
55637 var index = this.findColumnIndex(dataIndex);
55638 return index > -1 ? this.config[index] : false;
55642 * Returns the index for a specified column id.
55643 * @param {String} id The column id
55644 * @return {Number} the index, or -1 if not found
55646 getIndexById : function(id){
55647 for(var i = 0, len = this.config.length; i < len; i++){
55648 if(this.config[i].id == id){
55656 * Returns the index for a specified column dataIndex.
55657 * @param {String} dataIndex The column dataIndex
55658 * @return {Number} the index, or -1 if not found
55661 findColumnIndex : function(dataIndex){
55662 for(var i = 0, len = this.config.length; i < len; i++){
55663 if(this.config[i].dataIndex == dataIndex){
55671 moveColumn : function(oldIndex, newIndex){
55672 var c = this.config[oldIndex];
55673 this.config.splice(oldIndex, 1);
55674 this.config.splice(newIndex, 0, c);
55675 this.dataMap = null;
55676 this.fireEvent("columnmoved", this, oldIndex, newIndex);
55679 isLocked : function(colIndex){
55680 return this.config[colIndex].locked === true;
55683 setLocked : function(colIndex, value, suppressEvent){
55684 if(this.isLocked(colIndex) == value){
55687 this.config[colIndex].locked = value;
55688 if(!suppressEvent){
55689 this.fireEvent("columnlockchange", this, colIndex, value);
55693 getTotalLockedWidth : function(){
55694 var totalWidth = 0;
55695 for(var i = 0; i < this.config.length; i++){
55696 if(this.isLocked(i) && !this.isHidden(i)){
55697 this.totalWidth += this.getColumnWidth(i);
55703 getLockedCount : function(){
55704 for(var i = 0, len = this.config.length; i < len; i++){
55705 if(!this.isLocked(i)){
55710 return this.config.length;
55714 * Returns the number of columns.
55717 getColumnCount : function(visibleOnly){
55718 if(visibleOnly === true){
55720 for(var i = 0, len = this.config.length; i < len; i++){
55721 if(!this.isHidden(i)){
55727 return this.config.length;
55731 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
55732 * @param {Function} fn
55733 * @param {Object} scope (optional)
55734 * @return {Array} result
55736 getColumnsBy : function(fn, scope){
55738 for(var i = 0, len = this.config.length; i < len; i++){
55739 var c = this.config[i];
55740 if(fn.call(scope||this, c, i) === true){
55748 * Returns true if the specified column is sortable.
55749 * @param {Number} col The column index
55750 * @return {Boolean}
55752 isSortable : function(col){
55753 if(typeof this.config[col].sortable == "undefined"){
55754 return this.defaultSortable;
55756 return this.config[col].sortable;
55760 * Returns the rendering (formatting) function defined for the column.
55761 * @param {Number} col The column index.
55762 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
55764 getRenderer : function(col){
55765 if(!this.config[col].renderer){
55766 return Roo.grid.ColumnModel.defaultRenderer;
55768 return this.config[col].renderer;
55772 * Sets the rendering (formatting) function for a column.
55773 * @param {Number} col The column index
55774 * @param {Function} fn The function to use to process the cell's raw data
55775 * to return HTML markup for the grid view. The render function is called with
55776 * the following parameters:<ul>
55777 * <li>Data value.</li>
55778 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
55779 * <li>css A CSS style string to apply to the table cell.</li>
55780 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
55781 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
55782 * <li>Row index</li>
55783 * <li>Column index</li>
55784 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
55786 setRenderer : function(col, fn){
55787 this.config[col].renderer = fn;
55791 * Returns the width for the specified column.
55792 * @param {Number} col The column index
55795 getColumnWidth : function(col){
55796 return this.config[col].width * 1 || this.defaultWidth;
55800 * Sets the width for a column.
55801 * @param {Number} col The column index
55802 * @param {Number} width The new width
55804 setColumnWidth : function(col, width, suppressEvent){
55805 this.config[col].width = width;
55806 this.totalWidth = null;
55807 if(!suppressEvent){
55808 this.fireEvent("widthchange", this, col, width);
55813 * Returns the total width of all columns.
55814 * @param {Boolean} includeHidden True to include hidden column widths
55817 getTotalWidth : function(includeHidden){
55818 if(!this.totalWidth){
55819 this.totalWidth = 0;
55820 for(var i = 0, len = this.config.length; i < len; i++){
55821 if(includeHidden || !this.isHidden(i)){
55822 this.totalWidth += this.getColumnWidth(i);
55826 return this.totalWidth;
55830 * Returns the header for the specified column.
55831 * @param {Number} col The column index
55834 getColumnHeader : function(col){
55835 return this.config[col].header;
55839 * Sets the header for a column.
55840 * @param {Number} col The column index
55841 * @param {String} header The new header
55843 setColumnHeader : function(col, header){
55844 this.config[col].header = header;
55845 this.fireEvent("headerchange", this, col, header);
55849 * Returns the tooltip for the specified column.
55850 * @param {Number} col The column index
55853 getColumnTooltip : function(col){
55854 return this.config[col].tooltip;
55857 * Sets the tooltip for a column.
55858 * @param {Number} col The column index
55859 * @param {String} tooltip The new tooltip
55861 setColumnTooltip : function(col, tooltip){
55862 this.config[col].tooltip = tooltip;
55866 * Returns the dataIndex for the specified column.
55867 * @param {Number} col The column index
55870 getDataIndex : function(col){
55871 return this.config[col].dataIndex;
55875 * Sets the dataIndex for a column.
55876 * @param {Number} col The column index
55877 * @param {Number} dataIndex The new dataIndex
55879 setDataIndex : function(col, dataIndex){
55880 this.config[col].dataIndex = dataIndex;
55886 * Returns true if the cell is editable.
55887 * @param {Number} colIndex The column index
55888 * @param {Number} rowIndex The row index - this is nto actually used..?
55889 * @return {Boolean}
55891 isCellEditable : function(colIndex, rowIndex){
55892 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55896 * Returns the editor defined for the cell/column.
55897 * return false or null to disable editing.
55898 * @param {Number} colIndex The column index
55899 * @param {Number} rowIndex The row index
55902 getCellEditor : function(colIndex, rowIndex){
55903 return this.config[colIndex].editor;
55907 * Sets if a column is editable.
55908 * @param {Number} col The column index
55909 * @param {Boolean} editable True if the column is editable
55911 setEditable : function(col, editable){
55912 this.config[col].editable = editable;
55917 * Returns true if the column is hidden.
55918 * @param {Number} colIndex The column index
55919 * @return {Boolean}
55921 isHidden : function(colIndex){
55922 return this.config[colIndex].hidden;
55927 * Returns true if the column width cannot be changed
55929 isFixed : function(colIndex){
55930 return this.config[colIndex].fixed;
55934 * Returns true if the column can be resized
55935 * @return {Boolean}
55937 isResizable : function(colIndex){
55938 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55941 * Sets if a column is hidden.
55942 * @param {Number} colIndex The column index
55943 * @param {Boolean} hidden True if the column is hidden
55945 setHidden : function(colIndex, hidden){
55946 this.config[colIndex].hidden = hidden;
55947 this.totalWidth = null;
55948 this.fireEvent("hiddenchange", this, colIndex, hidden);
55952 * Sets the editor for a column.
55953 * @param {Number} col The column index
55954 * @param {Object} editor The editor object
55956 setEditor : function(col, editor){
55957 this.config[col].editor = editor;
55961 Roo.grid.ColumnModel.defaultRenderer = function(value){
55962 if(typeof value == "string" && value.length < 1){
55968 // Alias for backwards compatibility
55969 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55972 * Ext JS Library 1.1.1
55973 * Copyright(c) 2006-2007, Ext JS, LLC.
55975 * Originally Released Under LGPL - original licence link has changed is not relivant.
55978 * <script type="text/javascript">
55982 * @class Roo.grid.AbstractSelectionModel
55983 * @extends Roo.util.Observable
55984 * Abstract base class for grid SelectionModels. It provides the interface that should be
55985 * implemented by descendant classes. This class should not be directly instantiated.
55988 Roo.grid.AbstractSelectionModel = function(){
55989 this.locked = false;
55990 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55993 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55994 /** @ignore Called by the grid automatically. Do not call directly. */
55995 init : function(grid){
56001 * Locks the selections.
56004 this.locked = true;
56008 * Unlocks the selections.
56010 unlock : function(){
56011 this.locked = false;
56015 * Returns true if the selections are locked.
56016 * @return {Boolean}
56018 isLocked : function(){
56019 return this.locked;
56023 * Ext JS Library 1.1.1
56024 * Copyright(c) 2006-2007, Ext JS, LLC.
56026 * Originally Released Under LGPL - original licence link has changed is not relivant.
56029 * <script type="text/javascript">
56032 * @extends Roo.grid.AbstractSelectionModel
56033 * @class Roo.grid.RowSelectionModel
56034 * The default SelectionModel used by {@link Roo.grid.Grid}.
56035 * It supports multiple selections and keyboard selection/navigation.
56037 * @param {Object} config
56039 Roo.grid.RowSelectionModel = function(config){
56040 Roo.apply(this, config);
56041 this.selections = new Roo.util.MixedCollection(false, function(o){
56046 this.lastActive = false;
56050 * @event selectionchange
56051 * Fires when the selection changes
56052 * @param {SelectionModel} this
56054 "selectionchange" : true,
56056 * @event afterselectionchange
56057 * Fires after the selection changes (eg. by key press or clicking)
56058 * @param {SelectionModel} this
56060 "afterselectionchange" : true,
56062 * @event beforerowselect
56063 * Fires when a row is selected being selected, return false to cancel.
56064 * @param {SelectionModel} this
56065 * @param {Number} rowIndex The selected index
56066 * @param {Boolean} keepExisting False if other selections will be cleared
56068 "beforerowselect" : true,
56071 * Fires when a row is selected.
56072 * @param {SelectionModel} this
56073 * @param {Number} rowIndex The selected index
56074 * @param {Roo.data.Record} r The record
56076 "rowselect" : true,
56078 * @event rowdeselect
56079 * Fires when a row is deselected.
56080 * @param {SelectionModel} this
56081 * @param {Number} rowIndex The selected index
56083 "rowdeselect" : true
56085 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
56086 this.locked = false;
56089 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
56091 * @cfg {Boolean} singleSelect
56092 * True to allow selection of only one row at a time (defaults to false)
56094 singleSelect : false,
56097 initEvents : function(){
56099 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
56100 this.grid.on("mousedown", this.handleMouseDown, this);
56101 }else{ // allow click to work like normal
56102 this.grid.on("rowclick", this.handleDragableRowClick, this);
56105 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
56106 "up" : function(e){
56108 this.selectPrevious(e.shiftKey);
56109 }else if(this.last !== false && this.lastActive !== false){
56110 var last = this.last;
56111 this.selectRange(this.last, this.lastActive-1);
56112 this.grid.getView().focusRow(this.lastActive);
56113 if(last !== false){
56117 this.selectFirstRow();
56119 this.fireEvent("afterselectionchange", this);
56121 "down" : function(e){
56123 this.selectNext(e.shiftKey);
56124 }else if(this.last !== false && this.lastActive !== false){
56125 var last = this.last;
56126 this.selectRange(this.last, this.lastActive+1);
56127 this.grid.getView().focusRow(this.lastActive);
56128 if(last !== false){
56132 this.selectFirstRow();
56134 this.fireEvent("afterselectionchange", this);
56139 var view = this.grid.view;
56140 view.on("refresh", this.onRefresh, this);
56141 view.on("rowupdated", this.onRowUpdated, this);
56142 view.on("rowremoved", this.onRemove, this);
56146 onRefresh : function(){
56147 var ds = this.grid.dataSource, i, v = this.grid.view;
56148 var s = this.selections;
56149 s.each(function(r){
56150 if((i = ds.indexOfId(r.id)) != -1){
56152 s.add(ds.getAt(i)); // updating the selection relate data
56160 onRemove : function(v, index, r){
56161 this.selections.remove(r);
56165 onRowUpdated : function(v, index, r){
56166 if(this.isSelected(r)){
56167 v.onRowSelect(index);
56173 * @param {Array} records The records to select
56174 * @param {Boolean} keepExisting (optional) True to keep existing selections
56176 selectRecords : function(records, keepExisting){
56178 this.clearSelections();
56180 var ds = this.grid.dataSource;
56181 for(var i = 0, len = records.length; i < len; i++){
56182 this.selectRow(ds.indexOf(records[i]), true);
56187 * Gets the number of selected rows.
56190 getCount : function(){
56191 return this.selections.length;
56195 * Selects the first row in the grid.
56197 selectFirstRow : function(){
56202 * Select the last row.
56203 * @param {Boolean} keepExisting (optional) True to keep existing selections
56205 selectLastRow : function(keepExisting){
56206 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
56210 * Selects the row immediately following the last selected row.
56211 * @param {Boolean} keepExisting (optional) True to keep existing selections
56213 selectNext : function(keepExisting){
56214 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
56215 this.selectRow(this.last+1, keepExisting);
56216 this.grid.getView().focusRow(this.last);
56221 * Selects the row that precedes the last selected row.
56222 * @param {Boolean} keepExisting (optional) True to keep existing selections
56224 selectPrevious : function(keepExisting){
56226 this.selectRow(this.last-1, keepExisting);
56227 this.grid.getView().focusRow(this.last);
56232 * Returns the selected records
56233 * @return {Array} Array of selected records
56235 getSelections : function(){
56236 return [].concat(this.selections.items);
56240 * Returns the first selected record.
56243 getSelected : function(){
56244 return this.selections.itemAt(0);
56249 * Clears all selections.
56251 clearSelections : function(fast){
56256 var ds = this.grid.dataSource;
56257 var s = this.selections;
56258 s.each(function(r){
56259 this.deselectRow(ds.indexOfId(r.id));
56263 this.selections.clear();
56270 * Selects all rows.
56272 selectAll : function(){
56276 this.selections.clear();
56277 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
56278 this.selectRow(i, true);
56283 * Returns True if there is a selection.
56284 * @return {Boolean}
56286 hasSelection : function(){
56287 return this.selections.length > 0;
56291 * Returns True if the specified row is selected.
56292 * @param {Number/Record} record The record or index of the record to check
56293 * @return {Boolean}
56295 isSelected : function(index){
56296 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
56297 return (r && this.selections.key(r.id) ? true : false);
56301 * Returns True if the specified record id is selected.
56302 * @param {String} id The id of record to check
56303 * @return {Boolean}
56305 isIdSelected : function(id){
56306 return (this.selections.key(id) ? true : false);
56310 handleMouseDown : function(e, t){
56311 var view = this.grid.getView(), rowIndex;
56312 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
56315 if(e.shiftKey && this.last !== false){
56316 var last = this.last;
56317 this.selectRange(last, rowIndex, e.ctrlKey);
56318 this.last = last; // reset the last
56319 view.focusRow(rowIndex);
56321 var isSelected = this.isSelected(rowIndex);
56322 if(e.button !== 0 && isSelected){
56323 view.focusRow(rowIndex);
56324 }else if(e.ctrlKey && isSelected){
56325 this.deselectRow(rowIndex);
56326 }else if(!isSelected){
56327 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
56328 view.focusRow(rowIndex);
56331 this.fireEvent("afterselectionchange", this);
56334 handleDragableRowClick : function(grid, rowIndex, e)
56336 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
56337 this.selectRow(rowIndex, false);
56338 grid.view.focusRow(rowIndex);
56339 this.fireEvent("afterselectionchange", this);
56344 * Selects multiple rows.
56345 * @param {Array} rows Array of the indexes of the row to select
56346 * @param {Boolean} keepExisting (optional) True to keep existing selections
56348 selectRows : function(rows, keepExisting){
56350 this.clearSelections();
56352 for(var i = 0, len = rows.length; i < len; i++){
56353 this.selectRow(rows[i], true);
56358 * Selects a range of rows. All rows in between startRow and endRow are also selected.
56359 * @param {Number} startRow The index of the first row in the range
56360 * @param {Number} endRow The index of the last row in the range
56361 * @param {Boolean} keepExisting (optional) True to retain existing selections
56363 selectRange : function(startRow, endRow, keepExisting){
56368 this.clearSelections();
56370 if(startRow <= endRow){
56371 for(var i = startRow; i <= endRow; i++){
56372 this.selectRow(i, true);
56375 for(var i = startRow; i >= endRow; i--){
56376 this.selectRow(i, true);
56382 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
56383 * @param {Number} startRow The index of the first row in the range
56384 * @param {Number} endRow The index of the last row in the range
56386 deselectRange : function(startRow, endRow, preventViewNotify){
56390 for(var i = startRow; i <= endRow; i++){
56391 this.deselectRow(i, preventViewNotify);
56397 * @param {Number} row The index of the row to select
56398 * @param {Boolean} keepExisting (optional) True to keep existing selections
56400 selectRow : function(index, keepExisting, preventViewNotify){
56401 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
56404 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
56405 if(!keepExisting || this.singleSelect){
56406 this.clearSelections();
56408 var r = this.grid.dataSource.getAt(index);
56409 this.selections.add(r);
56410 this.last = this.lastActive = index;
56411 if(!preventViewNotify){
56412 this.grid.getView().onRowSelect(index);
56414 this.fireEvent("rowselect", this, index, r);
56415 this.fireEvent("selectionchange", this);
56421 * @param {Number} row The index of the row to deselect
56423 deselectRow : function(index, preventViewNotify){
56427 if(this.last == index){
56430 if(this.lastActive == index){
56431 this.lastActive = false;
56433 var r = this.grid.dataSource.getAt(index);
56434 this.selections.remove(r);
56435 if(!preventViewNotify){
56436 this.grid.getView().onRowDeselect(index);
56438 this.fireEvent("rowdeselect", this, index);
56439 this.fireEvent("selectionchange", this);
56443 restoreLast : function(){
56445 this.last = this._last;
56450 acceptsNav : function(row, col, cm){
56451 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56455 onEditorKey : function(field, e){
56456 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
56461 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56463 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56465 }else if(k == e.ENTER && !e.ctrlKey){
56469 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
56471 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
56473 }else if(k == e.ESC){
56477 g.startEditing(newCell[0], newCell[1]);
56482 * Ext JS Library 1.1.1
56483 * Copyright(c) 2006-2007, Ext JS, LLC.
56485 * Originally Released Under LGPL - original licence link has changed is not relivant.
56488 * <script type="text/javascript">
56491 * @class Roo.grid.CellSelectionModel
56492 * @extends Roo.grid.AbstractSelectionModel
56493 * This class provides the basic implementation for cell selection in a grid.
56495 * @param {Object} config The object containing the configuration of this model.
56496 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
56498 Roo.grid.CellSelectionModel = function(config){
56499 Roo.apply(this, config);
56501 this.selection = null;
56505 * @event beforerowselect
56506 * Fires before a cell is selected.
56507 * @param {SelectionModel} this
56508 * @param {Number} rowIndex The selected row index
56509 * @param {Number} colIndex The selected cell index
56511 "beforecellselect" : true,
56513 * @event cellselect
56514 * Fires when a cell is selected.
56515 * @param {SelectionModel} this
56516 * @param {Number} rowIndex The selected row index
56517 * @param {Number} colIndex The selected cell index
56519 "cellselect" : true,
56521 * @event selectionchange
56522 * Fires when the active selection changes.
56523 * @param {SelectionModel} this
56524 * @param {Object} selection null for no selection or an object (o) with two properties
56526 <li>o.record: the record object for the row the selection is in</li>
56527 <li>o.cell: An array of [rowIndex, columnIndex]</li>
56530 "selectionchange" : true,
56533 * Fires when the tab (or enter) was pressed on the last editable cell
56534 * You can use this to trigger add new row.
56535 * @param {SelectionModel} this
56539 * @event beforeeditnext
56540 * Fires before the next editable sell is made active
56541 * You can use this to skip to another cell or fire the tabend
56542 * if you set cell to false
56543 * @param {Object} eventdata object : { cell : [ row, col ] }
56545 "beforeeditnext" : true
56547 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
56550 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
56552 enter_is_tab: false,
56555 initEvents : function(){
56556 this.grid.on("mousedown", this.handleMouseDown, this);
56557 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
56558 var view = this.grid.view;
56559 view.on("refresh", this.onViewChange, this);
56560 view.on("rowupdated", this.onRowUpdated, this);
56561 view.on("beforerowremoved", this.clearSelections, this);
56562 view.on("beforerowsinserted", this.clearSelections, this);
56563 if(this.grid.isEditor){
56564 this.grid.on("beforeedit", this.beforeEdit, this);
56569 beforeEdit : function(e){
56570 this.select(e.row, e.column, false, true, e.record);
56574 onRowUpdated : function(v, index, r){
56575 if(this.selection && this.selection.record == r){
56576 v.onCellSelect(index, this.selection.cell[1]);
56581 onViewChange : function(){
56582 this.clearSelections(true);
56586 * Returns the currently selected cell,.
56587 * @return {Array} The selected cell (row, column) or null if none selected.
56589 getSelectedCell : function(){
56590 return this.selection ? this.selection.cell : null;
56594 * Clears all selections.
56595 * @param {Boolean} true to prevent the gridview from being notified about the change.
56597 clearSelections : function(preventNotify){
56598 var s = this.selection;
56600 if(preventNotify !== true){
56601 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
56603 this.selection = null;
56604 this.fireEvent("selectionchange", this, null);
56609 * Returns true if there is a selection.
56610 * @return {Boolean}
56612 hasSelection : function(){
56613 return this.selection ? true : false;
56617 handleMouseDown : function(e, t){
56618 var v = this.grid.getView();
56619 if(this.isLocked()){
56622 var row = v.findRowIndex(t);
56623 var cell = v.findCellIndex(t);
56624 if(row !== false && cell !== false){
56625 this.select(row, cell);
56631 * @param {Number} rowIndex
56632 * @param {Number} collIndex
56634 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
56635 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
56636 this.clearSelections();
56637 r = r || this.grid.dataSource.getAt(rowIndex);
56640 cell : [rowIndex, colIndex]
56642 if(!preventViewNotify){
56643 var v = this.grid.getView();
56644 v.onCellSelect(rowIndex, colIndex);
56645 if(preventFocus !== true){
56646 v.focusCell(rowIndex, colIndex);
56649 this.fireEvent("cellselect", this, rowIndex, colIndex);
56650 this.fireEvent("selectionchange", this, this.selection);
56655 isSelectable : function(rowIndex, colIndex, cm){
56656 return !cm.isHidden(colIndex);
56660 handleKeyDown : function(e){
56661 //Roo.log('Cell Sel Model handleKeyDown');
56662 if(!e.isNavKeyPress()){
56665 var g = this.grid, s = this.selection;
56668 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
56670 this.select(cell[0], cell[1]);
56675 var walk = function(row, col, step){
56676 return g.walkCells(row, col, step, sm.isSelectable, sm);
56678 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
56685 // handled by onEditorKey
56686 if (g.isEditor && g.editing) {
56690 newCell = walk(r, c-1, -1);
56692 newCell = walk(r, c+1, 1);
56697 newCell = walk(r+1, c, 1);
56701 newCell = walk(r-1, c, -1);
56705 newCell = walk(r, c+1, 1);
56709 newCell = walk(r, c-1, -1);
56714 if(g.isEditor && !g.editing){
56715 g.startEditing(r, c);
56724 this.select(newCell[0], newCell[1]);
56730 acceptsNav : function(row, col, cm){
56731 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56735 * @param {Number} field (not used) - as it's normally used as a listener
56736 * @param {Number} e - event - fake it by using
56738 * var e = Roo.EventObjectImpl.prototype;
56739 * e.keyCode = e.TAB
56743 onEditorKey : function(field, e){
56745 var k = e.getKey(),
56748 ed = g.activeEditor,
56750 ///Roo.log('onEditorKey' + k);
56753 if (this.enter_is_tab && k == e.ENTER) {
56759 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56761 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56767 } else if(k == e.ENTER && !e.ctrlKey){
56770 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56772 } else if(k == e.ESC){
56777 var ecall = { cell : newCell, forward : forward };
56778 this.fireEvent('beforeeditnext', ecall );
56779 newCell = ecall.cell;
56780 forward = ecall.forward;
56784 //Roo.log('next cell after edit');
56785 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
56786 } else if (forward) {
56787 // tabbed past last
56788 this.fireEvent.defer(100, this, ['tabend',this]);
56793 * Ext JS Library 1.1.1
56794 * Copyright(c) 2006-2007, Ext JS, LLC.
56796 * Originally Released Under LGPL - original licence link has changed is not relivant.
56799 * <script type="text/javascript">
56803 * @class Roo.grid.EditorGrid
56804 * @extends Roo.grid.Grid
56805 * Class for creating and editable grid.
56806 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56807 * The container MUST have some type of size defined for the grid to fill. The container will be
56808 * automatically set to position relative if it isn't already.
56809 * @param {Object} dataSource The data model to bind to
56810 * @param {Object} colModel The column model with info about this grid's columns
56812 Roo.grid.EditorGrid = function(container, config){
56813 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
56814 this.getGridEl().addClass("xedit-grid");
56816 if(!this.selModel){
56817 this.selModel = new Roo.grid.CellSelectionModel();
56820 this.activeEditor = null;
56824 * @event beforeedit
56825 * Fires before cell editing is triggered. The edit event object has the following properties <br />
56826 * <ul style="padding:5px;padding-left:16px;">
56827 * <li>grid - This grid</li>
56828 * <li>record - The record being edited</li>
56829 * <li>field - The field name being edited</li>
56830 * <li>value - The value for the field being edited.</li>
56831 * <li>row - The grid row index</li>
56832 * <li>column - The grid column index</li>
56833 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56835 * @param {Object} e An edit event (see above for description)
56837 "beforeedit" : true,
56840 * Fires after a cell is edited. <br />
56841 * <ul style="padding:5px;padding-left:16px;">
56842 * <li>grid - This grid</li>
56843 * <li>record - The record being edited</li>
56844 * <li>field - The field name being edited</li>
56845 * <li>value - The value being set</li>
56846 * <li>originalValue - The original value for the field, before the edit.</li>
56847 * <li>row - The grid row index</li>
56848 * <li>column - The grid column index</li>
56850 * @param {Object} e An edit event (see above for description)
56852 "afteredit" : true,
56854 * @event validateedit
56855 * Fires after a cell is edited, but before the value is set in the record.
56856 * You can use this to modify the value being set in the field, Return false
56857 * to cancel the change. The edit event object has the following properties <br />
56858 * <ul style="padding:5px;padding-left:16px;">
56859 * <li>editor - This editor</li>
56860 * <li>grid - This grid</li>
56861 * <li>record - The record being edited</li>
56862 * <li>field - The field name being edited</li>
56863 * <li>value - The value being set</li>
56864 * <li>originalValue - The original value for the field, before the edit.</li>
56865 * <li>row - The grid row index</li>
56866 * <li>column - The grid column index</li>
56867 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56869 * @param {Object} e An edit event (see above for description)
56871 "validateedit" : true
56873 this.on("bodyscroll", this.stopEditing, this);
56874 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56877 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56879 * @cfg {Number} clicksToEdit
56880 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56887 trackMouseOver: false, // causes very odd FF errors
56889 onCellDblClick : function(g, row, col){
56890 this.startEditing(row, col);
56893 onEditComplete : function(ed, value, startValue){
56894 this.editing = false;
56895 this.activeEditor = null;
56896 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56898 var field = this.colModel.getDataIndex(ed.col);
56903 originalValue: startValue,
56910 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
56913 if(String(value) !== String(startValue)){
56915 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56916 r.set(field, e.value);
56917 // if we are dealing with a combo box..
56918 // then we also set the 'name' colum to be the displayField
56919 if (ed.field.displayField && ed.field.name) {
56920 r.set(ed.field.name, ed.field.el.dom.value);
56923 delete e.cancel; //?? why!!!
56924 this.fireEvent("afteredit", e);
56927 this.fireEvent("afteredit", e); // always fire it!
56929 this.view.focusCell(ed.row, ed.col);
56933 * Starts editing the specified for the specified row/column
56934 * @param {Number} rowIndex
56935 * @param {Number} colIndex
56937 startEditing : function(row, col){
56938 this.stopEditing();
56939 if(this.colModel.isCellEditable(col, row)){
56940 this.view.ensureVisible(row, col, true);
56942 var r = this.dataSource.getAt(row);
56943 var field = this.colModel.getDataIndex(col);
56944 var cell = Roo.get(this.view.getCell(row,col));
56949 value: r.data[field],
56954 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56955 this.editing = true;
56956 var ed = this.colModel.getCellEditor(col, row);
56962 ed.render(ed.parentEl || document.body);
56968 (function(){ // complex but required for focus issues in safari, ie and opera
56972 ed.on("complete", this.onEditComplete, this, {single: true});
56973 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56974 this.activeEditor = ed;
56975 var v = r.data[field];
56976 ed.startEdit(this.view.getCell(row, col), v);
56977 // combo's with 'displayField and name set
56978 if (ed.field.displayField && ed.field.name) {
56979 ed.field.el.dom.value = r.data[ed.field.name];
56983 }).defer(50, this);
56989 * Stops any active editing
56991 stopEditing : function(){
56992 if(this.activeEditor){
56993 this.activeEditor.completeEdit();
56995 this.activeEditor = null;
56999 * Called to get grid's drag proxy text, by default returns this.ddText.
57002 getDragDropText : function(){
57003 var count = this.selModel.getSelectedCell() ? 1 : 0;
57004 return String.format(this.ddText, count, count == 1 ? '' : 's');
57009 * Ext JS Library 1.1.1
57010 * Copyright(c) 2006-2007, Ext JS, LLC.
57012 * Originally Released Under LGPL - original licence link has changed is not relivant.
57015 * <script type="text/javascript">
57018 // private - not really -- you end up using it !
57019 // This is a support class used internally by the Grid components
57022 * @class Roo.grid.GridEditor
57023 * @extends Roo.Editor
57024 * Class for creating and editable grid elements.
57025 * @param {Object} config any settings (must include field)
57027 Roo.grid.GridEditor = function(field, config){
57028 if (!config && field.field) {
57030 field = Roo.factory(config.field, Roo.form);
57032 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
57033 field.monitorTab = false;
57036 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
57039 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
57042 alignment: "tl-tl",
57045 cls: "x-small-editor x-grid-editor",
57050 * Ext JS Library 1.1.1
57051 * Copyright(c) 2006-2007, Ext JS, LLC.
57053 * Originally Released Under LGPL - original licence link has changed is not relivant.
57056 * <script type="text/javascript">
57061 Roo.grid.PropertyRecord = Roo.data.Record.create([
57062 {name:'name',type:'string'}, 'value'
57066 Roo.grid.PropertyStore = function(grid, source){
57068 this.store = new Roo.data.Store({
57069 recordType : Roo.grid.PropertyRecord
57071 this.store.on('update', this.onUpdate, this);
57073 this.setSource(source);
57075 Roo.grid.PropertyStore.superclass.constructor.call(this);
57080 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
57081 setSource : function(o){
57083 this.store.removeAll();
57086 if(this.isEditableValue(o[k])){
57087 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
57090 this.store.loadRecords({records: data}, {}, true);
57093 onUpdate : function(ds, record, type){
57094 if(type == Roo.data.Record.EDIT){
57095 var v = record.data['value'];
57096 var oldValue = record.modified['value'];
57097 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
57098 this.source[record.id] = v;
57100 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
57107 getProperty : function(row){
57108 return this.store.getAt(row);
57111 isEditableValue: function(val){
57112 if(val && val instanceof Date){
57114 }else if(typeof val == 'object' || typeof val == 'function'){
57120 setValue : function(prop, value){
57121 this.source[prop] = value;
57122 this.store.getById(prop).set('value', value);
57125 getSource : function(){
57126 return this.source;
57130 Roo.grid.PropertyColumnModel = function(grid, store){
57133 g.PropertyColumnModel.superclass.constructor.call(this, [
57134 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
57135 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
57137 this.store = store;
57138 this.bselect = Roo.DomHelper.append(document.body, {
57139 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
57140 {tag: 'option', value: 'true', html: 'true'},
57141 {tag: 'option', value: 'false', html: 'false'}
57144 Roo.id(this.bselect);
57147 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
57148 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
57149 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
57150 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
57151 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
57153 this.renderCellDelegate = this.renderCell.createDelegate(this);
57154 this.renderPropDelegate = this.renderProp.createDelegate(this);
57157 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
57161 valueText : 'Value',
57163 dateFormat : 'm/j/Y',
57166 renderDate : function(dateVal){
57167 return dateVal.dateFormat(this.dateFormat);
57170 renderBool : function(bVal){
57171 return bVal ? 'true' : 'false';
57174 isCellEditable : function(colIndex, rowIndex){
57175 return colIndex == 1;
57178 getRenderer : function(col){
57180 this.renderCellDelegate : this.renderPropDelegate;
57183 renderProp : function(v){
57184 return this.getPropertyName(v);
57187 renderCell : function(val){
57189 if(val instanceof Date){
57190 rv = this.renderDate(val);
57191 }else if(typeof val == 'boolean'){
57192 rv = this.renderBool(val);
57194 return Roo.util.Format.htmlEncode(rv);
57197 getPropertyName : function(name){
57198 var pn = this.grid.propertyNames;
57199 return pn && pn[name] ? pn[name] : name;
57202 getCellEditor : function(colIndex, rowIndex){
57203 var p = this.store.getProperty(rowIndex);
57204 var n = p.data['name'], val = p.data['value'];
57206 if(typeof(this.grid.customEditors[n]) == 'string'){
57207 return this.editors[this.grid.customEditors[n]];
57209 if(typeof(this.grid.customEditors[n]) != 'undefined'){
57210 return this.grid.customEditors[n];
57212 if(val instanceof Date){
57213 return this.editors['date'];
57214 }else if(typeof val == 'number'){
57215 return this.editors['number'];
57216 }else if(typeof val == 'boolean'){
57217 return this.editors['boolean'];
57219 return this.editors['string'];
57225 * @class Roo.grid.PropertyGrid
57226 * @extends Roo.grid.EditorGrid
57227 * This class represents the interface of a component based property grid control.
57228 * <br><br>Usage:<pre><code>
57229 var grid = new Roo.grid.PropertyGrid("my-container-id", {
57237 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57238 * The container MUST have some type of size defined for the grid to fill. The container will be
57239 * automatically set to position relative if it isn't already.
57240 * @param {Object} config A config object that sets properties on this grid.
57242 Roo.grid.PropertyGrid = function(container, config){
57243 config = config || {};
57244 var store = new Roo.grid.PropertyStore(this);
57245 this.store = store;
57246 var cm = new Roo.grid.PropertyColumnModel(this, store);
57247 store.store.sort('name', 'ASC');
57248 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
57251 enableColLock:false,
57252 enableColumnMove:false,
57254 trackMouseOver: false,
57257 this.getGridEl().addClass('x-props-grid');
57258 this.lastEditRow = null;
57259 this.on('columnresize', this.onColumnResize, this);
57262 * @event beforepropertychange
57263 * Fires before a property changes (return false to stop?)
57264 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57265 * @param {String} id Record Id
57266 * @param {String} newval New Value
57267 * @param {String} oldval Old Value
57269 "beforepropertychange": true,
57271 * @event propertychange
57272 * Fires after a property changes
57273 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57274 * @param {String} id Record Id
57275 * @param {String} newval New Value
57276 * @param {String} oldval Old Value
57278 "propertychange": true
57280 this.customEditors = this.customEditors || {};
57282 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
57285 * @cfg {Object} customEditors map of colnames=> custom editors.
57286 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
57287 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
57288 * false disables editing of the field.
57292 * @cfg {Object} propertyNames map of property Names to their displayed value
57295 render : function(){
57296 Roo.grid.PropertyGrid.superclass.render.call(this);
57297 this.autoSize.defer(100, this);
57300 autoSize : function(){
57301 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
57303 this.view.fitColumns();
57307 onColumnResize : function(){
57308 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
57312 * Sets the data for the Grid
57313 * accepts a Key => Value object of all the elements avaiable.
57314 * @param {Object} data to appear in grid.
57316 setSource : function(source){
57317 this.store.setSource(source);
57321 * Gets all the data from the grid.
57322 * @return {Object} data data stored in grid
57324 getSource : function(){
57325 return this.store.getSource();
57334 * @class Roo.grid.Calendar
57335 * @extends Roo.util.Grid
57336 * This class extends the Grid to provide a calendar widget
57337 * <br><br>Usage:<pre><code>
57338 var grid = new Roo.grid.Calendar("my-container-id", {
57341 selModel: mySelectionModel,
57342 autoSizeColumns: true,
57343 monitorWindowResize: false,
57344 trackMouseOver: true
57345 eventstore : real data store..
57351 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57352 * The container MUST have some type of size defined for the grid to fill. The container will be
57353 * automatically set to position relative if it isn't already.
57354 * @param {Object} config A config object that sets properties on this grid.
57356 Roo.grid.Calendar = function(container, config){
57357 // initialize the container
57358 this.container = Roo.get(container);
57359 this.container.update("");
57360 this.container.setStyle("overflow", "hidden");
57361 this.container.addClass('x-grid-container');
57363 this.id = this.container.id;
57365 Roo.apply(this, config);
57366 // check and correct shorthanded configs
57370 for (var r = 0;r < 6;r++) {
57373 for (var c =0;c < 7;c++) {
57377 if (this.eventStore) {
57378 this.eventStore= Roo.factory(this.eventStore, Roo.data);
57379 this.eventStore.on('load',this.onLoad, this);
57380 this.eventStore.on('beforeload',this.clearEvents, this);
57384 this.dataSource = new Roo.data.Store({
57385 proxy: new Roo.data.MemoryProxy(rows),
57386 reader: new Roo.data.ArrayReader({}, [
57387 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
57390 this.dataSource.load();
57391 this.ds = this.dataSource;
57392 this.ds.xmodule = this.xmodule || false;
57395 var cellRender = function(v,x,r)
57397 return String.format(
57398 '<div class="fc-day fc-widget-content"><div>' +
57399 '<div class="fc-event-container"></div>' +
57400 '<div class="fc-day-number">{0}</div>'+
57402 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
57403 '</div></div>', v);
57408 this.colModel = new Roo.grid.ColumnModel( [
57410 xtype: 'ColumnModel',
57412 dataIndex : 'weekday0',
57414 renderer : cellRender
57417 xtype: 'ColumnModel',
57419 dataIndex : 'weekday1',
57421 renderer : cellRender
57424 xtype: 'ColumnModel',
57426 dataIndex : 'weekday2',
57427 header : 'Tuesday',
57428 renderer : cellRender
57431 xtype: 'ColumnModel',
57433 dataIndex : 'weekday3',
57434 header : 'Wednesday',
57435 renderer : cellRender
57438 xtype: 'ColumnModel',
57440 dataIndex : 'weekday4',
57441 header : 'Thursday',
57442 renderer : cellRender
57445 xtype: 'ColumnModel',
57447 dataIndex : 'weekday5',
57449 renderer : cellRender
57452 xtype: 'ColumnModel',
57454 dataIndex : 'weekday6',
57455 header : 'Saturday',
57456 renderer : cellRender
57459 this.cm = this.colModel;
57460 this.cm.xmodule = this.xmodule || false;
57464 //this.selModel = new Roo.grid.CellSelectionModel();
57465 //this.sm = this.selModel;
57466 //this.selModel.init(this);
57470 this.container.setWidth(this.width);
57474 this.container.setHeight(this.height);
57481 * The raw click event for the entire grid.
57482 * @param {Roo.EventObject} e
57487 * The raw dblclick event for the entire grid.
57488 * @param {Roo.EventObject} e
57492 * @event contextmenu
57493 * The raw contextmenu event for the entire grid.
57494 * @param {Roo.EventObject} e
57496 "contextmenu" : true,
57499 * The raw mousedown event for the entire grid.
57500 * @param {Roo.EventObject} e
57502 "mousedown" : true,
57505 * The raw mouseup event for the entire grid.
57506 * @param {Roo.EventObject} e
57511 * The raw mouseover event for the entire grid.
57512 * @param {Roo.EventObject} e
57514 "mouseover" : true,
57517 * The raw mouseout event for the entire grid.
57518 * @param {Roo.EventObject} e
57523 * The raw keypress event for the entire grid.
57524 * @param {Roo.EventObject} e
57529 * The raw keydown event for the entire grid.
57530 * @param {Roo.EventObject} e
57538 * Fires when a cell is clicked
57539 * @param {Grid} this
57540 * @param {Number} rowIndex
57541 * @param {Number} columnIndex
57542 * @param {Roo.EventObject} e
57544 "cellclick" : true,
57546 * @event celldblclick
57547 * Fires when a cell is double clicked
57548 * @param {Grid} this
57549 * @param {Number} rowIndex
57550 * @param {Number} columnIndex
57551 * @param {Roo.EventObject} e
57553 "celldblclick" : true,
57556 * Fires when a row is clicked
57557 * @param {Grid} this
57558 * @param {Number} rowIndex
57559 * @param {Roo.EventObject} e
57563 * @event rowdblclick
57564 * Fires when a row is double clicked
57565 * @param {Grid} this
57566 * @param {Number} rowIndex
57567 * @param {Roo.EventObject} e
57569 "rowdblclick" : true,
57571 * @event headerclick
57572 * Fires when a header is clicked
57573 * @param {Grid} this
57574 * @param {Number} columnIndex
57575 * @param {Roo.EventObject} e
57577 "headerclick" : true,
57579 * @event headerdblclick
57580 * Fires when a header cell is double clicked
57581 * @param {Grid} this
57582 * @param {Number} columnIndex
57583 * @param {Roo.EventObject} e
57585 "headerdblclick" : true,
57587 * @event rowcontextmenu
57588 * Fires when a row is right clicked
57589 * @param {Grid} this
57590 * @param {Number} rowIndex
57591 * @param {Roo.EventObject} e
57593 "rowcontextmenu" : true,
57595 * @event cellcontextmenu
57596 * Fires when a cell is right clicked
57597 * @param {Grid} this
57598 * @param {Number} rowIndex
57599 * @param {Number} cellIndex
57600 * @param {Roo.EventObject} e
57602 "cellcontextmenu" : true,
57604 * @event headercontextmenu
57605 * Fires when a header is right clicked
57606 * @param {Grid} this
57607 * @param {Number} columnIndex
57608 * @param {Roo.EventObject} e
57610 "headercontextmenu" : true,
57612 * @event bodyscroll
57613 * Fires when the body element is scrolled
57614 * @param {Number} scrollLeft
57615 * @param {Number} scrollTop
57617 "bodyscroll" : true,
57619 * @event columnresize
57620 * Fires when the user resizes a column
57621 * @param {Number} columnIndex
57622 * @param {Number} newSize
57624 "columnresize" : true,
57626 * @event columnmove
57627 * Fires when the user moves a column
57628 * @param {Number} oldIndex
57629 * @param {Number} newIndex
57631 "columnmove" : true,
57634 * Fires when row(s) start being dragged
57635 * @param {Grid} this
57636 * @param {Roo.GridDD} dd The drag drop object
57637 * @param {event} e The raw browser event
57639 "startdrag" : true,
57642 * Fires when a drag operation is complete
57643 * @param {Grid} this
57644 * @param {Roo.GridDD} dd The drag drop object
57645 * @param {event} e The raw browser event
57650 * Fires when dragged row(s) are dropped on a valid DD target
57651 * @param {Grid} this
57652 * @param {Roo.GridDD} dd The drag drop object
57653 * @param {String} targetId The target drag drop object
57654 * @param {event} e The raw browser event
57659 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
57660 * @param {Grid} this
57661 * @param {Roo.GridDD} dd The drag drop object
57662 * @param {String} targetId The target drag drop object
57663 * @param {event} e The raw browser event
57668 * Fires when the dragged row(s) first cross another DD target while being dragged
57669 * @param {Grid} this
57670 * @param {Roo.GridDD} dd The drag drop object
57671 * @param {String} targetId The target drag drop object
57672 * @param {event} e The raw browser event
57674 "dragenter" : true,
57677 * Fires when the dragged row(s) leave another DD target while being dragged
57678 * @param {Grid} this
57679 * @param {Roo.GridDD} dd The drag drop object
57680 * @param {String} targetId The target drag drop object
57681 * @param {event} e The raw browser event
57686 * Fires when a row is rendered, so you can change add a style to it.
57687 * @param {GridView} gridview The grid view
57688 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
57694 * Fires when the grid is rendered
57695 * @param {Grid} grid
57700 * Fires when a date is selected
57701 * @param {DatePicker} this
57702 * @param {Date} date The selected date
57706 * @event monthchange
57707 * Fires when the displayed month changes
57708 * @param {DatePicker} this
57709 * @param {Date} date The selected month
57711 'monthchange': true,
57713 * @event evententer
57714 * Fires when mouse over an event
57715 * @param {Calendar} this
57716 * @param {event} Event
57718 'evententer': true,
57720 * @event eventleave
57721 * Fires when the mouse leaves an
57722 * @param {Calendar} this
57725 'eventleave': true,
57727 * @event eventclick
57728 * Fires when the mouse click an
57729 * @param {Calendar} this
57732 'eventclick': true,
57734 * @event eventrender
57735 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
57736 * @param {Calendar} this
57737 * @param {data} data to be modified
57739 'eventrender': true
57743 Roo.grid.Grid.superclass.constructor.call(this);
57744 this.on('render', function() {
57745 this.view.el.addClass('x-grid-cal');
57747 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
57751 if (!Roo.grid.Calendar.style) {
57752 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
57755 '.x-grid-cal .x-grid-col' : {
57756 height: 'auto !important',
57757 'vertical-align': 'top'
57759 '.x-grid-cal .fc-event-hori' : {
57770 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
57772 * @cfg {Store} eventStore The store that loads events.
57777 activeDate : false,
57780 monitorWindowResize : false,
57783 resizeColumns : function() {
57784 var col = (this.view.el.getWidth() / 7) - 3;
57785 // loop through cols, and setWidth
57786 for(var i =0 ; i < 7 ; i++){
57787 this.cm.setColumnWidth(i, col);
57790 setDate :function(date) {
57792 Roo.log('setDate?');
57794 this.resizeColumns();
57795 var vd = this.activeDate;
57796 this.activeDate = date;
57797 // if(vd && this.el){
57798 // var t = date.getTime();
57799 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
57800 // Roo.log('using add remove');
57802 // this.fireEvent('monthchange', this, date);
57804 // this.cells.removeClass("fc-state-highlight");
57805 // this.cells.each(function(c){
57806 // if(c.dateValue == t){
57807 // c.addClass("fc-state-highlight");
57808 // setTimeout(function(){
57809 // try{c.dom.firstChild.focus();}catch(e){}
57819 var days = date.getDaysInMonth();
57821 var firstOfMonth = date.getFirstDateOfMonth();
57822 var startingPos = firstOfMonth.getDay()-this.startDay;
57824 if(startingPos < this.startDay){
57828 var pm = date.add(Date.MONTH, -1);
57829 var prevStart = pm.getDaysInMonth()-startingPos;
57833 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57835 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57836 //this.cells.addClassOnOver('fc-state-hover');
57838 var cells = this.cells.elements;
57839 var textEls = this.textNodes;
57841 //Roo.each(cells, function(cell){
57842 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57845 days += startingPos;
57847 // convert everything to numbers so it's fast
57848 var day = 86400000;
57849 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57852 //Roo.log(prevStart);
57854 var today = new Date().clearTime().getTime();
57855 var sel = date.clearTime().getTime();
57856 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57857 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57858 var ddMatch = this.disabledDatesRE;
57859 var ddText = this.disabledDatesText;
57860 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57861 var ddaysText = this.disabledDaysText;
57862 var format = this.format;
57864 var setCellClass = function(cal, cell){
57866 //Roo.log('set Cell Class');
57868 var t = d.getTime();
57873 cell.dateValue = t;
57875 cell.className += " fc-today";
57876 cell.className += " fc-state-highlight";
57877 cell.title = cal.todayText;
57880 // disable highlight in other month..
57881 cell.className += " fc-state-highlight";
57886 //cell.className = " fc-state-disabled";
57887 cell.title = cal.minText;
57891 //cell.className = " fc-state-disabled";
57892 cell.title = cal.maxText;
57896 if(ddays.indexOf(d.getDay()) != -1){
57897 // cell.title = ddaysText;
57898 // cell.className = " fc-state-disabled";
57901 if(ddMatch && format){
57902 var fvalue = d.dateFormat(format);
57903 if(ddMatch.test(fvalue)){
57904 cell.title = ddText.replace("%0", fvalue);
57905 cell.className = " fc-state-disabled";
57909 if (!cell.initialClassName) {
57910 cell.initialClassName = cell.dom.className;
57913 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57918 for(; i < startingPos; i++) {
57919 cells[i].dayName = (++prevStart);
57920 Roo.log(textEls[i]);
57921 d.setDate(d.getDate()+1);
57923 //cells[i].className = "fc-past fc-other-month";
57924 setCellClass(this, cells[i]);
57929 for(; i < days; i++){
57930 intDay = i - startingPos + 1;
57931 cells[i].dayName = (intDay);
57932 d.setDate(d.getDate()+1);
57934 cells[i].className = ''; // "x-date-active";
57935 setCellClass(this, cells[i]);
57939 for(; i < 42; i++) {
57940 //textEls[i].innerHTML = (++extraDays);
57942 d.setDate(d.getDate()+1);
57943 cells[i].dayName = (++extraDays);
57944 cells[i].className = "fc-future fc-other-month";
57945 setCellClass(this, cells[i]);
57948 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57950 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57952 // this will cause all the cells to mis
57955 for (var r = 0;r < 6;r++) {
57956 for (var c =0;c < 7;c++) {
57957 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57961 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57962 for(i=0;i<cells.length;i++) {
57964 this.cells.elements[i].dayName = cells[i].dayName ;
57965 this.cells.elements[i].className = cells[i].className;
57966 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57967 this.cells.elements[i].title = cells[i].title ;
57968 this.cells.elements[i].dateValue = cells[i].dateValue ;
57974 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57975 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57977 ////if(totalRows != 6){
57978 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57979 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57982 this.fireEvent('monthchange', this, date);
57987 * Returns the grid's SelectionModel.
57988 * @return {SelectionModel}
57990 getSelectionModel : function(){
57991 if(!this.selModel){
57992 this.selModel = new Roo.grid.CellSelectionModel();
57994 return this.selModel;
57998 this.eventStore.load()
58004 findCell : function(dt) {
58005 dt = dt.clearTime().getTime();
58007 this.cells.each(function(c){
58008 //Roo.log("check " +c.dateValue + '?=' + dt);
58009 if(c.dateValue == dt){
58019 findCells : function(rec) {
58020 var s = rec.data.start_dt.clone().clearTime().getTime();
58022 var e= rec.data.end_dt.clone().clearTime().getTime();
58025 this.cells.each(function(c){
58026 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
58028 if(c.dateValue > e){
58031 if(c.dateValue < s){
58040 findBestRow: function(cells)
58044 for (var i =0 ; i < cells.length;i++) {
58045 ret = Math.max(cells[i].rows || 0,ret);
58052 addItem : function(rec)
58054 // look for vertical location slot in
58055 var cells = this.findCells(rec);
58057 rec.row = this.findBestRow(cells);
58059 // work out the location.
58063 for(var i =0; i < cells.length; i++) {
58071 if (crow.start.getY() == cells[i].getY()) {
58073 crow.end = cells[i];
58089 for (var i = 0; i < cells.length;i++) {
58090 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
58097 clearEvents: function() {
58099 if (!this.eventStore.getCount()) {
58102 // reset number of rows in cells.
58103 Roo.each(this.cells.elements, function(c){
58107 this.eventStore.each(function(e) {
58108 this.clearEvent(e);
58113 clearEvent : function(ev)
58116 Roo.each(ev.els, function(el) {
58117 el.un('mouseenter' ,this.onEventEnter, this);
58118 el.un('mouseleave' ,this.onEventLeave, this);
58126 renderEvent : function(ev,ctr) {
58128 ctr = this.view.el.select('.fc-event-container',true).first();
58132 this.clearEvent(ev);
58138 var cells = ev.cells;
58139 var rows = ev.rows;
58140 this.fireEvent('eventrender', this, ev);
58142 for(var i =0; i < rows.length; i++) {
58146 cls += ' fc-event-start';
58148 if ((i+1) == rows.length) {
58149 cls += ' fc-event-end';
58152 //Roo.log(ev.data);
58153 // how many rows should it span..
58154 var cg = this.eventTmpl.append(ctr,Roo.apply({
58157 }, ev.data) , true);
58160 cg.on('mouseenter' ,this.onEventEnter, this, ev);
58161 cg.on('mouseleave' ,this.onEventLeave, this, ev);
58162 cg.on('click', this.onEventClick, this, ev);
58166 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
58167 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
58170 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
58171 cg.setWidth(ebox.right - sbox.x -2);
58175 renderEvents: function()
58177 // first make sure there is enough space..
58179 if (!this.eventTmpl) {
58180 this.eventTmpl = new Roo.Template(
58181 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
58182 '<div class="fc-event-inner">' +
58183 '<span class="fc-event-time">{time}</span>' +
58184 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
58186 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
58194 this.cells.each(function(c) {
58195 //Roo.log(c.select('.fc-day-content div',true).first());
58196 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
58199 var ctr = this.view.el.select('.fc-event-container',true).first();
58202 this.eventStore.each(function(ev){
58204 this.renderEvent(ev);
58208 this.view.layout();
58212 onEventEnter: function (e, el,event,d) {
58213 this.fireEvent('evententer', this, el, event);
58216 onEventLeave: function (e, el,event,d) {
58217 this.fireEvent('eventleave', this, el, event);
58220 onEventClick: function (e, el,event,d) {
58221 this.fireEvent('eventclick', this, el, event);
58224 onMonthChange: function () {
58228 onLoad: function () {
58230 //Roo.log('calendar onload');
58232 if(this.eventStore.getCount() > 0){
58236 this.eventStore.each(function(d){
58241 if (typeof(add.end_dt) == 'undefined') {
58242 Roo.log("Missing End time in calendar data: ");
58246 if (typeof(add.start_dt) == 'undefined') {
58247 Roo.log("Missing Start time in calendar data: ");
58251 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
58252 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
58253 add.id = add.id || d.id;
58254 add.title = add.title || '??';
58262 this.renderEvents();
58272 render : function ()
58276 if (!this.view.el.hasClass('course-timesheet')) {
58277 this.view.el.addClass('course-timesheet');
58279 if (this.tsStyle) {
58284 Roo.log(_this.grid.view.el.getWidth());
58287 this.tsStyle = Roo.util.CSS.createStyleSheet({
58288 '.course-timesheet .x-grid-row' : {
58291 '.x-grid-row td' : {
58292 'vertical-align' : 0
58294 '.course-edit-link' : {
58296 'text-overflow' : 'ellipsis',
58297 'overflow' : 'hidden',
58298 'white-space' : 'nowrap',
58299 'cursor' : 'pointer'
58304 '.de-act-sup-link' : {
58305 'color' : 'purple',
58306 'text-decoration' : 'line-through'
58310 'text-decoration' : 'line-through'
58312 '.course-timesheet .course-highlight' : {
58313 'border-top-style': 'dashed !important',
58314 'border-bottom-bottom': 'dashed !important'
58316 '.course-timesheet .course-item' : {
58317 'font-family' : 'tahoma, arial, helvetica',
58318 'font-size' : '11px',
58319 'overflow' : 'hidden',
58320 'padding-left' : '10px',
58321 'padding-right' : '10px',
58322 'padding-top' : '10px'
58330 monitorWindowResize : false,
58331 cellrenderer : function(v,x,r)
58336 xtype: 'CellSelectionModel',
58343 beforeload : function (_self, options)
58345 options.params = options.params || {};
58346 options.params._month = _this.monthField.getValue();
58347 options.params.limit = 9999;
58348 options.params['sort'] = 'when_dt';
58349 options.params['dir'] = 'ASC';
58350 this.proxy.loadResponse = this.loadResponse;
58352 //this.addColumns();
58354 load : function (_self, records, options)
58356 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
58357 // if you click on the translation.. you can edit it...
58358 var el = Roo.get(this);
58359 var id = el.dom.getAttribute('data-id');
58360 var d = el.dom.getAttribute('data-date');
58361 var t = el.dom.getAttribute('data-time');
58362 //var id = this.child('span').dom.textContent;
58365 Pman.Dialog.CourseCalendar.show({
58369 productitem_active : id ? 1 : 0
58371 _this.grid.ds.load({});
58376 _this.panel.fireEvent('resize', [ '', '' ]);
58379 loadResponse : function(o, success, response){
58380 // this is overridden on before load..
58382 Roo.log("our code?");
58383 //Roo.log(success);
58384 //Roo.log(response)
58385 delete this.activeRequest;
58387 this.fireEvent("loadexception", this, o, response);
58388 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58393 result = o.reader.read(response);
58395 Roo.log("load exception?");
58396 this.fireEvent("loadexception", this, o, response, e);
58397 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58400 Roo.log("ready...");
58401 // loop through result.records;
58402 // and set this.tdate[date] = [] << array of records..
58404 Roo.each(result.records, function(r){
58406 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
58407 _this.tdata[r.data.when_dt.format('j')] = [];
58409 _this.tdata[r.data.when_dt.format('j')].push(r.data);
58412 //Roo.log(_this.tdata);
58414 result.records = [];
58415 result.totalRecords = 6;
58417 // let's generate some duumy records for the rows.
58418 //var st = _this.dateField.getValue();
58420 // work out monday..
58421 //st = st.add(Date.DAY, -1 * st.format('w'));
58423 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58425 var firstOfMonth = date.getFirstDayOfMonth();
58426 var days = date.getDaysInMonth();
58428 var firstAdded = false;
58429 for (var i = 0; i < result.totalRecords ; i++) {
58430 //var d= st.add(Date.DAY, i);
58433 for(var w = 0 ; w < 7 ; w++){
58434 if(!firstAdded && firstOfMonth != w){
58441 var dd = (d > 0 && d < 10) ? "0"+d : d;
58442 row['weekday'+w] = String.format(
58443 '<span style="font-size: 16px;"><b>{0}</b></span>'+
58444 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
58446 date.format('Y-m-')+dd
58449 if(typeof(_this.tdata[d]) != 'undefined'){
58450 Roo.each(_this.tdata[d], function(r){
58454 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
58455 if(r.parent_id*1>0){
58456 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
58459 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
58460 deactive = 'de-act-link';
58463 row['weekday'+w] += String.format(
58464 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
58466 r.product_id_name, //1
58467 r.when_dt.format('h:ia'), //2
58477 // only do this if something added..
58479 result.records.push(_this.grid.dataSource.reader.newRow(row));
58483 // push it twice. (second one with an hour..
58487 this.fireEvent("load", this, o, o.request.arg);
58488 o.request.callback.call(o.request.scope, result, o.request.arg, true);
58490 sortInfo : {field: 'when_dt', direction : 'ASC' },
58492 xtype: 'HttpProxy',
58495 url : baseURL + '/Roo/Shop_course.php'
58498 xtype: 'JsonReader',
58515 'name': 'parent_id',
58519 'name': 'product_id',
58523 'name': 'productitem_id',
58541 click : function (_self, e)
58543 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58544 sd.setMonth(sd.getMonth()-1);
58545 _this.monthField.setValue(sd.format('Y-m-d'));
58546 _this.grid.ds.load({});
58552 xtype: 'Separator',
58556 xtype: 'MonthField',
58559 render : function (_self)
58561 _this.monthField = _self;
58562 // _this.monthField.set today
58564 select : function (combo, date)
58566 _this.grid.ds.load({});
58569 value : (function() { return new Date(); })()
58572 xtype: 'Separator',
58578 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
58588 click : function (_self, e)
58590 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58591 sd.setMonth(sd.getMonth()+1);
58592 _this.monthField.setValue(sd.format('Y-m-d'));
58593 _this.grid.ds.load({});
58606 * Ext JS Library 1.1.1
58607 * Copyright(c) 2006-2007, Ext JS, LLC.
58609 * Originally Released Under LGPL - original licence link has changed is not relivant.
58612 * <script type="text/javascript">
58616 * @class Roo.LoadMask
58617 * A simple utility class for generically masking elements while loading data. If the element being masked has
58618 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
58619 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
58620 * element's UpdateManager load indicator and will be destroyed after the initial load.
58622 * Create a new LoadMask
58623 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
58624 * @param {Object} config The config object
58626 Roo.LoadMask = function(el, config){
58627 this.el = Roo.get(el);
58628 Roo.apply(this, config);
58630 this.store.on('beforeload', this.onBeforeLoad, this);
58631 this.store.on('load', this.onLoad, this);
58632 this.store.on('loadexception', this.onLoadException, this);
58633 this.removeMask = false;
58635 var um = this.el.getUpdateManager();
58636 um.showLoadIndicator = false; // disable the default indicator
58637 um.on('beforeupdate', this.onBeforeLoad, this);
58638 um.on('update', this.onLoad, this);
58639 um.on('failure', this.onLoad, this);
58640 this.removeMask = true;
58644 Roo.LoadMask.prototype = {
58646 * @cfg {Boolean} removeMask
58647 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
58648 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
58651 * @cfg {String} msg
58652 * The text to display in a centered loading message box (defaults to 'Loading...')
58654 msg : 'Loading...',
58656 * @cfg {String} msgCls
58657 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
58659 msgCls : 'x-mask-loading',
58662 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
58668 * Disables the mask to prevent it from being displayed
58670 disable : function(){
58671 this.disabled = true;
58675 * Enables the mask so that it can be displayed
58677 enable : function(){
58678 this.disabled = false;
58681 onLoadException : function()
58683 Roo.log(arguments);
58685 if (typeof(arguments[3]) != 'undefined') {
58686 Roo.MessageBox.alert("Error loading",arguments[3]);
58690 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
58691 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
58700 this.el.unmask(this.removeMask);
58703 onLoad : function()
58705 this.el.unmask(this.removeMask);
58709 onBeforeLoad : function(){
58710 if(!this.disabled){
58711 this.el.mask(this.msg, this.msgCls);
58716 destroy : function(){
58718 this.store.un('beforeload', this.onBeforeLoad, this);
58719 this.store.un('load', this.onLoad, this);
58720 this.store.un('loadexception', this.onLoadException, this);
58722 var um = this.el.getUpdateManager();
58723 um.un('beforeupdate', this.onBeforeLoad, this);
58724 um.un('update', this.onLoad, this);
58725 um.un('failure', this.onLoad, this);
58730 * Ext JS Library 1.1.1
58731 * Copyright(c) 2006-2007, Ext JS, LLC.
58733 * Originally Released Under LGPL - original licence link has changed is not relivant.
58736 * <script type="text/javascript">
58741 * @class Roo.XTemplate
58742 * @extends Roo.Template
58743 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
58745 var t = new Roo.XTemplate(
58746 '<select name="{name}">',
58747 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
58751 // then append, applying the master template values
58754 * Supported features:
58759 {a_variable} - output encoded.
58760 {a_variable.format:("Y-m-d")} - call a method on the variable
58761 {a_variable:raw} - unencoded output
58762 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
58763 {a_variable:this.method_on_template(...)} - call a method on the template object.
58768 <tpl for="a_variable or condition.."></tpl>
58769 <tpl if="a_variable or condition"></tpl>
58770 <tpl exec="some javascript"></tpl>
58771 <tpl name="named_template"></tpl> (experimental)
58773 <tpl for="."></tpl> - just iterate the property..
58774 <tpl for=".."></tpl> - iterates with the parent (probably the template)
58778 Roo.XTemplate = function()
58780 Roo.XTemplate.superclass.constructor.apply(this, arguments);
58787 Roo.extend(Roo.XTemplate, Roo.Template, {
58790 * The various sub templates
58795 * basic tag replacing syntax
58798 * // you can fake an object call by doing this
58802 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
58805 * compile the template
58807 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
58810 compile: function()
58814 s = ['<tpl>', s, '</tpl>'].join('');
58816 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
58817 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
58818 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
58819 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
58820 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
58825 while(true == !!(m = s.match(re))){
58826 var forMatch = m[0].match(nameRe),
58827 ifMatch = m[0].match(ifRe),
58828 execMatch = m[0].match(execRe),
58829 namedMatch = m[0].match(namedRe),
58834 name = forMatch && forMatch[1] ? forMatch[1] : '';
58837 // if - puts fn into test..
58838 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58840 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58845 // exec - calls a function... returns empty if true is returned.
58846 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58848 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58856 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58857 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58858 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58861 var uid = namedMatch ? namedMatch[1] : id;
58865 id: namedMatch ? namedMatch[1] : id,
58872 s = s.replace(m[0], '');
58874 s = s.replace(m[0], '{xtpl'+ id + '}');
58879 for(var i = tpls.length-1; i >= 0; --i){
58880 this.compileTpl(tpls[i]);
58881 this.tpls[tpls[i].id] = tpls[i];
58883 this.master = tpls[tpls.length-1];
58887 * same as applyTemplate, except it's done to one of the subTemplates
58888 * when using named templates, you can do:
58890 * var str = pl.applySubTemplate('your-name', values);
58893 * @param {Number} id of the template
58894 * @param {Object} values to apply to template
58895 * @param {Object} parent (normaly the instance of this object)
58897 applySubTemplate : function(id, values, parent)
58901 var t = this.tpls[id];
58905 if(t.test && !t.test.call(this, values, parent)){
58909 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58910 Roo.log(e.toString());
58916 if(t.exec && t.exec.call(this, values, parent)){
58920 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58921 Roo.log(e.toString());
58926 var vs = t.target ? t.target.call(this, values, parent) : values;
58927 parent = t.target ? values : parent;
58928 if(t.target && vs instanceof Array){
58930 for(var i = 0, len = vs.length; i < len; i++){
58931 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58933 return buf.join('');
58935 return t.compiled.call(this, vs, parent);
58937 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58938 Roo.log(e.toString());
58939 Roo.log(t.compiled);
58944 compileTpl : function(tpl)
58946 var fm = Roo.util.Format;
58947 var useF = this.disableFormats !== true;
58948 var sep = Roo.isGecko ? "+" : ",";
58949 var undef = function(str) {
58950 Roo.log("Property not found :" + str);
58954 var fn = function(m, name, format, args)
58956 //Roo.log(arguments);
58957 args = args ? args.replace(/\\'/g,"'") : args;
58958 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58959 if (typeof(format) == 'undefined') {
58960 format= 'htmlEncode';
58962 if (format == 'raw' ) {
58966 if(name.substr(0, 4) == 'xtpl'){
58967 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58970 // build an array of options to determine if value is undefined..
58972 // basically get 'xxxx.yyyy' then do
58973 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58974 // (function () { Roo.log("Property not found"); return ''; })() :
58979 Roo.each(name.split('.'), function(st) {
58980 lookfor += (lookfor.length ? '.': '') + st;
58981 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58984 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58987 if(format && useF){
58989 args = args ? ',' + args : "";
58991 if(format.substr(0, 5) != "this."){
58992 format = "fm." + format + '(';
58994 format = 'this.call("'+ format.substr(5) + '", ';
58998 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
59002 // called with xxyx.yuu:(test,test)
59004 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
59006 // raw.. - :raw modifier..
59007 return "'"+ sep + udef_st + name + ")"+sep+"'";
59011 // branched to use + in gecko and [].join() in others
59013 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
59014 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
59017 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
59018 body.push(tpl.body.replace(/(\r\n|\n)/g,
59019 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
59020 body.push("'].join('');};};");
59021 body = body.join('');
59024 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
59026 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
59032 applyTemplate : function(values){
59033 return this.master.compiled.call(this, values, {});
59034 //var s = this.subs;
59037 apply : function(){
59038 return this.applyTemplate.apply(this, arguments);
59043 Roo.XTemplate.from = function(el){
59044 el = Roo.getDom(el);
59045 return new Roo.XTemplate(el.value || el.innerHTML);