4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isGecko = !isSafari && ua.indexOf("gecko") > -1,
61 isBorderBox = isIE && !isStrict,
62 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64 isLinux = (ua.indexOf("linux") != -1),
65 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66 isIOS = /iphone|ipad/.test(ua),
67 isTouch = (function() {
69 document.createEvent("TouchEvent");
76 // remove css image flicker
79 document.execCommand("BackgroundImageCache", false, true);
85 * True if the browser is in strict mode
90 * True if the page is running over SSL
95 * True when the document is fully initialized and ready for action
100 * Turn on debugging output (currently only the factory uses this)
107 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
110 enableGarbageCollector : true,
113 * True to automatically purge event listeners after uncaching an element (defaults to false).
114 * Note: this only happens if enableGarbageCollector is true.
117 enableListenerCollection:false,
120 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
121 * the IE insecure content warning (defaults to javascript:false).
124 SSL_SECURE_URL : "javascript:false",
127 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
128 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
131 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
133 emptyFn : function(){},
136 * Copies all the properties of config to obj if they don't already exist.
137 * @param {Object} obj The receiver of the properties
138 * @param {Object} config The source of the properties
139 * @return {Object} returns obj
141 applyIf : function(o, c){
144 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
151 * Applies event listeners to elements by selectors when the document is ready.
152 * The event name is specified with an @ suffix.
155 // add a listener for click on all anchors in element with id foo
156 '#foo a@click' : function(e, t){
160 // add the same listener to multiple selectors (separated by comma BEFORE the @)
161 '#foo a, #bar span.some-class@mouseover' : function(){
166 * @param {Object} obj The list of behaviors to apply
168 addBehaviors : function(o){
170 Roo.onReady(function(){
175 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
177 var parts = b.split('@');
178 if(parts[1]){ // for Object prototype breakers
181 cache[s] = Roo.select(s);
183 cache[s].on(parts[1], o[b]);
190 * Generates unique ids. If the element already has an id, it is unchanged
191 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
192 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
193 * @return {String} The generated Id.
195 id : function(el, prefix){
196 prefix = prefix || "roo-gen";
198 var id = prefix + (++idSeed);
199 return el ? (el.id ? el.id : (el.id = id)) : id;
204 * Extends one class with another class and optionally overrides members with the passed literal. This class
205 * also adds the function "override()" to the class that can be used to override
206 * members on an instance.
207 * @param {Object} subclass The class inheriting the functionality
208 * @param {Object} superclass The class being extended
209 * @param {Object} overrides (optional) A literal with members
214 var io = function(o){
219 return function(sb, sp, overrides){
220 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
223 sb = function(){sp.apply(this, arguments);};
225 var F = function(){}, sbp, spp = sp.prototype;
227 sbp = sb.prototype = new F();
231 if(spp.constructor == Object.prototype.constructor){
236 sb.override = function(o){
240 Roo.override(sb, overrides);
246 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
248 Roo.override(MyClass, {
249 newMethod1: function(){
252 newMethod2: function(foo){
257 * @param {Object} origclass The class to override
258 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
259 * containing one or more methods.
262 override : function(origclass, overrides){
264 var p = origclass.prototype;
265 for(var method in overrides){
266 p[method] = overrides[method];
271 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
273 Roo.namespace('Company', 'Company.data');
274 Company.Widget = function() { ... }
275 Company.data.CustomStore = function(config) { ... }
277 * @param {String} namespace1
278 * @param {String} namespace2
279 * @param {String} etc
282 namespace : function(){
283 var a=arguments, o=null, i, j, d, rt;
284 for (i=0; i<a.length; ++i) {
288 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
289 for (j=1; j<d.length; ++j) {
290 o[d[j]]=o[d[j]] || {};
296 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
298 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
299 Roo.factory(conf, Roo.data);
301 * @param {String} classname
302 * @param {String} namespace (optional)
306 factory : function(c, ns)
308 // no xtype, no ns or c.xns - or forced off by c.xns
309 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
312 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
313 if (c.constructor == ns[c.xtype]) {// already created...
317 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
318 var ret = new ns[c.xtype](c);
322 c.xns = false; // prevent recursion..
326 * Logs to console if it can.
328 * @param {String|Object} string
333 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
340 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
344 urlEncode : function(o){
350 var ov = o[key], k = Roo.encodeURIComponent(key);
351 var type = typeof ov;
352 if(type == 'undefined'){
354 }else if(type != "function" && type != "object"){
355 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
356 }else if(ov instanceof Array){
358 for(var i = 0, len = ov.length; i < len; i++) {
359 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
370 * Safe version of encodeURIComponent
371 * @param {String} data
375 encodeURIComponent : function (data)
378 return encodeURIComponent(data);
379 } catch(e) {} // should be an uri encode error.
381 if (data == '' || data == null){
384 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
385 function nibble_to_hex(nibble){
386 var chars = '0123456789ABCDEF';
387 return chars.charAt(nibble);
389 data = data.toString();
391 for(var i=0; i<data.length; i++){
392 var c = data.charCodeAt(i);
393 var bs = new Array();
396 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
397 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
398 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
399 bs[3] = 0x80 | (c & 0x3F);
400 }else if (c > 0x800){
402 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
403 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
404 bs[2] = 0x80 | (c & 0x3F);
407 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
408 bs[1] = 0x80 | (c & 0x3F);
413 for(var j=0; j<bs.length; j++){
415 var hex = nibble_to_hex((b & 0xF0) >>> 4)
416 + nibble_to_hex(b &0x0F);
425 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
426 * @param {String} string
427 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
428 * @return {Object} A literal with members
430 urlDecode : function(string, overwrite){
431 if(!string || !string.length){
435 var pairs = string.split('&');
436 var pair, name, value;
437 for(var i = 0, len = pairs.length; i < len; i++){
438 pair = pairs[i].split('=');
439 name = decodeURIComponent(pair[0]);
440 value = decodeURIComponent(pair[1]);
441 if(overwrite !== true){
442 if(typeof obj[name] == "undefined"){
444 }else if(typeof obj[name] == "string"){
445 obj[name] = [obj[name]];
446 obj[name].push(value);
448 obj[name].push(value);
458 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
459 * passed array is not really an array, your function is called once with it.
460 * The supplied function is called with (Object item, Number index, Array allItems).
461 * @param {Array/NodeList/Mixed} array
462 * @param {Function} fn
463 * @param {Object} scope
465 each : function(array, fn, scope){
466 if(typeof array.length == "undefined" || typeof array == "string"){
469 for(var i = 0, len = array.length; i < len; i++){
470 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
475 combine : function(){
476 var as = arguments, l = as.length, r = [];
477 for(var i = 0; i < l; i++){
479 if(a instanceof Array){
481 }else if(a.length !== undefined && !a.substr){
482 r = r.concat(Array.prototype.slice.call(a, 0));
491 * Escapes the passed string for use in a regular expression
492 * @param {String} str
495 escapeRe : function(s) {
496 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
500 callback : function(cb, scope, args, delay){
501 if(typeof cb == "function"){
503 cb.defer(delay, scope, args || []);
505 cb.apply(scope, args || []);
511 * Return the dom node for the passed string (id), dom node, or Roo.Element
512 * @param {String/HTMLElement/Roo.Element} el
513 * @return HTMLElement
515 getDom : function(el){
519 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
523 * Shorthand for {@link Roo.ComponentMgr#get}
525 * @return Roo.Component
527 getCmp : function(id){
528 return Roo.ComponentMgr.get(id);
531 num : function(v, defaultValue){
532 if(typeof v != 'number'){
538 destroy : function(){
539 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
543 as.removeAllListeners();
547 if(typeof as.purgeListeners == 'function'){
550 if(typeof as.destroy == 'function'){
557 // inpired by a similar function in mootools library
559 * Returns the type of object that is passed in. If the object passed in is null or undefined it
560 * return false otherwise it returns one of the following values:<ul>
561 * <li><b>string</b>: If the object passed is a string</li>
562 * <li><b>number</b>: If the object passed is a number</li>
563 * <li><b>boolean</b>: If the object passed is a boolean value</li>
564 * <li><b>function</b>: If the object passed is a function reference</li>
565 * <li><b>object</b>: If the object passed is an object</li>
566 * <li><b>array</b>: If the object passed is an array</li>
567 * <li><b>regexp</b>: If the object passed is a regular expression</li>
568 * <li><b>element</b>: If the object passed is a DOM Element</li>
569 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
570 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
571 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
572 * @param {Mixed} object
576 if(o === undefined || o === null){
583 if(t == 'object' && o.nodeName) {
585 case 1: return 'element';
586 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
589 if(t == 'object' || t == 'function') {
590 switch(o.constructor) {
591 case Array: return 'array';
592 case RegExp: return 'regexp';
594 if(typeof o.length == 'number' && typeof o.item == 'function') {
602 * Returns true if the passed value is null, undefined or an empty string (optional).
603 * @param {Mixed} value The value to test
604 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
607 isEmpty : function(v, allowBlank){
608 return v === null || v === undefined || (!allowBlank ? v === '' : false);
616 isFirefox : isFirefox,
626 isBorderBox : isBorderBox,
628 isWindows : isWindows,
639 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
640 * you may want to set this to true.
643 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
648 * Selects a single element as a Roo Element
649 * This is about as close as you can get to jQuery's $('do crazy stuff')
650 * @param {String} selector The selector/xpath query
651 * @param {Node} root (optional) The start of the query (defaults to document).
652 * @return {Roo.Element}
654 selectNode : function(selector, root)
656 var node = Roo.DomQuery.selectNode(selector,root);
657 return node ? Roo.get(node) : new Roo.Element(false);
665 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
666 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
669 "Roo.bootstrap.dash");
672 * Ext JS Library 1.1.1
673 * Copyright(c) 2006-2007, Ext JS, LLC.
675 * Originally Released Under LGPL - original licence link has changed is not relivant.
678 * <script type="text/javascript">
682 // wrappedn so fnCleanup is not in global scope...
684 function fnCleanUp() {
685 var p = Function.prototype;
686 delete p.createSequence;
688 delete p.createDelegate;
689 delete p.createCallback;
690 delete p.createInterceptor;
692 window.detachEvent("onunload", fnCleanUp);
694 window.attachEvent("onunload", fnCleanUp);
701 * These functions are available on every Function object (any JavaScript function).
703 Roo.apply(Function.prototype, {
705 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
706 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
707 * Will create a function that is bound to those 2 args.
708 * @return {Function} The new function
710 createCallback : function(/*args...*/){
711 // make args available, in function below
712 var args = arguments;
715 return method.apply(window, args);
720 * Creates a delegate (callback) that sets the scope to obj.
721 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
722 * Will create a function that is automatically scoped to this.
723 * @param {Object} obj (optional) The object for which the scope is set
724 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
725 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
726 * if a number the args are inserted at the specified position
727 * @return {Function} The new function
729 createDelegate : function(obj, args, appendArgs){
732 var callArgs = args || arguments;
733 if(appendArgs === true){
734 callArgs = Array.prototype.slice.call(arguments, 0);
735 callArgs = callArgs.concat(args);
736 }else if(typeof appendArgs == "number"){
737 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
738 var applyArgs = [appendArgs, 0].concat(args); // create method call params
739 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
741 return method.apply(obj || window, callArgs);
746 * Calls this function after the number of millseconds specified.
747 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
748 * @param {Object} obj (optional) The object for which the scope is set
749 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
750 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
751 * if a number the args are inserted at the specified position
752 * @return {Number} The timeout id that can be used with clearTimeout
754 defer : function(millis, obj, args, appendArgs){
755 var fn = this.createDelegate(obj, args, appendArgs);
757 return setTimeout(fn, millis);
763 * Create a combined function call sequence of the original function + the passed function.
764 * The resulting function returns the results of the original function.
765 * The passed fcn is called with the parameters of the original function
766 * @param {Function} fcn The function to sequence
767 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
768 * @return {Function} The new function
770 createSequence : function(fcn, scope){
771 if(typeof fcn != "function"){
776 var retval = method.apply(this || window, arguments);
777 fcn.apply(scope || this || window, arguments);
783 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
784 * The resulting function returns the results of the original function.
785 * The passed fcn is called with the parameters of the original function.
787 * @param {Function} fcn The function to call before the original
788 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
789 * @return {Function} The new function
791 createInterceptor : function(fcn, scope){
792 if(typeof fcn != "function"){
799 if(fcn.apply(scope || this || window, arguments) === false){
802 return method.apply(this || window, arguments);
808 * Ext JS Library 1.1.1
809 * Copyright(c) 2006-2007, Ext JS, LLC.
811 * Originally Released Under LGPL - original licence link has changed is not relivant.
814 * <script type="text/javascript">
817 Roo.applyIf(String, {
822 * Escapes the passed string for ' and \
823 * @param {String} string The string to escape
824 * @return {String} The escaped string
827 escape : function(string) {
828 return string.replace(/('|\\)/g, "\\$1");
832 * Pads the left side of a string with a specified character. This is especially useful
833 * for normalizing number and date strings. Example usage:
835 var s = String.leftPad('123', 5, '0');
836 // s now contains the string: '00123'
838 * @param {String} string The original string
839 * @param {Number} size The total length of the output string
840 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
841 * @return {String} The padded string
844 leftPad : function (val, size, ch) {
845 var result = new String(val);
846 if(ch === null || ch === undefined || ch === '') {
849 while (result.length < size) {
850 result = ch + result;
856 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
857 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
859 var cls = 'my-class', text = 'Some text';
860 var s = String.format('<div class="{0}">{1}</div>', cls, text);
861 // s now contains the string: '<div class="my-class">Some text</div>'
863 * @param {String} string The tokenized string to be formatted
864 * @param {String} value1 The value to replace token {0}
865 * @param {String} value2 Etc...
866 * @return {String} The formatted string
869 format : function(format){
870 var args = Array.prototype.slice.call(arguments, 1);
871 return format.replace(/\{(\d+)\}/g, function(m, i){
872 return Roo.util.Format.htmlEncode(args[i]);
878 * Utility function that allows you to easily switch a string between two alternating values. The passed value
879 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
880 * they are already different, the first value passed in is returned. Note that this method returns the new value
881 * but does not change the current string.
883 // alternate sort directions
884 sort = sort.toggle('ASC', 'DESC');
886 // instead of conditional logic:
887 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
889 * @param {String} value The value to compare to the current string
890 * @param {String} other The new value to use if the string already equals the first value passed in
891 * @return {String} The new value
894 String.prototype.toggle = function(value, other){
895 return this == value ? other : value;
898 * Ext JS Library 1.1.1
899 * Copyright(c) 2006-2007, Ext JS, LLC.
901 * Originally Released Under LGPL - original licence link has changed is not relivant.
904 * <script type="text/javascript">
910 Roo.applyIf(Number.prototype, {
912 * Checks whether or not the current number is within a desired range. If the number is already within the
913 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
914 * exceeded. Note that this method returns the constrained value but does not change the current number.
915 * @param {Number} min The minimum number in the range
916 * @param {Number} max The maximum number in the range
917 * @return {Number} The constrained value if outside the range, otherwise the current value
919 constrain : function(min, max){
920 return Math.min(Math.max(this, min), max);
924 * Ext JS Library 1.1.1
925 * Copyright(c) 2006-2007, Ext JS, LLC.
927 * Originally Released Under LGPL - original licence link has changed is not relivant.
930 * <script type="text/javascript">
935 Roo.applyIf(Array.prototype, {
938 * Checks whether or not the specified object exists in the array.
939 * @param {Object} o The object to check for
940 * @return {Number} The index of o in the array (or -1 if it is not found)
942 indexOf : function(o){
943 for (var i = 0, len = this.length; i < len; i++){
944 if(this[i] == o) return i;
950 * Removes the specified object from the array. If the object is not found nothing happens.
951 * @param {Object} o The object to remove
953 remove : function(o){
954 var index = this.indexOf(o);
956 this.splice(index, 1);
960 * Map (JS 1.6 compatibility)
961 * @param {Function} function to call
965 var len = this.length >>> 0;
966 if (typeof fun != "function")
967 throw new TypeError();
969 var res = new Array(len);
970 var thisp = arguments[1];
971 for (var i = 0; i < len; i++)
974 res[i] = fun.call(thisp, this[i], i, this);
985 * Ext JS Library 1.1.1
986 * Copyright(c) 2006-2007, Ext JS, LLC.
988 * Originally Released Under LGPL - original licence link has changed is not relivant.
991 * <script type="text/javascript">
997 * The date parsing and format syntax is a subset of
998 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
999 * supported will provide results equivalent to their PHP versions.
1001 * Following is the list of all currently supported formats:
1004 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1006 Format Output Description
1007 ------ ---------- --------------------------------------------------------------
1008 d 10 Day of the month, 2 digits with leading zeros
1009 D Wed A textual representation of a day, three letters
1010 j 10 Day of the month without leading zeros
1011 l Wednesday A full textual representation of the day of the week
1012 S th English ordinal day of month suffix, 2 chars (use with j)
1013 w 3 Numeric representation of the day of the week
1014 z 9 The julian date, or day of the year (0-365)
1015 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1016 F January A full textual representation of the month
1017 m 01 Numeric representation of a month, with leading zeros
1018 M Jan Month name abbreviation, three letters
1019 n 1 Numeric representation of a month, without leading zeros
1020 t 31 Number of days in the given month
1021 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1022 Y 2007 A full numeric representation of a year, 4 digits
1023 y 07 A two digit representation of a year
1024 a pm Lowercase Ante meridiem and Post meridiem
1025 A PM Uppercase Ante meridiem and Post meridiem
1026 g 3 12-hour format of an hour without leading zeros
1027 G 15 24-hour format of an hour without leading zeros
1028 h 03 12-hour format of an hour with leading zeros
1029 H 15 24-hour format of an hour with leading zeros
1030 i 05 Minutes with leading zeros
1031 s 01 Seconds, with leading zeros
1032 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1033 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1034 T CST Timezone setting of the machine running the code
1035 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1038 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1040 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1041 document.write(dt.format('Y-m-d')); //2007-01-10
1042 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1043 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1046 * Here are some standard date/time patterns that you might find helpful. They
1047 * are not part of the source of Date.js, but to use them you can simply copy this
1048 * block of code into any script that is included after Date.js and they will also become
1049 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1052 ISO8601Long:"Y-m-d H:i:s",
1053 ISO8601Short:"Y-m-d",
1055 LongDate: "l, F d, Y",
1056 FullDateTime: "l, F d, Y g:i:s A",
1059 LongTime: "g:i:s A",
1060 SortableDateTime: "Y-m-d\\TH:i:s",
1061 UniversalSortableDateTime: "Y-m-d H:i:sO",
1068 var dt = new Date();
1069 document.write(dt.format(Date.patterns.ShortDate));
1074 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1075 * They generate precompiled functions from date formats instead of parsing and
1076 * processing the pattern every time you format a date. These functions are available
1077 * on every Date object (any javascript function).
1079 * The original article and download are here:
1080 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1087 Returns the number of milliseconds between this date and date
1088 @param {Date} date (optional) Defaults to now
1089 @return {Number} The diff in milliseconds
1090 @member Date getElapsed
1092 Date.prototype.getElapsed = function(date) {
1093 return Math.abs((date || new Date()).getTime()-this.getTime());
1095 // was in date file..
1099 Date.parseFunctions = {count:0};
1101 Date.parseRegexes = [];
1103 Date.formatFunctions = {count:0};
1106 Date.prototype.dateFormat = function(format) {
1107 if (Date.formatFunctions[format] == null) {
1108 Date.createNewFormat(format);
1110 var func = Date.formatFunctions[format];
1111 return this[func]();
1116 * Formats a date given the supplied format string
1117 * @param {String} format The format string
1118 * @return {String} The formatted date
1121 Date.prototype.format = Date.prototype.dateFormat;
1124 Date.createNewFormat = function(format) {
1125 var funcName = "format" + Date.formatFunctions.count++;
1126 Date.formatFunctions[format] = funcName;
1127 var code = "Date.prototype." + funcName + " = function(){return ";
1128 var special = false;
1130 for (var i = 0; i < format.length; ++i) {
1131 ch = format.charAt(i);
1132 if (!special && ch == "\\") {
1137 code += "'" + String.escape(ch) + "' + ";
1140 code += Date.getFormatCode(ch);
1143 /** eval:var:zzzzzzzzzzzzz */
1144 eval(code.substring(0, code.length - 3) + ";}");
1148 Date.getFormatCode = function(character) {
1149 switch (character) {
1151 return "String.leftPad(this.getDate(), 2, '0') + ";
1153 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1155 return "this.getDate() + ";
1157 return "Date.dayNames[this.getDay()] + ";
1159 return "this.getSuffix() + ";
1161 return "this.getDay() + ";
1163 return "this.getDayOfYear() + ";
1165 return "this.getWeekOfYear() + ";
1167 return "Date.monthNames[this.getMonth()] + ";
1169 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1171 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1173 return "(this.getMonth() + 1) + ";
1175 return "this.getDaysInMonth() + ";
1177 return "(this.isLeapYear() ? 1 : 0) + ";
1179 return "this.getFullYear() + ";
1181 return "('' + this.getFullYear()).substring(2, 4) + ";
1183 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1185 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1187 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1189 return "this.getHours() + ";
1191 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1193 return "String.leftPad(this.getHours(), 2, '0') + ";
1195 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1197 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1199 return "this.getGMTOffset() + ";
1201 return "this.getGMTColonOffset() + ";
1203 return "this.getTimezone() + ";
1205 return "(this.getTimezoneOffset() * -60) + ";
1207 return "'" + String.escape(character) + "' + ";
1212 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1213 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1214 * the date format that is not specified will default to the current date value for that part. Time parts can also
1215 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1216 * string or the parse operation will fail.
1219 //dt = Fri May 25 2007 (current date)
1220 var dt = new Date();
1222 //dt = Thu May 25 2006 (today's month/day in 2006)
1223 dt = Date.parseDate("2006", "Y");
1225 //dt = Sun Jan 15 2006 (all date parts specified)
1226 dt = Date.parseDate("2006-1-15", "Y-m-d");
1228 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1229 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1231 * @param {String} input The unparsed date as a string
1232 * @param {String} format The format the date is in
1233 * @return {Date} The parsed date
1236 Date.parseDate = function(input, format) {
1237 if (Date.parseFunctions[format] == null) {
1238 Date.createParser(format);
1240 var func = Date.parseFunctions[format];
1241 return Date[func](input);
1247 Date.createParser = function(format) {
1248 var funcName = "parse" + Date.parseFunctions.count++;
1249 var regexNum = Date.parseRegexes.length;
1250 var currentGroup = 1;
1251 Date.parseFunctions[format] = funcName;
1253 var code = "Date." + funcName + " = function(input){\n"
1254 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1255 + "var d = new Date();\n"
1256 + "y = d.getFullYear();\n"
1257 + "m = d.getMonth();\n"
1258 + "d = d.getDate();\n"
1259 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1260 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1261 + "if (results && results.length > 0) {";
1264 var special = false;
1266 for (var i = 0; i < format.length; ++i) {
1267 ch = format.charAt(i);
1268 if (!special && ch == "\\") {
1273 regex += String.escape(ch);
1276 var obj = Date.formatCodeToRegex(ch, currentGroup);
1277 currentGroup += obj.g;
1279 if (obj.g && obj.c) {
1285 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1286 + "{v = new Date(y, m, d, h, i, s);}\n"
1287 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1288 + "{v = new Date(y, m, d, h, i);}\n"
1289 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1290 + "{v = new Date(y, m, d, h);}\n"
1291 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1292 + "{v = new Date(y, m, d);}\n"
1293 + "else if (y >= 0 && m >= 0)\n"
1294 + "{v = new Date(y, m);}\n"
1295 + "else if (y >= 0)\n"
1296 + "{v = new Date(y);}\n"
1297 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1298 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1299 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1302 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1303 /** eval:var:zzzzzzzzzzzzz */
1308 Date.formatCodeToRegex = function(character, currentGroup) {
1309 switch (character) {
1313 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1316 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1317 s:"(\\d{1,2})"}; // day of month without leading zeroes
1320 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1321 s:"(\\d{2})"}; // day of month with leading zeroes
1325 s:"(?:" + Date.dayNames.join("|") + ")"};
1329 s:"(?:st|nd|rd|th)"};
1344 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1345 s:"(" + Date.monthNames.join("|") + ")"};
1348 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1349 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1352 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1353 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1356 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1357 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1368 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1372 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1373 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1377 c:"if (results[" + currentGroup + "] == 'am') {\n"
1378 + "if (h == 12) { h = 0; }\n"
1379 + "} else { if (h < 12) { h += 12; }}",
1383 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1384 + "if (h == 12) { h = 0; }\n"
1385 + "} else { if (h < 12) { h += 12; }}",
1390 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1391 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1395 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1396 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1399 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1403 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1408 "o = results[", currentGroup, "];\n",
1409 "var sn = o.substring(0,1);\n", // get + / - sign
1410 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1411 "var mn = o.substring(3,5) % 60;\n", // get minutes
1412 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1413 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1415 s:"([+\-]\\d{2,4})"};
1421 "o = results[", currentGroup, "];\n",
1422 "var sn = o.substring(0,1);\n",
1423 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1424 "var mn = o.substring(4,6) % 60;\n",
1425 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1426 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1432 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1435 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1436 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1437 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1441 s:String.escape(character)};
1446 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1447 * @return {String} The abbreviated timezone name (e.g. 'CST')
1449 Date.prototype.getTimezone = function() {
1450 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1454 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1455 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1457 Date.prototype.getGMTOffset = function() {
1458 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1459 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1460 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1464 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1465 * @return {String} 2-characters representing hours and 2-characters representing minutes
1466 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1468 Date.prototype.getGMTColonOffset = function() {
1469 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1470 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1472 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1476 * Get the numeric day number of the year, adjusted for leap year.
1477 * @return {Number} 0 through 364 (365 in leap years)
1479 Date.prototype.getDayOfYear = function() {
1481 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1482 for (var i = 0; i < this.getMonth(); ++i) {
1483 num += Date.daysInMonth[i];
1485 return num + this.getDate() - 1;
1489 * Get the string representation of the numeric week number of the year
1490 * (equivalent to the format specifier 'W').
1491 * @return {String} '00' through '52'
1493 Date.prototype.getWeekOfYear = function() {
1494 // Skip to Thursday of this week
1495 var now = this.getDayOfYear() + (4 - this.getDay());
1496 // Find the first Thursday of the year
1497 var jan1 = new Date(this.getFullYear(), 0, 1);
1498 var then = (7 - jan1.getDay() + 4);
1499 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1503 * Whether or not the current date is in a leap year.
1504 * @return {Boolean} True if the current date is in a leap year, else false
1506 Date.prototype.isLeapYear = function() {
1507 var year = this.getFullYear();
1508 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1512 * Get the first day of the current month, adjusted for leap year. The returned value
1513 * is the numeric day index within the week (0-6) which can be used in conjunction with
1514 * the {@link #monthNames} array to retrieve the textual day name.
1517 var dt = new Date('1/10/2007');
1518 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1520 * @return {Number} The day number (0-6)
1522 Date.prototype.getFirstDayOfMonth = function() {
1523 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1524 return (day < 0) ? (day + 7) : day;
1528 * Get the last day of the current month, adjusted for leap year. The returned value
1529 * is the numeric day index within the week (0-6) which can be used in conjunction with
1530 * the {@link #monthNames} array to retrieve the textual day name.
1533 var dt = new Date('1/10/2007');
1534 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1536 * @return {Number} The day number (0-6)
1538 Date.prototype.getLastDayOfMonth = function() {
1539 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1540 return (day < 0) ? (day + 7) : day;
1545 * Get the first date of this date's month
1548 Date.prototype.getFirstDateOfMonth = function() {
1549 return new Date(this.getFullYear(), this.getMonth(), 1);
1553 * Get the last date of this date's month
1556 Date.prototype.getLastDateOfMonth = function() {
1557 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1560 * Get the number of days in the current month, adjusted for leap year.
1561 * @return {Number} The number of days in the month
1563 Date.prototype.getDaysInMonth = function() {
1564 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1565 return Date.daysInMonth[this.getMonth()];
1569 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1570 * @return {String} 'st, 'nd', 'rd' or 'th'
1572 Date.prototype.getSuffix = function() {
1573 switch (this.getDate()) {
1590 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1593 * An array of textual month names.
1594 * Override these values for international dates, for example...
1595 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1614 * An array of textual day names.
1615 * Override these values for international dates, for example...
1616 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1632 Date.monthNumbers = {
1647 * Creates and returns a new Date instance with the exact same date value as the called instance.
1648 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1649 * variable will also be changed. When the intention is to create a new variable that will not
1650 * modify the original instance, you should create a clone.
1652 * Example of correctly cloning a date:
1655 var orig = new Date('10/1/2006');
1658 document.write(orig); //returns 'Thu Oct 05 2006'!
1661 var orig = new Date('10/1/2006');
1662 var copy = orig.clone();
1664 document.write(orig); //returns 'Thu Oct 01 2006'
1666 * @return {Date} The new Date instance
1668 Date.prototype.clone = function() {
1669 return new Date(this.getTime());
1673 * Clears any time information from this date
1674 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1675 @return {Date} this or the clone
1677 Date.prototype.clearTime = function(clone){
1679 return this.clone().clearTime();
1684 this.setMilliseconds(0);
1689 // safari setMonth is broken
1691 Date.brokenSetMonth = Date.prototype.setMonth;
1692 Date.prototype.setMonth = function(num){
1694 var n = Math.ceil(-num);
1695 var back_year = Math.ceil(n/12);
1696 var month = (n % 12) ? 12 - n % 12 : 0 ;
1697 this.setFullYear(this.getFullYear() - back_year);
1698 return Date.brokenSetMonth.call(this, month);
1700 return Date.brokenSetMonth.apply(this, arguments);
1705 /** Date interval constant
1709 /** Date interval constant
1713 /** Date interval constant
1717 /** Date interval constant
1721 /** Date interval constant
1725 /** Date interval constant
1729 /** Date interval constant
1735 * Provides a convenient method of performing basic date arithmetic. This method
1736 * does not modify the Date instance being called - it creates and returns
1737 * a new Date instance containing the resulting date value.
1742 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1743 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1745 //Negative values will subtract correctly:
1746 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1747 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1749 //You can even chain several calls together in one line!
1750 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1751 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1754 * @param {String} interval A valid date interval enum value
1755 * @param {Number} value The amount to add to the current date
1756 * @return {Date} The new Date instance
1758 Date.prototype.add = function(interval, value){
1759 var d = this.clone();
1760 if (!interval || value === 0) return d;
1761 switch(interval.toLowerCase()){
1763 d.setMilliseconds(this.getMilliseconds() + value);
1766 d.setSeconds(this.getSeconds() + value);
1769 d.setMinutes(this.getMinutes() + value);
1772 d.setHours(this.getHours() + value);
1775 d.setDate(this.getDate() + value);
1778 var day = this.getDate();
1780 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1783 d.setMonth(this.getMonth() + value);
1786 d.setFullYear(this.getFullYear() + value);
1793 * Ext JS Library 1.1.1
1794 * Copyright(c) 2006-2007, Ext JS, LLC.
1796 * Originally Released Under LGPL - original licence link has changed is not relivant.
1799 * <script type="text/javascript">
1803 * @class Roo.lib.Dom
1806 * Dom utils (from YIU afaik)
1811 * Get the view width
1812 * @param {Boolean} full True will get the full document, otherwise it's the view width
1813 * @return {Number} The width
1816 getViewWidth : function(full) {
1817 return full ? this.getDocumentWidth() : this.getViewportWidth();
1820 * Get the view height
1821 * @param {Boolean} full True will get the full document, otherwise it's the view height
1822 * @return {Number} The height
1824 getViewHeight : function(full) {
1825 return full ? this.getDocumentHeight() : this.getViewportHeight();
1828 getDocumentHeight: function() {
1829 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1830 return Math.max(scrollHeight, this.getViewportHeight());
1833 getDocumentWidth: function() {
1834 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1835 return Math.max(scrollWidth, this.getViewportWidth());
1838 getViewportHeight: function() {
1839 var height = self.innerHeight;
1840 var mode = document.compatMode;
1842 if ((mode || Roo.isIE) && !Roo.isOpera) {
1843 height = (mode == "CSS1Compat") ?
1844 document.documentElement.clientHeight :
1845 document.body.clientHeight;
1851 getViewportWidth: function() {
1852 var width = self.innerWidth;
1853 var mode = document.compatMode;
1855 if (mode || Roo.isIE) {
1856 width = (mode == "CSS1Compat") ?
1857 document.documentElement.clientWidth :
1858 document.body.clientWidth;
1863 isAncestor : function(p, c) {
1870 if (p.contains && !Roo.isSafari) {
1871 return p.contains(c);
1872 } else if (p.compareDocumentPosition) {
1873 return !!(p.compareDocumentPosition(c) & 16);
1875 var parent = c.parentNode;
1880 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1883 parent = parent.parentNode;
1889 getRegion : function(el) {
1890 return Roo.lib.Region.getRegion(el);
1893 getY : function(el) {
1894 return this.getXY(el)[1];
1897 getX : function(el) {
1898 return this.getXY(el)[0];
1901 getXY : function(el) {
1902 var p, pe, b, scroll, bd = document.body;
1903 el = Roo.getDom(el);
1904 var fly = Roo.lib.AnimBase.fly;
1905 if (el.getBoundingClientRect) {
1906 b = el.getBoundingClientRect();
1907 scroll = fly(document).getScroll();
1908 return [b.left + scroll.left, b.top + scroll.top];
1914 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1921 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1928 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1929 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1936 if (p != el && pe.getStyle('overflow') != 'visible') {
1944 if (Roo.isSafari && hasAbsolute) {
1949 if (Roo.isGecko && !hasAbsolute) {
1951 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1952 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1956 while (p && p != bd) {
1957 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1969 setXY : function(el, xy) {
1970 el = Roo.fly(el, '_setXY');
1972 var pts = el.translatePoints(xy);
1973 if (xy[0] !== false) {
1974 el.dom.style.left = pts.left + "px";
1976 if (xy[1] !== false) {
1977 el.dom.style.top = pts.top + "px";
1981 setX : function(el, x) {
1982 this.setXY(el, [x, false]);
1985 setY : function(el, y) {
1986 this.setXY(el, [false, y]);
1990 * Portions of this file are based on pieces of Yahoo User Interface Library
1991 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1992 * YUI licensed under the BSD License:
1993 * http://developer.yahoo.net/yui/license.txt
1994 * <script type="text/javascript">
1998 Roo.lib.Event = function() {
1999 var loadComplete = false;
2001 var unloadListeners = [];
2003 var onAvailStack = [];
2005 var lastError = null;
2018 startInterval: function() {
2019 if (!this._interval) {
2021 var callback = function() {
2022 self._tryPreloadAttach();
2024 this._interval = setInterval(callback, this.POLL_INTERVAL);
2029 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2030 onAvailStack.push({ id: p_id,
2033 override: p_override,
2034 checkReady: false });
2036 retryCount = this.POLL_RETRYS;
2037 this.startInterval();
2041 addListener: function(el, eventName, fn) {
2042 el = Roo.getDom(el);
2047 if ("unload" == eventName) {
2048 unloadListeners[unloadListeners.length] =
2049 [el, eventName, fn];
2053 var wrappedFn = function(e) {
2054 return fn(Roo.lib.Event.getEvent(e));
2057 var li = [el, eventName, fn, wrappedFn];
2059 var index = listeners.length;
2060 listeners[index] = li;
2062 this.doAdd(el, eventName, wrappedFn, false);
2068 removeListener: function(el, eventName, fn) {
2071 el = Roo.getDom(el);
2074 return this.purgeElement(el, false, eventName);
2078 if ("unload" == eventName) {
2080 for (i = 0,len = unloadListeners.length; i < len; i++) {
2081 var li = unloadListeners[i];
2084 li[1] == eventName &&
2086 unloadListeners.splice(i, 1);
2094 var cacheItem = null;
2097 var index = arguments[3];
2099 if ("undefined" == typeof index) {
2100 index = this._getCacheIndex(el, eventName, fn);
2104 cacheItem = listeners[index];
2107 if (!el || !cacheItem) {
2111 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2113 delete listeners[index][this.WFN];
2114 delete listeners[index][this.FN];
2115 listeners.splice(index, 1);
2122 getTarget: function(ev, resolveTextNode) {
2123 ev = ev.browserEvent || ev;
2124 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2125 var t = ev.target || ev.srcElement;
2126 return this.resolveTextNode(t);
2130 resolveTextNode: function(node) {
2131 if (Roo.isSafari && node && 3 == node.nodeType) {
2132 return node.parentNode;
2139 getPageX: function(ev) {
2140 ev = ev.browserEvent || ev;
2141 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2143 if (!x && 0 !== x) {
2144 x = ev.clientX || 0;
2147 x += this.getScroll()[1];
2155 getPageY: function(ev) {
2156 ev = ev.browserEvent || ev;
2157 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2159 if (!y && 0 !== y) {
2160 y = ev.clientY || 0;
2163 y += this.getScroll()[0];
2172 getXY: function(ev) {
2173 ev = ev.browserEvent || ev;
2174 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2175 return [this.getPageX(ev), this.getPageY(ev)];
2179 getRelatedTarget: function(ev) {
2180 ev = ev.browserEvent || ev;
2181 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2182 var t = ev.relatedTarget;
2184 if (ev.type == "mouseout") {
2186 } else if (ev.type == "mouseover") {
2191 return this.resolveTextNode(t);
2195 getTime: function(ev) {
2196 ev = ev.browserEvent || ev;
2197 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2199 var t = new Date().getTime();
2203 this.lastError = ex;
2212 stopEvent: function(ev) {
2213 this.stopPropagation(ev);
2214 this.preventDefault(ev);
2218 stopPropagation: function(ev) {
2219 ev = ev.browserEvent || ev;
2220 if (ev.stopPropagation) {
2221 ev.stopPropagation();
2223 ev.cancelBubble = true;
2228 preventDefault: function(ev) {
2229 ev = ev.browserEvent || ev;
2230 if(ev.preventDefault) {
2231 ev.preventDefault();
2233 ev.returnValue = false;
2238 getEvent: function(e) {
2239 var ev = e || window.event;
2241 var c = this.getEvent.caller;
2243 ev = c.arguments[0];
2244 if (ev && Event == ev.constructor) {
2254 getCharCode: function(ev) {
2255 ev = ev.browserEvent || ev;
2256 return ev.charCode || ev.keyCode || 0;
2260 _getCacheIndex: function(el, eventName, fn) {
2261 for (var i = 0,len = listeners.length; i < len; ++i) {
2262 var li = listeners[i];
2264 li[this.FN] == fn &&
2265 li[this.EL] == el &&
2266 li[this.TYPE] == eventName) {
2278 getEl: function(id) {
2279 return document.getElementById(id);
2283 clearCache: function() {
2287 _load: function(e) {
2288 loadComplete = true;
2289 var EU = Roo.lib.Event;
2293 EU.doRemove(window, "load", EU._load);
2298 _tryPreloadAttach: function() {
2307 var tryAgain = !loadComplete;
2309 tryAgain = (retryCount > 0);
2314 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2315 var item = onAvailStack[i];
2317 var el = this.getEl(item.id);
2320 if (!item.checkReady ||
2323 (document && document.body)) {
2326 if (item.override) {
2327 if (item.override === true) {
2330 scope = item.override;
2333 item.fn.call(scope, item.obj);
2334 onAvailStack[i] = null;
2337 notAvail.push(item);
2342 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2346 this.startInterval();
2348 clearInterval(this._interval);
2349 this._interval = null;
2352 this.locked = false;
2359 purgeElement: function(el, recurse, eventName) {
2360 var elListeners = this.getListeners(el, eventName);
2362 for (var i = 0,len = elListeners.length; i < len; ++i) {
2363 var l = elListeners[i];
2364 this.removeListener(el, l.type, l.fn);
2368 if (recurse && el && el.childNodes) {
2369 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2370 this.purgeElement(el.childNodes[i], recurse, eventName);
2376 getListeners: function(el, eventName) {
2377 var results = [], searchLists;
2379 searchLists = [listeners, unloadListeners];
2380 } else if (eventName == "unload") {
2381 searchLists = [unloadListeners];
2383 searchLists = [listeners];
2386 for (var j = 0; j < searchLists.length; ++j) {
2387 var searchList = searchLists[j];
2388 if (searchList && searchList.length > 0) {
2389 for (var i = 0,len = searchList.length; i < len; ++i) {
2390 var l = searchList[i];
2391 if (l && l[this.EL] === el &&
2392 (!eventName || eventName === l[this.TYPE])) {
2397 adjust: l[this.ADJ_SCOPE],
2405 return (results.length) ? results : null;
2409 _unload: function(e) {
2411 var EU = Roo.lib.Event, i, j, l, len, index;
2413 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2414 l = unloadListeners[i];
2417 if (l[EU.ADJ_SCOPE]) {
2418 if (l[EU.ADJ_SCOPE] === true) {
2421 scope = l[EU.ADJ_SCOPE];
2424 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2425 unloadListeners[i] = null;
2431 unloadListeners = null;
2433 if (listeners && listeners.length > 0) {
2434 j = listeners.length;
2437 l = listeners[index];
2439 EU.removeListener(l[EU.EL], l[EU.TYPE],
2449 EU.doRemove(window, "unload", EU._unload);
2454 getScroll: function() {
2455 var dd = document.documentElement, db = document.body;
2456 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2457 return [dd.scrollTop, dd.scrollLeft];
2459 return [db.scrollTop, db.scrollLeft];
2466 doAdd: function () {
2467 if (window.addEventListener) {
2468 return function(el, eventName, fn, capture) {
2469 el.addEventListener(eventName, fn, (capture));
2471 } else if (window.attachEvent) {
2472 return function(el, eventName, fn, capture) {
2473 el.attachEvent("on" + eventName, fn);
2482 doRemove: function() {
2483 if (window.removeEventListener) {
2484 return function (el, eventName, fn, capture) {
2485 el.removeEventListener(eventName, fn, (capture));
2487 } else if (window.detachEvent) {
2488 return function (el, eventName, fn) {
2489 el.detachEvent("on" + eventName, fn);
2501 var E = Roo.lib.Event;
2502 E.on = E.addListener;
2503 E.un = E.removeListener;
2505 if (document && document.body) {
2508 E.doAdd(window, "load", E._load);
2510 E.doAdd(window, "unload", E._unload);
2511 E._tryPreloadAttach();
2515 * Portions of this file are based on pieces of Yahoo User Interface Library
2516 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2517 * YUI licensed under the BSD License:
2518 * http://developer.yahoo.net/yui/license.txt
2519 * <script type="text/javascript">
2525 * @class Roo.lib.Ajax
2532 request : function(method, uri, cb, data, options) {
2534 var hs = options.headers;
2537 if(hs.hasOwnProperty(h)){
2538 this.initHeader(h, hs[h], false);
2542 if(options.xmlData){
2543 this.initHeader('Content-Type', 'text/xml', false);
2545 data = options.xmlData;
2549 return this.asyncRequest(method, uri, cb, data);
2552 serializeForm : function(form) {
2553 if(typeof form == 'string') {
2554 form = (document.getElementById(form) || document.forms[form]);
2557 var el, name, val, disabled, data = '', hasSubmit = false;
2558 for (var i = 0; i < form.elements.length; i++) {
2559 el = form.elements[i];
2560 disabled = form.elements[i].disabled;
2561 name = form.elements[i].name;
2562 val = form.elements[i].value;
2564 if (!disabled && name){
2568 case 'select-multiple':
2569 for (var j = 0; j < el.options.length; j++) {
2570 if (el.options[j].selected) {
2572 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2575 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2583 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2596 if(hasSubmit == false) {
2597 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2602 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2607 data = data.substr(0, data.length - 1);
2615 useDefaultHeader:true,
2617 defaultPostHeader:'application/x-www-form-urlencoded',
2619 useDefaultXhrHeader:true,
2621 defaultXhrHeader:'XMLHttpRequest',
2623 hasDefaultHeaders:true,
2635 setProgId:function(id)
2637 this.activeX.unshift(id);
2640 setDefaultPostHeader:function(b)
2642 this.useDefaultHeader = b;
2645 setDefaultXhrHeader:function(b)
2647 this.useDefaultXhrHeader = b;
2650 setPollingInterval:function(i)
2652 if (typeof i == 'number' && isFinite(i)) {
2653 this.pollInterval = i;
2657 createXhrObject:function(transactionId)
2663 http = new XMLHttpRequest();
2665 obj = { conn:http, tId:transactionId };
2669 for (var i = 0; i < this.activeX.length; ++i) {
2673 http = new ActiveXObject(this.activeX[i]);
2675 obj = { conn:http, tId:transactionId };
2688 getConnectionObject:function()
2691 var tId = this.transactionId;
2695 o = this.createXhrObject(tId);
2697 this.transactionId++;
2708 asyncRequest:function(method, uri, callback, postData)
2710 var o = this.getConnectionObject();
2716 o.conn.open(method, uri, true);
2718 if (this.useDefaultXhrHeader) {
2719 if (!this.defaultHeaders['X-Requested-With']) {
2720 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2724 if(postData && this.useDefaultHeader){
2725 this.initHeader('Content-Type', this.defaultPostHeader);
2728 if (this.hasDefaultHeaders || this.hasHeaders) {
2732 this.handleReadyState(o, callback);
2733 o.conn.send(postData || null);
2739 handleReadyState:function(o, callback)
2743 if (callback && callback.timeout) {
2745 this.timeout[o.tId] = window.setTimeout(function() {
2746 oConn.abort(o, callback, true);
2747 }, callback.timeout);
2750 this.poll[o.tId] = window.setInterval(
2752 if (o.conn && o.conn.readyState == 4) {
2753 window.clearInterval(oConn.poll[o.tId]);
2754 delete oConn.poll[o.tId];
2756 if(callback && callback.timeout) {
2757 window.clearTimeout(oConn.timeout[o.tId]);
2758 delete oConn.timeout[o.tId];
2761 oConn.handleTransactionResponse(o, callback);
2764 , this.pollInterval);
2767 handleTransactionResponse:function(o, callback, isAbort)
2771 this.releaseObject(o);
2775 var httpStatus, responseObject;
2779 if (o.conn.status !== undefined && o.conn.status != 0) {
2780 httpStatus = o.conn.status;
2792 if (httpStatus >= 200 && httpStatus < 300) {
2793 responseObject = this.createResponseObject(o, callback.argument);
2794 if (callback.success) {
2795 if (!callback.scope) {
2796 callback.success(responseObject);
2801 callback.success.apply(callback.scope, [responseObject]);
2806 switch (httpStatus) {
2814 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2815 if (callback.failure) {
2816 if (!callback.scope) {
2817 callback.failure(responseObject);
2820 callback.failure.apply(callback.scope, [responseObject]);
2825 responseObject = this.createResponseObject(o, callback.argument);
2826 if (callback.failure) {
2827 if (!callback.scope) {
2828 callback.failure(responseObject);
2831 callback.failure.apply(callback.scope, [responseObject]);
2837 this.releaseObject(o);
2838 responseObject = null;
2841 createResponseObject:function(o, callbackArg)
2848 var headerStr = o.conn.getAllResponseHeaders();
2849 var header = headerStr.split('\n');
2850 for (var i = 0; i < header.length; i++) {
2851 var delimitPos = header[i].indexOf(':');
2852 if (delimitPos != -1) {
2853 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2861 obj.status = o.conn.status;
2862 obj.statusText = o.conn.statusText;
2863 obj.getResponseHeader = headerObj;
2864 obj.getAllResponseHeaders = headerStr;
2865 obj.responseText = o.conn.responseText;
2866 obj.responseXML = o.conn.responseXML;
2868 if (typeof callbackArg !== undefined) {
2869 obj.argument = callbackArg;
2875 createExceptionObject:function(tId, callbackArg, isAbort)
2878 var COMM_ERROR = 'communication failure';
2879 var ABORT_CODE = -1;
2880 var ABORT_ERROR = 'transaction aborted';
2886 obj.status = ABORT_CODE;
2887 obj.statusText = ABORT_ERROR;
2890 obj.status = COMM_CODE;
2891 obj.statusText = COMM_ERROR;
2895 obj.argument = callbackArg;
2901 initHeader:function(label, value, isDefault)
2903 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2905 if (headerObj[label] === undefined) {
2906 headerObj[label] = value;
2911 headerObj[label] = value + "," + headerObj[label];
2915 this.hasDefaultHeaders = true;
2918 this.hasHeaders = true;
2923 setHeader:function(o)
2925 if (this.hasDefaultHeaders) {
2926 for (var prop in this.defaultHeaders) {
2927 if (this.defaultHeaders.hasOwnProperty(prop)) {
2928 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2933 if (this.hasHeaders) {
2934 for (var prop in this.headers) {
2935 if (this.headers.hasOwnProperty(prop)) {
2936 o.conn.setRequestHeader(prop, this.headers[prop]);
2940 this.hasHeaders = false;
2944 resetDefaultHeaders:function() {
2945 delete this.defaultHeaders;
2946 this.defaultHeaders = {};
2947 this.hasDefaultHeaders = false;
2950 abort:function(o, callback, isTimeout)
2952 if(this.isCallInProgress(o)) {
2954 window.clearInterval(this.poll[o.tId]);
2955 delete this.poll[o.tId];
2957 delete this.timeout[o.tId];
2960 this.handleTransactionResponse(o, callback, true);
2970 isCallInProgress:function(o)
2973 return o.conn.readyState != 4 && o.conn.readyState != 0;
2982 releaseObject:function(o)
2991 'MSXML2.XMLHTTP.3.0',
2999 * Portions of this file are based on pieces of Yahoo User Interface Library
3000 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3001 * YUI licensed under the BSD License:
3002 * http://developer.yahoo.net/yui/license.txt
3003 * <script type="text/javascript">
3007 Roo.lib.Region = function(t, r, b, l) {
3017 Roo.lib.Region.prototype = {
3018 contains : function(region) {
3019 return ( region.left >= this.left &&
3020 region.right <= this.right &&
3021 region.top >= this.top &&
3022 region.bottom <= this.bottom );
3026 getArea : function() {
3027 return ( (this.bottom - this.top) * (this.right - this.left) );
3030 intersect : function(region) {
3031 var t = Math.max(this.top, region.top);
3032 var r = Math.min(this.right, region.right);
3033 var b = Math.min(this.bottom, region.bottom);
3034 var l = Math.max(this.left, region.left);
3036 if (b >= t && r >= l) {
3037 return new Roo.lib.Region(t, r, b, l);
3042 union : function(region) {
3043 var t = Math.min(this.top, region.top);
3044 var r = Math.max(this.right, region.right);
3045 var b = Math.max(this.bottom, region.bottom);
3046 var l = Math.min(this.left, region.left);
3048 return new Roo.lib.Region(t, r, b, l);
3051 adjust : function(t, l, b, r) {
3060 Roo.lib.Region.getRegion = function(el) {
3061 var p = Roo.lib.Dom.getXY(el);
3064 var r = p[0] + el.offsetWidth;
3065 var b = p[1] + el.offsetHeight;
3068 return new Roo.lib.Region(t, r, b, l);
3071 * Portions of this file are based on pieces of Yahoo User Interface Library
3072 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3073 * YUI licensed under the BSD License:
3074 * http://developer.yahoo.net/yui/license.txt
3075 * <script type="text/javascript">
3078 //@@dep Roo.lib.Region
3081 Roo.lib.Point = function(x, y) {
3082 if (x instanceof Array) {
3086 this.x = this.right = this.left = this[0] = x;
3087 this.y = this.top = this.bottom = this[1] = y;
3090 Roo.lib.Point.prototype = new Roo.lib.Region();
3092 * Portions of this file are based on pieces of Yahoo User Interface Library
3093 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3094 * YUI licensed under the BSD License:
3095 * http://developer.yahoo.net/yui/license.txt
3096 * <script type="text/javascript">
3103 scroll : function(el, args, duration, easing, cb, scope) {
3104 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3107 motion : function(el, args, duration, easing, cb, scope) {
3108 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3111 color : function(el, args, duration, easing, cb, scope) {
3112 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3115 run : function(el, args, duration, easing, cb, scope, type) {
3116 type = type || Roo.lib.AnimBase;
3117 if (typeof easing == "string") {
3118 easing = Roo.lib.Easing[easing];
3120 var anim = new type(el, args, duration, easing);
3121 anim.animateX(function() {
3122 Roo.callback(cb, scope);
3128 * Portions of this file are based on pieces of Yahoo User Interface Library
3129 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3130 * YUI licensed under the BSD License:
3131 * http://developer.yahoo.net/yui/license.txt
3132 * <script type="text/javascript">
3140 if (!libFlyweight) {
3141 libFlyweight = new Roo.Element.Flyweight();
3143 libFlyweight.dom = el;
3144 return libFlyweight;
3147 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3151 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3153 this.init(el, attributes, duration, method);
3157 Roo.lib.AnimBase.fly = fly;
3161 Roo.lib.AnimBase.prototype = {
3163 toString: function() {
3164 var el = this.getEl();
3165 var id = el.id || el.tagName;
3166 return ("Anim " + id);
3170 noNegatives: /width|height|opacity|padding/i,
3171 offsetAttribute: /^((width|height)|(top|left))$/,
3172 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3173 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3177 doMethod: function(attr, start, end) {
3178 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3182 setAttribute: function(attr, val, unit) {
3183 if (this.patterns.noNegatives.test(attr)) {
3184 val = (val > 0) ? val : 0;
3187 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3191 getAttribute: function(attr) {
3192 var el = this.getEl();
3193 var val = fly(el).getStyle(attr);
3195 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3196 return parseFloat(val);
3199 var a = this.patterns.offsetAttribute.exec(attr) || [];
3200 var pos = !!( a[3] );
3201 var box = !!( a[2] );
3204 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3205 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3214 getDefaultUnit: function(attr) {
3215 if (this.patterns.defaultUnit.test(attr)) {
3222 animateX : function(callback, scope) {
3223 var f = function() {
3224 this.onComplete.removeListener(f);
3225 if (typeof callback == "function") {
3226 callback.call(scope || this, this);
3229 this.onComplete.addListener(f, this);
3234 setRuntimeAttribute: function(attr) {
3237 var attributes = this.attributes;
3239 this.runtimeAttributes[attr] = {};
3241 var isset = function(prop) {
3242 return (typeof prop !== 'undefined');
3245 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3249 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3252 if (isset(attributes[attr]['to'])) {
3253 end = attributes[attr]['to'];
3254 } else if (isset(attributes[attr]['by'])) {
3255 if (start.constructor == Array) {
3257 for (var i = 0, len = start.length; i < len; ++i) {
3258 end[i] = start[i] + attributes[attr]['by'][i];
3261 end = start + attributes[attr]['by'];
3265 this.runtimeAttributes[attr].start = start;
3266 this.runtimeAttributes[attr].end = end;
3269 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3273 init: function(el, attributes, duration, method) {
3275 var isAnimated = false;
3278 var startTime = null;
3281 var actualFrames = 0;
3284 el = Roo.getDom(el);
3287 this.attributes = attributes || {};
3290 this.duration = duration || 1;
3293 this.method = method || Roo.lib.Easing.easeNone;
3296 this.useSeconds = true;
3299 this.currentFrame = 0;
3302 this.totalFrames = Roo.lib.AnimMgr.fps;
3305 this.getEl = function() {
3310 this.isAnimated = function() {
3315 this.getStartTime = function() {
3319 this.runtimeAttributes = {};
3322 this.animate = function() {
3323 if (this.isAnimated()) {
3327 this.currentFrame = 0;
3329 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3331 Roo.lib.AnimMgr.registerElement(this);
3335 this.stop = function(finish) {
3337 this.currentFrame = this.totalFrames;
3338 this._onTween.fire();
3340 Roo.lib.AnimMgr.stop(this);
3343 var onStart = function() {
3344 this.onStart.fire();
3346 this.runtimeAttributes = {};
3347 for (var attr in this.attributes) {
3348 this.setRuntimeAttribute(attr);
3353 startTime = new Date();
3357 var onTween = function() {
3359 duration: new Date() - this.getStartTime(),
3360 currentFrame: this.currentFrame
3363 data.toString = function() {
3365 'duration: ' + data.duration +
3366 ', currentFrame: ' + data.currentFrame
3370 this.onTween.fire(data);
3372 var runtimeAttributes = this.runtimeAttributes;
3374 for (var attr in runtimeAttributes) {
3375 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3381 var onComplete = function() {
3382 var actual_duration = (new Date() - startTime) / 1000 ;
3385 duration: actual_duration,
3386 frames: actualFrames,
3387 fps: actualFrames / actual_duration
3390 data.toString = function() {
3392 'duration: ' + data.duration +
3393 ', frames: ' + data.frames +
3394 ', fps: ' + data.fps
3400 this.onComplete.fire(data);
3404 this._onStart = new Roo.util.Event(this);
3405 this.onStart = new Roo.util.Event(this);
3406 this.onTween = new Roo.util.Event(this);
3407 this._onTween = new Roo.util.Event(this);
3408 this.onComplete = new Roo.util.Event(this);
3409 this._onComplete = new Roo.util.Event(this);
3410 this._onStart.addListener(onStart);
3411 this._onTween.addListener(onTween);
3412 this._onComplete.addListener(onComplete);
3417 * Portions of this file are based on pieces of Yahoo User Interface Library
3418 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3419 * YUI licensed under the BSD License:
3420 * http://developer.yahoo.net/yui/license.txt
3421 * <script type="text/javascript">
3425 Roo.lib.AnimMgr = new function() {
3442 this.registerElement = function(tween) {
3443 queue[queue.length] = tween;
3445 tween._onStart.fire();
3450 this.unRegister = function(tween, index) {
3451 tween._onComplete.fire();
3452 index = index || getIndex(tween);
3454 queue.splice(index, 1);
3458 if (tweenCount <= 0) {
3464 this.start = function() {
3465 if (thread === null) {
3466 thread = setInterval(this.run, this.delay);
3471 this.stop = function(tween) {
3473 clearInterval(thread);
3475 for (var i = 0, len = queue.length; i < len; ++i) {
3476 if (queue[0].isAnimated()) {
3477 this.unRegister(queue[0], 0);
3486 this.unRegister(tween);
3491 this.run = function() {
3492 for (var i = 0, len = queue.length; i < len; ++i) {
3493 var tween = queue[i];
3494 if (!tween || !tween.isAnimated()) {
3498 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3500 tween.currentFrame += 1;
3502 if (tween.useSeconds) {
3503 correctFrame(tween);
3505 tween._onTween.fire();
3508 Roo.lib.AnimMgr.stop(tween, i);
3513 var getIndex = function(anim) {
3514 for (var i = 0, len = queue.length; i < len; ++i) {
3515 if (queue[i] == anim) {
3523 var correctFrame = function(tween) {
3524 var frames = tween.totalFrames;
3525 var frame = tween.currentFrame;
3526 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3527 var elapsed = (new Date() - tween.getStartTime());
3530 if (elapsed < tween.duration * 1000) {
3531 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3533 tweak = frames - (frame + 1);
3535 if (tweak > 0 && isFinite(tweak)) {
3536 if (tween.currentFrame + tweak >= frames) {
3537 tweak = frames - (frame + 1);
3540 tween.currentFrame += tweak;
3546 * Portions of this file are based on pieces of Yahoo User Interface Library
3547 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3548 * YUI licensed under the BSD License:
3549 * http://developer.yahoo.net/yui/license.txt
3550 * <script type="text/javascript">
3553 Roo.lib.Bezier = new function() {
3555 this.getPosition = function(points, t) {
3556 var n = points.length;
3559 for (var i = 0; i < n; ++i) {
3560 tmp[i] = [points[i][0], points[i][1]];
3563 for (var j = 1; j < n; ++j) {
3564 for (i = 0; i < n - j; ++i) {
3565 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3566 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3570 return [ tmp[0][0], tmp[0][1] ];
3574 * Portions of this file are based on pieces of Yahoo User Interface Library
3575 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3576 * YUI licensed under the BSD License:
3577 * http://developer.yahoo.net/yui/license.txt
3578 * <script type="text/javascript">
3583 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3584 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3587 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3589 var fly = Roo.lib.AnimBase.fly;
3591 var superclass = Y.ColorAnim.superclass;
3592 var proto = Y.ColorAnim.prototype;
3594 proto.toString = function() {
3595 var el = this.getEl();
3596 var id = el.id || el.tagName;
3597 return ("ColorAnim " + id);
3600 proto.patterns.color = /color$/i;
3601 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3602 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3603 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3604 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3607 proto.parseColor = function(s) {
3608 if (s.length == 3) {
3612 var c = this.patterns.hex.exec(s);
3613 if (c && c.length == 4) {
3614 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3617 c = this.patterns.rgb.exec(s);
3618 if (c && c.length == 4) {
3619 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3622 c = this.patterns.hex3.exec(s);
3623 if (c && c.length == 4) {
3624 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3629 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3630 proto.getAttribute = function(attr) {
3631 var el = this.getEl();
3632 if (this.patterns.color.test(attr)) {
3633 var val = fly(el).getStyle(attr);
3635 if (this.patterns.transparent.test(val)) {
3636 var parent = el.parentNode;
3637 val = fly(parent).getStyle(attr);
3639 while (parent && this.patterns.transparent.test(val)) {
3640 parent = parent.parentNode;
3641 val = fly(parent).getStyle(attr);
3642 if (parent.tagName.toUpperCase() == 'HTML') {
3648 val = superclass.getAttribute.call(this, attr);
3653 proto.getAttribute = function(attr) {
3654 var el = this.getEl();
3655 if (this.patterns.color.test(attr)) {
3656 var val = fly(el).getStyle(attr);
3658 if (this.patterns.transparent.test(val)) {
3659 var parent = el.parentNode;
3660 val = fly(parent).getStyle(attr);
3662 while (parent && this.patterns.transparent.test(val)) {
3663 parent = parent.parentNode;
3664 val = fly(parent).getStyle(attr);
3665 if (parent.tagName.toUpperCase() == 'HTML') {
3671 val = superclass.getAttribute.call(this, attr);
3677 proto.doMethod = function(attr, start, end) {
3680 if (this.patterns.color.test(attr)) {
3682 for (var i = 0, len = start.length; i < len; ++i) {
3683 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3686 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3689 val = superclass.doMethod.call(this, attr, start, end);
3695 proto.setRuntimeAttribute = function(attr) {
3696 superclass.setRuntimeAttribute.call(this, attr);
3698 if (this.patterns.color.test(attr)) {
3699 var attributes = this.attributes;
3700 var start = this.parseColor(this.runtimeAttributes[attr].start);
3701 var end = this.parseColor(this.runtimeAttributes[attr].end);
3703 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3704 end = this.parseColor(attributes[attr].by);
3706 for (var i = 0, len = start.length; i < len; ++i) {
3707 end[i] = start[i] + end[i];
3711 this.runtimeAttributes[attr].start = start;
3712 this.runtimeAttributes[attr].end = end;
3718 * Portions of this file are based on pieces of Yahoo User Interface Library
3719 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3720 * YUI licensed under the BSD License:
3721 * http://developer.yahoo.net/yui/license.txt
3722 * <script type="text/javascript">
3728 easeNone: function (t, b, c, d) {
3729 return c * t / d + b;
3733 easeIn: function (t, b, c, d) {
3734 return c * (t /= d) * t + b;
3738 easeOut: function (t, b, c, d) {
3739 return -c * (t /= d) * (t - 2) + b;
3743 easeBoth: function (t, b, c, d) {
3744 if ((t /= d / 2) < 1) {
3745 return c / 2 * t * t + b;
3748 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3752 easeInStrong: function (t, b, c, d) {
3753 return c * (t /= d) * t * t * t + b;
3757 easeOutStrong: function (t, b, c, d) {
3758 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3762 easeBothStrong: function (t, b, c, d) {
3763 if ((t /= d / 2) < 1) {
3764 return c / 2 * t * t * t * t + b;
3767 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3772 elasticIn: function (t, b, c, d, a, p) {
3776 if ((t /= d) == 1) {
3783 if (!a || a < Math.abs(c)) {
3788 var s = p / (2 * Math.PI) * Math.asin(c / a);
3791 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3795 elasticOut: function (t, b, c, d, a, p) {
3799 if ((t /= d) == 1) {
3806 if (!a || a < Math.abs(c)) {
3811 var s = p / (2 * Math.PI) * Math.asin(c / a);
3814 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3818 elasticBoth: function (t, b, c, d, a, p) {
3823 if ((t /= d / 2) == 2) {
3831 if (!a || a < Math.abs(c)) {
3836 var s = p / (2 * Math.PI) * Math.asin(c / a);
3840 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3841 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3843 return a * Math.pow(2, -10 * (t -= 1)) *
3844 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3849 backIn: function (t, b, c, d, s) {
3850 if (typeof s == 'undefined') {
3853 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3857 backOut: function (t, b, c, d, s) {
3858 if (typeof s == 'undefined') {
3861 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3865 backBoth: function (t, b, c, d, s) {
3866 if (typeof s == 'undefined') {
3870 if ((t /= d / 2 ) < 1) {
3871 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3873 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3877 bounceIn: function (t, b, c, d) {
3878 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3882 bounceOut: function (t, b, c, d) {
3883 if ((t /= d) < (1 / 2.75)) {
3884 return c * (7.5625 * t * t) + b;
3885 } else if (t < (2 / 2.75)) {
3886 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3887 } else if (t < (2.5 / 2.75)) {
3888 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3890 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3894 bounceBoth: function (t, b, c, d) {
3896 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3898 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3901 * Portions of this file are based on pieces of Yahoo User Interface Library
3902 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3903 * YUI licensed under the BSD License:
3904 * http://developer.yahoo.net/yui/license.txt
3905 * <script type="text/javascript">
3909 Roo.lib.Motion = function(el, attributes, duration, method) {
3911 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3915 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3919 var superclass = Y.Motion.superclass;
3920 var proto = Y.Motion.prototype;
3922 proto.toString = function() {
3923 var el = this.getEl();
3924 var id = el.id || el.tagName;
3925 return ("Motion " + id);
3928 proto.patterns.points = /^points$/i;
3930 proto.setAttribute = function(attr, val, unit) {
3931 if (this.patterns.points.test(attr)) {
3932 unit = unit || 'px';
3933 superclass.setAttribute.call(this, 'left', val[0], unit);
3934 superclass.setAttribute.call(this, 'top', val[1], unit);
3936 superclass.setAttribute.call(this, attr, val, unit);
3940 proto.getAttribute = function(attr) {
3941 if (this.patterns.points.test(attr)) {
3943 superclass.getAttribute.call(this, 'left'),
3944 superclass.getAttribute.call(this, 'top')
3947 val = superclass.getAttribute.call(this, attr);
3953 proto.doMethod = function(attr, start, end) {
3956 if (this.patterns.points.test(attr)) {
3957 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3958 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3960 val = superclass.doMethod.call(this, attr, start, end);
3965 proto.setRuntimeAttribute = function(attr) {
3966 if (this.patterns.points.test(attr)) {
3967 var el = this.getEl();
3968 var attributes = this.attributes;
3970 var control = attributes['points']['control'] || [];
3974 if (control.length > 0 && !(control[0] instanceof Array)) {
3975 control = [control];
3978 for (i = 0,len = control.length; i < len; ++i) {
3979 tmp[i] = control[i];
3984 Roo.fly(el).position();
3986 if (isset(attributes['points']['from'])) {
3987 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3990 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3993 start = this.getAttribute('points');
3996 if (isset(attributes['points']['to'])) {
3997 end = translateValues.call(this, attributes['points']['to'], start);
3999 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4000 for (i = 0,len = control.length; i < len; ++i) {
4001 control[i] = translateValues.call(this, control[i], start);
4005 } else if (isset(attributes['points']['by'])) {
4006 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4008 for (i = 0,len = control.length; i < len; ++i) {
4009 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4013 this.runtimeAttributes[attr] = [start];
4015 if (control.length > 0) {
4016 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4019 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4022 superclass.setRuntimeAttribute.call(this, attr);
4026 var translateValues = function(val, start) {
4027 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4028 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4033 var isset = function(prop) {
4034 return (typeof prop !== 'undefined');
4038 * Portions of this file are based on pieces of Yahoo User Interface Library
4039 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4040 * YUI licensed under the BSD License:
4041 * http://developer.yahoo.net/yui/license.txt
4042 * <script type="text/javascript">
4046 Roo.lib.Scroll = function(el, attributes, duration, method) {
4048 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4052 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4056 var superclass = Y.Scroll.superclass;
4057 var proto = Y.Scroll.prototype;
4059 proto.toString = function() {
4060 var el = this.getEl();
4061 var id = el.id || el.tagName;
4062 return ("Scroll " + id);
4065 proto.doMethod = function(attr, start, end) {
4068 if (attr == 'scroll') {
4070 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4071 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4075 val = superclass.doMethod.call(this, attr, start, end);
4080 proto.getAttribute = function(attr) {
4082 var el = this.getEl();
4084 if (attr == 'scroll') {
4085 val = [ el.scrollLeft, el.scrollTop ];
4087 val = superclass.getAttribute.call(this, attr);
4093 proto.setAttribute = function(attr, val, unit) {
4094 var el = this.getEl();
4096 if (attr == 'scroll') {
4097 el.scrollLeft = val[0];
4098 el.scrollTop = val[1];
4100 superclass.setAttribute.call(this, attr, val, unit);
4106 * Ext JS Library 1.1.1
4107 * Copyright(c) 2006-2007, Ext JS, LLC.
4109 * Originally Released Under LGPL - original licence link has changed is not relivant.
4112 * <script type="text/javascript">
4116 // nasty IE9 hack - what a pile of crap that is..
4118 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4119 Range.prototype.createContextualFragment = function (html) {
4120 var doc = window.document;
4121 var container = doc.createElement("div");
4122 container.innerHTML = html;
4123 var frag = doc.createDocumentFragment(), n;
4124 while ((n = container.firstChild)) {
4125 frag.appendChild(n);
4132 * @class Roo.DomHelper
4133 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4134 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4137 Roo.DomHelper = function(){
4138 var tempTableEl = null;
4139 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4140 var tableRe = /^table|tbody|tr|td$/i;
4142 // build as innerHTML where available
4144 var createHtml = function(o){
4145 if(typeof o == 'string'){
4154 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4155 if(attr == "style"){
4157 if(typeof s == "function"){
4160 if(typeof s == "string"){
4161 b += ' style="' + s + '"';
4162 }else if(typeof s == "object"){
4165 if(typeof s[key] != "function"){
4166 b += key + ":" + s[key] + ";";
4173 b += ' class="' + o["cls"] + '"';
4174 }else if(attr == "htmlFor"){
4175 b += ' for="' + o["htmlFor"] + '"';
4177 b += " " + attr + '="' + o[attr] + '"';
4181 if(emptyTags.test(o.tag)){
4185 var cn = o.children || o.cn;
4187 //http://bugs.kde.org/show_bug.cgi?id=71506
4188 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4189 for(var i = 0, len = cn.length; i < len; i++) {
4190 b += createHtml(cn[i], b);
4193 b += createHtml(cn, b);
4199 b += "</" + o.tag + ">";
4206 var createDom = function(o, parentNode){
4208 // defininition craeted..
4210 if (o.ns && o.ns != 'html') {
4212 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4213 xmlns[o.ns] = o.xmlns;
4216 if (typeof(xmlns[o.ns]) == 'undefined') {
4217 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4223 if (typeof(o) == 'string') {
4224 return parentNode.appendChild(document.createTextNode(o));
4226 o.tag = o.tag || div;
4227 if (o.ns && Roo.isIE) {
4229 o.tag = o.ns + ':' + o.tag;
4232 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4233 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4236 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4237 attr == "style" || typeof o[attr] == "function") continue;
4239 if(attr=="cls" && Roo.isIE){
4240 el.className = o["cls"];
4242 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4248 Roo.DomHelper.applyStyles(el, o.style);
4249 var cn = o.children || o.cn;
4251 //http://bugs.kde.org/show_bug.cgi?id=71506
4252 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4253 for(var i = 0, len = cn.length; i < len; i++) {
4254 createDom(cn[i], el);
4261 el.innerHTML = o.html;
4264 parentNode.appendChild(el);
4269 var ieTable = function(depth, s, h, e){
4270 tempTableEl.innerHTML = [s, h, e].join('');
4271 var i = -1, el = tempTableEl;
4278 // kill repeat to save bytes
4282 tbe = '</tbody>'+te,
4288 * Nasty code for IE's broken table implementation
4290 var insertIntoTable = function(tag, where, el, html){
4292 tempTableEl = document.createElement('div');
4297 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4300 if(where == 'beforebegin'){
4304 before = el.nextSibling;
4307 node = ieTable(4, trs, html, tre);
4309 else if(tag == 'tr'){
4310 if(where == 'beforebegin'){
4313 node = ieTable(3, tbs, html, tbe);
4314 } else if(where == 'afterend'){
4315 before = el.nextSibling;
4317 node = ieTable(3, tbs, html, tbe);
4318 } else{ // INTO a TR
4319 if(where == 'afterbegin'){
4320 before = el.firstChild;
4322 node = ieTable(4, trs, html, tre);
4324 } else if(tag == 'tbody'){
4325 if(where == 'beforebegin'){
4328 node = ieTable(2, ts, html, te);
4329 } else if(where == 'afterend'){
4330 before = el.nextSibling;
4332 node = ieTable(2, ts, html, te);
4334 if(where == 'afterbegin'){
4335 before = el.firstChild;
4337 node = ieTable(3, tbs, html, tbe);
4340 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4343 if(where == 'afterbegin'){
4344 before = el.firstChild;
4346 node = ieTable(2, ts, html, te);
4348 el.insertBefore(node, before);
4353 /** True to force the use of DOM instead of html fragments @type Boolean */
4357 * Returns the markup for the passed Element(s) config
4358 * @param {Object} o The Dom object spec (and children)
4361 markup : function(o){
4362 return createHtml(o);
4366 * Applies a style specification to an element
4367 * @param {String/HTMLElement} el The element to apply styles to
4368 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4369 * a function which returns such a specification.
4371 applyStyles : function(el, styles){
4374 if(typeof styles == "string"){
4375 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4377 while ((matches = re.exec(styles)) != null){
4378 el.setStyle(matches[1], matches[2]);
4380 }else if (typeof styles == "object"){
4381 for (var style in styles){
4382 el.setStyle(style, styles[style]);
4384 }else if (typeof styles == "function"){
4385 Roo.DomHelper.applyStyles(el, styles.call());
4391 * Inserts an HTML fragment into the Dom
4392 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4393 * @param {HTMLElement} el The context element
4394 * @param {String} html The HTML fragmenet
4395 * @return {HTMLElement} The new node
4397 insertHtml : function(where, el, html){
4398 where = where.toLowerCase();
4399 if(el.insertAdjacentHTML){
4400 if(tableRe.test(el.tagName)){
4402 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4408 el.insertAdjacentHTML('BeforeBegin', html);
4409 return el.previousSibling;
4411 el.insertAdjacentHTML('AfterBegin', html);
4412 return el.firstChild;
4414 el.insertAdjacentHTML('BeforeEnd', html);
4415 return el.lastChild;
4417 el.insertAdjacentHTML('AfterEnd', html);
4418 return el.nextSibling;
4420 throw 'Illegal insertion point -> "' + where + '"';
4422 var range = el.ownerDocument.createRange();
4426 range.setStartBefore(el);
4427 frag = range.createContextualFragment(html);
4428 el.parentNode.insertBefore(frag, el);
4429 return el.previousSibling;
4432 range.setStartBefore(el.firstChild);
4433 frag = range.createContextualFragment(html);
4434 el.insertBefore(frag, el.firstChild);
4435 return el.firstChild;
4437 el.innerHTML = html;
4438 return el.firstChild;
4442 range.setStartAfter(el.lastChild);
4443 frag = range.createContextualFragment(html);
4444 el.appendChild(frag);
4445 return el.lastChild;
4447 el.innerHTML = html;
4448 return el.lastChild;
4451 range.setStartAfter(el);
4452 frag = range.createContextualFragment(html);
4453 el.parentNode.insertBefore(frag, el.nextSibling);
4454 return el.nextSibling;
4456 throw 'Illegal insertion point -> "' + where + '"';
4460 * Creates new Dom element(s) and inserts them before el
4461 * @param {String/HTMLElement/Element} el The context element
4462 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4463 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4464 * @return {HTMLElement/Roo.Element} The new node
4466 insertBefore : function(el, o, returnElement){
4467 return this.doInsert(el, o, returnElement, "beforeBegin");
4471 * Creates new Dom element(s) and inserts them after el
4472 * @param {String/HTMLElement/Element} el The context element
4473 * @param {Object} o The Dom object spec (and children)
4474 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4475 * @return {HTMLElement/Roo.Element} The new node
4477 insertAfter : function(el, o, returnElement){
4478 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4482 * Creates new Dom element(s) and inserts them as the first child of el
4483 * @param {String/HTMLElement/Element} el The context element
4484 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4485 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4486 * @return {HTMLElement/Roo.Element} The new node
4488 insertFirst : function(el, o, returnElement){
4489 return this.doInsert(el, o, returnElement, "afterBegin");
4493 doInsert : function(el, o, returnElement, pos, sibling){
4494 el = Roo.getDom(el);
4496 if(this.useDom || o.ns){
4497 newNode = createDom(o, null);
4498 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4500 var html = createHtml(o);
4501 newNode = this.insertHtml(pos, el, html);
4503 return returnElement ? Roo.get(newNode, true) : newNode;
4507 * Creates new Dom element(s) and appends them to el
4508 * @param {String/HTMLElement/Element} el The context element
4509 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4510 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4511 * @return {HTMLElement/Roo.Element} The new node
4513 append : function(el, o, returnElement){
4514 el = Roo.getDom(el);
4516 if(this.useDom || o.ns){
4517 newNode = createDom(o, null);
4518 el.appendChild(newNode);
4520 var html = createHtml(o);
4521 newNode = this.insertHtml("beforeEnd", el, html);
4523 return returnElement ? Roo.get(newNode, true) : newNode;
4527 * Creates new Dom element(s) and overwrites the contents of el with them
4528 * @param {String/HTMLElement/Element} el The context element
4529 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4530 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4531 * @return {HTMLElement/Roo.Element} The new node
4533 overwrite : function(el, o, returnElement){
4534 el = Roo.getDom(el);
4537 while (el.childNodes.length) {
4538 el.removeChild(el.firstChild);
4542 el.innerHTML = createHtml(o);
4545 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4549 * Creates a new Roo.DomHelper.Template from the Dom object spec
4550 * @param {Object} o The Dom object spec (and children)
4551 * @return {Roo.DomHelper.Template} The new template
4553 createTemplate : function(o){
4554 var html = createHtml(o);
4555 return new Roo.Template(html);
4561 * Ext JS Library 1.1.1
4562 * Copyright(c) 2006-2007, Ext JS, LLC.
4564 * Originally Released Under LGPL - original licence link has changed is not relivant.
4567 * <script type="text/javascript">
4571 * @class Roo.Template
4572 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4573 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4576 var t = new Roo.Template({
4577 html : '<div name="{id}">' +
4578 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4580 myformat: function (value, allValues) {
4581 return 'XX' + value;
4584 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4586 * For more information see this blog post with examples:
4587 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4588 - Create Elements using DOM, HTML fragments and Templates</a>.
4590 * @param {Object} cfg - Configuration object.
4592 Roo.Template = function(cfg){
4594 if(cfg instanceof Array){
4596 }else if(arguments.length > 1){
4597 cfg = Array.prototype.join.call(arguments, "");
4601 if (typeof(cfg) == 'object') {
4612 Roo.Template.prototype = {
4615 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4616 * it should be fixed so that template is observable...
4620 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4624 * Returns an HTML fragment of this template with the specified values applied.
4625 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4626 * @return {String} The HTML fragment
4628 applyTemplate : function(values){
4632 return this.compiled(values);
4634 var useF = this.disableFormats !== true;
4635 var fm = Roo.util.Format, tpl = this;
4636 var fn = function(m, name, format, args){
4638 if(format.substr(0, 5) == "this."){
4639 return tpl.call(format.substr(5), values[name], values);
4642 // quoted values are required for strings in compiled templates,
4643 // but for non compiled we need to strip them
4644 // quoted reversed for jsmin
4645 var re = /^\s*['"](.*)["']\s*$/;
4646 args = args.split(',');
4647 for(var i = 0, len = args.length; i < len; i++){
4648 args[i] = args[i].replace(re, "$1");
4650 args = [values[name]].concat(args);
4652 args = [values[name]];
4654 return fm[format].apply(fm, args);
4657 return values[name] !== undefined ? values[name] : "";
4660 return this.html.replace(this.re, fn);
4678 this.loading = true;
4679 this.compiled = false;
4681 var cx = new Roo.data.Connection();
4685 success : function (response) {
4687 _t.html = response.responseText;
4691 failure : function(response) {
4692 Roo.log("Template failed to load from " + _t.url);
4699 * Sets the HTML used as the template and optionally compiles it.
4700 * @param {String} html
4701 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4702 * @return {Roo.Template} this
4704 set : function(html, compile){
4706 this.compiled = null;
4714 * True to disable format functions (defaults to false)
4717 disableFormats : false,
4720 * The regular expression used to match template variables
4724 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4727 * Compiles the template into an internal function, eliminating the RegEx overhead.
4728 * @return {Roo.Template} this
4730 compile : function(){
4731 var fm = Roo.util.Format;
4732 var useF = this.disableFormats !== true;
4733 var sep = Roo.isGecko ? "+" : ",";
4734 var fn = function(m, name, format, args){
4736 args = args ? ',' + args : "";
4737 if(format.substr(0, 5) != "this."){
4738 format = "fm." + format + '(';
4740 format = 'this.call("'+ format.substr(5) + '", ';
4744 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4746 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4749 // branched to use + in gecko and [].join() in others
4751 body = "this.compiled = function(values){ return '" +
4752 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4755 body = ["this.compiled = function(values){ return ['"];
4756 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4757 body.push("'].join('');};");
4758 body = body.join('');
4768 // private function used to call members
4769 call : function(fnName, value, allValues){
4770 return this[fnName](value, allValues);
4774 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4775 * @param {String/HTMLElement/Roo.Element} el The context element
4776 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4777 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4778 * @return {HTMLElement/Roo.Element} The new node or Element
4780 insertFirst: function(el, values, returnElement){
4781 return this.doInsert('afterBegin', el, values, returnElement);
4785 * Applies the supplied values to the template and inserts the new node(s) before el.
4786 * @param {String/HTMLElement/Roo.Element} el The context element
4787 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4788 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4789 * @return {HTMLElement/Roo.Element} The new node or Element
4791 insertBefore: function(el, values, returnElement){
4792 return this.doInsert('beforeBegin', el, values, returnElement);
4796 * Applies the supplied values to the template and inserts the new node(s) after el.
4797 * @param {String/HTMLElement/Roo.Element} el The context element
4798 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4799 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4800 * @return {HTMLElement/Roo.Element} The new node or Element
4802 insertAfter : function(el, values, returnElement){
4803 return this.doInsert('afterEnd', el, values, returnElement);
4807 * Applies the supplied values to the template and appends the new node(s) to el.
4808 * @param {String/HTMLElement/Roo.Element} el The context element
4809 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4810 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4811 * @return {HTMLElement/Roo.Element} The new node or Element
4813 append : function(el, values, returnElement){
4814 return this.doInsert('beforeEnd', el, values, returnElement);
4817 doInsert : function(where, el, values, returnEl){
4818 el = Roo.getDom(el);
4819 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4820 return returnEl ? Roo.get(newNode, true) : newNode;
4824 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4825 * @param {String/HTMLElement/Roo.Element} el The context element
4826 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4827 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4828 * @return {HTMLElement/Roo.Element} The new node or Element
4830 overwrite : function(el, values, returnElement){
4831 el = Roo.getDom(el);
4832 el.innerHTML = this.applyTemplate(values);
4833 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4837 * Alias for {@link #applyTemplate}
4840 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4843 Roo.DomHelper.Template = Roo.Template;
4846 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4847 * @param {String/HTMLElement} el A DOM element or its id
4848 * @returns {Roo.Template} The created template
4851 Roo.Template.from = function(el){
4852 el = Roo.getDom(el);
4853 return new Roo.Template(el.value || el.innerHTML);
4856 * Ext JS Library 1.1.1
4857 * Copyright(c) 2006-2007, Ext JS, LLC.
4859 * Originally Released Under LGPL - original licence link has changed is not relivant.
4862 * <script type="text/javascript">
4867 * This is code is also distributed under MIT license for use
4868 * with jQuery and prototype JavaScript libraries.
4871 * @class Roo.DomQuery
4872 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4874 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4877 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4879 <h4>Element Selectors:</h4>
4881 <li> <b>*</b> any element</li>
4882 <li> <b>E</b> an element with the tag E</li>
4883 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4884 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4885 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4886 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4888 <h4>Attribute Selectors:</h4>
4889 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4891 <li> <b>E[foo]</b> has an attribute "foo"</li>
4892 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4893 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4894 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4895 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4896 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4897 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4899 <h4>Pseudo Classes:</h4>
4901 <li> <b>E:first-child</b> E is the first child of its parent</li>
4902 <li> <b>E:last-child</b> E is the last child of its parent</li>
4903 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4904 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4905 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4906 <li> <b>E:only-child</b> E is the only child of its parent</li>
4907 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4908 <li> <b>E:first</b> the first E in the resultset</li>
4909 <li> <b>E:last</b> the last E in the resultset</li>
4910 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4911 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4912 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4913 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4914 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4915 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4916 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4917 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4918 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4920 <h4>CSS Value Selectors:</h4>
4922 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4923 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4924 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4925 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4926 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4927 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4931 Roo.DomQuery = function(){
4932 var cache = {}, simpleCache = {}, valueCache = {};
4933 var nonSpace = /\S/;
4934 var trimRe = /^\s+|\s+$/g;
4935 var tplRe = /\{(\d+)\}/g;
4936 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4937 var tagTokenRe = /^(#)?([\w-\*]+)/;
4938 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4940 function child(p, index){
4942 var n = p.firstChild;
4944 if(n.nodeType == 1){
4955 while((n = n.nextSibling) && n.nodeType != 1);
4960 while((n = n.previousSibling) && n.nodeType != 1);
4964 function children(d){
4965 var n = d.firstChild, ni = -1;
4967 var nx = n.nextSibling;
4968 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4978 function byClassName(c, a, v){
4982 var r = [], ri = -1, cn;
4983 for(var i = 0, ci; ci = c[i]; i++){
4984 if((' '+ci.className+' ').indexOf(v) != -1){
4991 function attrValue(n, attr){
4992 if(!n.tagName && typeof n.length != "undefined"){
5001 if(attr == "class" || attr == "className"){
5004 return n.getAttribute(attr) || n[attr];
5008 function getNodes(ns, mode, tagName){
5009 var result = [], ri = -1, cs;
5013 tagName = tagName || "*";
5014 if(typeof ns.getElementsByTagName != "undefined"){
5018 for(var i = 0, ni; ni = ns[i]; i++){
5019 cs = ni.getElementsByTagName(tagName);
5020 for(var j = 0, ci; ci = cs[j]; j++){
5024 }else if(mode == "/" || mode == ">"){
5025 var utag = tagName.toUpperCase();
5026 for(var i = 0, ni, cn; ni = ns[i]; i++){
5027 cn = ni.children || ni.childNodes;
5028 for(var j = 0, cj; cj = cn[j]; j++){
5029 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5034 }else if(mode == "+"){
5035 var utag = tagName.toUpperCase();
5036 for(var i = 0, n; n = ns[i]; i++){
5037 while((n = n.nextSibling) && n.nodeType != 1);
5038 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5042 }else if(mode == "~"){
5043 for(var i = 0, n; n = ns[i]; i++){
5044 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5053 function concat(a, b){
5057 for(var i = 0, l = b.length; i < l; i++){
5063 function byTag(cs, tagName){
5064 if(cs.tagName || cs == document){
5070 var r = [], ri = -1;
5071 tagName = tagName.toLowerCase();
5072 for(var i = 0, ci; ci = cs[i]; i++){
5073 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5080 function byId(cs, attr, id){
5081 if(cs.tagName || cs == document){
5087 var r = [], ri = -1;
5088 for(var i = 0,ci; ci = cs[i]; i++){
5089 if(ci && ci.id == id){
5097 function byAttribute(cs, attr, value, op, custom){
5098 var r = [], ri = -1, st = custom=="{";
5099 var f = Roo.DomQuery.operators[op];
5100 for(var i = 0, ci; ci = cs[i]; i++){
5103 a = Roo.DomQuery.getStyle(ci, attr);
5105 else if(attr == "class" || attr == "className"){
5107 }else if(attr == "for"){
5109 }else if(attr == "href"){
5110 a = ci.getAttribute("href", 2);
5112 a = ci.getAttribute(attr);
5114 if((f && f(a, value)) || (!f && a)){
5121 function byPseudo(cs, name, value){
5122 return Roo.DomQuery.pseudos[name](cs, value);
5125 // This is for IE MSXML which does not support expandos.
5126 // IE runs the same speed using setAttribute, however FF slows way down
5127 // and Safari completely fails so they need to continue to use expandos.
5128 var isIE = window.ActiveXObject ? true : false;
5130 // this eval is stop the compressor from
5131 // renaming the variable to something shorter
5133 /** eval:var:batch */
5138 function nodupIEXml(cs){
5140 cs[0].setAttribute("_nodup", d);
5142 for(var i = 1, len = cs.length; i < len; i++){
5144 if(!c.getAttribute("_nodup") != d){
5145 c.setAttribute("_nodup", d);
5149 for(var i = 0, len = cs.length; i < len; i++){
5150 cs[i].removeAttribute("_nodup");
5159 var len = cs.length, c, i, r = cs, cj, ri = -1;
5160 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5163 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5164 return nodupIEXml(cs);
5168 for(i = 1; c = cs[i]; i++){
5173 for(var j = 0; j < i; j++){
5176 for(j = i+1; cj = cs[j]; j++){
5188 function quickDiffIEXml(c1, c2){
5190 for(var i = 0, len = c1.length; i < len; i++){
5191 c1[i].setAttribute("_qdiff", d);
5194 for(var i = 0, len = c2.length; i < len; i++){
5195 if(c2[i].getAttribute("_qdiff") != d){
5196 r[r.length] = c2[i];
5199 for(var i = 0, len = c1.length; i < len; i++){
5200 c1[i].removeAttribute("_qdiff");
5205 function quickDiff(c1, c2){
5206 var len1 = c1.length;
5210 if(isIE && c1[0].selectSingleNode){
5211 return quickDiffIEXml(c1, c2);
5214 for(var i = 0; i < len1; i++){
5218 for(var i = 0, len = c2.length; i < len; i++){
5219 if(c2[i]._qdiff != d){
5220 r[r.length] = c2[i];
5226 function quickId(ns, mode, root, id){
5228 var d = root.ownerDocument || root;
5229 return d.getElementById(id);
5231 ns = getNodes(ns, mode, "*");
5232 return byId(ns, null, id);
5236 getStyle : function(el, name){
5237 return Roo.fly(el).getStyle(name);
5240 * Compiles a selector/xpath query into a reusable function. The returned function
5241 * takes one parameter "root" (optional), which is the context node from where the query should start.
5242 * @param {String} selector The selector/xpath query
5243 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5244 * @return {Function}
5246 compile : function(path, type){
5247 type = type || "select";
5249 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5250 var q = path, mode, lq;
5251 var tk = Roo.DomQuery.matchers;
5252 var tklen = tk.length;
5255 // accept leading mode switch
5256 var lmode = q.match(modeRe);
5257 if(lmode && lmode[1]){
5258 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5259 q = q.replace(lmode[1], "");
5261 // strip leading slashes
5262 while(path.substr(0, 1)=="/"){
5263 path = path.substr(1);
5266 while(q && lq != q){
5268 var tm = q.match(tagTokenRe);
5269 if(type == "select"){
5272 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5274 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5276 q = q.replace(tm[0], "");
5277 }else if(q.substr(0, 1) != '@'){
5278 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5283 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5285 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5287 q = q.replace(tm[0], "");
5290 while(!(mm = q.match(modeRe))){
5291 var matched = false;
5292 for(var j = 0; j < tklen; j++){
5294 var m = q.match(t.re);
5296 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5299 q = q.replace(m[0], "");
5304 // prevent infinite loop on bad selector
5306 throw 'Error parsing selector, parsing failed at "' + q + '"';
5310 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5311 q = q.replace(mm[1], "");
5314 fn[fn.length] = "return nodup(n);\n}";
5317 * list of variables that need from compression as they are used by eval.
5327 * eval:var:byClassName
5329 * eval:var:byAttribute
5330 * eval:var:attrValue
5338 * Selects a group of elements.
5339 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5340 * @param {Node} root (optional) The start of the query (defaults to document).
5343 select : function(path, root, type){
5344 if(!root || root == document){
5347 if(typeof root == "string"){
5348 root = document.getElementById(root);
5350 var paths = path.split(",");
5352 for(var i = 0, len = paths.length; i < len; i++){
5353 var p = paths[i].replace(trimRe, "");
5355 cache[p] = Roo.DomQuery.compile(p);
5357 throw p + " is not a valid selector";
5360 var result = cache[p](root);
5361 if(result && result != document){
5362 results = results.concat(result);
5365 if(paths.length > 1){
5366 return nodup(results);
5372 * Selects a single element.
5373 * @param {String} selector The selector/xpath query
5374 * @param {Node} root (optional) The start of the query (defaults to document).
5377 selectNode : function(path, root){
5378 return Roo.DomQuery.select(path, root)[0];
5382 * Selects the value of a node, optionally replacing null with the defaultValue.
5383 * @param {String} selector The selector/xpath query
5384 * @param {Node} root (optional) The start of the query (defaults to document).
5385 * @param {String} defaultValue
5387 selectValue : function(path, root, defaultValue){
5388 path = path.replace(trimRe, "");
5389 if(!valueCache[path]){
5390 valueCache[path] = Roo.DomQuery.compile(path, "select");
5392 var n = valueCache[path](root);
5393 n = n[0] ? n[0] : n;
5394 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5395 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5399 * Selects the value of a node, parsing integers and floats.
5400 * @param {String} selector The selector/xpath query
5401 * @param {Node} root (optional) The start of the query (defaults to document).
5402 * @param {Number} defaultValue
5405 selectNumber : function(path, root, defaultValue){
5406 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5407 return parseFloat(v);
5411 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5412 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5413 * @param {String} selector The simple selector to test
5416 is : function(el, ss){
5417 if(typeof el == "string"){
5418 el = document.getElementById(el);
5420 var isArray = (el instanceof Array);
5421 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5422 return isArray ? (result.length == el.length) : (result.length > 0);
5426 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5427 * @param {Array} el An array of elements to filter
5428 * @param {String} selector The simple selector to test
5429 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5430 * the selector instead of the ones that match
5433 filter : function(els, ss, nonMatches){
5434 ss = ss.replace(trimRe, "");
5435 if(!simpleCache[ss]){
5436 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5438 var result = simpleCache[ss](els);
5439 return nonMatches ? quickDiff(result, els) : result;
5443 * Collection of matching regular expressions and code snippets.
5447 select: 'n = byClassName(n, null, " {1} ");'
5449 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5450 select: 'n = byPseudo(n, "{1}", "{2}");'
5452 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5453 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5456 select: 'n = byId(n, null, "{1}");'
5459 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5464 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5465 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5468 "=" : function(a, v){
5471 "!=" : function(a, v){
5474 "^=" : function(a, v){
5475 return a && a.substr(0, v.length) == v;
5477 "$=" : function(a, v){
5478 return a && a.substr(a.length-v.length) == v;
5480 "*=" : function(a, v){
5481 return a && a.indexOf(v) !== -1;
5483 "%=" : function(a, v){
5484 return (a % v) == 0;
5486 "|=" : function(a, v){
5487 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5489 "~=" : function(a, v){
5490 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5495 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5496 * and the argument (if any) supplied in the selector.
5499 "first-child" : function(c){
5500 var r = [], ri = -1, n;
5501 for(var i = 0, ci; ci = n = c[i]; i++){
5502 while((n = n.previousSibling) && n.nodeType != 1);
5510 "last-child" : function(c){
5511 var r = [], ri = -1, n;
5512 for(var i = 0, ci; ci = n = c[i]; i++){
5513 while((n = n.nextSibling) && n.nodeType != 1);
5521 "nth-child" : function(c, a) {
5522 var r = [], ri = -1;
5523 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5524 var f = (m[1] || 1) - 0, l = m[2] - 0;
5525 for(var i = 0, n; n = c[i]; i++){
5526 var pn = n.parentNode;
5527 if (batch != pn._batch) {
5529 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5530 if(cn.nodeType == 1){
5537 if (l == 0 || n.nodeIndex == l){
5540 } else if ((n.nodeIndex + l) % f == 0){
5548 "only-child" : function(c){
5549 var r = [], ri = -1;;
5550 for(var i = 0, ci; ci = c[i]; i++){
5551 if(!prev(ci) && !next(ci)){
5558 "empty" : function(c){
5559 var r = [], ri = -1;
5560 for(var i = 0, ci; ci = c[i]; i++){
5561 var cns = ci.childNodes, j = 0, cn, empty = true;
5564 if(cn.nodeType == 1 || cn.nodeType == 3){
5576 "contains" : function(c, v){
5577 var r = [], ri = -1;
5578 for(var i = 0, ci; ci = c[i]; i++){
5579 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5586 "nodeValue" : function(c, v){
5587 var r = [], ri = -1;
5588 for(var i = 0, ci; ci = c[i]; i++){
5589 if(ci.firstChild && ci.firstChild.nodeValue == v){
5596 "checked" : function(c){
5597 var r = [], ri = -1;
5598 for(var i = 0, ci; ci = c[i]; i++){
5599 if(ci.checked == true){
5606 "not" : function(c, ss){
5607 return Roo.DomQuery.filter(c, ss, true);
5610 "odd" : function(c){
5611 return this["nth-child"](c, "odd");
5614 "even" : function(c){
5615 return this["nth-child"](c, "even");
5618 "nth" : function(c, a){
5619 return c[a-1] || [];
5622 "first" : function(c){
5626 "last" : function(c){
5627 return c[c.length-1] || [];
5630 "has" : function(c, ss){
5631 var s = Roo.DomQuery.select;
5632 var r = [], ri = -1;
5633 for(var i = 0, ci; ci = c[i]; i++){
5634 if(s(ss, ci).length > 0){
5641 "next" : function(c, ss){
5642 var is = Roo.DomQuery.is;
5643 var r = [], ri = -1;
5644 for(var i = 0, ci; ci = c[i]; i++){
5653 "prev" : function(c, ss){
5654 var is = Roo.DomQuery.is;
5655 var r = [], ri = -1;
5656 for(var i = 0, ci; ci = c[i]; i++){
5669 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5670 * @param {String} path The selector/xpath query
5671 * @param {Node} root (optional) The start of the query (defaults to document).
5676 Roo.query = Roo.DomQuery.select;
5679 * Ext JS Library 1.1.1
5680 * Copyright(c) 2006-2007, Ext JS, LLC.
5682 * Originally Released Under LGPL - original licence link has changed is not relivant.
5685 * <script type="text/javascript">
5689 * @class Roo.util.Observable
5690 * Base class that provides a common interface for publishing events. Subclasses are expected to
5691 * to have a property "events" with all the events defined.<br>
5694 Employee = function(name){
5701 Roo.extend(Employee, Roo.util.Observable);
5703 * @param {Object} config properties to use (incuding events / listeners)
5706 Roo.util.Observable = function(cfg){
5709 this.addEvents(cfg.events || {});
5711 delete cfg.events; // make sure
5714 Roo.apply(this, cfg);
5717 this.on(this.listeners);
5718 delete this.listeners;
5721 Roo.util.Observable.prototype = {
5723 * @cfg {Object} listeners list of events and functions to call for this object,
5727 'click' : function(e) {
5737 * Fires the specified event with the passed parameters (minus the event name).
5738 * @param {String} eventName
5739 * @param {Object...} args Variable number of parameters are passed to handlers
5740 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5742 fireEvent : function(){
5743 var ce = this.events[arguments[0].toLowerCase()];
5744 if(typeof ce == "object"){
5745 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5752 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5755 * Appends an event handler to this component
5756 * @param {String} eventName The type of event to listen for
5757 * @param {Function} handler The method the event invokes
5758 * @param {Object} scope (optional) The scope in which to execute the handler
5759 * function. The handler function's "this" context.
5760 * @param {Object} options (optional) An object containing handler configuration
5761 * properties. This may contain any of the following properties:<ul>
5762 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5763 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5764 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5765 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5766 * by the specified number of milliseconds. If the event fires again within that time, the original
5767 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5770 * <b>Combining Options</b><br>
5771 * Using the options argument, it is possible to combine different types of listeners:<br>
5773 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5775 el.on('click', this.onClick, this, {
5782 * <b>Attaching multiple handlers in 1 call</b><br>
5783 * The method also allows for a single argument to be passed which is a config object containing properties
5784 * which specify multiple handlers.
5793 fn: this.onMouseOver,
5797 fn: this.onMouseOut,
5803 * Or a shorthand syntax which passes the same scope object to all handlers:
5806 'click': this.onClick,
5807 'mouseover': this.onMouseOver,
5808 'mouseout': this.onMouseOut,
5813 addListener : function(eventName, fn, scope, o){
5814 if(typeof eventName == "object"){
5817 if(this.filterOptRe.test(e)){
5820 if(typeof o[e] == "function"){
5822 this.addListener(e, o[e], o.scope, o);
5824 // individual options
5825 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5830 o = (!o || typeof o == "boolean") ? {} : o;
5831 eventName = eventName.toLowerCase();
5832 var ce = this.events[eventName] || true;
5833 if(typeof ce == "boolean"){
5834 ce = new Roo.util.Event(this, eventName);
5835 this.events[eventName] = ce;
5837 ce.addListener(fn, scope, o);
5841 * Removes a listener
5842 * @param {String} eventName The type of event to listen for
5843 * @param {Function} handler The handler to remove
5844 * @param {Object} scope (optional) The scope (this object) for the handler
5846 removeListener : function(eventName, fn, scope){
5847 var ce = this.events[eventName.toLowerCase()];
5848 if(typeof ce == "object"){
5849 ce.removeListener(fn, scope);
5854 * Removes all listeners for this object
5856 purgeListeners : function(){
5857 for(var evt in this.events){
5858 if(typeof this.events[evt] == "object"){
5859 this.events[evt].clearListeners();
5864 relayEvents : function(o, events){
5865 var createHandler = function(ename){
5867 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5870 for(var i = 0, len = events.length; i < len; i++){
5871 var ename = events[i];
5872 if(!this.events[ename]){ this.events[ename] = true; };
5873 o.on(ename, createHandler(ename), this);
5878 * Used to define events on this Observable
5879 * @param {Object} object The object with the events defined
5881 addEvents : function(o){
5885 Roo.applyIf(this.events, o);
5889 * Checks to see if this object has any listeners for a specified event
5890 * @param {String} eventName The name of the event to check for
5891 * @return {Boolean} True if the event is being listened for, else false
5893 hasListener : function(eventName){
5894 var e = this.events[eventName];
5895 return typeof e == "object" && e.listeners.length > 0;
5899 * Appends an event handler to this element (shorthand for addListener)
5900 * @param {String} eventName The type of event to listen for
5901 * @param {Function} handler The method the event invokes
5902 * @param {Object} scope (optional) The scope in which to execute the handler
5903 * function. The handler function's "this" context.
5904 * @param {Object} options (optional)
5907 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5909 * Removes a listener (shorthand for removeListener)
5910 * @param {String} eventName The type of event to listen for
5911 * @param {Function} handler The handler to remove
5912 * @param {Object} scope (optional) The scope (this object) for the handler
5915 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5918 * Starts capture on the specified Observable. All events will be passed
5919 * to the supplied function with the event name + standard signature of the event
5920 * <b>before</b> the event is fired. If the supplied function returns false,
5921 * the event will not fire.
5922 * @param {Observable} o The Observable to capture
5923 * @param {Function} fn The function to call
5924 * @param {Object} scope (optional) The scope (this object) for the fn
5927 Roo.util.Observable.capture = function(o, fn, scope){
5928 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5932 * Removes <b>all</b> added captures from the Observable.
5933 * @param {Observable} o The Observable to release
5936 Roo.util.Observable.releaseCapture = function(o){
5937 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5942 var createBuffered = function(h, o, scope){
5943 var task = new Roo.util.DelayedTask();
5945 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5949 var createSingle = function(h, e, fn, scope){
5951 e.removeListener(fn, scope);
5952 return h.apply(scope, arguments);
5956 var createDelayed = function(h, o, scope){
5958 var args = Array.prototype.slice.call(arguments, 0);
5959 setTimeout(function(){
5960 h.apply(scope, args);
5965 Roo.util.Event = function(obj, name){
5968 this.listeners = [];
5971 Roo.util.Event.prototype = {
5972 addListener : function(fn, scope, options){
5973 var o = options || {};
5974 scope = scope || this.obj;
5975 if(!this.isListening(fn, scope)){
5976 var l = {fn: fn, scope: scope, options: o};
5979 h = createDelayed(h, o, scope);
5982 h = createSingle(h, this, fn, scope);
5985 h = createBuffered(h, o, scope);
5988 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5989 this.listeners.push(l);
5991 this.listeners = this.listeners.slice(0);
5992 this.listeners.push(l);
5997 findListener : function(fn, scope){
5998 scope = scope || this.obj;
5999 var ls = this.listeners;
6000 for(var i = 0, len = ls.length; i < len; i++){
6002 if(l.fn == fn && l.scope == scope){
6009 isListening : function(fn, scope){
6010 return this.findListener(fn, scope) != -1;
6013 removeListener : function(fn, scope){
6015 if((index = this.findListener(fn, scope)) != -1){
6017 this.listeners.splice(index, 1);
6019 this.listeners = this.listeners.slice(0);
6020 this.listeners.splice(index, 1);
6027 clearListeners : function(){
6028 this.listeners = [];
6032 var ls = this.listeners, scope, len = ls.length;
6035 var args = Array.prototype.slice.call(arguments, 0);
6036 for(var i = 0; i < len; i++){
6038 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6039 this.firing = false;
6043 this.firing = false;
6050 * Ext JS Library 1.1.1
6051 * Copyright(c) 2006-2007, Ext JS, LLC.
6053 * Originally Released Under LGPL - original licence link has changed is not relivant.
6056 * <script type="text/javascript">
6060 * @class Roo.EventManager
6061 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6062 * several useful events directly.
6063 * See {@link Roo.EventObject} for more details on normalized event objects.
6066 Roo.EventManager = function(){
6067 var docReadyEvent, docReadyProcId, docReadyState = false;
6068 var resizeEvent, resizeTask, textEvent, textSize;
6069 var E = Roo.lib.Event;
6070 var D = Roo.lib.Dom;
6075 var fireDocReady = function(){
6077 docReadyState = true;
6080 clearInterval(docReadyProcId);
6082 if(Roo.isGecko || Roo.isOpera) {
6083 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6086 var defer = document.getElementById("ie-deferred-loader");
6088 defer.onreadystatechange = null;
6089 defer.parentNode.removeChild(defer);
6093 docReadyEvent.fire();
6094 docReadyEvent.clearListeners();
6099 var initDocReady = function(){
6100 docReadyEvent = new Roo.util.Event();
6101 if(Roo.isGecko || Roo.isOpera) {
6102 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6104 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6105 var defer = document.getElementById("ie-deferred-loader");
6106 defer.onreadystatechange = function(){
6107 if(this.readyState == "complete"){
6111 }else if(Roo.isSafari){
6112 docReadyProcId = setInterval(function(){
6113 var rs = document.readyState;
6114 if(rs == "complete") {
6119 // no matter what, make sure it fires on load
6120 E.on(window, "load", fireDocReady);
6123 var createBuffered = function(h, o){
6124 var task = new Roo.util.DelayedTask(h);
6126 // create new event object impl so new events don't wipe out properties
6127 e = new Roo.EventObjectImpl(e);
6128 task.delay(o.buffer, h, null, [e]);
6132 var createSingle = function(h, el, ename, fn){
6134 Roo.EventManager.removeListener(el, ename, fn);
6139 var createDelayed = function(h, o){
6141 // create new event object impl so new events don't wipe out properties
6142 e = new Roo.EventObjectImpl(e);
6143 setTimeout(function(){
6148 var transitionEndVal = false;
6150 var transitionEnd = function()
6152 if (transitionEndVal) {
6153 return transitionEndVal;
6155 var el = document.createElement('div');
6157 var transEndEventNames = {
6158 WebkitTransition : 'webkitTransitionEnd',
6159 MozTransition : 'transitionend',
6160 OTransition : 'oTransitionEnd otransitionend',
6161 transition : 'transitionend'
6164 for (var name in transEndEventNames) {
6165 if (el.style[name] !== undefined) {
6166 transitionEndVal = transEndEventNames[name];
6167 return transitionEndVal ;
6173 var listen = function(element, ename, opt, fn, scope){
6174 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6175 fn = fn || o.fn; scope = scope || o.scope;
6176 var el = Roo.getDom(element);
6180 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6183 if (ename == 'transitionend') {
6184 ename = transitionEnd();
6186 var h = function(e){
6187 e = Roo.EventObject.setEvent(e);
6190 t = e.getTarget(o.delegate, el);
6197 if(o.stopEvent === true){
6200 if(o.preventDefault === true){
6203 if(o.stopPropagation === true){
6204 e.stopPropagation();
6207 if(o.normalized === false){
6211 fn.call(scope || el, e, t, o);
6214 h = createDelayed(h, o);
6217 h = createSingle(h, el, ename, fn);
6220 h = createBuffered(h, o);
6222 fn._handlers = fn._handlers || [];
6225 fn._handlers.push([Roo.id(el), ename, h]);
6230 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6231 el.addEventListener("DOMMouseScroll", h, false);
6232 E.on(window, 'unload', function(){
6233 el.removeEventListener("DOMMouseScroll", h, false);
6236 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6237 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6242 var stopListening = function(el, ename, fn){
6243 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6245 for(var i = 0, len = hds.length; i < len; i++){
6247 if(h[0] == id && h[1] == ename){
6254 E.un(el, ename, hd);
6255 el = Roo.getDom(el);
6256 if(ename == "mousewheel" && el.addEventListener){
6257 el.removeEventListener("DOMMouseScroll", hd, false);
6259 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6260 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6264 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6271 * @scope Roo.EventManager
6276 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6277 * object with a Roo.EventObject
6278 * @param {Function} fn The method the event invokes
6279 * @param {Object} scope An object that becomes the scope of the handler
6280 * @param {boolean} override If true, the obj passed in becomes
6281 * the execution scope of the listener
6282 * @return {Function} The wrapped function
6285 wrap : function(fn, scope, override){
6287 Roo.EventObject.setEvent(e);
6288 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6293 * Appends an event handler to an element (shorthand for addListener)
6294 * @param {String/HTMLElement} element The html element or id to assign the
6295 * @param {String} eventName The type of event to listen for
6296 * @param {Function} handler The method the event invokes
6297 * @param {Object} scope (optional) The scope in which to execute the handler
6298 * function. The handler function's "this" context.
6299 * @param {Object} options (optional) An object containing handler configuration
6300 * properties. This may contain any of the following properties:<ul>
6301 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6302 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6303 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6304 * <li>preventDefault {Boolean} True to prevent the default action</li>
6305 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6306 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6307 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6308 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6309 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6310 * by the specified number of milliseconds. If the event fires again within that time, the original
6311 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6314 * <b>Combining Options</b><br>
6315 * Using the options argument, it is possible to combine different types of listeners:<br>
6317 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6319 el.on('click', this.onClick, this, {
6326 * <b>Attaching multiple handlers in 1 call</b><br>
6327 * The method also allows for a single argument to be passed which is a config object containing properties
6328 * which specify multiple handlers.
6338 fn: this.onMouseOver
6347 * Or a shorthand syntax:<br>
6350 'click' : this.onClick,
6351 'mouseover' : this.onMouseOver,
6352 'mouseout' : this.onMouseOut
6356 addListener : function(element, eventName, fn, scope, options){
6357 if(typeof eventName == "object"){
6363 if(typeof o[e] == "function"){
6365 listen(element, e, o, o[e], o.scope);
6367 // individual options
6368 listen(element, e, o[e]);
6373 return listen(element, eventName, options, fn, scope);
6377 * Removes an event handler
6379 * @param {String/HTMLElement} element The id or html element to remove the
6381 * @param {String} eventName The type of event
6382 * @param {Function} fn
6383 * @return {Boolean} True if a listener was actually removed
6385 removeListener : function(element, eventName, fn){
6386 return stopListening(element, eventName, fn);
6390 * Fires when the document is ready (before onload and before images are loaded). Can be
6391 * accessed shorthanded Roo.onReady().
6392 * @param {Function} fn The method the event invokes
6393 * @param {Object} scope An object that becomes the scope of the handler
6394 * @param {boolean} options
6396 onDocumentReady : function(fn, scope, options){
6397 if(docReadyState){ // if it already fired
6398 docReadyEvent.addListener(fn, scope, options);
6399 docReadyEvent.fire();
6400 docReadyEvent.clearListeners();
6406 docReadyEvent.addListener(fn, scope, options);
6410 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6411 * @param {Function} fn The method the event invokes
6412 * @param {Object} scope An object that becomes the scope of the handler
6413 * @param {boolean} options
6415 onWindowResize : function(fn, scope, options){
6417 resizeEvent = new Roo.util.Event();
6418 resizeTask = new Roo.util.DelayedTask(function(){
6419 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6421 E.on(window, "resize", function(){
6423 resizeTask.delay(50);
6425 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6429 resizeEvent.addListener(fn, scope, options);
6433 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6434 * @param {Function} fn The method the event invokes
6435 * @param {Object} scope An object that becomes the scope of the handler
6436 * @param {boolean} options
6438 onTextResize : function(fn, scope, options){
6440 textEvent = new Roo.util.Event();
6441 var textEl = new Roo.Element(document.createElement('div'));
6442 textEl.dom.className = 'x-text-resize';
6443 textEl.dom.innerHTML = 'X';
6444 textEl.appendTo(document.body);
6445 textSize = textEl.dom.offsetHeight;
6446 setInterval(function(){
6447 if(textEl.dom.offsetHeight != textSize){
6448 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6450 }, this.textResizeInterval);
6452 textEvent.addListener(fn, scope, options);
6456 * Removes the passed window resize listener.
6457 * @param {Function} fn The method the event invokes
6458 * @param {Object} scope The scope of handler
6460 removeResizeListener : function(fn, scope){
6462 resizeEvent.removeListener(fn, scope);
6467 fireResize : function(){
6469 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6473 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6477 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6479 textResizeInterval : 50
6484 * @scopeAlias pub=Roo.EventManager
6488 * Appends an event handler to an element (shorthand for addListener)
6489 * @param {String/HTMLElement} element The html element or id to assign the
6490 * @param {String} eventName The type of event to listen for
6491 * @param {Function} handler The method the event invokes
6492 * @param {Object} scope (optional) The scope in which to execute the handler
6493 * function. The handler function's "this" context.
6494 * @param {Object} options (optional) An object containing handler configuration
6495 * properties. This may contain any of the following properties:<ul>
6496 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6497 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6498 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6499 * <li>preventDefault {Boolean} True to prevent the default action</li>
6500 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6501 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6502 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6503 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6504 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6505 * by the specified number of milliseconds. If the event fires again within that time, the original
6506 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6509 * <b>Combining Options</b><br>
6510 * Using the options argument, it is possible to combine different types of listeners:<br>
6512 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6514 el.on('click', this.onClick, this, {
6521 * <b>Attaching multiple handlers in 1 call</b><br>
6522 * The method also allows for a single argument to be passed which is a config object containing properties
6523 * which specify multiple handlers.
6533 fn: this.onMouseOver
6542 * Or a shorthand syntax:<br>
6545 'click' : this.onClick,
6546 'mouseover' : this.onMouseOver,
6547 'mouseout' : this.onMouseOut
6551 pub.on = pub.addListener;
6552 pub.un = pub.removeListener;
6554 pub.stoppedMouseDownEvent = new Roo.util.Event();
6558 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6559 * @param {Function} fn The method the event invokes
6560 * @param {Object} scope An object that becomes the scope of the handler
6561 * @param {boolean} override If true, the obj passed in becomes
6562 * the execution scope of the listener
6566 Roo.onReady = Roo.EventManager.onDocumentReady;
6568 Roo.onReady(function(){
6569 var bd = Roo.get(document.body);
6574 : Roo.isGecko ? "roo-gecko"
6575 : Roo.isOpera ? "roo-opera"
6576 : Roo.isSafari ? "roo-safari" : ""];
6579 cls.push("roo-mac");
6582 cls.push("roo-linux");
6585 cls.push("roo-ios");
6588 cls.push("roo-touch");
6590 if(Roo.isBorderBox){
6591 cls.push('roo-border-box');
6593 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6594 var p = bd.dom.parentNode;
6596 p.className += ' roo-strict';
6599 bd.addClass(cls.join(' '));
6603 * @class Roo.EventObject
6604 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6605 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6608 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6610 var target = e.getTarget();
6613 var myDiv = Roo.get("myDiv");
6614 myDiv.on("click", handleClick);
6616 Roo.EventManager.on("myDiv", 'click', handleClick);
6617 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6621 Roo.EventObject = function(){
6623 var E = Roo.lib.Event;
6625 // safari keypress events for special keys return bad keycodes
6628 63235 : 39, // right
6631 63276 : 33, // page up
6632 63277 : 34, // page down
6633 63272 : 46, // delete
6638 // normalize button clicks
6639 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6640 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6642 Roo.EventObjectImpl = function(e){
6644 this.setEvent(e.browserEvent || e);
6647 Roo.EventObjectImpl.prototype = {
6649 * Used to fix doc tools.
6650 * @scope Roo.EventObject.prototype
6656 /** The normal browser event */
6657 browserEvent : null,
6658 /** The button pressed in a mouse event */
6660 /** True if the shift key was down during the event */
6662 /** True if the control key was down during the event */
6664 /** True if the alt key was down during the event */
6723 setEvent : function(e){
6724 if(e == this || (e && e.browserEvent)){ // already wrapped
6727 this.browserEvent = e;
6729 // normalize buttons
6730 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6731 if(e.type == 'click' && this.button == -1){
6735 this.shiftKey = e.shiftKey;
6736 // mac metaKey behaves like ctrlKey
6737 this.ctrlKey = e.ctrlKey || e.metaKey;
6738 this.altKey = e.altKey;
6739 // in getKey these will be normalized for the mac
6740 this.keyCode = e.keyCode;
6741 // keyup warnings on firefox.
6742 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6743 // cache the target for the delayed and or buffered events
6744 this.target = E.getTarget(e);
6746 this.xy = E.getXY(e);
6749 this.shiftKey = false;
6750 this.ctrlKey = false;
6751 this.altKey = false;
6761 * Stop the event (preventDefault and stopPropagation)
6763 stopEvent : function(){
6764 if(this.browserEvent){
6765 if(this.browserEvent.type == 'mousedown'){
6766 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6768 E.stopEvent(this.browserEvent);
6773 * Prevents the browsers default handling of the event.
6775 preventDefault : function(){
6776 if(this.browserEvent){
6777 E.preventDefault(this.browserEvent);
6782 isNavKeyPress : function(){
6783 var k = this.keyCode;
6784 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6785 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6788 isSpecialKey : function(){
6789 var k = this.keyCode;
6790 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6791 (k == 16) || (k == 17) ||
6792 (k >= 18 && k <= 20) ||
6793 (k >= 33 && k <= 35) ||
6794 (k >= 36 && k <= 39) ||
6795 (k >= 44 && k <= 45);
6798 * Cancels bubbling of the event.
6800 stopPropagation : function(){
6801 if(this.browserEvent){
6802 if(this.type == 'mousedown'){
6803 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6805 E.stopPropagation(this.browserEvent);
6810 * Gets the key code for the event.
6813 getCharCode : function(){
6814 return this.charCode || this.keyCode;
6818 * Returns a normalized keyCode for the event.
6819 * @return {Number} The key code
6821 getKey : function(){
6822 var k = this.keyCode || this.charCode;
6823 return Roo.isSafari ? (safariKeys[k] || k) : k;
6827 * Gets the x coordinate of the event.
6830 getPageX : function(){
6835 * Gets the y coordinate of the event.
6838 getPageY : function(){
6843 * Gets the time of the event.
6846 getTime : function(){
6847 if(this.browserEvent){
6848 return E.getTime(this.browserEvent);
6854 * Gets the page coordinates of the event.
6855 * @return {Array} The xy values like [x, y]
6862 * Gets the target for the event.
6863 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6864 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6865 search as a number or element (defaults to 10 || document.body)
6866 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6867 * @return {HTMLelement}
6869 getTarget : function(selector, maxDepth, returnEl){
6870 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6873 * Gets the related target.
6874 * @return {HTMLElement}
6876 getRelatedTarget : function(){
6877 if(this.browserEvent){
6878 return E.getRelatedTarget(this.browserEvent);
6884 * Normalizes mouse wheel delta across browsers
6885 * @return {Number} The delta
6887 getWheelDelta : function(){
6888 var e = this.browserEvent;
6890 if(e.wheelDelta){ /* IE/Opera. */
6891 delta = e.wheelDelta/120;
6892 }else if(e.detail){ /* Mozilla case. */
6893 delta = -e.detail/3;
6899 * Returns true if the control, meta, shift or alt key was pressed during this event.
6902 hasModifier : function(){
6903 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6907 * Returns true if the target of this event equals el or is a child of el
6908 * @param {String/HTMLElement/Element} el
6909 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6912 within : function(el, related){
6913 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6914 return t && Roo.fly(el).contains(t);
6917 getPoint : function(){
6918 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6922 return new Roo.EventObjectImpl();
6927 * Ext JS Library 1.1.1
6928 * Copyright(c) 2006-2007, Ext JS, LLC.
6930 * Originally Released Under LGPL - original licence link has changed is not relivant.
6933 * <script type="text/javascript">
6937 // was in Composite Element!??!?!
6940 var D = Roo.lib.Dom;
6941 var E = Roo.lib.Event;
6942 var A = Roo.lib.Anim;
6944 // local style camelizing for speed
6946 var camelRe = /(-[a-z])/gi;
6947 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6948 var view = document.defaultView;
6951 * @class Roo.Element
6952 * Represents an Element in the DOM.<br><br>
6955 var el = Roo.get("my-div");
6958 var el = getEl("my-div");
6960 // or with a DOM element
6961 var el = Roo.get(myDivElement);
6963 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6964 * each call instead of constructing a new one.<br><br>
6965 * <b>Animations</b><br />
6966 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6967 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6969 Option Default Description
6970 --------- -------- ---------------------------------------------
6971 duration .35 The duration of the animation in seconds
6972 easing easeOut The YUI easing method
6973 callback none A function to execute when the anim completes
6974 scope this The scope (this) of the callback function
6976 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6977 * manipulate the animation. Here's an example:
6979 var el = Roo.get("my-div");
6984 // default animation
6985 el.setWidth(100, true);
6987 // animation with some options set
6994 // using the "anim" property to get the Anim object
7000 el.setWidth(100, opt);
7002 if(opt.anim.isAnimated()){
7006 * <b> Composite (Collections of) Elements</b><br />
7007 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7008 * @constructor Create a new Element directly.
7009 * @param {String/HTMLElement} element
7010 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
7012 Roo.Element = function(element, forceNew){
7013 var dom = typeof element == "string" ?
7014 document.getElementById(element) : element;
7015 if(!dom){ // invalid id/element
7019 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7020 return Roo.Element.cache[id];
7030 * The DOM element ID
7033 this.id = id || Roo.id(dom);
7036 var El = Roo.Element;
7040 * The element's default display mode (defaults to "")
7043 originalDisplay : "",
7047 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7053 * Sets the element's visibility mode. When setVisible() is called it
7054 * will use this to determine whether to set the visibility or the display property.
7055 * @param visMode Element.VISIBILITY or Element.DISPLAY
7056 * @return {Roo.Element} this
7058 setVisibilityMode : function(visMode){
7059 this.visibilityMode = visMode;
7063 * Convenience method for setVisibilityMode(Element.DISPLAY)
7064 * @param {String} display (optional) What to set display to when visible
7065 * @return {Roo.Element} this
7067 enableDisplayMode : function(display){
7068 this.setVisibilityMode(El.DISPLAY);
7069 if(typeof display != "undefined") this.originalDisplay = display;
7074 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7075 * @param {String} selector The simple selector to test
7076 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7077 search as a number or element (defaults to 10 || document.body)
7078 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7079 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7081 findParent : function(simpleSelector, maxDepth, returnEl){
7082 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7083 maxDepth = maxDepth || 50;
7084 if(typeof maxDepth != "number"){
7085 stopEl = Roo.getDom(maxDepth);
7088 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7089 if(dq.is(p, simpleSelector)){
7090 return returnEl ? Roo.get(p) : p;
7100 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7101 * @param {String} selector The simple selector to test
7102 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7103 search as a number or element (defaults to 10 || document.body)
7104 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7105 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7107 findParentNode : function(simpleSelector, maxDepth, returnEl){
7108 var p = Roo.fly(this.dom.parentNode, '_internal');
7109 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7113 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7114 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7115 * @param {String} selector The simple selector to test
7116 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7117 search as a number or element (defaults to 10 || document.body)
7118 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7120 up : function(simpleSelector, maxDepth){
7121 return this.findParentNode(simpleSelector, maxDepth, true);
7127 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7128 * @param {String} selector The simple selector to test
7129 * @return {Boolean} True if this element matches the selector, else false
7131 is : function(simpleSelector){
7132 return Roo.DomQuery.is(this.dom, simpleSelector);
7136 * Perform animation on this element.
7137 * @param {Object} args The YUI animation control args
7138 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7139 * @param {Function} onComplete (optional) Function to call when animation completes
7140 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7141 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7142 * @return {Roo.Element} this
7144 animate : function(args, duration, onComplete, easing, animType){
7145 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7150 * @private Internal animation call
7152 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7153 animType = animType || 'run';
7155 var anim = Roo.lib.Anim[animType](
7157 (opt.duration || defaultDur) || .35,
7158 (opt.easing || defaultEase) || 'easeOut',
7160 Roo.callback(cb, this);
7161 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7169 // private legacy anim prep
7170 preanim : function(a, i){
7171 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7175 * Removes worthless text nodes
7176 * @param {Boolean} forceReclean (optional) By default the element
7177 * keeps track if it has been cleaned already so
7178 * you can call this over and over. However, if you update the element and
7179 * need to force a reclean, you can pass true.
7181 clean : function(forceReclean){
7182 if(this.isCleaned && forceReclean !== true){
7186 var d = this.dom, n = d.firstChild, ni = -1;
7188 var nx = n.nextSibling;
7189 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7196 this.isCleaned = true;
7201 calcOffsetsTo : function(el){
7204 var restorePos = false;
7205 if(el.getStyle('position') == 'static'){
7206 el.position('relative');
7211 while(op && op != d && op.tagName != 'HTML'){
7214 op = op.offsetParent;
7217 el.position('static');
7223 * Scrolls this element into view within the passed container.
7224 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7225 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7226 * @return {Roo.Element} this
7228 scrollIntoView : function(container, hscroll){
7229 var c = Roo.getDom(container) || document.body;
7232 var o = this.calcOffsetsTo(c),
7235 b = t+el.offsetHeight,
7236 r = l+el.offsetWidth;
7238 var ch = c.clientHeight;
7239 var ct = parseInt(c.scrollTop, 10);
7240 var cl = parseInt(c.scrollLeft, 10);
7242 var cr = cl + c.clientWidth;
7250 if(hscroll !== false){
7254 c.scrollLeft = r-c.clientWidth;
7261 scrollChildIntoView : function(child, hscroll){
7262 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7266 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7267 * the new height may not be available immediately.
7268 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7269 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7270 * @param {Function} onComplete (optional) Function to call when animation completes
7271 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7272 * @return {Roo.Element} this
7274 autoHeight : function(animate, duration, onComplete, easing){
7275 var oldHeight = this.getHeight();
7277 this.setHeight(1); // force clipping
7278 setTimeout(function(){
7279 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7281 this.setHeight(height);
7283 if(typeof onComplete == "function"){
7287 this.setHeight(oldHeight); // restore original height
7288 this.setHeight(height, animate, duration, function(){
7290 if(typeof onComplete == "function") onComplete();
7291 }.createDelegate(this), easing);
7293 }.createDelegate(this), 0);
7298 * Returns true if this element is an ancestor of the passed element
7299 * @param {HTMLElement/String} el The element to check
7300 * @return {Boolean} True if this element is an ancestor of el, else false
7302 contains : function(el){
7303 if(!el){return false;}
7304 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7308 * Checks whether the element is currently visible using both visibility and display properties.
7309 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7310 * @return {Boolean} True if the element is currently visible, else false
7312 isVisible : function(deep) {
7313 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7314 if(deep !== true || !vis){
7317 var p = this.dom.parentNode;
7318 while(p && p.tagName.toLowerCase() != "body"){
7319 if(!Roo.fly(p, '_isVisible').isVisible()){
7328 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7329 * @param {String} selector The CSS selector
7330 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7331 * @return {CompositeElement/CompositeElementLite} The composite element
7333 select : function(selector, unique){
7334 return El.select(selector, unique, this.dom);
7338 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7339 * @param {String} selector The CSS selector
7340 * @return {Array} An array of the matched nodes
7342 query : function(selector, unique){
7343 return Roo.DomQuery.select(selector, this.dom);
7347 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7348 * @param {String} selector The CSS selector
7349 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7350 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7352 child : function(selector, returnDom){
7353 var n = Roo.DomQuery.selectNode(selector, this.dom);
7354 return returnDom ? n : Roo.get(n);
7358 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7359 * @param {String} selector The CSS selector
7360 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7361 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7363 down : function(selector, returnDom){
7364 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7365 return returnDom ? n : Roo.get(n);
7369 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7370 * @param {String} group The group the DD object is member of
7371 * @param {Object} config The DD config object
7372 * @param {Object} overrides An object containing methods to override/implement on the DD object
7373 * @return {Roo.dd.DD} The DD object
7375 initDD : function(group, config, overrides){
7376 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7377 return Roo.apply(dd, overrides);
7381 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7382 * @param {String} group The group the DDProxy object is member of
7383 * @param {Object} config The DDProxy config object
7384 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7385 * @return {Roo.dd.DDProxy} The DDProxy object
7387 initDDProxy : function(group, config, overrides){
7388 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7389 return Roo.apply(dd, overrides);
7393 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7394 * @param {String} group The group the DDTarget object is member of
7395 * @param {Object} config The DDTarget config object
7396 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7397 * @return {Roo.dd.DDTarget} The DDTarget object
7399 initDDTarget : function(group, config, overrides){
7400 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7401 return Roo.apply(dd, overrides);
7405 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7406 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7407 * @param {Boolean} visible Whether the element is visible
7408 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7409 * @return {Roo.Element} this
7411 setVisible : function(visible, animate){
7413 if(this.visibilityMode == El.DISPLAY){
7414 this.setDisplayed(visible);
7417 this.dom.style.visibility = visible ? "visible" : "hidden";
7420 // closure for composites
7422 var visMode = this.visibilityMode;
7424 this.setOpacity(.01);
7425 this.setVisible(true);
7427 this.anim({opacity: { to: (visible?1:0) }},
7428 this.preanim(arguments, 1),
7429 null, .35, 'easeIn', function(){
7431 if(visMode == El.DISPLAY){
7432 dom.style.display = "none";
7434 dom.style.visibility = "hidden";
7436 Roo.get(dom).setOpacity(1);
7444 * Returns true if display is not "none"
7447 isDisplayed : function() {
7448 return this.getStyle("display") != "none";
7452 * Toggles the element's visibility or display, depending on visibility mode.
7453 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7454 * @return {Roo.Element} this
7456 toggle : function(animate){
7457 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7462 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7463 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7464 * @return {Roo.Element} this
7466 setDisplayed : function(value) {
7467 if(typeof value == "boolean"){
7468 value = value ? this.originalDisplay : "none";
7470 this.setStyle("display", value);
7475 * Tries to focus the element. Any exceptions are caught and ignored.
7476 * @return {Roo.Element} this
7478 focus : function() {
7486 * Tries to blur the element. Any exceptions are caught and ignored.
7487 * @return {Roo.Element} this
7497 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7498 * @param {String/Array} className The CSS class to add, or an array of classes
7499 * @return {Roo.Element} this
7501 addClass : function(className){
7502 if(className instanceof Array){
7503 for(var i = 0, len = className.length; i < len; i++) {
7504 this.addClass(className[i]);
7507 if(className && !this.hasClass(className)){
7508 this.dom.className = this.dom.className + " " + className;
7515 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7516 * @param {String/Array} className The CSS class to add, or an array of classes
7517 * @return {Roo.Element} this
7519 radioClass : function(className){
7520 var siblings = this.dom.parentNode.childNodes;
7521 for(var i = 0; i < siblings.length; i++) {
7522 var s = siblings[i];
7523 if(s.nodeType == 1){
7524 Roo.get(s).removeClass(className);
7527 this.addClass(className);
7532 * Removes one or more CSS classes from the element.
7533 * @param {String/Array} className The CSS class to remove, or an array of classes
7534 * @return {Roo.Element} this
7536 removeClass : function(className){
7537 if(!className || !this.dom.className){
7540 if(className instanceof Array){
7541 for(var i = 0, len = className.length; i < len; i++) {
7542 this.removeClass(className[i]);
7545 if(this.hasClass(className)){
7546 var re = this.classReCache[className];
7548 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7549 this.classReCache[className] = re;
7551 this.dom.className =
7552 this.dom.className.replace(re, " ");
7562 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7563 * @param {String} className The CSS class to toggle
7564 * @return {Roo.Element} this
7566 toggleClass : function(className){
7567 if(this.hasClass(className)){
7568 this.removeClass(className);
7570 this.addClass(className);
7576 * Checks if the specified CSS class exists on this element's DOM node.
7577 * @param {String} className The CSS class to check for
7578 * @return {Boolean} True if the class exists, else false
7580 hasClass : function(className){
7581 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7585 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7586 * @param {String} oldClassName The CSS class to replace
7587 * @param {String} newClassName The replacement CSS class
7588 * @return {Roo.Element} this
7590 replaceClass : function(oldClassName, newClassName){
7591 this.removeClass(oldClassName);
7592 this.addClass(newClassName);
7597 * Returns an object with properties matching the styles requested.
7598 * For example, el.getStyles('color', 'font-size', 'width') might return
7599 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7600 * @param {String} style1 A style name
7601 * @param {String} style2 A style name
7602 * @param {String} etc.
7603 * @return {Object} The style object
7605 getStyles : function(){
7606 var a = arguments, len = a.length, r = {};
7607 for(var i = 0; i < len; i++){
7608 r[a[i]] = this.getStyle(a[i]);
7614 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7615 * @param {String} property The style property whose value is returned.
7616 * @return {String} The current value of the style property for this element.
7618 getStyle : function(){
7619 return view && view.getComputedStyle ?
7621 var el = this.dom, v, cs, camel;
7622 if(prop == 'float'){
7625 if(el.style && (v = el.style[prop])){
7628 if(cs = view.getComputedStyle(el, "")){
7629 if(!(camel = propCache[prop])){
7630 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7637 var el = this.dom, v, cs, camel;
7638 if(prop == 'opacity'){
7639 if(typeof el.style.filter == 'string'){
7640 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7642 var fv = parseFloat(m[1]);
7644 return fv ? fv / 100 : 0;
7649 }else if(prop == 'float'){
7650 prop = "styleFloat";
7652 if(!(camel = propCache[prop])){
7653 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7655 if(v = el.style[camel]){
7658 if(cs = el.currentStyle){
7666 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7667 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7668 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7669 * @return {Roo.Element} this
7671 setStyle : function(prop, value){
7672 if(typeof prop == "string"){
7674 if (prop == 'float') {
7675 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7680 if(!(camel = propCache[prop])){
7681 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7684 if(camel == 'opacity') {
7685 this.setOpacity(value);
7687 this.dom.style[camel] = value;
7690 for(var style in prop){
7691 if(typeof prop[style] != "function"){
7692 this.setStyle(style, prop[style]);
7700 * More flexible version of {@link #setStyle} for setting style properties.
7701 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7702 * a function which returns such a specification.
7703 * @return {Roo.Element} this
7705 applyStyles : function(style){
7706 Roo.DomHelper.applyStyles(this.dom, style);
7711 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7712 * @return {Number} The X position of the element
7715 return D.getX(this.dom);
7719 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7720 * @return {Number} The Y position of the element
7723 return D.getY(this.dom);
7727 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7728 * @return {Array} The XY position of the element
7731 return D.getXY(this.dom);
7735 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7736 * @param {Number} The X position of the element
7737 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7738 * @return {Roo.Element} this
7740 setX : function(x, animate){
7742 D.setX(this.dom, x);
7744 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7750 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7751 * @param {Number} The Y position of the element
7752 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7753 * @return {Roo.Element} this
7755 setY : function(y, animate){
7757 D.setY(this.dom, y);
7759 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7765 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7766 * @param {String} left The left CSS property value
7767 * @return {Roo.Element} this
7769 setLeft : function(left){
7770 this.setStyle("left", this.addUnits(left));
7775 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7776 * @param {String} top The top CSS property value
7777 * @return {Roo.Element} this
7779 setTop : function(top){
7780 this.setStyle("top", this.addUnits(top));
7785 * Sets the element's CSS right style.
7786 * @param {String} right The right CSS property value
7787 * @return {Roo.Element} this
7789 setRight : function(right){
7790 this.setStyle("right", this.addUnits(right));
7795 * Sets the element's CSS bottom style.
7796 * @param {String} bottom The bottom CSS property value
7797 * @return {Roo.Element} this
7799 setBottom : function(bottom){
7800 this.setStyle("bottom", this.addUnits(bottom));
7805 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7806 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7807 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7808 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7809 * @return {Roo.Element} this
7811 setXY : function(pos, animate){
7813 D.setXY(this.dom, pos);
7815 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7821 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7822 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7823 * @param {Number} x X value for new position (coordinates are page-based)
7824 * @param {Number} y Y value for new position (coordinates are page-based)
7825 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7826 * @return {Roo.Element} this
7828 setLocation : function(x, y, animate){
7829 this.setXY([x, y], this.preanim(arguments, 2));
7834 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7835 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7836 * @param {Number} x X value for new position (coordinates are page-based)
7837 * @param {Number} y Y value for new position (coordinates are page-based)
7838 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7839 * @return {Roo.Element} this
7841 moveTo : function(x, y, animate){
7842 this.setXY([x, y], this.preanim(arguments, 2));
7847 * Returns the region of the given element.
7848 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7849 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7851 getRegion : function(){
7852 return D.getRegion(this.dom);
7856 * Returns the offset height of the element
7857 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7858 * @return {Number} The element's height
7860 getHeight : function(contentHeight){
7861 var h = this.dom.offsetHeight || 0;
7862 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7866 * Returns the offset width of the element
7867 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7868 * @return {Number} The element's width
7870 getWidth : function(contentWidth){
7871 var w = this.dom.offsetWidth || 0;
7872 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7876 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7877 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7878 * if a height has not been set using CSS.
7881 getComputedHeight : function(){
7882 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7884 h = parseInt(this.getStyle('height'), 10) || 0;
7885 if(!this.isBorderBox()){
7886 h += this.getFrameWidth('tb');
7893 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7894 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7895 * if a width has not been set using CSS.
7898 getComputedWidth : function(){
7899 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7901 w = parseInt(this.getStyle('width'), 10) || 0;
7902 if(!this.isBorderBox()){
7903 w += this.getFrameWidth('lr');
7910 * Returns the size of the element.
7911 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7912 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7914 getSize : function(contentSize){
7915 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7919 * Returns the width and height of the viewport.
7920 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7922 getViewSize : function(){
7923 var d = this.dom, doc = document, aw = 0, ah = 0;
7924 if(d == doc || d == doc.body){
7925 return {width : D.getViewWidth(), height: D.getViewHeight()};
7928 width : d.clientWidth,
7929 height: d.clientHeight
7935 * Returns the value of the "value" attribute
7936 * @param {Boolean} asNumber true to parse the value as a number
7937 * @return {String/Number}
7939 getValue : function(asNumber){
7940 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7944 adjustWidth : function(width){
7945 if(typeof width == "number"){
7946 if(this.autoBoxAdjust && !this.isBorderBox()){
7947 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7957 adjustHeight : function(height){
7958 if(typeof height == "number"){
7959 if(this.autoBoxAdjust && !this.isBorderBox()){
7960 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7970 * Set the width of the element
7971 * @param {Number} width The new width
7972 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7973 * @return {Roo.Element} this
7975 setWidth : function(width, animate){
7976 width = this.adjustWidth(width);
7978 this.dom.style.width = this.addUnits(width);
7980 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7986 * Set the height of the element
7987 * @param {Number} height The new height
7988 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7989 * @return {Roo.Element} this
7991 setHeight : function(height, animate){
7992 height = this.adjustHeight(height);
7994 this.dom.style.height = this.addUnits(height);
7996 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8002 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8003 * @param {Number} width The new width
8004 * @param {Number} height The new height
8005 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8006 * @return {Roo.Element} this
8008 setSize : function(width, height, animate){
8009 if(typeof width == "object"){ // in case of object from getSize()
8010 height = width.height; width = width.width;
8012 width = this.adjustWidth(width); height = this.adjustHeight(height);
8014 this.dom.style.width = this.addUnits(width);
8015 this.dom.style.height = this.addUnits(height);
8017 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8023 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8024 * @param {Number} x X value for new position (coordinates are page-based)
8025 * @param {Number} y Y value for new position (coordinates are page-based)
8026 * @param {Number} width The new width
8027 * @param {Number} height The new height
8028 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8029 * @return {Roo.Element} this
8031 setBounds : function(x, y, width, height, animate){
8033 this.setSize(width, height);
8034 this.setLocation(x, y);
8036 width = this.adjustWidth(width); height = this.adjustHeight(height);
8037 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8038 this.preanim(arguments, 4), 'motion');
8044 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
8045 * @param {Roo.lib.Region} region The region to fill
8046 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8047 * @return {Roo.Element} this
8049 setRegion : function(region, animate){
8050 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8055 * Appends an event handler
8057 * @param {String} eventName The type of event to append
8058 * @param {Function} fn The method the event invokes
8059 * @param {Object} scope (optional) The scope (this object) of the fn
8060 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8062 addListener : function(eventName, fn, scope, options){
8064 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8069 * Removes an event handler from this element
8070 * @param {String} eventName the type of event to remove
8071 * @param {Function} fn the method the event invokes
8072 * @return {Roo.Element} this
8074 removeListener : function(eventName, fn){
8075 Roo.EventManager.removeListener(this.dom, eventName, fn);
8080 * Removes all previous added listeners from this element
8081 * @return {Roo.Element} this
8083 removeAllListeners : function(){
8084 E.purgeElement(this.dom);
8088 relayEvent : function(eventName, observable){
8089 this.on(eventName, function(e){
8090 observable.fireEvent(eventName, e);
8095 * Set the opacity of the element
8096 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8097 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8098 * @return {Roo.Element} this
8100 setOpacity : function(opacity, animate){
8102 var s = this.dom.style;
8105 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8106 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8108 s.opacity = opacity;
8111 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8117 * Gets the left X coordinate
8118 * @param {Boolean} local True to get the local css position instead of page coordinate
8121 getLeft : function(local){
8125 return parseInt(this.getStyle("left"), 10) || 0;
8130 * Gets the right X coordinate of the element (element X position + element width)
8131 * @param {Boolean} local True to get the local css position instead of page coordinate
8134 getRight : function(local){
8136 return this.getX() + this.getWidth();
8138 return (this.getLeft(true) + this.getWidth()) || 0;
8143 * Gets the top Y coordinate
8144 * @param {Boolean} local True to get the local css position instead of page coordinate
8147 getTop : function(local) {
8151 return parseInt(this.getStyle("top"), 10) || 0;
8156 * Gets the bottom Y coordinate of the element (element Y position + element height)
8157 * @param {Boolean} local True to get the local css position instead of page coordinate
8160 getBottom : function(local){
8162 return this.getY() + this.getHeight();
8164 return (this.getTop(true) + this.getHeight()) || 0;
8169 * Initializes positioning on this element. If a desired position is not passed, it will make the
8170 * the element positioned relative IF it is not already positioned.
8171 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8172 * @param {Number} zIndex (optional) The zIndex to apply
8173 * @param {Number} x (optional) Set the page X position
8174 * @param {Number} y (optional) Set the page Y position
8176 position : function(pos, zIndex, x, y){
8178 if(this.getStyle('position') == 'static'){
8179 this.setStyle('position', 'relative');
8182 this.setStyle("position", pos);
8185 this.setStyle("z-index", zIndex);
8187 if(x !== undefined && y !== undefined){
8189 }else if(x !== undefined){
8191 }else if(y !== undefined){
8197 * Clear positioning back to the default when the document was loaded
8198 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8199 * @return {Roo.Element} this
8201 clearPositioning : function(value){
8209 "position" : "static"
8215 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8216 * snapshot before performing an update and then restoring the element.
8219 getPositioning : function(){
8220 var l = this.getStyle("left");
8221 var t = this.getStyle("top");
8223 "position" : this.getStyle("position"),
8225 "right" : l ? "" : this.getStyle("right"),
8227 "bottom" : t ? "" : this.getStyle("bottom"),
8228 "z-index" : this.getStyle("z-index")
8233 * Gets the width of the border(s) for the specified side(s)
8234 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8235 * passing lr would get the border (l)eft width + the border (r)ight width.
8236 * @return {Number} The width of the sides passed added together
8238 getBorderWidth : function(side){
8239 return this.addStyles(side, El.borders);
8243 * Gets the width of the padding(s) for the specified side(s)
8244 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8245 * passing lr would get the padding (l)eft + the padding (r)ight.
8246 * @return {Number} The padding of the sides passed added together
8248 getPadding : function(side){
8249 return this.addStyles(side, El.paddings);
8253 * Set positioning with an object returned by getPositioning().
8254 * @param {Object} posCfg
8255 * @return {Roo.Element} this
8257 setPositioning : function(pc){
8258 this.applyStyles(pc);
8259 if(pc.right == "auto"){
8260 this.dom.style.right = "";
8262 if(pc.bottom == "auto"){
8263 this.dom.style.bottom = "";
8269 fixDisplay : function(){
8270 if(this.getStyle("display") == "none"){
8271 this.setStyle("visibility", "hidden");
8272 this.setStyle("display", this.originalDisplay); // first try reverting to default
8273 if(this.getStyle("display") == "none"){ // if that fails, default to block
8274 this.setStyle("display", "block");
8280 * Quick set left and top adding default units
8281 * @param {String} left The left CSS property value
8282 * @param {String} top The top CSS property value
8283 * @return {Roo.Element} this
8285 setLeftTop : function(left, top){
8286 this.dom.style.left = this.addUnits(left);
8287 this.dom.style.top = this.addUnits(top);
8292 * Move this element relative to its current position.
8293 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8294 * @param {Number} distance How far to move the element in pixels
8295 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8296 * @return {Roo.Element} this
8298 move : function(direction, distance, animate){
8299 var xy = this.getXY();
8300 direction = direction.toLowerCase();
8304 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8308 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8313 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8318 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8325 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8326 * @return {Roo.Element} this
8329 if(!this.isClipped){
8330 this.isClipped = true;
8331 this.originalClip = {
8332 "o": this.getStyle("overflow"),
8333 "x": this.getStyle("overflow-x"),
8334 "y": this.getStyle("overflow-y")
8336 this.setStyle("overflow", "hidden");
8337 this.setStyle("overflow-x", "hidden");
8338 this.setStyle("overflow-y", "hidden");
8344 * Return clipping (overflow) to original clipping before clip() was called
8345 * @return {Roo.Element} this
8347 unclip : function(){
8349 this.isClipped = false;
8350 var o = this.originalClip;
8351 if(o.o){this.setStyle("overflow", o.o);}
8352 if(o.x){this.setStyle("overflow-x", o.x);}
8353 if(o.y){this.setStyle("overflow-y", o.y);}
8360 * Gets the x,y coordinates specified by the anchor position on the element.
8361 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8362 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8363 * {width: (target width), height: (target height)} (defaults to the element's current size)
8364 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8365 * @return {Array} [x, y] An array containing the element's x and y coordinates
8367 getAnchorXY : function(anchor, local, s){
8368 //Passing a different size is useful for pre-calculating anchors,
8369 //especially for anchored animations that change the el size.
8371 var w, h, vp = false;
8374 if(d == document.body || d == document){
8376 w = D.getViewWidth(); h = D.getViewHeight();
8378 w = this.getWidth(); h = this.getHeight();
8381 w = s.width; h = s.height;
8383 var x = 0, y = 0, r = Math.round;
8384 switch((anchor || "tl").toLowerCase()){
8426 var sc = this.getScroll();
8427 return [x + sc.left, y + sc.top];
8429 //Add the element's offset xy
8430 var o = this.getXY();
8431 return [x+o[0], y+o[1]];
8435 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8436 * supported position values.
8437 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8438 * @param {String} position The position to align to.
8439 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8440 * @return {Array} [x, y]
8442 getAlignToXY : function(el, p, o){
8446 throw "Element.alignTo with an element that doesn't exist";
8448 var c = false; //constrain to viewport
8449 var p1 = "", p2 = "";
8456 }else if(p.indexOf("-") == -1){
8459 p = p.toLowerCase();
8460 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8462 throw "Element.alignTo with an invalid alignment " + p;
8464 p1 = m[1]; p2 = m[2]; c = !!m[3];
8466 //Subtract the aligned el's internal xy from the target's offset xy
8467 //plus custom offset to get the aligned el's new offset xy
8468 var a1 = this.getAnchorXY(p1, true);
8469 var a2 = el.getAnchorXY(p2, false);
8470 var x = a2[0] - a1[0] + o[0];
8471 var y = a2[1] - a1[1] + o[1];
8473 //constrain the aligned el to viewport if necessary
8474 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8475 // 5px of margin for ie
8476 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8478 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8479 //perpendicular to the vp border, allow the aligned el to slide on that border,
8480 //otherwise swap the aligned el to the opposite border of the target.
8481 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8482 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8483 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8484 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8487 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8488 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8490 if((x+w) > dw + scrollX){
8491 x = swapX ? r.left-w : dw+scrollX-w;
8494 x = swapX ? r.right : scrollX;
8496 if((y+h) > dh + scrollY){
8497 y = swapY ? r.top-h : dh+scrollY-h;
8500 y = swapY ? r.bottom : scrollY;
8507 getConstrainToXY : function(){
8508 var os = {top:0, left:0, bottom:0, right: 0};
8510 return function(el, local, offsets, proposedXY){
8512 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8514 var vw, vh, vx = 0, vy = 0;
8515 if(el.dom == document.body || el.dom == document){
8516 vw = Roo.lib.Dom.getViewWidth();
8517 vh = Roo.lib.Dom.getViewHeight();
8519 vw = el.dom.clientWidth;
8520 vh = el.dom.clientHeight;
8522 var vxy = el.getXY();
8528 var s = el.getScroll();
8530 vx += offsets.left + s.left;
8531 vy += offsets.top + s.top;
8533 vw -= offsets.right;
8534 vh -= offsets.bottom;
8539 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8540 var x = xy[0], y = xy[1];
8541 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8543 // only move it if it needs it
8546 // first validate right/bottom
8555 // then make sure top/left isn't negative
8564 return moved ? [x, y] : false;
8569 adjustForConstraints : function(xy, parent, offsets){
8570 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8574 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8575 * document it aligns it to the viewport.
8576 * The position parameter is optional, and can be specified in any one of the following formats:
8578 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8579 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8580 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8581 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8582 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8583 * element's anchor point, and the second value is used as the target's anchor point.</li>
8585 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8586 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8587 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8588 * that specified in order to enforce the viewport constraints.
8589 * Following are all of the supported anchor positions:
8592 ----- -----------------------------
8593 tl The top left corner (default)
8594 t The center of the top edge
8595 tr The top right corner
8596 l The center of the left edge
8597 c In the center of the element
8598 r The center of the right edge
8599 bl The bottom left corner
8600 b The center of the bottom edge
8601 br The bottom right corner
8605 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8606 el.alignTo("other-el");
8608 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8609 el.alignTo("other-el", "tr?");
8611 // align the bottom right corner of el with the center left edge of other-el
8612 el.alignTo("other-el", "br-l?");
8614 // align the center of el with the bottom left corner of other-el and
8615 // adjust the x position by -6 pixels (and the y position by 0)
8616 el.alignTo("other-el", "c-bl", [-6, 0]);
8618 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8619 * @param {String} position The position to align to.
8620 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8621 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8622 * @return {Roo.Element} this
8624 alignTo : function(element, position, offsets, animate){
8625 var xy = this.getAlignToXY(element, position, offsets);
8626 this.setXY(xy, this.preanim(arguments, 3));
8631 * Anchors an element to another element and realigns it when the window is resized.
8632 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8633 * @param {String} position The position to align to.
8634 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8635 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8636 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8637 * is a number, it is used as the buffer delay (defaults to 50ms).
8638 * @param {Function} callback The function to call after the animation finishes
8639 * @return {Roo.Element} this
8641 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8642 var action = function(){
8643 this.alignTo(el, alignment, offsets, animate);
8644 Roo.callback(callback, this);
8646 Roo.EventManager.onWindowResize(action, this);
8647 var tm = typeof monitorScroll;
8648 if(tm != 'undefined'){
8649 Roo.EventManager.on(window, 'scroll', action, this,
8650 {buffer: tm == 'number' ? monitorScroll : 50});
8652 action.call(this); // align immediately
8656 * Clears any opacity settings from this element. Required in some cases for IE.
8657 * @return {Roo.Element} this
8659 clearOpacity : function(){
8660 if (window.ActiveXObject) {
8661 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8662 this.dom.style.filter = "";
8665 this.dom.style.opacity = "";
8666 this.dom.style["-moz-opacity"] = "";
8667 this.dom.style["-khtml-opacity"] = "";
8673 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8674 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8675 * @return {Roo.Element} this
8677 hide : function(animate){
8678 this.setVisible(false, this.preanim(arguments, 0));
8683 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8684 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8685 * @return {Roo.Element} this
8687 show : function(animate){
8688 this.setVisible(true, this.preanim(arguments, 0));
8693 * @private Test if size has a unit, otherwise appends the default
8695 addUnits : function(size){
8696 return Roo.Element.addUnits(size, this.defaultUnit);
8700 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8701 * @return {Roo.Element} this
8703 beginMeasure : function(){
8705 if(el.offsetWidth || el.offsetHeight){
8706 return this; // offsets work already
8709 var p = this.dom, b = document.body; // start with this element
8710 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8711 var pe = Roo.get(p);
8712 if(pe.getStyle('display') == 'none'){
8713 changed.push({el: p, visibility: pe.getStyle("visibility")});
8714 p.style.visibility = "hidden";
8715 p.style.display = "block";
8719 this._measureChanged = changed;
8725 * Restores displays to before beginMeasure was called
8726 * @return {Roo.Element} this
8728 endMeasure : function(){
8729 var changed = this._measureChanged;
8731 for(var i = 0, len = changed.length; i < len; i++) {
8733 r.el.style.visibility = r.visibility;
8734 r.el.style.display = "none";
8736 this._measureChanged = null;
8742 * Update the innerHTML of this element, optionally searching for and processing scripts
8743 * @param {String} html The new HTML
8744 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8745 * @param {Function} callback For async script loading you can be noticed when the update completes
8746 * @return {Roo.Element} this
8748 update : function(html, loadScripts, callback){
8749 if(typeof html == "undefined"){
8752 if(loadScripts !== true){
8753 this.dom.innerHTML = html;
8754 if(typeof callback == "function"){
8762 html += '<span id="' + id + '"></span>';
8764 E.onAvailable(id, function(){
8765 var hd = document.getElementsByTagName("head")[0];
8766 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8767 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8768 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8771 while(match = re.exec(html)){
8772 var attrs = match[1];
8773 var srcMatch = attrs ? attrs.match(srcRe) : false;
8774 if(srcMatch && srcMatch[2]){
8775 var s = document.createElement("script");
8776 s.src = srcMatch[2];
8777 var typeMatch = attrs.match(typeRe);
8778 if(typeMatch && typeMatch[2]){
8779 s.type = typeMatch[2];
8782 }else if(match[2] && match[2].length > 0){
8783 if(window.execScript) {
8784 window.execScript(match[2]);
8792 window.eval(match[2]);
8796 var el = document.getElementById(id);
8797 if(el){el.parentNode.removeChild(el);}
8798 if(typeof callback == "function"){
8802 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8807 * Direct access to the UpdateManager update() method (takes the same parameters).
8808 * @param {String/Function} url The url for this request or a function to call to get the url
8809 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8810 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8811 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8812 * @return {Roo.Element} this
8815 var um = this.getUpdateManager();
8816 um.update.apply(um, arguments);
8821 * Gets this element's UpdateManager
8822 * @return {Roo.UpdateManager} The UpdateManager
8824 getUpdateManager : function(){
8825 if(!this.updateManager){
8826 this.updateManager = new Roo.UpdateManager(this);
8828 return this.updateManager;
8832 * Disables text selection for this element (normalized across browsers)
8833 * @return {Roo.Element} this
8835 unselectable : function(){
8836 this.dom.unselectable = "on";
8837 this.swallowEvent("selectstart", true);
8838 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8839 this.addClass("x-unselectable");
8844 * Calculates the x, y to center this element on the screen
8845 * @return {Array} The x, y values [x, y]
8847 getCenterXY : function(){
8848 return this.getAlignToXY(document, 'c-c');
8852 * Centers the Element in either the viewport, or another Element.
8853 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8855 center : function(centerIn){
8856 this.alignTo(centerIn || document, 'c-c');
8861 * Tests various css rules/browsers to determine if this element uses a border box
8864 isBorderBox : function(){
8865 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8869 * Return a box {x, y, width, height} that can be used to set another elements
8870 * size/location to match this element.
8871 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8872 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8873 * @return {Object} box An object in the format {x, y, width, height}
8875 getBox : function(contentBox, local){
8880 var left = parseInt(this.getStyle("left"), 10) || 0;
8881 var top = parseInt(this.getStyle("top"), 10) || 0;
8884 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8886 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8888 var l = this.getBorderWidth("l")+this.getPadding("l");
8889 var r = this.getBorderWidth("r")+this.getPadding("r");
8890 var t = this.getBorderWidth("t")+this.getPadding("t");
8891 var b = this.getBorderWidth("b")+this.getPadding("b");
8892 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8894 bx.right = bx.x + bx.width;
8895 bx.bottom = bx.y + bx.height;
8900 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8901 for more information about the sides.
8902 * @param {String} sides
8905 getFrameWidth : function(sides, onlyContentBox){
8906 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8910 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8911 * @param {Object} box The box to fill {x, y, width, height}
8912 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8913 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8914 * @return {Roo.Element} this
8916 setBox : function(box, adjust, animate){
8917 var w = box.width, h = box.height;
8918 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8919 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8920 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8922 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8927 * Forces the browser to repaint this element
8928 * @return {Roo.Element} this
8930 repaint : function(){
8932 this.addClass("x-repaint");
8933 setTimeout(function(){
8934 Roo.get(dom).removeClass("x-repaint");
8940 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8941 * then it returns the calculated width of the sides (see getPadding)
8942 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8943 * @return {Object/Number}
8945 getMargins : function(side){
8948 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8949 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8950 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8951 right: parseInt(this.getStyle("margin-right"), 10) || 0
8954 return this.addStyles(side, El.margins);
8959 addStyles : function(sides, styles){
8961 for(var i = 0, len = sides.length; i < len; i++){
8962 v = this.getStyle(styles[sides.charAt(i)]);
8964 w = parseInt(v, 10);
8972 * Creates a proxy element of this element
8973 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8974 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8975 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8976 * @return {Roo.Element} The new proxy element
8978 createProxy : function(config, renderTo, matchBox){
8980 renderTo = Roo.getDom(renderTo);
8982 renderTo = document.body;
8984 config = typeof config == "object" ?
8985 config : {tag : "div", cls: config};
8986 var proxy = Roo.DomHelper.append(renderTo, config, true);
8988 proxy.setBox(this.getBox());
8994 * Puts a mask over this element to disable user interaction. Requires core.css.
8995 * This method can only be applied to elements which accept child nodes.
8996 * @param {String} msg (optional) A message to display in the mask
8997 * @param {String} msgCls (optional) A css class to apply to the msg element
8998 * @return {Element} The mask element
9000 mask : function(msg, msgCls)
9002 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9003 this.setStyle("position", "relative");
9006 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9008 this.addClass("x-masked");
9009 this._mask.setDisplayed(true);
9014 while (dom && dom.style) {
9015 if (!isNaN(parseInt(dom.style.zIndex))) {
9016 z = Math.max(z, parseInt(dom.style.zIndex));
9018 dom = dom.parentNode;
9020 // if we are masking the body - then it hides everything..
9021 if (this.dom == document.body) {
9023 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9024 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9027 if(typeof msg == 'string'){
9029 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9031 var mm = this._maskMsg;
9032 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9033 if (mm.dom.firstChild) { // weird IE issue?
9034 mm.dom.firstChild.innerHTML = msg;
9036 mm.setDisplayed(true);
9038 mm.setStyle('z-index', z + 102);
9040 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9041 this._mask.setHeight(this.getHeight());
9043 this._mask.setStyle('z-index', z + 100);
9049 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9050 * it is cached for reuse.
9052 unmask : function(removeEl){
9054 if(removeEl === true){
9055 this._mask.remove();
9058 this._maskMsg.remove();
9059 delete this._maskMsg;
9062 this._mask.setDisplayed(false);
9064 this._maskMsg.setDisplayed(false);
9068 this.removeClass("x-masked");
9072 * Returns true if this element is masked
9075 isMasked : function(){
9076 return this._mask && this._mask.isVisible();
9080 * Creates an iframe shim for this element to keep selects and other windowed objects from
9082 * @return {Roo.Element} The new shim element
9084 createShim : function(){
9085 var el = document.createElement('iframe');
9086 el.frameBorder = 'no';
9087 el.className = 'roo-shim';
9088 if(Roo.isIE && Roo.isSecure){
9089 el.src = Roo.SSL_SECURE_URL;
9091 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9092 shim.autoBoxAdjust = false;
9097 * Removes this element from the DOM and deletes it from the cache
9099 remove : function(){
9100 if(this.dom.parentNode){
9101 this.dom.parentNode.removeChild(this.dom);
9103 delete El.cache[this.dom.id];
9107 * Sets up event handlers to add and remove a css class when the mouse is over this element
9108 * @param {String} className
9109 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9110 * mouseout events for children elements
9111 * @return {Roo.Element} this
9113 addClassOnOver : function(className, preventFlicker){
9114 this.on("mouseover", function(){
9115 Roo.fly(this, '_internal').addClass(className);
9117 var removeFn = function(e){
9118 if(preventFlicker !== true || !e.within(this, true)){
9119 Roo.fly(this, '_internal').removeClass(className);
9122 this.on("mouseout", removeFn, this.dom);
9127 * Sets up event handlers to add and remove a css class when this element has the focus
9128 * @param {String} className
9129 * @return {Roo.Element} this
9131 addClassOnFocus : function(className){
9132 this.on("focus", function(){
9133 Roo.fly(this, '_internal').addClass(className);
9135 this.on("blur", function(){
9136 Roo.fly(this, '_internal').removeClass(className);
9141 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
9142 * @param {String} className
9143 * @return {Roo.Element} this
9145 addClassOnClick : function(className){
9147 this.on("mousedown", function(){
9148 Roo.fly(dom, '_internal').addClass(className);
9149 var d = Roo.get(document);
9150 var fn = function(){
9151 Roo.fly(dom, '_internal').removeClass(className);
9152 d.removeListener("mouseup", fn);
9154 d.on("mouseup", fn);
9160 * Stops the specified event from bubbling and optionally prevents the default action
9161 * @param {String} eventName
9162 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9163 * @return {Roo.Element} this
9165 swallowEvent : function(eventName, preventDefault){
9166 var fn = function(e){
9167 e.stopPropagation();
9172 if(eventName instanceof Array){
9173 for(var i = 0, len = eventName.length; i < len; i++){
9174 this.on(eventName[i], fn);
9178 this.on(eventName, fn);
9185 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9188 * Sizes this element to its parent element's dimensions performing
9189 * neccessary box adjustments.
9190 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9191 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9192 * @return {Roo.Element} this
9194 fitToParent : function(monitorResize, targetParent) {
9195 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9196 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9197 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9200 var p = Roo.get(targetParent || this.dom.parentNode);
9201 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9202 if (monitorResize === true) {
9203 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9204 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9210 * Gets the next sibling, skipping text nodes
9211 * @return {HTMLElement} The next sibling or null
9213 getNextSibling : function(){
9214 var n = this.dom.nextSibling;
9215 while(n && n.nodeType != 1){
9222 * Gets the previous sibling, skipping text nodes
9223 * @return {HTMLElement} The previous sibling or null
9225 getPrevSibling : function(){
9226 var n = this.dom.previousSibling;
9227 while(n && n.nodeType != 1){
9228 n = n.previousSibling;
9235 * Appends the passed element(s) to this element
9236 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9237 * @return {Roo.Element} this
9239 appendChild: function(el){
9246 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9247 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9248 * automatically generated with the specified attributes.
9249 * @param {HTMLElement} insertBefore (optional) a child element of this element
9250 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9251 * @return {Roo.Element} The new child element
9253 createChild: function(config, insertBefore, returnDom){
9254 config = config || {tag:'div'};
9256 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9258 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9262 * Appends this element to the passed element
9263 * @param {String/HTMLElement/Element} el The new parent element
9264 * @return {Roo.Element} this
9266 appendTo: function(el){
9267 el = Roo.getDom(el);
9268 el.appendChild(this.dom);
9273 * Inserts this element before the passed element in the DOM
9274 * @param {String/HTMLElement/Element} el The element to insert before
9275 * @return {Roo.Element} this
9277 insertBefore: function(el){
9278 el = Roo.getDom(el);
9279 el.parentNode.insertBefore(this.dom, el);
9284 * Inserts this element after the passed element in the DOM
9285 * @param {String/HTMLElement/Element} el The element to insert after
9286 * @return {Roo.Element} this
9288 insertAfter: function(el){
9289 el = Roo.getDom(el);
9290 el.parentNode.insertBefore(this.dom, el.nextSibling);
9295 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9296 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9297 * @return {Roo.Element} The new child
9299 insertFirst: function(el, returnDom){
9301 if(typeof el == 'object' && !el.nodeType){ // dh config
9302 return this.createChild(el, this.dom.firstChild, returnDom);
9304 el = Roo.getDom(el);
9305 this.dom.insertBefore(el, this.dom.firstChild);
9306 return !returnDom ? Roo.get(el) : el;
9311 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9312 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9313 * @param {String} where (optional) 'before' or 'after' defaults to before
9314 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9315 * @return {Roo.Element} the inserted Element
9317 insertSibling: function(el, where, returnDom){
9318 where = where ? where.toLowerCase() : 'before';
9320 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9322 if(typeof el == 'object' && !el.nodeType){ // dh config
9323 if(where == 'after' && !this.dom.nextSibling){
9324 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9326 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9330 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9331 where == 'before' ? this.dom : this.dom.nextSibling);
9340 * Creates and wraps this element with another element
9341 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9342 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9343 * @return {HTMLElement/Element} The newly created wrapper element
9345 wrap: function(config, returnDom){
9347 config = {tag: "div"};
9349 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9350 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9355 * Replaces the passed element with this element
9356 * @param {String/HTMLElement/Element} el The element to replace
9357 * @return {Roo.Element} this
9359 replace: function(el){
9361 this.insertBefore(el);
9367 * Inserts an html fragment into this element
9368 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9369 * @param {String} html The HTML fragment
9370 * @param {Boolean} returnEl True to return an Roo.Element
9371 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9373 insertHtml : function(where, html, returnEl){
9374 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9375 return returnEl ? Roo.get(el) : el;
9379 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9380 * @param {Object} o The object with the attributes
9381 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9382 * @return {Roo.Element} this
9384 set : function(o, useSet){
9386 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9388 if(attr == "style" || typeof o[attr] == "function") continue;
9390 el.className = o["cls"];
9392 if(useSet) el.setAttribute(attr, o[attr]);
9393 else el[attr] = o[attr];
9397 Roo.DomHelper.applyStyles(el, o.style);
9403 * Convenience method for constructing a KeyMap
9404 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9405 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9406 * @param {Function} fn The function to call
9407 * @param {Object} scope (optional) The scope of the function
9408 * @return {Roo.KeyMap} The KeyMap created
9410 addKeyListener : function(key, fn, scope){
9412 if(typeof key != "object" || key instanceof Array){
9428 return new Roo.KeyMap(this, config);
9432 * Creates a KeyMap for this element
9433 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9434 * @return {Roo.KeyMap} The KeyMap created
9436 addKeyMap : function(config){
9437 return new Roo.KeyMap(this, config);
9441 * Returns true if this element is scrollable.
9444 isScrollable : function(){
9446 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9450 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9451 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9452 * @param {Number} value The new scroll value
9453 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9454 * @return {Element} this
9457 scrollTo : function(side, value, animate){
9458 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9460 this.dom[prop] = value;
9462 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9463 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9469 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9470 * within this element's scrollable range.
9471 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9472 * @param {Number} distance How far to scroll the element in pixels
9473 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9474 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9475 * was scrolled as far as it could go.
9477 scroll : function(direction, distance, animate){
9478 if(!this.isScrollable()){
9482 var l = el.scrollLeft, t = el.scrollTop;
9483 var w = el.scrollWidth, h = el.scrollHeight;
9484 var cw = el.clientWidth, ch = el.clientHeight;
9485 direction = direction.toLowerCase();
9486 var scrolled = false;
9487 var a = this.preanim(arguments, 2);
9492 var v = Math.min(l + distance, w-cw);
9493 this.scrollTo("left", v, a);
9500 var v = Math.max(l - distance, 0);
9501 this.scrollTo("left", v, a);
9509 var v = Math.max(t - distance, 0);
9510 this.scrollTo("top", v, a);
9518 var v = Math.min(t + distance, h-ch);
9519 this.scrollTo("top", v, a);
9528 * Translates the passed page coordinates into left/top css values for this element
9529 * @param {Number/Array} x The page x or an array containing [x, y]
9530 * @param {Number} y The page y
9531 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9533 translatePoints : function(x, y){
9534 if(typeof x == 'object' || x instanceof Array){
9537 var p = this.getStyle('position');
9538 var o = this.getXY();
9540 var l = parseInt(this.getStyle('left'), 10);
9541 var t = parseInt(this.getStyle('top'), 10);
9544 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9547 t = (p == "relative") ? 0 : this.dom.offsetTop;
9550 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9554 * Returns the current scroll position of the element.
9555 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9557 getScroll : function(){
9558 var d = this.dom, doc = document;
9559 if(d == doc || d == doc.body){
9560 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9561 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9562 return {left: l, top: t};
9564 return {left: d.scrollLeft, top: d.scrollTop};
9569 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9570 * are convert to standard 6 digit hex color.
9571 * @param {String} attr The css attribute
9572 * @param {String} defaultValue The default value to use when a valid color isn't found
9573 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9576 getColor : function(attr, defaultValue, prefix){
9577 var v = this.getStyle(attr);
9578 if(!v || v == "transparent" || v == "inherit") {
9579 return defaultValue;
9581 var color = typeof prefix == "undefined" ? "#" : prefix;
9582 if(v.substr(0, 4) == "rgb("){
9583 var rvs = v.slice(4, v.length -1).split(",");
9584 for(var i = 0; i < 3; i++){
9585 var h = parseInt(rvs[i]).toString(16);
9592 if(v.substr(0, 1) == "#"){
9594 for(var i = 1; i < 4; i++){
9595 var c = v.charAt(i);
9598 }else if(v.length == 7){
9599 color += v.substr(1);
9603 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9607 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9608 * gradient background, rounded corners and a 4-way shadow.
9609 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9610 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9611 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9612 * @return {Roo.Element} this
9614 boxWrap : function(cls){
9615 cls = cls || 'x-box';
9616 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9617 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9622 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9623 * @param {String} namespace The namespace in which to look for the attribute
9624 * @param {String} name The attribute name
9625 * @return {String} The attribute value
9627 getAttributeNS : Roo.isIE ? function(ns, name){
9629 var type = typeof d[ns+":"+name];
9630 if(type != 'undefined' && type != 'unknown'){
9631 return d[ns+":"+name];
9634 } : function(ns, name){
9636 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9641 * Sets or Returns the value the dom attribute value
9642 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9643 * @param {String} value (optional) The value to set the attribute to
9644 * @return {String} The attribute value
9646 attr : function(name){
9647 if (arguments.length > 1) {
9648 this.dom.setAttribute(name, arguments[1]);
9649 return arguments[1];
9651 if (typeof(name) == 'object') {
9652 for(var i in name) {
9653 this.attr(i, name[i]);
9659 if (!this.dom.hasAttribute(name)) {
9662 return this.dom.getAttribute(name);
9669 var ep = El.prototype;
9672 * Appends an event handler (Shorthand for addListener)
9673 * @param {String} eventName The type of event to append
9674 * @param {Function} fn The method the event invokes
9675 * @param {Object} scope (optional) The scope (this object) of the fn
9676 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9679 ep.on = ep.addListener;
9681 ep.mon = ep.addListener;
9684 * Removes an event handler from this element (shorthand for removeListener)
9685 * @param {String} eventName the type of event to remove
9686 * @param {Function} fn the method the event invokes
9687 * @return {Roo.Element} this
9690 ep.un = ep.removeListener;
9693 * true to automatically adjust width and height settings for box-model issues (default to true)
9695 ep.autoBoxAdjust = true;
9698 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9701 El.addUnits = function(v, defaultUnit){
9702 if(v === "" || v == "auto"){
9705 if(v === undefined){
9708 if(typeof v == "number" || !El.unitPattern.test(v)){
9709 return v + (defaultUnit || 'px');
9714 // special markup used throughout Roo when box wrapping elements
9715 El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9717 * Visibility mode constant - Use visibility to hide element
9723 * Visibility mode constant - Use display to hide element
9729 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9730 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9731 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9743 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9744 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9745 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9746 * @return {Element} The Element object
9749 El.get = function(el){
9751 if(!el){ return null; }
9752 if(typeof el == "string"){ // element id
9753 if(!(elm = document.getElementById(el))){
9756 if(ex = El.cache[el]){
9759 ex = El.cache[el] = new El(elm);
9762 }else if(el.tagName){ // dom element
9766 if(ex = El.cache[id]){
9769 ex = El.cache[id] = new El(el);
9772 }else if(el instanceof El){
9774 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9775 // catch case where it hasn't been appended
9776 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9779 }else if(el.isComposite){
9781 }else if(el instanceof Array){
9782 return El.select(el);
9783 }else if(el == document){
9784 // create a bogus element object representing the document object
9786 var f = function(){};
9787 f.prototype = El.prototype;
9789 docEl.dom = document;
9797 El.uncache = function(el){
9798 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9800 delete El.cache[a[i].id || a[i]];
9806 // Garbage collection - uncache elements/purge listeners on orphaned elements
9807 // so we don't hold a reference and cause the browser to retain them
9808 El.garbageCollect = function(){
9809 if(!Roo.enableGarbageCollector){
9810 clearInterval(El.collectorThread);
9813 for(var eid in El.cache){
9814 var el = El.cache[eid], d = el.dom;
9815 // -------------------------------------------------------
9816 // Determining what is garbage:
9817 // -------------------------------------------------------
9819 // dom node is null, definitely garbage
9820 // -------------------------------------------------------
9822 // no parentNode == direct orphan, definitely garbage
9823 // -------------------------------------------------------
9824 // !d.offsetParent && !document.getElementById(eid)
9825 // display none elements have no offsetParent so we will
9826 // also try to look it up by it's id. However, check
9827 // offsetParent first so we don't do unneeded lookups.
9828 // This enables collection of elements that are not orphans
9829 // directly, but somewhere up the line they have an orphan
9831 // -------------------------------------------------------
9832 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9833 delete El.cache[eid];
9834 if(d && Roo.enableListenerCollection){
9840 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9844 El.Flyweight = function(dom){
9847 El.Flyweight.prototype = El.prototype;
9849 El._flyweights = {};
9851 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9852 * the dom node can be overwritten by other code.
9853 * @param {String/HTMLElement} el The dom node or id
9854 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9855 * prevent conflicts (e.g. internally Roo uses "_internal")
9857 * @return {Element} The shared Element object
9859 El.fly = function(el, named){
9860 named = named || '_global';
9861 el = Roo.getDom(el);
9865 if(!El._flyweights[named]){
9866 El._flyweights[named] = new El.Flyweight();
9868 El._flyweights[named].dom = el;
9869 return El._flyweights[named];
9873 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9874 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9875 * Shorthand of {@link Roo.Element#get}
9876 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9877 * @return {Element} The Element object
9883 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9884 * the dom node can be overwritten by other code.
9885 * Shorthand of {@link Roo.Element#fly}
9886 * @param {String/HTMLElement} el The dom node or id
9887 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9888 * prevent conflicts (e.g. internally Roo uses "_internal")
9890 * @return {Element} The shared Element object
9896 // speedy lookup for elements never to box adjust
9897 var noBoxAdjust = Roo.isStrict ? {
9900 input:1, select:1, textarea:1
9902 if(Roo.isIE || Roo.isGecko){
9903 noBoxAdjust['button'] = 1;
9907 Roo.EventManager.on(window, 'unload', function(){
9909 delete El._flyweights;
9917 Roo.Element.selectorFunction = Roo.DomQuery.select;
9920 Roo.Element.select = function(selector, unique, root){
9922 if(typeof selector == "string"){
9923 els = Roo.Element.selectorFunction(selector, root);
9924 }else if(selector.length !== undefined){
9927 throw "Invalid selector";
9929 if(unique === true){
9930 return new Roo.CompositeElement(els);
9932 return new Roo.CompositeElementLite(els);
9936 * Selects elements based on the passed CSS selector to enable working on them as 1.
9937 * @param {String/Array} selector The CSS selector or an array of elements
9938 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9939 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9940 * @return {CompositeElementLite/CompositeElement}
9944 Roo.select = Roo.Element.select;
9961 * Ext JS Library 1.1.1
9962 * Copyright(c) 2006-2007, Ext JS, LLC.
9964 * Originally Released Under LGPL - original licence link has changed is not relivant.
9967 * <script type="text/javascript">
9972 //Notifies Element that fx methods are available
9973 Roo.enableFx = true;
9977 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9978 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9979 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9980 * Element effects to work.</p><br/>
9982 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9983 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9984 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9985 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9986 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9987 * expected results and should be done with care.</p><br/>
9989 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9990 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9993 ----- -----------------------------
9994 tl The top left corner
9995 t The center of the top edge
9996 tr The top right corner
9997 l The center of the left edge
9998 r The center of the right edge
9999 bl The bottom left corner
10000 b The center of the bottom edge
10001 br The bottom right corner
10003 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10004 * below are common options that can be passed to any Fx method.</b>
10005 * @cfg {Function} callback A function called when the effect is finished
10006 * @cfg {Object} scope The scope of the effect function
10007 * @cfg {String} easing A valid Easing value for the effect
10008 * @cfg {String} afterCls A css class to apply after the effect
10009 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10010 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10011 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10012 * effects that end with the element being visually hidden, ignored otherwise)
10013 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10014 * a function which returns such a specification that will be applied to the Element after the effect finishes
10015 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10016 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
10017 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10021 * Slides the element into view. An anchor point can be optionally passed to set the point of
10022 * origin for the slide effect. This function automatically handles wrapping the element with
10023 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10026 // default: slide the element in from the top
10029 // custom: slide the element in from the right with a 2-second duration
10030 el.slideIn('r', { duration: 2 });
10032 // common config options shown with default values
10038 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10039 * @param {Object} options (optional) Object literal with any of the Fx config options
10040 * @return {Roo.Element} The Element
10042 slideIn : function(anchor, o){
10043 var el = this.getFxEl();
10046 el.queueFx(o, function(){
10048 anchor = anchor || "t";
10050 // fix display to visibility
10053 // restore values after effect
10054 var r = this.getFxRestore();
10055 var b = this.getBox();
10056 // fixed size for slide
10060 var wrap = this.fxWrap(r.pos, o, "hidden");
10062 var st = this.dom.style;
10063 st.visibility = "visible";
10064 st.position = "absolute";
10066 // clear out temp styles after slide and unwrap
10067 var after = function(){
10068 el.fxUnwrap(wrap, r.pos, o);
10069 st.width = r.width;
10070 st.height = r.height;
10073 // time to calc the positions
10074 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10076 switch(anchor.toLowerCase()){
10078 wrap.setSize(b.width, 0);
10079 st.left = st.bottom = "0";
10083 wrap.setSize(0, b.height);
10084 st.right = st.top = "0";
10088 wrap.setSize(0, b.height);
10089 wrap.setX(b.right);
10090 st.left = st.top = "0";
10091 a = {width: bw, points: pt};
10094 wrap.setSize(b.width, 0);
10095 wrap.setY(b.bottom);
10096 st.left = st.top = "0";
10097 a = {height: bh, points: pt};
10100 wrap.setSize(0, 0);
10101 st.right = st.bottom = "0";
10102 a = {width: bw, height: bh};
10105 wrap.setSize(0, 0);
10106 wrap.setY(b.y+b.height);
10107 st.right = st.top = "0";
10108 a = {width: bw, height: bh, points: pt};
10111 wrap.setSize(0, 0);
10112 wrap.setXY([b.right, b.bottom]);
10113 st.left = st.top = "0";
10114 a = {width: bw, height: bh, points: pt};
10117 wrap.setSize(0, 0);
10118 wrap.setX(b.x+b.width);
10119 st.left = st.bottom = "0";
10120 a = {width: bw, height: bh, points: pt};
10123 this.dom.style.visibility = "visible";
10126 arguments.callee.anim = wrap.fxanim(a,
10136 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10137 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10138 * 'hidden') but block elements will still take up space in the document. The element must be removed
10139 * from the DOM using the 'remove' config option if desired. This function automatically handles
10140 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10143 // default: slide the element out to the top
10146 // custom: slide the element out to the right with a 2-second duration
10147 el.slideOut('r', { duration: 2 });
10149 // common config options shown with default values
10157 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10158 * @param {Object} options (optional) Object literal with any of the Fx config options
10159 * @return {Roo.Element} The Element
10161 slideOut : function(anchor, o){
10162 var el = this.getFxEl();
10165 el.queueFx(o, function(){
10167 anchor = anchor || "t";
10169 // restore values after effect
10170 var r = this.getFxRestore();
10172 var b = this.getBox();
10173 // fixed size for slide
10177 var wrap = this.fxWrap(r.pos, o, "visible");
10179 var st = this.dom.style;
10180 st.visibility = "visible";
10181 st.position = "absolute";
10185 var after = function(){
10187 el.setDisplayed(false);
10192 el.fxUnwrap(wrap, r.pos, o);
10194 st.width = r.width;
10195 st.height = r.height;
10200 var a, zero = {to: 0};
10201 switch(anchor.toLowerCase()){
10203 st.left = st.bottom = "0";
10204 a = {height: zero};
10207 st.right = st.top = "0";
10211 st.left = st.top = "0";
10212 a = {width: zero, points: {to:[b.right, b.y]}};
10215 st.left = st.top = "0";
10216 a = {height: zero, points: {to:[b.x, b.bottom]}};
10219 st.right = st.bottom = "0";
10220 a = {width: zero, height: zero};
10223 st.right = st.top = "0";
10224 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10227 st.left = st.top = "0";
10228 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10231 st.left = st.bottom = "0";
10232 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10236 arguments.callee.anim = wrap.fxanim(a,
10246 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10247 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10248 * The element must be removed from the DOM using the 'remove' config option if desired.
10254 // common config options shown with default values
10262 * @param {Object} options (optional) Object literal with any of the Fx config options
10263 * @return {Roo.Element} The Element
10265 puff : function(o){
10266 var el = this.getFxEl();
10269 el.queueFx(o, function(){
10270 this.clearOpacity();
10273 // restore values after effect
10274 var r = this.getFxRestore();
10275 var st = this.dom.style;
10277 var after = function(){
10279 el.setDisplayed(false);
10286 el.setPositioning(r.pos);
10287 st.width = r.width;
10288 st.height = r.height;
10293 var width = this.getWidth();
10294 var height = this.getHeight();
10296 arguments.callee.anim = this.fxanim({
10297 width : {to: this.adjustWidth(width * 2)},
10298 height : {to: this.adjustHeight(height * 2)},
10299 points : {by: [-(width * .5), -(height * .5)]},
10301 fontSize: {to:200, unit: "%"}
10312 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10313 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10314 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10320 // all config options shown with default values
10328 * @param {Object} options (optional) Object literal with any of the Fx config options
10329 * @return {Roo.Element} The Element
10331 switchOff : function(o){
10332 var el = this.getFxEl();
10335 el.queueFx(o, function(){
10336 this.clearOpacity();
10339 // restore values after effect
10340 var r = this.getFxRestore();
10341 var st = this.dom.style;
10343 var after = function(){
10345 el.setDisplayed(false);
10351 el.setPositioning(r.pos);
10352 st.width = r.width;
10353 st.height = r.height;
10358 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10359 this.clearOpacity();
10363 points:{by:[0, this.getHeight() * .5]}
10364 }, o, 'motion', 0.3, 'easeIn', after);
10365 }).defer(100, this);
10372 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10373 * changed using the "attr" config option) and then fading back to the original color. If no original
10374 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10377 // default: highlight background to yellow
10380 // custom: highlight foreground text to blue for 2 seconds
10381 el.highlight("0000ff", { attr: 'color', duration: 2 });
10383 // common config options shown with default values
10384 el.highlight("ffff9c", {
10385 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10386 endColor: (current color) or "ffffff",
10391 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10392 * @param {Object} options (optional) Object literal with any of the Fx config options
10393 * @return {Roo.Element} The Element
10395 highlight : function(color, o){
10396 var el = this.getFxEl();
10399 el.queueFx(o, function(){
10400 color = color || "ffff9c";
10401 attr = o.attr || "backgroundColor";
10403 this.clearOpacity();
10406 var origColor = this.getColor(attr);
10407 var restoreColor = this.dom.style[attr];
10408 endColor = (o.endColor || origColor) || "ffffff";
10410 var after = function(){
10411 el.dom.style[attr] = restoreColor;
10416 a[attr] = {from: color, to: endColor};
10417 arguments.callee.anim = this.fxanim(a,
10427 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10430 // default: a single light blue ripple
10433 // custom: 3 red ripples lasting 3 seconds total
10434 el.frame("ff0000", 3, { duration: 3 });
10436 // common config options shown with default values
10437 el.frame("C3DAF9", 1, {
10438 duration: 1 //duration of entire animation (not each individual ripple)
10439 // Note: Easing is not configurable and will be ignored if included
10442 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10443 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10444 * @param {Object} options (optional) Object literal with any of the Fx config options
10445 * @return {Roo.Element} The Element
10447 frame : function(color, count, o){
10448 var el = this.getFxEl();
10451 el.queueFx(o, function(){
10452 color = color || "#C3DAF9";
10453 if(color.length == 6){
10454 color = "#" + color;
10456 count = count || 1;
10457 duration = o.duration || 1;
10460 var b = this.getBox();
10461 var animFn = function(){
10462 var proxy = this.createProxy({
10465 visbility:"hidden",
10466 position:"absolute",
10467 "z-index":"35000", // yee haw
10468 border:"0px solid " + color
10471 var scale = Roo.isBorderBox ? 2 : 1;
10473 top:{from:b.y, to:b.y - 20},
10474 left:{from:b.x, to:b.x - 20},
10475 borderWidth:{from:0, to:10},
10476 opacity:{from:1, to:0},
10477 height:{from:b.height, to:(b.height + (20*scale))},
10478 width:{from:b.width, to:(b.width + (20*scale))}
10479 }, duration, function(){
10483 animFn.defer((duration/2)*1000, this);
10494 * Creates a pause before any subsequent queued effects begin. If there are
10495 * no effects queued after the pause it will have no effect.
10500 * @param {Number} seconds The length of time to pause (in seconds)
10501 * @return {Roo.Element} The Element
10503 pause : function(seconds){
10504 var el = this.getFxEl();
10507 el.queueFx(o, function(){
10508 setTimeout(function(){
10510 }, seconds * 1000);
10516 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10517 * using the "endOpacity" config option.
10520 // default: fade in from opacity 0 to 100%
10523 // custom: fade in from opacity 0 to 75% over 2 seconds
10524 el.fadeIn({ endOpacity: .75, duration: 2});
10526 // common config options shown with default values
10528 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10533 * @param {Object} options (optional) Object literal with any of the Fx config options
10534 * @return {Roo.Element} The Element
10536 fadeIn : function(o){
10537 var el = this.getFxEl();
10539 el.queueFx(o, function(){
10540 this.setOpacity(0);
10542 this.dom.style.visibility = 'visible';
10543 var to = o.endOpacity || 1;
10544 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10545 o, null, .5, "easeOut", function(){
10547 this.clearOpacity();
10556 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10557 * using the "endOpacity" config option.
10560 // default: fade out from the element's current opacity to 0
10563 // custom: fade out from the element's current opacity to 25% over 2 seconds
10564 el.fadeOut({ endOpacity: .25, duration: 2});
10566 // common config options shown with default values
10568 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10575 * @param {Object} options (optional) Object literal with any of the Fx config options
10576 * @return {Roo.Element} The Element
10578 fadeOut : function(o){
10579 var el = this.getFxEl();
10581 el.queueFx(o, function(){
10582 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10583 o, null, .5, "easeOut", function(){
10584 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10585 this.dom.style.display = "none";
10587 this.dom.style.visibility = "hidden";
10589 this.clearOpacity();
10597 * Animates the transition of an element's dimensions from a starting height/width
10598 * to an ending height/width.
10601 // change height and width to 100x100 pixels
10602 el.scale(100, 100);
10604 // common config options shown with default values. The height and width will default to
10605 // the element's existing values if passed as null.
10608 [element's height], {
10613 * @param {Number} width The new width (pass undefined to keep the original width)
10614 * @param {Number} height The new height (pass undefined to keep the original height)
10615 * @param {Object} options (optional) Object literal with any of the Fx config options
10616 * @return {Roo.Element} The Element
10618 scale : function(w, h, o){
10619 this.shift(Roo.apply({}, o, {
10627 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10628 * Any of these properties not specified in the config object will not be changed. This effect
10629 * requires that at least one new dimension, position or opacity setting must be passed in on
10630 * the config object in order for the function to have any effect.
10633 // slide the element horizontally to x position 200 while changing the height and opacity
10634 el.shift({ x: 200, height: 50, opacity: .8 });
10636 // common config options shown with default values.
10638 width: [element's width],
10639 height: [element's height],
10640 x: [element's x position],
10641 y: [element's y position],
10642 opacity: [element's opacity],
10647 * @param {Object} options Object literal with any of the Fx config options
10648 * @return {Roo.Element} The Element
10650 shift : function(o){
10651 var el = this.getFxEl();
10653 el.queueFx(o, function(){
10654 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10655 if(w !== undefined){
10656 a.width = {to: this.adjustWidth(w)};
10658 if(h !== undefined){
10659 a.height = {to: this.adjustHeight(h)};
10661 if(x !== undefined || y !== undefined){
10663 x !== undefined ? x : this.getX(),
10664 y !== undefined ? y : this.getY()
10667 if(op !== undefined){
10668 a.opacity = {to: op};
10670 if(o.xy !== undefined){
10671 a.points = {to: o.xy};
10673 arguments.callee.anim = this.fxanim(a,
10674 o, 'motion', .35, "easeOut", function(){
10682 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10683 * ending point of the effect.
10686 // default: slide the element downward while fading out
10689 // custom: slide the element out to the right with a 2-second duration
10690 el.ghost('r', { duration: 2 });
10692 // common config options shown with default values
10700 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10701 * @param {Object} options (optional) Object literal with any of the Fx config options
10702 * @return {Roo.Element} The Element
10704 ghost : function(anchor, o){
10705 var el = this.getFxEl();
10708 el.queueFx(o, function(){
10709 anchor = anchor || "b";
10711 // restore values after effect
10712 var r = this.getFxRestore();
10713 var w = this.getWidth(),
10714 h = this.getHeight();
10716 var st = this.dom.style;
10718 var after = function(){
10720 el.setDisplayed(false);
10726 el.setPositioning(r.pos);
10727 st.width = r.width;
10728 st.height = r.height;
10733 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10734 switch(anchor.toLowerCase()){
10761 arguments.callee.anim = this.fxanim(a,
10771 * Ensures that all effects queued after syncFx is called on the element are
10772 * run concurrently. This is the opposite of {@link #sequenceFx}.
10773 * @return {Roo.Element} The Element
10775 syncFx : function(){
10776 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10785 * Ensures that all effects queued after sequenceFx is called on the element are
10786 * run in sequence. This is the opposite of {@link #syncFx}.
10787 * @return {Roo.Element} The Element
10789 sequenceFx : function(){
10790 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10792 concurrent : false,
10799 nextFx : function(){
10800 var ef = this.fxQueue[0];
10807 * Returns true if the element has any effects actively running or queued, else returns false.
10808 * @return {Boolean} True if element has active effects, else false
10810 hasActiveFx : function(){
10811 return this.fxQueue && this.fxQueue[0];
10815 * Stops any running effects and clears the element's internal effects queue if it contains
10816 * any additional effects that haven't started yet.
10817 * @return {Roo.Element} The Element
10819 stopFx : function(){
10820 if(this.hasActiveFx()){
10821 var cur = this.fxQueue[0];
10822 if(cur && cur.anim && cur.anim.isAnimated()){
10823 this.fxQueue = [cur]; // clear out others
10824 cur.anim.stop(true);
10831 beforeFx : function(o){
10832 if(this.hasActiveFx() && !o.concurrent){
10843 * Returns true if the element is currently blocking so that no other effect can be queued
10844 * until this effect is finished, else returns false if blocking is not set. This is commonly
10845 * used to ensure that an effect initiated by a user action runs to completion prior to the
10846 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10847 * @return {Boolean} True if blocking, else false
10849 hasFxBlock : function(){
10850 var q = this.fxQueue;
10851 return q && q[0] && q[0].block;
10855 queueFx : function(o, fn){
10859 if(!this.hasFxBlock()){
10860 Roo.applyIf(o, this.fxDefaults);
10862 var run = this.beforeFx(o);
10863 fn.block = o.block;
10864 this.fxQueue.push(fn);
10876 fxWrap : function(pos, o, vis){
10878 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10881 wrapXY = this.getXY();
10883 var div = document.createElement("div");
10884 div.style.visibility = vis;
10885 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10886 wrap.setPositioning(pos);
10887 if(wrap.getStyle("position") == "static"){
10888 wrap.position("relative");
10890 this.clearPositioning('auto');
10892 wrap.dom.appendChild(this.dom);
10894 wrap.setXY(wrapXY);
10901 fxUnwrap : function(wrap, pos, o){
10902 this.clearPositioning();
10903 this.setPositioning(pos);
10905 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10911 getFxRestore : function(){
10912 var st = this.dom.style;
10913 return {pos: this.getPositioning(), width: st.width, height : st.height};
10917 afterFx : function(o){
10919 this.applyStyles(o.afterStyle);
10922 this.addClass(o.afterCls);
10924 if(o.remove === true){
10927 Roo.callback(o.callback, o.scope, [this]);
10929 this.fxQueue.shift();
10935 getFxEl : function(){ // support for composite element fx
10936 return Roo.get(this.dom);
10940 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10941 animType = animType || 'run';
10943 var anim = Roo.lib.Anim[animType](
10945 (opt.duration || defaultDur) || .35,
10946 (opt.easing || defaultEase) || 'easeOut',
10948 Roo.callback(cb, this);
10957 // backwords compat
10958 Roo.Fx.resize = Roo.Fx.scale;
10960 //When included, Roo.Fx is automatically applied to Element so that all basic
10961 //effects are available directly via the Element API
10962 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10964 * Ext JS Library 1.1.1
10965 * Copyright(c) 2006-2007, Ext JS, LLC.
10967 * Originally Released Under LGPL - original licence link has changed is not relivant.
10970 * <script type="text/javascript">
10975 * @class Roo.CompositeElement
10976 * Standard composite class. Creates a Roo.Element for every element in the collection.
10978 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10979 * actions will be performed on all the elements in this collection.</b>
10981 * All methods return <i>this</i> and can be chained.
10983 var els = Roo.select("#some-el div.some-class", true);
10984 // or select directly from an existing element
10985 var el = Roo.get('some-el');
10986 el.select('div.some-class', true);
10988 els.setWidth(100); // all elements become 100 width
10989 els.hide(true); // all elements fade out and hide
10991 els.setWidth(100).hide(true);
10994 Roo.CompositeElement = function(els){
10995 this.elements = [];
10996 this.addElements(els);
10998 Roo.CompositeElement.prototype = {
11000 addElements : function(els){
11001 if(!els) return this;
11002 if(typeof els == "string"){
11003 els = Roo.Element.selectorFunction(els);
11005 var yels = this.elements;
11006 var index = yels.length-1;
11007 for(var i = 0, len = els.length; i < len; i++) {
11008 yels[++index] = Roo.get(els[i]);
11014 * Clears this composite and adds the elements returned by the passed selector.
11015 * @param {String/Array} els A string CSS selector, an array of elements or an element
11016 * @return {CompositeElement} this
11018 fill : function(els){
11019 this.elements = [];
11025 * Filters this composite to only elements that match the passed selector.
11026 * @param {String} selector A string CSS selector
11027 * @param {Boolean} inverse return inverse filter (not matches)
11028 * @return {CompositeElement} this
11030 filter : function(selector, inverse){
11032 inverse = inverse || false;
11033 this.each(function(el){
11034 var match = inverse ? !el.is(selector) : el.is(selector);
11036 els[els.length] = el.dom;
11043 invoke : function(fn, args){
11044 var els = this.elements;
11045 for(var i = 0, len = els.length; i < len; i++) {
11046 Roo.Element.prototype[fn].apply(els[i], args);
11051 * Adds elements to this composite.
11052 * @param {String/Array} els A string CSS selector, an array of elements or an element
11053 * @return {CompositeElement} this
11055 add : function(els){
11056 if(typeof els == "string"){
11057 this.addElements(Roo.Element.selectorFunction(els));
11058 }else if(els.length !== undefined){
11059 this.addElements(els);
11061 this.addElements([els]);
11066 * Calls the passed function passing (el, this, index) for each element in this composite.
11067 * @param {Function} fn The function to call
11068 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11069 * @return {CompositeElement} this
11071 each : function(fn, scope){
11072 var els = this.elements;
11073 for(var i = 0, len = els.length; i < len; i++){
11074 if(fn.call(scope || els[i], els[i], this, i) === false) {
11082 * Returns the Element object at the specified index
11083 * @param {Number} index
11084 * @return {Roo.Element}
11086 item : function(index){
11087 return this.elements[index] || null;
11091 * Returns the first Element
11092 * @return {Roo.Element}
11094 first : function(){
11095 return this.item(0);
11099 * Returns the last Element
11100 * @return {Roo.Element}
11103 return this.item(this.elements.length-1);
11107 * Returns the number of elements in this composite
11110 getCount : function(){
11111 return this.elements.length;
11115 * Returns true if this composite contains the passed element
11118 contains : function(el){
11119 return this.indexOf(el) !== -1;
11123 * Returns true if this composite contains the passed element
11126 indexOf : function(el){
11127 return this.elements.indexOf(Roo.get(el));
11132 * Removes the specified element(s).
11133 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11134 * or an array of any of those.
11135 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11136 * @return {CompositeElement} this
11138 removeElement : function(el, removeDom){
11139 if(el instanceof Array){
11140 for(var i = 0, len = el.length; i < len; i++){
11141 this.removeElement(el[i]);
11145 var index = typeof el == 'number' ? el : this.indexOf(el);
11148 var d = this.elements[index];
11152 d.parentNode.removeChild(d);
11155 this.elements.splice(index, 1);
11161 * Replaces the specified element with the passed element.
11162 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11164 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11165 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11166 * @return {CompositeElement} this
11168 replaceElement : function(el, replacement, domReplace){
11169 var index = typeof el == 'number' ? el : this.indexOf(el);
11172 this.elements[index].replaceWith(replacement);
11174 this.elements.splice(index, 1, Roo.get(replacement))
11181 * Removes all elements.
11183 clear : function(){
11184 this.elements = [];
11188 Roo.CompositeElement.createCall = function(proto, fnName){
11189 if(!proto[fnName]){
11190 proto[fnName] = function(){
11191 return this.invoke(fnName, arguments);
11195 for(var fnName in Roo.Element.prototype){
11196 if(typeof Roo.Element.prototype[fnName] == "function"){
11197 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11203 * Ext JS Library 1.1.1
11204 * Copyright(c) 2006-2007, Ext JS, LLC.
11206 * Originally Released Under LGPL - original licence link has changed is not relivant.
11209 * <script type="text/javascript">
11213 * @class Roo.CompositeElementLite
11214 * @extends Roo.CompositeElement
11215 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11217 var els = Roo.select("#some-el div.some-class");
11218 // or select directly from an existing element
11219 var el = Roo.get('some-el');
11220 el.select('div.some-class');
11222 els.setWidth(100); // all elements become 100 width
11223 els.hide(true); // all elements fade out and hide
11225 els.setWidth(100).hide(true);
11226 </code></pre><br><br>
11227 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11228 * actions will be performed on all the elements in this collection.</b>
11230 Roo.CompositeElementLite = function(els){
11231 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11232 this.el = new Roo.Element.Flyweight();
11234 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11235 addElements : function(els){
11237 if(els instanceof Array){
11238 this.elements = this.elements.concat(els);
11240 var yels = this.elements;
11241 var index = yels.length-1;
11242 for(var i = 0, len = els.length; i < len; i++) {
11243 yels[++index] = els[i];
11249 invoke : function(fn, args){
11250 var els = this.elements;
11252 for(var i = 0, len = els.length; i < len; i++) {
11254 Roo.Element.prototype[fn].apply(el, args);
11259 * Returns a flyweight Element of the dom element object at the specified index
11260 * @param {Number} index
11261 * @return {Roo.Element}
11263 item : function(index){
11264 if(!this.elements[index]){
11267 this.el.dom = this.elements[index];
11271 // fixes scope with flyweight
11272 addListener : function(eventName, handler, scope, opt){
11273 var els = this.elements;
11274 for(var i = 0, len = els.length; i < len; i++) {
11275 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11281 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11282 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11283 * a reference to the dom node, use el.dom.</b>
11284 * @param {Function} fn The function to call
11285 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11286 * @return {CompositeElement} this
11288 each : function(fn, scope){
11289 var els = this.elements;
11291 for(var i = 0, len = els.length; i < len; i++){
11293 if(fn.call(scope || el, el, this, i) === false){
11300 indexOf : function(el){
11301 return this.elements.indexOf(Roo.getDom(el));
11304 replaceElement : function(el, replacement, domReplace){
11305 var index = typeof el == 'number' ? el : this.indexOf(el);
11307 replacement = Roo.getDom(replacement);
11309 var d = this.elements[index];
11310 d.parentNode.insertBefore(replacement, d);
11311 d.parentNode.removeChild(d);
11313 this.elements.splice(index, 1, replacement);
11318 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11322 * Ext JS Library 1.1.1
11323 * Copyright(c) 2006-2007, Ext JS, LLC.
11325 * Originally Released Under LGPL - original licence link has changed is not relivant.
11328 * <script type="text/javascript">
11334 * @class Roo.data.Connection
11335 * @extends Roo.util.Observable
11336 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11337 * either to a configured URL, or to a URL specified at request time.<br><br>
11339 * Requests made by this class are asynchronous, and will return immediately. No data from
11340 * the server will be available to the statement immediately following the {@link #request} call.
11341 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11343 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11344 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11345 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11346 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11347 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11348 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11349 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11350 * standard DOM methods.
11352 * @param {Object} config a configuration object.
11354 Roo.data.Connection = function(config){
11355 Roo.apply(this, config);
11358 * @event beforerequest
11359 * Fires before a network request is made to retrieve a data object.
11360 * @param {Connection} conn This Connection object.
11361 * @param {Object} options The options config object passed to the {@link #request} method.
11363 "beforerequest" : true,
11365 * @event requestcomplete
11366 * Fires if the request was successfully completed.
11367 * @param {Connection} conn This Connection object.
11368 * @param {Object} response The XHR object containing the response data.
11369 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11370 * @param {Object} options The options config object passed to the {@link #request} method.
11372 "requestcomplete" : true,
11374 * @event requestexception
11375 * Fires if an error HTTP status was returned from the server.
11376 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11377 * @param {Connection} conn This Connection object.
11378 * @param {Object} response The XHR object containing the response data.
11379 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11380 * @param {Object} options The options config object passed to the {@link #request} method.
11382 "requestexception" : true
11384 Roo.data.Connection.superclass.constructor.call(this);
11387 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11389 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11392 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11393 * extra parameters to each request made by this object. (defaults to undefined)
11396 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11397 * to each request made by this object. (defaults to undefined)
11400 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11403 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11407 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11413 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11416 disableCaching: true,
11419 * Sends an HTTP request to a remote server.
11420 * @param {Object} options An object which may contain the following properties:<ul>
11421 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11422 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11423 * request, a url encoded string or a function to call to get either.</li>
11424 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11425 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11426 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11427 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11428 * <li>options {Object} The parameter to the request call.</li>
11429 * <li>success {Boolean} True if the request succeeded.</li>
11430 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11432 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11433 * The callback is passed the following parameters:<ul>
11434 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11435 * <li>options {Object} The parameter to the request call.</li>
11437 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11438 * The callback is passed the following parameters:<ul>
11439 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11440 * <li>options {Object} The parameter to the request call.</li>
11442 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11443 * for the callback function. Defaults to the browser window.</li>
11444 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11445 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11446 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11447 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11448 * params for the post data. Any params will be appended to the URL.</li>
11449 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11451 * @return {Number} transactionId
11453 request : function(o){
11454 if(this.fireEvent("beforerequest", this, o) !== false){
11457 if(typeof p == "function"){
11458 p = p.call(o.scope||window, o);
11460 if(typeof p == "object"){
11461 p = Roo.urlEncode(o.params);
11463 if(this.extraParams){
11464 var extras = Roo.urlEncode(this.extraParams);
11465 p = p ? (p + '&' + extras) : extras;
11468 var url = o.url || this.url;
11469 if(typeof url == 'function'){
11470 url = url.call(o.scope||window, o);
11474 var form = Roo.getDom(o.form);
11475 url = url || form.action;
11477 var enctype = form.getAttribute("enctype");
11478 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11479 return this.doFormUpload(o, p, url);
11481 var f = Roo.lib.Ajax.serializeForm(form);
11482 p = p ? (p + '&' + f) : f;
11485 var hs = o.headers;
11486 if(this.defaultHeaders){
11487 hs = Roo.apply(hs || {}, this.defaultHeaders);
11494 success: this.handleResponse,
11495 failure: this.handleFailure,
11497 argument: {options: o},
11498 timeout : o.timeout || this.timeout
11501 var method = o.method||this.method||(p ? "POST" : "GET");
11503 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11504 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11507 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11511 }else if(this.autoAbort !== false){
11515 if((method == 'GET' && p) || o.xmlData){
11516 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11519 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11520 return this.transId;
11522 Roo.callback(o.callback, o.scope, [o, null, null]);
11528 * Determine whether this object has a request outstanding.
11529 * @param {Number} transactionId (Optional) defaults to the last transaction
11530 * @return {Boolean} True if there is an outstanding request.
11532 isLoading : function(transId){
11534 return Roo.lib.Ajax.isCallInProgress(transId);
11536 return this.transId ? true : false;
11541 * Aborts any outstanding request.
11542 * @param {Number} transactionId (Optional) defaults to the last transaction
11544 abort : function(transId){
11545 if(transId || this.isLoading()){
11546 Roo.lib.Ajax.abort(transId || this.transId);
11551 handleResponse : function(response){
11552 this.transId = false;
11553 var options = response.argument.options;
11554 response.argument = options ? options.argument : null;
11555 this.fireEvent("requestcomplete", this, response, options);
11556 Roo.callback(options.success, options.scope, [response, options]);
11557 Roo.callback(options.callback, options.scope, [options, true, response]);
11561 handleFailure : function(response, e){
11562 this.transId = false;
11563 var options = response.argument.options;
11564 response.argument = options ? options.argument : null;
11565 this.fireEvent("requestexception", this, response, options, e);
11566 Roo.callback(options.failure, options.scope, [response, options]);
11567 Roo.callback(options.callback, options.scope, [options, false, response]);
11571 doFormUpload : function(o, ps, url){
11573 var frame = document.createElement('iframe');
11576 frame.className = 'x-hidden';
11578 frame.src = Roo.SSL_SECURE_URL;
11580 document.body.appendChild(frame);
11583 document.frames[id].name = id;
11586 var form = Roo.getDom(o.form);
11588 form.method = 'POST';
11589 form.enctype = form.encoding = 'multipart/form-data';
11595 if(ps){ // add dynamic params
11597 ps = Roo.urlDecode(ps, false);
11599 if(ps.hasOwnProperty(k)){
11600 hd = document.createElement('input');
11601 hd.type = 'hidden';
11604 form.appendChild(hd);
11611 var r = { // bogus response object
11616 r.argument = o ? o.argument : null;
11621 doc = frame.contentWindow.document;
11623 doc = (frame.contentDocument || window.frames[id].document);
11625 if(doc && doc.body){
11626 r.responseText = doc.body.innerHTML;
11628 if(doc && doc.XMLDocument){
11629 r.responseXML = doc.XMLDocument;
11631 r.responseXML = doc;
11638 Roo.EventManager.removeListener(frame, 'load', cb, this);
11640 this.fireEvent("requestcomplete", this, r, o);
11641 Roo.callback(o.success, o.scope, [r, o]);
11642 Roo.callback(o.callback, o.scope, [o, true, r]);
11644 setTimeout(function(){document.body.removeChild(frame);}, 100);
11647 Roo.EventManager.on(frame, 'load', cb, this);
11650 if(hiddens){ // remove dynamic params
11651 for(var i = 0, len = hiddens.length; i < len; i++){
11652 form.removeChild(hiddens[i]);
11659 * Ext JS Library 1.1.1
11660 * Copyright(c) 2006-2007, Ext JS, LLC.
11662 * Originally Released Under LGPL - original licence link has changed is not relivant.
11665 * <script type="text/javascript">
11669 * Global Ajax request class.
11672 * @extends Roo.data.Connection
11675 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11676 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11677 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11678 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11679 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11680 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11681 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11683 Roo.Ajax = new Roo.data.Connection({
11692 * Serialize the passed form into a url encoded string
11694 * @param {String/HTMLElement} form
11697 serializeForm : function(form){
11698 return Roo.lib.Ajax.serializeForm(form);
11702 * Ext JS Library 1.1.1
11703 * Copyright(c) 2006-2007, Ext JS, LLC.
11705 * Originally Released Under LGPL - original licence link has changed is not relivant.
11708 * <script type="text/javascript">
11713 * @class Roo.UpdateManager
11714 * @extends Roo.util.Observable
11715 * Provides AJAX-style update for Element object.<br><br>
11718 * // Get it from a Roo.Element object
11719 * var el = Roo.get("foo");
11720 * var mgr = el.getUpdateManager();
11721 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11723 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11725 * // or directly (returns the same UpdateManager instance)
11726 * var mgr = new Roo.UpdateManager("myElementId");
11727 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11728 * mgr.on("update", myFcnNeedsToKnow);
11730 // short handed call directly from the element object
11731 Roo.get("foo").load({
11735 text: "Loading Foo..."
11739 * Create new UpdateManager directly.
11740 * @param {String/HTMLElement/Roo.Element} el The element to update
11741 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11743 Roo.UpdateManager = function(el, forceNew){
11745 if(!forceNew && el.updateManager){
11746 return el.updateManager;
11749 * The Element object
11750 * @type Roo.Element
11754 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11757 this.defaultUrl = null;
11761 * @event beforeupdate
11762 * Fired before an update is made, return false from your handler and the update is cancelled.
11763 * @param {Roo.Element} el
11764 * @param {String/Object/Function} url
11765 * @param {String/Object} params
11767 "beforeupdate": true,
11770 * Fired after successful update is made.
11771 * @param {Roo.Element} el
11772 * @param {Object} oResponseObject The response Object
11777 * Fired on update failure.
11778 * @param {Roo.Element} el
11779 * @param {Object} oResponseObject The response Object
11783 var d = Roo.UpdateManager.defaults;
11785 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11788 this.sslBlankUrl = d.sslBlankUrl;
11790 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11793 this.disableCaching = d.disableCaching;
11795 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11798 this.indicatorText = d.indicatorText;
11800 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11803 this.showLoadIndicator = d.showLoadIndicator;
11805 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11808 this.timeout = d.timeout;
11811 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11814 this.loadScripts = d.loadScripts;
11817 * Transaction object of current executing transaction
11819 this.transaction = null;
11824 this.autoRefreshProcId = null;
11826 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11829 this.refreshDelegate = this.refresh.createDelegate(this);
11831 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11834 this.updateDelegate = this.update.createDelegate(this);
11836 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11839 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11843 this.successDelegate = this.processSuccess.createDelegate(this);
11847 this.failureDelegate = this.processFailure.createDelegate(this);
11849 if(!this.renderer){
11851 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11853 this.renderer = new Roo.UpdateManager.BasicRenderer();
11856 Roo.UpdateManager.superclass.constructor.call(this);
11859 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11861 * Get the Element this UpdateManager is bound to
11862 * @return {Roo.Element} The element
11864 getEl : function(){
11868 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11869 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11872 url: "your-url.php",<br/>
11873 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11874 callback: yourFunction,<br/>
11875 scope: yourObject, //(optional scope) <br/>
11876 discardUrl: false, <br/>
11877 nocache: false,<br/>
11878 text: "Loading...",<br/>
11880 scripts: false<br/>
11883 * The only required property is url. The optional properties nocache, text and scripts
11884 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11885 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
11886 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11887 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11889 update : function(url, params, callback, discardUrl){
11890 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11891 var method = this.method,
11893 if(typeof url == "object"){ // must be config object
11896 params = params || cfg.params;
11897 callback = callback || cfg.callback;
11898 discardUrl = discardUrl || cfg.discardUrl;
11899 if(callback && cfg.scope){
11900 callback = callback.createDelegate(cfg.scope);
11902 if(typeof cfg.method != "undefined"){method = cfg.method;};
11903 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11904 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11905 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11906 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11908 this.showLoading();
11910 this.defaultUrl = url;
11912 if(typeof url == "function"){
11913 url = url.call(this);
11916 method = method || (params ? "POST" : "GET");
11917 if(method == "GET"){
11918 url = this.prepareUrl(url);
11921 var o = Roo.apply(cfg ||{}, {
11924 success: this.successDelegate,
11925 failure: this.failureDelegate,
11926 callback: undefined,
11927 timeout: (this.timeout*1000),
11928 argument: {"url": url, "form": null, "callback": callback, "params": params}
11930 Roo.log("updated manager called with timeout of " + o.timeout);
11931 this.transaction = Roo.Ajax.request(o);
11936 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11937 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11938 * @param {String/HTMLElement} form The form Id or form element
11939 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11940 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11941 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11943 formUpdate : function(form, url, reset, callback){
11944 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11945 if(typeof url == "function"){
11946 url = url.call(this);
11948 form = Roo.getDom(form);
11949 this.transaction = Roo.Ajax.request({
11952 success: this.successDelegate,
11953 failure: this.failureDelegate,
11954 timeout: (this.timeout*1000),
11955 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11957 this.showLoading.defer(1, this);
11962 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11963 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11965 refresh : function(callback){
11966 if(this.defaultUrl == null){
11969 this.update(this.defaultUrl, null, callback, true);
11973 * Set this element to auto refresh.
11974 * @param {Number} interval How often to update (in seconds).
11975 * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11976 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
11977 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11978 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11980 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11982 this.update(url || this.defaultUrl, params, callback, true);
11984 if(this.autoRefreshProcId){
11985 clearInterval(this.autoRefreshProcId);
11987 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11991 * Stop auto refresh on this element.
11993 stopAutoRefresh : function(){
11994 if(this.autoRefreshProcId){
11995 clearInterval(this.autoRefreshProcId);
11996 delete this.autoRefreshProcId;
12000 isAutoRefreshing : function(){
12001 return this.autoRefreshProcId ? true : false;
12004 * Called to update the element to "Loading" state. Override to perform custom action.
12006 showLoading : function(){
12007 if(this.showLoadIndicator){
12008 this.el.update(this.indicatorText);
12013 * Adds unique parameter to query string if disableCaching = true
12016 prepareUrl : function(url){
12017 if(this.disableCaching){
12018 var append = "_dc=" + (new Date().getTime());
12019 if(url.indexOf("?") !== -1){
12020 url += "&" + append;
12022 url += "?" + append;
12031 processSuccess : function(response){
12032 this.transaction = null;
12033 if(response.argument.form && response.argument.reset){
12034 try{ // put in try/catch since some older FF releases had problems with this
12035 response.argument.form.reset();
12038 if(this.loadScripts){
12039 this.renderer.render(this.el, response, this,
12040 this.updateComplete.createDelegate(this, [response]));
12042 this.renderer.render(this.el, response, this);
12043 this.updateComplete(response);
12047 updateComplete : function(response){
12048 this.fireEvent("update", this.el, response);
12049 if(typeof response.argument.callback == "function"){
12050 response.argument.callback(this.el, true, response);
12057 processFailure : function(response){
12058 this.transaction = null;
12059 this.fireEvent("failure", this.el, response);
12060 if(typeof response.argument.callback == "function"){
12061 response.argument.callback(this.el, false, response);
12066 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12067 * @param {Object} renderer The object implementing the render() method
12069 setRenderer : function(renderer){
12070 this.renderer = renderer;
12073 getRenderer : function(){
12074 return this.renderer;
12078 * Set the defaultUrl used for updates
12079 * @param {String/Function} defaultUrl The url or a function to call to get the url
12081 setDefaultUrl : function(defaultUrl){
12082 this.defaultUrl = defaultUrl;
12086 * Aborts the executing transaction
12088 abort : function(){
12089 if(this.transaction){
12090 Roo.Ajax.abort(this.transaction);
12095 * Returns true if an update is in progress
12096 * @return {Boolean}
12098 isUpdating : function(){
12099 if(this.transaction){
12100 return Roo.Ajax.isLoading(this.transaction);
12107 * @class Roo.UpdateManager.defaults
12108 * @static (not really - but it helps the doc tool)
12109 * The defaults collection enables customizing the default properties of UpdateManager
12111 Roo.UpdateManager.defaults = {
12113 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12119 * True to process scripts by default (Defaults to false).
12122 loadScripts : false,
12125 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12128 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12130 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12133 disableCaching : false,
12135 * Whether to show indicatorText when loading (Defaults to true).
12138 showLoadIndicator : true,
12140 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12143 indicatorText : '<div class="loading-indicator">Loading...</div>'
12147 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12149 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12150 * @param {String/HTMLElement/Roo.Element} el The element to update
12151 * @param {String} url The url
12152 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12153 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12156 * @member Roo.UpdateManager
12158 Roo.UpdateManager.updateElement = function(el, url, params, options){
12159 var um = Roo.get(el, true).getUpdateManager();
12160 Roo.apply(um, options);
12161 um.update(url, params, options ? options.callback : null);
12163 // alias for backwards compat
12164 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12166 * @class Roo.UpdateManager.BasicRenderer
12167 * Default Content renderer. Updates the elements innerHTML with the responseText.
12169 Roo.UpdateManager.BasicRenderer = function(){};
12171 Roo.UpdateManager.BasicRenderer.prototype = {
12173 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12174 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12175 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12176 * @param {Roo.Element} el The element being rendered
12177 * @param {Object} response The YUI Connect response object
12178 * @param {UpdateManager} updateManager The calling update manager
12179 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12181 render : function(el, response, updateManager, callback){
12182 el.update(response.responseText, updateManager.loadScripts, callback);
12188 * (c)) Alan Knowles
12194 * @class Roo.DomTemplate
12195 * @extends Roo.Template
12196 * An effort at a dom based template engine..
12198 * Similar to XTemplate, except it uses dom parsing to create the template..
12200 * Supported features:
12205 {a_variable} - output encoded.
12206 {a_variable.format:("Y-m-d")} - call a method on the variable
12207 {a_variable:raw} - unencoded output
12208 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12209 {a_variable:this.method_on_template(...)} - call a method on the template object.
12214 <div roo-for="a_variable or condition.."></div>
12215 <div roo-if="a_variable or condition"></div>
12216 <div roo-exec="some javascript"></div>
12217 <div roo-name="named_template"></div>
12222 Roo.DomTemplate = function()
12224 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12231 Roo.extend(Roo.DomTemplate, Roo.Template, {
12233 * id counter for sub templates.
12237 * flag to indicate if dom parser is inside a pre,
12238 * it will strip whitespace if not.
12243 * The various sub templates
12251 * basic tag replacing syntax
12254 * // you can fake an object call by doing this
12258 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12259 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12261 iterChild : function (node, method) {
12263 var oldPre = this.inPre;
12264 if (node.tagName == 'PRE') {
12267 for( var i = 0; i < node.childNodes.length; i++) {
12268 method.call(this, node.childNodes[i]);
12270 this.inPre = oldPre;
12276 * compile the template
12278 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12281 compile: function()
12285 // covert the html into DOM...
12289 doc = document.implementation.createHTMLDocument("");
12290 doc.documentElement.innerHTML = this.html ;
12291 div = doc.documentElement;
12293 // old IE... - nasty -- it causes all sorts of issues.. with
12294 // images getting pulled from server..
12295 div = document.createElement('div');
12296 div.innerHTML = this.html;
12298 //doc.documentElement.innerHTML = htmlBody
12304 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12306 var tpls = this.tpls;
12308 // create a top level template from the snippet..
12310 //Roo.log(div.innerHTML);
12317 body : div.innerHTML,
12330 Roo.each(tpls, function(tp){
12331 this.compileTpl(tp);
12332 this.tpls[tp.id] = tp;
12335 this.master = tpls[0];
12341 compileNode : function(node, istop) {
12346 // skip anything not a tag..
12347 if (node.nodeType != 1) {
12348 if (node.nodeType == 3 && !this.inPre) {
12349 // reduce white space..
12350 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12373 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12374 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12375 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12376 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12382 // just itterate children..
12383 this.iterChild(node,this.compileNode);
12386 tpl.uid = this.id++;
12387 tpl.value = node.getAttribute('roo-' + tpl.attr);
12388 node.removeAttribute('roo-'+ tpl.attr);
12389 if (tpl.attr != 'name') {
12390 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12391 node.parentNode.replaceChild(placeholder, node);
12394 var placeholder = document.createElement('span');
12395 placeholder.className = 'roo-tpl-' + tpl.value;
12396 node.parentNode.replaceChild(placeholder, node);
12399 // parent now sees '{domtplXXXX}
12400 this.iterChild(node,this.compileNode);
12402 // we should now have node body...
12403 var div = document.createElement('div');
12404 div.appendChild(node);
12406 // this has the unfortunate side effect of converting tagged attributes
12407 // eg. href="{...}" into %7C...%7D
12408 // this has been fixed by searching for those combo's although it's a bit hacky..
12411 tpl.body = div.innerHTML;
12418 switch (tpl.value) {
12419 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12420 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12421 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12426 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12430 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12434 tpl.id = tpl.value; // replace non characters???
12440 this.tpls.push(tpl);
12450 * Compile a segment of the template into a 'sub-template'
12456 compileTpl : function(tpl)
12458 var fm = Roo.util.Format;
12459 var useF = this.disableFormats !== true;
12461 var sep = Roo.isGecko ? "+\n" : ",\n";
12463 var undef = function(str) {
12464 Roo.debug && Roo.log("Property not found :" + str);
12468 //Roo.log(tpl.body);
12472 var fn = function(m, lbrace, name, format, args)
12475 //Roo.log(arguments);
12476 args = args ? args.replace(/\\'/g,"'") : args;
12477 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12478 if (typeof(format) == 'undefined') {
12479 format = 'htmlEncode';
12481 if (format == 'raw' ) {
12485 if(name.substr(0, 6) == 'domtpl'){
12486 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12489 // build an array of options to determine if value is undefined..
12491 // basically get 'xxxx.yyyy' then do
12492 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12493 // (function () { Roo.log("Property not found"); return ''; })() :
12498 Roo.each(name.split('.'), function(st) {
12499 lookfor += (lookfor.length ? '.': '') + st;
12500 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12503 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12506 if(format && useF){
12508 args = args ? ',' + args : "";
12510 if(format.substr(0, 5) != "this."){
12511 format = "fm." + format + '(';
12513 format = 'this.call("'+ format.substr(5) + '", ';
12517 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12520 if (args && args.length) {
12521 // called with xxyx.yuu:(test,test)
12523 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12525 // raw.. - :raw modifier..
12526 return "'"+ sep + udef_st + name + ")"+sep+"'";
12530 // branched to use + in gecko and [].join() in others
12532 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12533 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12536 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12537 body.push(tpl.body.replace(/(\r\n|\n)/g,
12538 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12539 body.push("'].join('');};};");
12540 body = body.join('');
12543 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12545 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12552 * same as applyTemplate, except it's done to one of the subTemplates
12553 * when using named templates, you can do:
12555 * var str = pl.applySubTemplate('your-name', values);
12558 * @param {Number} id of the template
12559 * @param {Object} values to apply to template
12560 * @param {Object} parent (normaly the instance of this object)
12562 applySubTemplate : function(id, values, parent)
12566 var t = this.tpls[id];
12570 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12571 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12575 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12582 if(t.execCall && t.execCall.call(this, values, parent)){
12586 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12592 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12593 parent = t.target ? values : parent;
12594 if(t.forCall && vs instanceof Array){
12596 for(var i = 0, len = vs.length; i < len; i++){
12598 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12600 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12602 //Roo.log(t.compiled);
12606 return buf.join('');
12609 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12614 return t.compiled.call(this, vs, parent);
12616 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12618 //Roo.log(t.compiled);
12626 applyTemplate : function(values){
12627 return this.master.compiled.call(this, values, {});
12628 //var s = this.subs;
12631 apply : function(){
12632 return this.applyTemplate.apply(this, arguments);
12637 Roo.DomTemplate.from = function(el){
12638 el = Roo.getDom(el);
12639 return new Roo.Domtemplate(el.value || el.innerHTML);
12642 * Ext JS Library 1.1.1
12643 * Copyright(c) 2006-2007, Ext JS, LLC.
12645 * Originally Released Under LGPL - original licence link has changed is not relivant.
12648 * <script type="text/javascript">
12652 * @class Roo.util.DelayedTask
12653 * Provides a convenient method of performing setTimeout where a new
12654 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12655 * You can use this class to buffer
12656 * the keypress events for a certain number of milliseconds, and perform only if they stop
12657 * for that amount of time.
12658 * @constructor The parameters to this constructor serve as defaults and are not required.
12659 * @param {Function} fn (optional) The default function to timeout
12660 * @param {Object} scope (optional) The default scope of that timeout
12661 * @param {Array} args (optional) The default Array of arguments
12663 Roo.util.DelayedTask = function(fn, scope, args){
12664 var id = null, d, t;
12666 var call = function(){
12667 var now = new Date().getTime();
12671 fn.apply(scope, args || []);
12675 * Cancels any pending timeout and queues a new one
12676 * @param {Number} delay The milliseconds to delay
12677 * @param {Function} newFn (optional) Overrides function passed to constructor
12678 * @param {Object} newScope (optional) Overrides scope passed to constructor
12679 * @param {Array} newArgs (optional) Overrides args passed to constructor
12681 this.delay = function(delay, newFn, newScope, newArgs){
12682 if(id && delay != d){
12686 t = new Date().getTime();
12688 scope = newScope || scope;
12689 args = newArgs || args;
12691 id = setInterval(call, d);
12696 * Cancel the last queued timeout
12698 this.cancel = function(){
12706 * Ext JS Library 1.1.1
12707 * Copyright(c) 2006-2007, Ext JS, LLC.
12709 * Originally Released Under LGPL - original licence link has changed is not relivant.
12712 * <script type="text/javascript">
12716 Roo.util.TaskRunner = function(interval){
12717 interval = interval || 10;
12718 var tasks = [], removeQueue = [];
12720 var running = false;
12722 var stopThread = function(){
12728 var startThread = function(){
12731 id = setInterval(runTasks, interval);
12735 var removeTask = function(task){
12736 removeQueue.push(task);
12742 var runTasks = function(){
12743 if(removeQueue.length > 0){
12744 for(var i = 0, len = removeQueue.length; i < len; i++){
12745 tasks.remove(removeQueue[i]);
12748 if(tasks.length < 1){
12753 var now = new Date().getTime();
12754 for(var i = 0, len = tasks.length; i < len; ++i){
12756 var itime = now - t.taskRunTime;
12757 if(t.interval <= itime){
12758 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12759 t.taskRunTime = now;
12760 if(rt === false || t.taskRunCount === t.repeat){
12765 if(t.duration && t.duration <= (now - t.taskStartTime)){
12772 * Queues a new task.
12773 * @param {Object} task
12775 this.start = function(task){
12777 task.taskStartTime = new Date().getTime();
12778 task.taskRunTime = 0;
12779 task.taskRunCount = 0;
12784 this.stop = function(task){
12789 this.stopAll = function(){
12791 for(var i = 0, len = tasks.length; i < len; i++){
12792 if(tasks[i].onStop){
12801 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12803 * Ext JS Library 1.1.1
12804 * Copyright(c) 2006-2007, Ext JS, LLC.
12806 * Originally Released Under LGPL - original licence link has changed is not relivant.
12809 * <script type="text/javascript">
12814 * @class Roo.util.MixedCollection
12815 * @extends Roo.util.Observable
12816 * A Collection class that maintains both numeric indexes and keys and exposes events.
12818 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12819 * collection (defaults to false)
12820 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12821 * and return the key value for that item. This is used when available to look up the key on items that
12822 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12823 * equivalent to providing an implementation for the {@link #getKey} method.
12825 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12833 * Fires when the collection is cleared.
12838 * Fires when an item is added to the collection.
12839 * @param {Number} index The index at which the item was added.
12840 * @param {Object} o The item added.
12841 * @param {String} key The key associated with the added item.
12846 * Fires when an item is replaced in the collection.
12847 * @param {String} key he key associated with the new added.
12848 * @param {Object} old The item being replaced.
12849 * @param {Object} new The new item.
12854 * Fires when an item is removed from the collection.
12855 * @param {Object} o The item being removed.
12856 * @param {String} key (optional) The key associated with the removed item.
12861 this.allowFunctions = allowFunctions === true;
12863 this.getKey = keyFn;
12865 Roo.util.MixedCollection.superclass.constructor.call(this);
12868 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12869 allowFunctions : false,
12872 * Adds an item to the collection.
12873 * @param {String} key The key to associate with the item
12874 * @param {Object} o The item to add.
12875 * @return {Object} The item added.
12877 add : function(key, o){
12878 if(arguments.length == 1){
12880 key = this.getKey(o);
12882 if(typeof key == "undefined" || key === null){
12884 this.items.push(o);
12885 this.keys.push(null);
12887 var old = this.map[key];
12889 return this.replace(key, o);
12892 this.items.push(o);
12894 this.keys.push(key);
12896 this.fireEvent("add", this.length-1, o, key);
12901 * MixedCollection has a generic way to fetch keys if you implement getKey.
12904 var mc = new Roo.util.MixedCollection();
12905 mc.add(someEl.dom.id, someEl);
12906 mc.add(otherEl.dom.id, otherEl);
12910 var mc = new Roo.util.MixedCollection();
12911 mc.getKey = function(el){
12917 // or via the constructor
12918 var mc = new Roo.util.MixedCollection(false, function(el){
12924 * @param o {Object} The item for which to find the key.
12925 * @return {Object} The key for the passed item.
12927 getKey : function(o){
12932 * Replaces an item in the collection.
12933 * @param {String} key The key associated with the item to replace, or the item to replace.
12934 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12935 * @return {Object} The new item.
12937 replace : function(key, o){
12938 if(arguments.length == 1){
12940 key = this.getKey(o);
12942 var old = this.item(key);
12943 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12944 return this.add(key, o);
12946 var index = this.indexOfKey(key);
12947 this.items[index] = o;
12949 this.fireEvent("replace", key, old, o);
12954 * Adds all elements of an Array or an Object to the collection.
12955 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12956 * an Array of values, each of which are added to the collection.
12958 addAll : function(objs){
12959 if(arguments.length > 1 || objs instanceof Array){
12960 var args = arguments.length > 1 ? arguments : objs;
12961 for(var i = 0, len = args.length; i < len; i++){
12965 for(var key in objs){
12966 if(this.allowFunctions || typeof objs[key] != "function"){
12967 this.add(key, objs[key]);
12974 * Executes the specified function once for every item in the collection, passing each
12975 * item as the first and only parameter. returning false from the function will stop the iteration.
12976 * @param {Function} fn The function to execute for each item.
12977 * @param {Object} scope (optional) The scope in which to execute the function.
12979 each : function(fn, scope){
12980 var items = [].concat(this.items); // each safe for removal
12981 for(var i = 0, len = items.length; i < len; i++){
12982 if(fn.call(scope || items[i], items[i], i, len) === false){
12989 * Executes the specified function once for every key in the collection, passing each
12990 * key, and its associated item as the first two parameters.
12991 * @param {Function} fn The function to execute for each item.
12992 * @param {Object} scope (optional) The scope in which to execute the function.
12994 eachKey : function(fn, scope){
12995 for(var i = 0, len = this.keys.length; i < len; i++){
12996 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13001 * Returns the first item in the collection which elicits a true return value from the
13002 * passed selection function.
13003 * @param {Function} fn The selection function to execute for each item.
13004 * @param {Object} scope (optional) The scope in which to execute the function.
13005 * @return {Object} The first item in the collection which returned true from the selection function.
13007 find : function(fn, scope){
13008 for(var i = 0, len = this.items.length; i < len; i++){
13009 if(fn.call(scope || window, this.items[i], this.keys[i])){
13010 return this.items[i];
13017 * Inserts an item at the specified index in the collection.
13018 * @param {Number} index The index to insert the item at.
13019 * @param {String} key The key to associate with the new item, or the item itself.
13020 * @param {Object} o (optional) If the second parameter was a key, the new item.
13021 * @return {Object} The item inserted.
13023 insert : function(index, key, o){
13024 if(arguments.length == 2){
13026 key = this.getKey(o);
13028 if(index >= this.length){
13029 return this.add(key, o);
13032 this.items.splice(index, 0, o);
13033 if(typeof key != "undefined" && key != null){
13036 this.keys.splice(index, 0, key);
13037 this.fireEvent("add", index, o, key);
13042 * Removed an item from the collection.
13043 * @param {Object} o The item to remove.
13044 * @return {Object} The item removed.
13046 remove : function(o){
13047 return this.removeAt(this.indexOf(o));
13051 * Remove an item from a specified index in the collection.
13052 * @param {Number} index The index within the collection of the item to remove.
13054 removeAt : function(index){
13055 if(index < this.length && index >= 0){
13057 var o = this.items[index];
13058 this.items.splice(index, 1);
13059 var key = this.keys[index];
13060 if(typeof key != "undefined"){
13061 delete this.map[key];
13063 this.keys.splice(index, 1);
13064 this.fireEvent("remove", o, key);
13069 * Removed an item associated with the passed key fom the collection.
13070 * @param {String} key The key of the item to remove.
13072 removeKey : function(key){
13073 return this.removeAt(this.indexOfKey(key));
13077 * Returns the number of items in the collection.
13078 * @return {Number} the number of items in the collection.
13080 getCount : function(){
13081 return this.length;
13085 * Returns index within the collection of the passed Object.
13086 * @param {Object} o The item to find the index of.
13087 * @return {Number} index of the item.
13089 indexOf : function(o){
13090 if(!this.items.indexOf){
13091 for(var i = 0, len = this.items.length; i < len; i++){
13092 if(this.items[i] == o) return i;
13096 return this.items.indexOf(o);
13101 * Returns index within the collection of the passed key.
13102 * @param {String} key The key to find the index of.
13103 * @return {Number} index of the key.
13105 indexOfKey : function(key){
13106 if(!this.keys.indexOf){
13107 for(var i = 0, len = this.keys.length; i < len; i++){
13108 if(this.keys[i] == key) return i;
13112 return this.keys.indexOf(key);
13117 * Returns the item associated with the passed key OR index. Key has priority over index.
13118 * @param {String/Number} key The key or index of the item.
13119 * @return {Object} The item associated with the passed key.
13121 item : function(key){
13122 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13123 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13127 * Returns the item at the specified index.
13128 * @param {Number} index The index of the item.
13131 itemAt : function(index){
13132 return this.items[index];
13136 * Returns the item associated with the passed key.
13137 * @param {String/Number} key The key of the item.
13138 * @return {Object} The item associated with the passed key.
13140 key : function(key){
13141 return this.map[key];
13145 * Returns true if the collection contains the passed Object as an item.
13146 * @param {Object} o The Object to look for in the collection.
13147 * @return {Boolean} True if the collection contains the Object as an item.
13149 contains : function(o){
13150 return this.indexOf(o) != -1;
13154 * Returns true if the collection contains the passed Object as a key.
13155 * @param {String} key The key to look for in the collection.
13156 * @return {Boolean} True if the collection contains the Object as a key.
13158 containsKey : function(key){
13159 return typeof this.map[key] != "undefined";
13163 * Removes all items from the collection.
13165 clear : function(){
13170 this.fireEvent("clear");
13174 * Returns the first item in the collection.
13175 * @return {Object} the first item in the collection..
13177 first : function(){
13178 return this.items[0];
13182 * Returns the last item in the collection.
13183 * @return {Object} the last item in the collection..
13186 return this.items[this.length-1];
13189 _sort : function(property, dir, fn){
13190 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13191 fn = fn || function(a, b){
13194 var c = [], k = this.keys, items = this.items;
13195 for(var i = 0, len = items.length; i < len; i++){
13196 c[c.length] = {key: k[i], value: items[i], index: i};
13198 c.sort(function(a, b){
13199 var v = fn(a[property], b[property]) * dsc;
13201 v = (a.index < b.index ? -1 : 1);
13205 for(var i = 0, len = c.length; i < len; i++){
13206 items[i] = c[i].value;
13209 this.fireEvent("sort", this);
13213 * Sorts this collection with the passed comparison function
13214 * @param {String} direction (optional) "ASC" or "DESC"
13215 * @param {Function} fn (optional) comparison function
13217 sort : function(dir, fn){
13218 this._sort("value", dir, fn);
13222 * Sorts this collection by keys
13223 * @param {String} direction (optional) "ASC" or "DESC"
13224 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13226 keySort : function(dir, fn){
13227 this._sort("key", dir, fn || function(a, b){
13228 return String(a).toUpperCase()-String(b).toUpperCase();
13233 * Returns a range of items in this collection
13234 * @param {Number} startIndex (optional) defaults to 0
13235 * @param {Number} endIndex (optional) default to the last item
13236 * @return {Array} An array of items
13238 getRange : function(start, end){
13239 var items = this.items;
13240 if(items.length < 1){
13243 start = start || 0;
13244 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13247 for(var i = start; i <= end; i++) {
13248 r[r.length] = items[i];
13251 for(var i = start; i >= end; i--) {
13252 r[r.length] = items[i];
13259 * Filter the <i>objects</i> in this collection by a specific property.
13260 * Returns a new collection that has been filtered.
13261 * @param {String} property A property on your objects
13262 * @param {String/RegExp} value Either string that the property values
13263 * should start with or a RegExp to test against the property
13264 * @return {MixedCollection} The new filtered collection
13266 filter : function(property, value){
13267 if(!value.exec){ // not a regex
13268 value = String(value);
13269 if(value.length == 0){
13270 return this.clone();
13272 value = new RegExp("^" + Roo.escapeRe(value), "i");
13274 return this.filterBy(function(o){
13275 return o && value.test(o[property]);
13280 * Filter by a function. * Returns a new collection that has been filtered.
13281 * The passed function will be called with each
13282 * object in the collection. If the function returns true, the value is included
13283 * otherwise it is filtered.
13284 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13285 * @param {Object} scope (optional) The scope of the function (defaults to this)
13286 * @return {MixedCollection} The new filtered collection
13288 filterBy : function(fn, scope){
13289 var r = new Roo.util.MixedCollection();
13290 r.getKey = this.getKey;
13291 var k = this.keys, it = this.items;
13292 for(var i = 0, len = it.length; i < len; i++){
13293 if(fn.call(scope||this, it[i], k[i])){
13294 r.add(k[i], it[i]);
13301 * Creates a duplicate of this collection
13302 * @return {MixedCollection}
13304 clone : function(){
13305 var r = new Roo.util.MixedCollection();
13306 var k = this.keys, it = this.items;
13307 for(var i = 0, len = it.length; i < len; i++){
13308 r.add(k[i], it[i]);
13310 r.getKey = this.getKey;
13315 * Returns the item associated with the passed key or index.
13317 * @param {String/Number} key The key or index of the item.
13318 * @return {Object} The item associated with the passed key.
13320 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13322 * Ext JS Library 1.1.1
13323 * Copyright(c) 2006-2007, Ext JS, LLC.
13325 * Originally Released Under LGPL - original licence link has changed is not relivant.
13328 * <script type="text/javascript">
13331 * @class Roo.util.JSON
13332 * Modified version of Douglas Crockford"s json.js that doesn"t
13333 * mess with the Object prototype
13334 * http://www.json.org/js.html
13337 Roo.util.JSON = new (function(){
13338 var useHasOwn = {}.hasOwnProperty ? true : false;
13340 // crashes Safari in some instances
13341 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13343 var pad = function(n) {
13344 return n < 10 ? "0" + n : n;
13357 var encodeString = function(s){
13358 if (/["\\\x00-\x1f]/.test(s)) {
13359 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13364 c = b.charCodeAt();
13366 Math.floor(c / 16).toString(16) +
13367 (c % 16).toString(16);
13370 return '"' + s + '"';
13373 var encodeArray = function(o){
13374 var a = ["["], b, i, l = o.length, v;
13375 for (i = 0; i < l; i += 1) {
13377 switch (typeof v) {
13386 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13394 var encodeDate = function(o){
13395 return '"' + o.getFullYear() + "-" +
13396 pad(o.getMonth() + 1) + "-" +
13397 pad(o.getDate()) + "T" +
13398 pad(o.getHours()) + ":" +
13399 pad(o.getMinutes()) + ":" +
13400 pad(o.getSeconds()) + '"';
13404 * Encodes an Object, Array or other value
13405 * @param {Mixed} o The variable to encode
13406 * @return {String} The JSON string
13408 this.encode = function(o)
13410 // should this be extended to fully wrap stringify..
13412 if(typeof o == "undefined" || o === null){
13414 }else if(o instanceof Array){
13415 return encodeArray(o);
13416 }else if(o instanceof Date){
13417 return encodeDate(o);
13418 }else if(typeof o == "string"){
13419 return encodeString(o);
13420 }else if(typeof o == "number"){
13421 return isFinite(o) ? String(o) : "null";
13422 }else if(typeof o == "boolean"){
13425 var a = ["{"], b, i, v;
13427 if(!useHasOwn || o.hasOwnProperty(i)) {
13429 switch (typeof v) {
13438 a.push(this.encode(i), ":",
13439 v === null ? "null" : this.encode(v));
13450 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13451 * @param {String} json The JSON string
13452 * @return {Object} The resulting object
13454 this.decode = function(json){
13456 return /** eval:var:json */ eval("(" + json + ')');
13460 * Shorthand for {@link Roo.util.JSON#encode}
13461 * @member Roo encode
13463 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13465 * Shorthand for {@link Roo.util.JSON#decode}
13466 * @member Roo decode
13468 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13471 * Ext JS Library 1.1.1
13472 * Copyright(c) 2006-2007, Ext JS, LLC.
13474 * Originally Released Under LGPL - original licence link has changed is not relivant.
13477 * <script type="text/javascript">
13481 * @class Roo.util.Format
13482 * Reusable data formatting functions
13485 Roo.util.Format = function(){
13486 var trimRe = /^\s+|\s+$/g;
13489 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13490 * @param {String} value The string to truncate
13491 * @param {Number} length The maximum length to allow before truncating
13492 * @return {String} The converted text
13494 ellipsis : function(value, len){
13495 if(value && value.length > len){
13496 return value.substr(0, len-3)+"...";
13502 * Checks a reference and converts it to empty string if it is undefined
13503 * @param {Mixed} value Reference to check
13504 * @return {Mixed} Empty string if converted, otherwise the original value
13506 undef : function(value){
13507 return typeof value != "undefined" ? value : "";
13511 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13512 * @param {String} value The string to encode
13513 * @return {String} The encoded text
13515 htmlEncode : function(value){
13516 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13520 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13521 * @param {String} value The string to decode
13522 * @return {String} The decoded text
13524 htmlDecode : function(value){
13525 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13529 * Trims any whitespace from either side of a string
13530 * @param {String} value The text to trim
13531 * @return {String} The trimmed text
13533 trim : function(value){
13534 return String(value).replace(trimRe, "");
13538 * Returns a substring from within an original string
13539 * @param {String} value The original text
13540 * @param {Number} start The start index of the substring
13541 * @param {Number} length The length of the substring
13542 * @return {String} The substring
13544 substr : function(value, start, length){
13545 return String(value).substr(start, length);
13549 * Converts a string to all lower case letters
13550 * @param {String} value The text to convert
13551 * @return {String} The converted text
13553 lowercase : function(value){
13554 return String(value).toLowerCase();
13558 * Converts a string to all upper case letters
13559 * @param {String} value The text to convert
13560 * @return {String} The converted text
13562 uppercase : function(value){
13563 return String(value).toUpperCase();
13567 * Converts the first character only of a string to upper case
13568 * @param {String} value The text to convert
13569 * @return {String} The converted text
13571 capitalize : function(value){
13572 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13576 call : function(value, fn){
13577 if(arguments.length > 2){
13578 var args = Array.prototype.slice.call(arguments, 2);
13579 args.unshift(value);
13581 return /** eval:var:value */ eval(fn).apply(window, args);
13583 /** eval:var:value */
13584 return /** eval:var:value */ eval(fn).call(window, value);
13590 * safer version of Math.toFixed..??/
13591 * @param {Number/String} value The numeric value to format
13592 * @param {Number/String} value Decimal places
13593 * @return {String} The formatted currency string
13595 toFixed : function(v, n)
13597 // why not use to fixed - precision is buggered???
13599 return Math.round(v-0);
13601 var fact = Math.pow(10,n+1);
13602 v = (Math.round((v-0)*fact))/fact;
13603 var z = (''+fact).substring(2);
13604 if (v == Math.floor(v)) {
13605 return Math.floor(v) + '.' + z;
13608 // now just padd decimals..
13609 var ps = String(v).split('.');
13610 var fd = (ps[1] + z);
13611 var r = fd.substring(0,n);
13612 var rm = fd.substring(n);
13614 return ps[0] + '.' + r;
13616 r*=1; // turn it into a number;
13618 if (String(r).length != n) {
13621 r = String(r).substring(1); // chop the end off.
13624 return ps[0] + '.' + r;
13629 * Format a number as US currency
13630 * @param {Number/String} value The numeric value to format
13631 * @return {String} The formatted currency string
13633 usMoney : function(v){
13634 return '$' + Roo.util.Format.number(v);
13639 * eventually this should probably emulate php's number_format
13640 * @param {Number/String} value The numeric value to format
13641 * @param {Number} decimals number of decimal places
13642 * @return {String} The formatted currency string
13644 number : function(v,decimals)
13646 // multiply and round.
13647 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13648 var mul = Math.pow(10, decimals);
13649 var zero = String(mul).substring(1);
13650 v = (Math.round((v-0)*mul))/mul;
13652 // if it's '0' number.. then
13654 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13656 var ps = v.split('.');
13660 var r = /(\d+)(\d{3})/;
13662 while (r.test(whole)) {
13663 whole = whole.replace(r, '$1' + ',' + '$2');
13669 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13670 // does not have decimals
13671 (decimals ? ('.' + zero) : '');
13674 return whole + sub ;
13678 * Parse a value into a formatted date using the specified format pattern.
13679 * @param {Mixed} value The value to format
13680 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13681 * @return {String} The formatted date string
13683 date : function(v, format){
13687 if(!(v instanceof Date)){
13688 v = new Date(Date.parse(v));
13690 return v.dateFormat(format || Roo.util.Format.defaults.date);
13694 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13695 * @param {String} format Any valid date format string
13696 * @return {Function} The date formatting function
13698 dateRenderer : function(format){
13699 return function(v){
13700 return Roo.util.Format.date(v, format);
13705 stripTagsRE : /<\/?[^>]+>/gi,
13708 * Strips all HTML tags
13709 * @param {Mixed} value The text from which to strip tags
13710 * @return {String} The stripped text
13712 stripTags : function(v){
13713 return !v ? v : String(v).replace(this.stripTagsRE, "");
13717 Roo.util.Format.defaults = {
13721 * Ext JS Library 1.1.1
13722 * Copyright(c) 2006-2007, Ext JS, LLC.
13724 * Originally Released Under LGPL - original licence link has changed is not relivant.
13727 * <script type="text/javascript">
13734 * @class Roo.MasterTemplate
13735 * @extends Roo.Template
13736 * Provides a template that can have child templates. The syntax is:
13738 var t = new Roo.MasterTemplate(
13739 '<select name="{name}">',
13740 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13743 t.add('options', {value: 'foo', text: 'bar'});
13744 // or you can add multiple child elements in one shot
13745 t.addAll('options', [
13746 {value: 'foo', text: 'bar'},
13747 {value: 'foo2', text: 'bar2'},
13748 {value: 'foo3', text: 'bar3'}
13750 // then append, applying the master template values
13751 t.append('my-form', {name: 'my-select'});
13753 * A name attribute for the child template is not required if you have only one child
13754 * template or you want to refer to them by index.
13756 Roo.MasterTemplate = function(){
13757 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13758 this.originalHtml = this.html;
13760 var m, re = this.subTemplateRe;
13763 while(m = re.exec(this.html)){
13764 var name = m[1], content = m[2];
13769 tpl : new Roo.Template(content)
13772 st[name] = st[subIndex];
13774 st[subIndex].tpl.compile();
13775 st[subIndex].tpl.call = this.call.createDelegate(this);
13778 this.subCount = subIndex;
13781 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13783 * The regular expression used to match sub templates
13787 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13790 * Applies the passed values to a child template.
13791 * @param {String/Number} name (optional) The name or index of the child template
13792 * @param {Array/Object} values The values to be applied to the template
13793 * @return {MasterTemplate} this
13795 add : function(name, values){
13796 if(arguments.length == 1){
13797 values = arguments[0];
13800 var s = this.subs[name];
13801 s.buffer[s.buffer.length] = s.tpl.apply(values);
13806 * Applies all the passed values to a child template.
13807 * @param {String/Number} name (optional) The name or index of the child template
13808 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13809 * @param {Boolean} reset (optional) True to reset the template first
13810 * @return {MasterTemplate} this
13812 fill : function(name, values, reset){
13814 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13822 for(var i = 0, len = values.length; i < len; i++){
13823 this.add(name, values[i]);
13829 * Resets the template for reuse
13830 * @return {MasterTemplate} this
13832 reset : function(){
13834 for(var i = 0; i < this.subCount; i++){
13840 applyTemplate : function(values){
13842 var replaceIndex = -1;
13843 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13844 return s[++replaceIndex].buffer.join("");
13846 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13849 apply : function(){
13850 return this.applyTemplate.apply(this, arguments);
13853 compile : function(){return this;}
13857 * Alias for fill().
13860 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13862 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13863 * var tpl = Roo.MasterTemplate.from('element-id');
13864 * @param {String/HTMLElement} el
13865 * @param {Object} config
13868 Roo.MasterTemplate.from = function(el, config){
13869 el = Roo.getDom(el);
13870 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13873 * Ext JS Library 1.1.1
13874 * Copyright(c) 2006-2007, Ext JS, LLC.
13876 * Originally Released Under LGPL - original licence link has changed is not relivant.
13879 * <script type="text/javascript">
13884 * @class Roo.util.CSS
13885 * Utility class for manipulating CSS rules
13888 Roo.util.CSS = function(){
13890 var doc = document;
13892 var camelRe = /(-[a-z])/gi;
13893 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13897 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13898 * tag and appended to the HEAD of the document.
13899 * @param {String|Object} cssText The text containing the css rules
13900 * @param {String} id An id to add to the stylesheet for later removal
13901 * @return {StyleSheet}
13903 createStyleSheet : function(cssText, id){
13905 var head = doc.getElementsByTagName("head")[0];
13906 var nrules = doc.createElement("style");
13907 nrules.setAttribute("type", "text/css");
13909 nrules.setAttribute("id", id);
13911 if (typeof(cssText) != 'string') {
13912 // support object maps..
13913 // not sure if this a good idea..
13914 // perhaps it should be merged with the general css handling
13915 // and handle js style props.
13916 var cssTextNew = [];
13917 for(var n in cssText) {
13919 for(var k in cssText[n]) {
13920 citems.push( k + ' : ' +cssText[n][k] + ';' );
13922 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13925 cssText = cssTextNew.join("\n");
13931 head.appendChild(nrules);
13932 ss = nrules.styleSheet;
13933 ss.cssText = cssText;
13936 nrules.appendChild(doc.createTextNode(cssText));
13938 nrules.cssText = cssText;
13940 head.appendChild(nrules);
13941 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13943 this.cacheStyleSheet(ss);
13948 * Removes a style or link tag by id
13949 * @param {String} id The id of the tag
13951 removeStyleSheet : function(id){
13952 var existing = doc.getElementById(id);
13954 existing.parentNode.removeChild(existing);
13959 * Dynamically swaps an existing stylesheet reference for a new one
13960 * @param {String} id The id of an existing link tag to remove
13961 * @param {String} url The href of the new stylesheet to include
13963 swapStyleSheet : function(id, url){
13964 this.removeStyleSheet(id);
13965 var ss = doc.createElement("link");
13966 ss.setAttribute("rel", "stylesheet");
13967 ss.setAttribute("type", "text/css");
13968 ss.setAttribute("id", id);
13969 ss.setAttribute("href", url);
13970 doc.getElementsByTagName("head")[0].appendChild(ss);
13974 * Refresh the rule cache if you have dynamically added stylesheets
13975 * @return {Object} An object (hash) of rules indexed by selector
13977 refreshCache : function(){
13978 return this.getRules(true);
13982 cacheStyleSheet : function(stylesheet){
13986 try{// try catch for cross domain access issue
13987 var ssRules = stylesheet.cssRules || stylesheet.rules;
13988 for(var j = ssRules.length-1; j >= 0; --j){
13989 rules[ssRules[j].selectorText] = ssRules[j];
13995 * Gets all css rules for the document
13996 * @param {Boolean} refreshCache true to refresh the internal cache
13997 * @return {Object} An object (hash) of rules indexed by selector
13999 getRules : function(refreshCache){
14000 if(rules == null || refreshCache){
14002 var ds = doc.styleSheets;
14003 for(var i =0, len = ds.length; i < len; i++){
14005 this.cacheStyleSheet(ds[i]);
14013 * Gets an an individual CSS rule by selector(s)
14014 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14015 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14016 * @return {CSSRule} The CSS rule or null if one is not found
14018 getRule : function(selector, refreshCache){
14019 var rs = this.getRules(refreshCache);
14020 if(!(selector instanceof Array)){
14021 return rs[selector];
14023 for(var i = 0; i < selector.length; i++){
14024 if(rs[selector[i]]){
14025 return rs[selector[i]];
14033 * Updates a rule property
14034 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14035 * @param {String} property The css property
14036 * @param {String} value The new value for the property
14037 * @return {Boolean} true If a rule was found and updated
14039 updateRule : function(selector, property, value){
14040 if(!(selector instanceof Array)){
14041 var rule = this.getRule(selector);
14043 rule.style[property.replace(camelRe, camelFn)] = value;
14047 for(var i = 0; i < selector.length; i++){
14048 if(this.updateRule(selector[i], property, value)){
14058 * Ext JS Library 1.1.1
14059 * Copyright(c) 2006-2007, Ext JS, LLC.
14061 * Originally Released Under LGPL - original licence link has changed is not relivant.
14064 * <script type="text/javascript">
14070 * @class Roo.util.ClickRepeater
14071 * @extends Roo.util.Observable
14073 * A wrapper class which can be applied to any element. Fires a "click" event while the
14074 * mouse is pressed. The interval between firings may be specified in the config but
14075 * defaults to 10 milliseconds.
14077 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14079 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14080 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14081 * Similar to an autorepeat key delay.
14082 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14083 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14084 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14085 * "interval" and "delay" are ignored. "immediate" is honored.
14086 * @cfg {Boolean} preventDefault True to prevent the default click event
14087 * @cfg {Boolean} stopDefault True to stop the default click event
14090 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14091 * 2007-02-02 jvs Renamed to ClickRepeater
14092 * 2007-02-03 jvs Modifications for FF Mac and Safari
14095 * @param {String/HTMLElement/Element} el The element to listen on
14096 * @param {Object} config
14098 Roo.util.ClickRepeater = function(el, config)
14100 this.el = Roo.get(el);
14101 this.el.unselectable();
14103 Roo.apply(this, config);
14108 * Fires when the mouse button is depressed.
14109 * @param {Roo.util.ClickRepeater} this
14111 "mousedown" : true,
14114 * Fires on a specified interval during the time the element is pressed.
14115 * @param {Roo.util.ClickRepeater} this
14120 * Fires when the mouse key is released.
14121 * @param {Roo.util.ClickRepeater} this
14126 this.el.on("mousedown", this.handleMouseDown, this);
14127 if(this.preventDefault || this.stopDefault){
14128 this.el.on("click", function(e){
14129 if(this.preventDefault){
14130 e.preventDefault();
14132 if(this.stopDefault){
14138 // allow inline handler
14140 this.on("click", this.handler, this.scope || this);
14143 Roo.util.ClickRepeater.superclass.constructor.call(this);
14146 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14149 preventDefault : true,
14150 stopDefault : false,
14154 handleMouseDown : function(){
14155 clearTimeout(this.timer);
14157 if(this.pressClass){
14158 this.el.addClass(this.pressClass);
14160 this.mousedownTime = new Date();
14162 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14163 this.el.on("mouseout", this.handleMouseOut, this);
14165 this.fireEvent("mousedown", this);
14166 this.fireEvent("click", this);
14168 this.timer = this.click.defer(this.delay || this.interval, this);
14172 click : function(){
14173 this.fireEvent("click", this);
14174 this.timer = this.click.defer(this.getInterval(), this);
14178 getInterval: function(){
14179 if(!this.accelerate){
14180 return this.interval;
14182 var pressTime = this.mousedownTime.getElapsed();
14183 if(pressTime < 500){
14185 }else if(pressTime < 1700){
14187 }else if(pressTime < 2600){
14189 }else if(pressTime < 3500){
14191 }else if(pressTime < 4400){
14193 }else if(pressTime < 5300){
14195 }else if(pressTime < 6200){
14203 handleMouseOut : function(){
14204 clearTimeout(this.timer);
14205 if(this.pressClass){
14206 this.el.removeClass(this.pressClass);
14208 this.el.on("mouseover", this.handleMouseReturn, this);
14212 handleMouseReturn : function(){
14213 this.el.un("mouseover", this.handleMouseReturn);
14214 if(this.pressClass){
14215 this.el.addClass(this.pressClass);
14221 handleMouseUp : function(){
14222 clearTimeout(this.timer);
14223 this.el.un("mouseover", this.handleMouseReturn);
14224 this.el.un("mouseout", this.handleMouseOut);
14225 Roo.get(document).un("mouseup", this.handleMouseUp);
14226 this.el.removeClass(this.pressClass);
14227 this.fireEvent("mouseup", this);
14231 * Ext JS Library 1.1.1
14232 * Copyright(c) 2006-2007, Ext JS, LLC.
14234 * Originally Released Under LGPL - original licence link has changed is not relivant.
14237 * <script type="text/javascript">
14242 * @class Roo.KeyNav
14243 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14244 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14245 * way to implement custom navigation schemes for any UI component.</p>
14246 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14247 * pageUp, pageDown, del, home, end. Usage:</p>
14249 var nav = new Roo.KeyNav("my-element", {
14250 "left" : function(e){
14251 this.moveLeft(e.ctrlKey);
14253 "right" : function(e){
14254 this.moveRight(e.ctrlKey);
14256 "enter" : function(e){
14263 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14264 * @param {Object} config The config
14266 Roo.KeyNav = function(el, config){
14267 this.el = Roo.get(el);
14268 Roo.apply(this, config);
14269 if(!this.disabled){
14270 this.disabled = true;
14275 Roo.KeyNav.prototype = {
14277 * @cfg {Boolean} disabled
14278 * True to disable this KeyNav instance (defaults to false)
14282 * @cfg {String} defaultEventAction
14283 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14284 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14285 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14287 defaultEventAction: "stopEvent",
14289 * @cfg {Boolean} forceKeyDown
14290 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14291 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14292 * handle keydown instead of keypress.
14294 forceKeyDown : false,
14297 prepareEvent : function(e){
14298 var k = e.getKey();
14299 var h = this.keyToHandler[k];
14300 //if(h && this[h]){
14301 // e.stopPropagation();
14303 if(Roo.isSafari && h && k >= 37 && k <= 40){
14309 relay : function(e){
14310 var k = e.getKey();
14311 var h = this.keyToHandler[k];
14313 if(this.doRelay(e, this[h], h) !== true){
14314 e[this.defaultEventAction]();
14320 doRelay : function(e, h, hname){
14321 return h.call(this.scope || this, e);
14324 // possible handlers
14338 // quick lookup hash
14355 * Enable this KeyNav
14357 enable: function(){
14359 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14360 // the EventObject will normalize Safari automatically
14361 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14362 this.el.on("keydown", this.relay, this);
14364 this.el.on("keydown", this.prepareEvent, this);
14365 this.el.on("keypress", this.relay, this);
14367 this.disabled = false;
14372 * Disable this KeyNav
14374 disable: function(){
14375 if(!this.disabled){
14376 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14377 this.el.un("keydown", this.relay);
14379 this.el.un("keydown", this.prepareEvent);
14380 this.el.un("keypress", this.relay);
14382 this.disabled = true;
14387 * Ext JS Library 1.1.1
14388 * Copyright(c) 2006-2007, Ext JS, LLC.
14390 * Originally Released Under LGPL - original licence link has changed is not relivant.
14393 * <script type="text/javascript">
14398 * @class Roo.KeyMap
14399 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14400 * The constructor accepts the same config object as defined by {@link #addBinding}.
14401 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14402 * combination it will call the function with this signature (if the match is a multi-key
14403 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14404 * A KeyMap can also handle a string representation of keys.<br />
14407 // map one key by key code
14408 var map = new Roo.KeyMap("my-element", {
14409 key: 13, // or Roo.EventObject.ENTER
14414 // map multiple keys to one action by string
14415 var map = new Roo.KeyMap("my-element", {
14421 // map multiple keys to multiple actions by strings and array of codes
14422 var map = new Roo.KeyMap("my-element", [
14425 fn: function(){ alert("Return was pressed"); }
14428 fn: function(){ alert('a, b or c was pressed'); }
14433 fn: function(){ alert('Control + shift + tab was pressed.'); }
14437 * <b>Note: A KeyMap starts enabled</b>
14439 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14440 * @param {Object} config The config (see {@link #addBinding})
14441 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14443 Roo.KeyMap = function(el, config, eventName){
14444 this.el = Roo.get(el);
14445 this.eventName = eventName || "keydown";
14446 this.bindings = [];
14448 this.addBinding(config);
14453 Roo.KeyMap.prototype = {
14455 * True to stop the event from bubbling and prevent the default browser action if the
14456 * key was handled by the KeyMap (defaults to false)
14462 * Add a new binding to this KeyMap. The following config object properties are supported:
14464 Property Type Description
14465 ---------- --------------- ----------------------------------------------------------------------
14466 key String/Array A single keycode or an array of keycodes to handle
14467 shift Boolean True to handle key only when shift is pressed (defaults to false)
14468 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14469 alt Boolean True to handle key only when alt is pressed (defaults to false)
14470 fn Function The function to call when KeyMap finds the expected key combination
14471 scope Object The scope of the callback function
14477 var map = new Roo.KeyMap(document, {
14478 key: Roo.EventObject.ENTER,
14483 //Add a new binding to the existing KeyMap later
14491 * @param {Object/Array} config A single KeyMap config or an array of configs
14493 addBinding : function(config){
14494 if(config instanceof Array){
14495 for(var i = 0, len = config.length; i < len; i++){
14496 this.addBinding(config[i]);
14500 var keyCode = config.key,
14501 shift = config.shift,
14502 ctrl = config.ctrl,
14505 scope = config.scope;
14506 if(typeof keyCode == "string"){
14508 var keyString = keyCode.toUpperCase();
14509 for(var j = 0, len = keyString.length; j < len; j++){
14510 ks.push(keyString.charCodeAt(j));
14514 var keyArray = keyCode instanceof Array;
14515 var handler = function(e){
14516 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14517 var k = e.getKey();
14519 for(var i = 0, len = keyCode.length; i < len; i++){
14520 if(keyCode[i] == k){
14521 if(this.stopEvent){
14524 fn.call(scope || window, k, e);
14530 if(this.stopEvent){
14533 fn.call(scope || window, k, e);
14538 this.bindings.push(handler);
14542 * Shorthand for adding a single key listener
14543 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14544 * following options:
14545 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14546 * @param {Function} fn The function to call
14547 * @param {Object} scope (optional) The scope of the function
14549 on : function(key, fn, scope){
14550 var keyCode, shift, ctrl, alt;
14551 if(typeof key == "object" && !(key instanceof Array)){
14570 handleKeyDown : function(e){
14571 if(this.enabled){ //just in case
14572 var b = this.bindings;
14573 for(var i = 0, len = b.length; i < len; i++){
14574 b[i].call(this, e);
14580 * Returns true if this KeyMap is enabled
14581 * @return {Boolean}
14583 isEnabled : function(){
14584 return this.enabled;
14588 * Enables this KeyMap
14590 enable: function(){
14592 this.el.on(this.eventName, this.handleKeyDown, this);
14593 this.enabled = true;
14598 * Disable this KeyMap
14600 disable: function(){
14602 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14603 this.enabled = false;
14608 * Ext JS Library 1.1.1
14609 * Copyright(c) 2006-2007, Ext JS, LLC.
14611 * Originally Released Under LGPL - original licence link has changed is not relivant.
14614 * <script type="text/javascript">
14619 * @class Roo.util.TextMetrics
14620 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14621 * wide, in pixels, a given block of text will be.
14624 Roo.util.TextMetrics = function(){
14628 * Measures the size of the specified text
14629 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14630 * that can affect the size of the rendered text
14631 * @param {String} text The text to measure
14632 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14633 * in order to accurately measure the text height
14634 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14636 measure : function(el, text, fixedWidth){
14638 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14641 shared.setFixedWidth(fixedWidth || 'auto');
14642 return shared.getSize(text);
14646 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14647 * the overhead of multiple calls to initialize the style properties on each measurement.
14648 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14649 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14650 * in order to accurately measure the text height
14651 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14653 createInstance : function(el, fixedWidth){
14654 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14661 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14662 var ml = new Roo.Element(document.createElement('div'));
14663 document.body.appendChild(ml.dom);
14664 ml.position('absolute');
14665 ml.setLeftTop(-1000, -1000);
14669 ml.setWidth(fixedWidth);
14674 * Returns the size of the specified text based on the internal element's style and width properties
14675 * @memberOf Roo.util.TextMetrics.Instance#
14676 * @param {String} text The text to measure
14677 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14679 getSize : function(text){
14681 var s = ml.getSize();
14687 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14688 * that can affect the size of the rendered text
14689 * @memberOf Roo.util.TextMetrics.Instance#
14690 * @param {String/HTMLElement} el The element, dom node or id
14692 bind : function(el){
14694 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14699 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14700 * to set a fixed width in order to accurately measure the text height.
14701 * @memberOf Roo.util.TextMetrics.Instance#
14702 * @param {Number} width The width to set on the element
14704 setFixedWidth : function(width){
14705 ml.setWidth(width);
14709 * Returns the measured width of the specified text
14710 * @memberOf Roo.util.TextMetrics.Instance#
14711 * @param {String} text The text to measure
14712 * @return {Number} width The width in pixels
14714 getWidth : function(text){
14715 ml.dom.style.width = 'auto';
14716 return this.getSize(text).width;
14720 * Returns the measured height of the specified text. For multiline text, be sure to call
14721 * {@link #setFixedWidth} if necessary.
14722 * @memberOf Roo.util.TextMetrics.Instance#
14723 * @param {String} text The text to measure
14724 * @return {Number} height The height in pixels
14726 getHeight : function(text){
14727 return this.getSize(text).height;
14731 instance.bind(bindTo);
14736 // backwards compat
14737 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14739 * Ext JS Library 1.1.1
14740 * Copyright(c) 2006-2007, Ext JS, LLC.
14742 * Originally Released Under LGPL - original licence link has changed is not relivant.
14745 * <script type="text/javascript">
14749 * @class Roo.state.Provider
14750 * Abstract base class for state provider implementations. This class provides methods
14751 * for encoding and decoding <b>typed</b> variables including dates and defines the
14752 * Provider interface.
14754 Roo.state.Provider = function(){
14756 * @event statechange
14757 * Fires when a state change occurs.
14758 * @param {Provider} this This state provider
14759 * @param {String} key The state key which was changed
14760 * @param {String} value The encoded value for the state
14763 "statechange": true
14766 Roo.state.Provider.superclass.constructor.call(this);
14768 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14770 * Returns the current value for a key
14771 * @param {String} name The key name
14772 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14773 * @return {Mixed} The state data
14775 get : function(name, defaultValue){
14776 return typeof this.state[name] == "undefined" ?
14777 defaultValue : this.state[name];
14781 * Clears a value from the state
14782 * @param {String} name The key name
14784 clear : function(name){
14785 delete this.state[name];
14786 this.fireEvent("statechange", this, name, null);
14790 * Sets the value for a key
14791 * @param {String} name The key name
14792 * @param {Mixed} value The value to set
14794 set : function(name, value){
14795 this.state[name] = value;
14796 this.fireEvent("statechange", this, name, value);
14800 * Decodes a string previously encoded with {@link #encodeValue}.
14801 * @param {String} value The value to decode
14802 * @return {Mixed} The decoded value
14804 decodeValue : function(cookie){
14805 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14806 var matches = re.exec(unescape(cookie));
14807 if(!matches || !matches[1]) return; // non state cookie
14808 var type = matches[1];
14809 var v = matches[2];
14812 return parseFloat(v);
14814 return new Date(Date.parse(v));
14819 var values = v.split("^");
14820 for(var i = 0, len = values.length; i < len; i++){
14821 all.push(this.decodeValue(values[i]));
14826 var values = v.split("^");
14827 for(var i = 0, len = values.length; i < len; i++){
14828 var kv = values[i].split("=");
14829 all[kv[0]] = this.decodeValue(kv[1]);
14838 * Encodes a value including type information. Decode with {@link #decodeValue}.
14839 * @param {Mixed} value The value to encode
14840 * @return {String} The encoded value
14842 encodeValue : function(v){
14844 if(typeof v == "number"){
14846 }else if(typeof v == "boolean"){
14847 enc = "b:" + (v ? "1" : "0");
14848 }else if(v instanceof Date){
14849 enc = "d:" + v.toGMTString();
14850 }else if(v instanceof Array){
14852 for(var i = 0, len = v.length; i < len; i++){
14853 flat += this.encodeValue(v[i]);
14854 if(i != len-1) flat += "^";
14857 }else if(typeof v == "object"){
14860 if(typeof v[key] != "function"){
14861 flat += key + "=" + this.encodeValue(v[key]) + "^";
14864 enc = "o:" + flat.substring(0, flat.length-1);
14868 return escape(enc);
14874 * Ext JS Library 1.1.1
14875 * Copyright(c) 2006-2007, Ext JS, LLC.
14877 * Originally Released Under LGPL - original licence link has changed is not relivant.
14880 * <script type="text/javascript">
14883 * @class Roo.state.Manager
14884 * This is the global state manager. By default all components that are "state aware" check this class
14885 * for state information if you don't pass them a custom state provider. In order for this class
14886 * to be useful, it must be initialized with a provider when your application initializes.
14888 // in your initialization function
14890 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14892 // supposed you have a {@link Roo.BorderLayout}
14893 var layout = new Roo.BorderLayout(...);
14894 layout.restoreState();
14895 // or a {Roo.BasicDialog}
14896 var dialog = new Roo.BasicDialog(...);
14897 dialog.restoreState();
14901 Roo.state.Manager = function(){
14902 var provider = new Roo.state.Provider();
14906 * Configures the default state provider for your application
14907 * @param {Provider} stateProvider The state provider to set
14909 setProvider : function(stateProvider){
14910 provider = stateProvider;
14914 * Returns the current value for a key
14915 * @param {String} name The key name
14916 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14917 * @return {Mixed} The state data
14919 get : function(key, defaultValue){
14920 return provider.get(key, defaultValue);
14924 * Sets the value for a key
14925 * @param {String} name The key name
14926 * @param {Mixed} value The state data
14928 set : function(key, value){
14929 provider.set(key, value);
14933 * Clears a value from the state
14934 * @param {String} name The key name
14936 clear : function(key){
14937 provider.clear(key);
14941 * Gets the currently configured state provider
14942 * @return {Provider} The state provider
14944 getProvider : function(){
14951 * Ext JS Library 1.1.1
14952 * Copyright(c) 2006-2007, Ext JS, LLC.
14954 * Originally Released Under LGPL - original licence link has changed is not relivant.
14957 * <script type="text/javascript">
14960 * @class Roo.state.CookieProvider
14961 * @extends Roo.state.Provider
14962 * The default Provider implementation which saves state via cookies.
14965 var cp = new Roo.state.CookieProvider({
14967 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14968 domain: "roojs.com"
14970 Roo.state.Manager.setProvider(cp);
14972 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14973 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14974 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14975 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14976 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14977 * domain the page is running on including the 'www' like 'www.roojs.com')
14978 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14980 * Create a new CookieProvider
14981 * @param {Object} config The configuration object
14983 Roo.state.CookieProvider = function(config){
14984 Roo.state.CookieProvider.superclass.constructor.call(this);
14986 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14987 this.domain = null;
14988 this.secure = false;
14989 Roo.apply(this, config);
14990 this.state = this.readCookies();
14993 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14995 set : function(name, value){
14996 if(typeof value == "undefined" || value === null){
15000 this.setCookie(name, value);
15001 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15005 clear : function(name){
15006 this.clearCookie(name);
15007 Roo.state.CookieProvider.superclass.clear.call(this, name);
15011 readCookies : function(){
15013 var c = document.cookie + ";";
15014 var re = /\s?(.*?)=(.*?);/g;
15016 while((matches = re.exec(c)) != null){
15017 var name = matches[1];
15018 var value = matches[2];
15019 if(name && name.substring(0,3) == "ys-"){
15020 cookies[name.substr(3)] = this.decodeValue(value);
15027 setCookie : function(name, value){
15028 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15029 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15030 ((this.path == null) ? "" : ("; path=" + this.path)) +
15031 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15032 ((this.secure == true) ? "; secure" : "");
15036 clearCookie : function(name){
15037 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15038 ((this.path == null) ? "" : ("; path=" + this.path)) +
15039 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15040 ((this.secure == true) ? "; secure" : "");
15044 * Ext JS Library 1.1.1
15045 * Copyright(c) 2006-2007, Ext JS, LLC.
15047 * Originally Released Under LGPL - original licence link has changed is not relivant.
15050 * <script type="text/javascript">
15055 * @class Roo.ComponentMgr
15056 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15059 Roo.ComponentMgr = function(){
15060 var all = new Roo.util.MixedCollection();
15064 * Registers a component.
15065 * @param {Roo.Component} c The component
15067 register : function(c){
15072 * Unregisters a component.
15073 * @param {Roo.Component} c The component
15075 unregister : function(c){
15080 * Returns a component by id
15081 * @param {String} id The component id
15083 get : function(id){
15084 return all.get(id);
15088 * Registers a function that will be called when a specified component is added to ComponentMgr
15089 * @param {String} id The component id
15090 * @param {Funtction} fn The callback function
15091 * @param {Object} scope The scope of the callback
15093 onAvailable : function(id, fn, scope){
15094 all.on("add", function(index, o){
15096 fn.call(scope || o, o);
15097 all.un("add", fn, scope);
15104 * Ext JS Library 1.1.1
15105 * Copyright(c) 2006-2007, Ext JS, LLC.
15107 * Originally Released Under LGPL - original licence link has changed is not relivant.
15110 * <script type="text/javascript">
15114 * @class Roo.Component
15115 * @extends Roo.util.Observable
15116 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15117 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15118 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15119 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15120 * All visual components (widgets) that require rendering into a layout should subclass Component.
15122 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15123 * element and its id used as the component id. If a string is passed, it is assumed to be the id of an existing element
15124 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15126 Roo.Component = function(config){
15127 config = config || {};
15128 if(config.tagName || config.dom || typeof config == "string"){ // element object
15129 config = {el: config, id: config.id || config};
15131 this.initialConfig = config;
15133 Roo.apply(this, config);
15137 * Fires after the component is disabled.
15138 * @param {Roo.Component} this
15143 * Fires after the component is enabled.
15144 * @param {Roo.Component} this
15148 * @event beforeshow
15149 * Fires before the component is shown. Return false to stop the show.
15150 * @param {Roo.Component} this
15155 * Fires after the component is shown.
15156 * @param {Roo.Component} this
15160 * @event beforehide
15161 * Fires before the component is hidden. Return false to stop the hide.
15162 * @param {Roo.Component} this
15167 * Fires after the component is hidden.
15168 * @param {Roo.Component} this
15172 * @event beforerender
15173 * Fires before the component is rendered. Return false to stop the render.
15174 * @param {Roo.Component} this
15176 beforerender : true,
15179 * Fires after the component is rendered.
15180 * @param {Roo.Component} this
15184 * @event beforedestroy
15185 * Fires before the component is destroyed. Return false to stop the destroy.
15186 * @param {Roo.Component} this
15188 beforedestroy : true,
15191 * Fires after the component is destroyed.
15192 * @param {Roo.Component} this
15197 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15199 Roo.ComponentMgr.register(this);
15200 Roo.Component.superclass.constructor.call(this);
15201 this.initComponent();
15202 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15203 this.render(this.renderTo);
15204 delete this.renderTo;
15209 Roo.Component.AUTO_ID = 1000;
15211 Roo.extend(Roo.Component, Roo.util.Observable, {
15213 * @scope Roo.Component.prototype
15215 * true if this component is hidden. Read-only.
15220 * true if this component is disabled. Read-only.
15225 * true if this component has been rendered. Read-only.
15229 /** @cfg {String} disableClass
15230 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15232 disabledClass : "x-item-disabled",
15233 /** @cfg {Boolean} allowDomMove
15234 * Whether the component can move the Dom node when rendering (defaults to true).
15236 allowDomMove : true,
15237 /** @cfg {String} hideMode (display|visibility)
15238 * How this component should hidden. Supported values are
15239 * "visibility" (css visibility), "offsets" (negative offset position) and
15240 * "display" (css display) - defaults to "display".
15242 hideMode: 'display',
15245 ctype : "Roo.Component",
15248 * @cfg {String} actionMode
15249 * which property holds the element that used for hide() / show() / disable() / enable()
15255 getActionEl : function(){
15256 return this[this.actionMode];
15259 initComponent : Roo.emptyFn,
15261 * If this is a lazy rendering component, render it to its container element.
15262 * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
15264 render : function(container, position){
15265 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15266 if(!container && this.el){
15267 this.el = Roo.get(this.el);
15268 container = this.el.dom.parentNode;
15269 this.allowDomMove = false;
15271 this.container = Roo.get(container);
15272 this.rendered = true;
15273 if(position !== undefined){
15274 if(typeof position == 'number'){
15275 position = this.container.dom.childNodes[position];
15277 position = Roo.getDom(position);
15280 this.onRender(this.container, position || null);
15282 this.el.addClass(this.cls);
15286 this.el.applyStyles(this.style);
15289 this.fireEvent("render", this);
15290 this.afterRender(this.container);
15302 // default function is not really useful
15303 onRender : function(ct, position){
15305 this.el = Roo.get(this.el);
15306 if(this.allowDomMove !== false){
15307 ct.dom.insertBefore(this.el.dom, position);
15313 getAutoCreate : function(){
15314 var cfg = typeof this.autoCreate == "object" ?
15315 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15316 if(this.id && !cfg.id){
15323 afterRender : Roo.emptyFn,
15326 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15327 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15329 destroy : function(){
15330 if(this.fireEvent("beforedestroy", this) !== false){
15331 this.purgeListeners();
15332 this.beforeDestroy();
15334 this.el.removeAllListeners();
15336 if(this.actionMode == "container"){
15337 this.container.remove();
15341 Roo.ComponentMgr.unregister(this);
15342 this.fireEvent("destroy", this);
15347 beforeDestroy : function(){
15352 onDestroy : function(){
15357 * Returns the underlying {@link Roo.Element}.
15358 * @return {Roo.Element} The element
15360 getEl : function(){
15365 * Returns the id of this component.
15368 getId : function(){
15373 * Try to focus this component.
15374 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15375 * @return {Roo.Component} this
15377 focus : function(selectText){
15380 if(selectText === true){
15381 this.el.dom.select();
15396 * Disable this component.
15397 * @return {Roo.Component} this
15399 disable : function(){
15403 this.disabled = true;
15404 this.fireEvent("disable", this);
15409 onDisable : function(){
15410 this.getActionEl().addClass(this.disabledClass);
15411 this.el.dom.disabled = true;
15415 * Enable this component.
15416 * @return {Roo.Component} this
15418 enable : function(){
15422 this.disabled = false;
15423 this.fireEvent("enable", this);
15428 onEnable : function(){
15429 this.getActionEl().removeClass(this.disabledClass);
15430 this.el.dom.disabled = false;
15434 * Convenience function for setting disabled/enabled by boolean.
15435 * @param {Boolean} disabled
15437 setDisabled : function(disabled){
15438 this[disabled ? "disable" : "enable"]();
15442 * Show this component.
15443 * @return {Roo.Component} this
15446 if(this.fireEvent("beforeshow", this) !== false){
15447 this.hidden = false;
15451 this.fireEvent("show", this);
15457 onShow : function(){
15458 var ae = this.getActionEl();
15459 if(this.hideMode == 'visibility'){
15460 ae.dom.style.visibility = "visible";
15461 }else if(this.hideMode == 'offsets'){
15462 ae.removeClass('x-hidden');
15464 ae.dom.style.display = "";
15469 * Hide this component.
15470 * @return {Roo.Component} this
15473 if(this.fireEvent("beforehide", this) !== false){
15474 this.hidden = true;
15478 this.fireEvent("hide", this);
15484 onHide : function(){
15485 var ae = this.getActionEl();
15486 if(this.hideMode == 'visibility'){
15487 ae.dom.style.visibility = "hidden";
15488 }else if(this.hideMode == 'offsets'){
15489 ae.addClass('x-hidden');
15491 ae.dom.style.display = "none";
15496 * Convenience function to hide or show this component by boolean.
15497 * @param {Boolean} visible True to show, false to hide
15498 * @return {Roo.Component} this
15500 setVisible: function(visible){
15510 * Returns true if this component is visible.
15512 isVisible : function(){
15513 return this.getActionEl().isVisible();
15516 cloneConfig : function(overrides){
15517 overrides = overrides || {};
15518 var id = overrides.id || Roo.id();
15519 var cfg = Roo.applyIf(overrides, this.initialConfig);
15520 cfg.id = id; // prevent dup id
15521 return new this.constructor(cfg);
15525 * Ext JS Library 1.1.1
15526 * Copyright(c) 2006-2007, Ext JS, LLC.
15528 * Originally Released Under LGPL - original licence link has changed is not relivant.
15531 * <script type="text/javascript">
15535 * @class Roo.BoxComponent
15536 * @extends Roo.Component
15537 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15538 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15539 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15540 * layout containers.
15542 * @param {Roo.Element/String/Object} config The configuration options.
15544 Roo.BoxComponent = function(config){
15545 Roo.Component.call(this, config);
15549 * Fires after the component is resized.
15550 * @param {Roo.Component} this
15551 * @param {Number} adjWidth The box-adjusted width that was set
15552 * @param {Number} adjHeight The box-adjusted height that was set
15553 * @param {Number} rawWidth The width that was originally specified
15554 * @param {Number} rawHeight The height that was originally specified
15559 * Fires after the component is moved.
15560 * @param {Roo.Component} this
15561 * @param {Number} x The new x position
15562 * @param {Number} y The new y position
15568 Roo.extend(Roo.BoxComponent, Roo.Component, {
15569 // private, set in afterRender to signify that the component has been rendered
15571 // private, used to defer height settings to subclasses
15572 deferHeight: false,
15573 /** @cfg {Number} width
15574 * width (optional) size of component
15576 /** @cfg {Number} height
15577 * height (optional) size of component
15581 * Sets the width and height of the component. This method fires the resize event. This method can accept
15582 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15583 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15584 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15585 * @return {Roo.BoxComponent} this
15587 setSize : function(w, h){
15588 // support for standard size objects
15589 if(typeof w == 'object'){
15594 if(!this.boxReady){
15600 // prevent recalcs when not needed
15601 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15604 this.lastSize = {width: w, height: h};
15606 var adj = this.adjustSize(w, h);
15607 var aw = adj.width, ah = adj.height;
15608 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15609 var rz = this.getResizeEl();
15610 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15611 rz.setSize(aw, ah);
15612 }else if(!this.deferHeight && ah !== undefined){
15614 }else if(aw !== undefined){
15617 this.onResize(aw, ah, w, h);
15618 this.fireEvent('resize', this, aw, ah, w, h);
15624 * Gets the current size of the component's underlying element.
15625 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15627 getSize : function(){
15628 return this.el.getSize();
15632 * Gets the current XY position of the component's underlying element.
15633 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15634 * @return {Array} The XY position of the element (e.g., [100, 200])
15636 getPosition : function(local){
15637 if(local === true){
15638 return [this.el.getLeft(true), this.el.getTop(true)];
15640 return this.xy || this.el.getXY();
15644 * Gets the current box measurements of the component's underlying element.
15645 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15646 * @returns {Object} box An object in the format {x, y, width, height}
15648 getBox : function(local){
15649 var s = this.el.getSize();
15651 s.x = this.el.getLeft(true);
15652 s.y = this.el.getTop(true);
15654 var xy = this.xy || this.el.getXY();
15662 * Sets the current box measurements of the component's underlying element.
15663 * @param {Object} box An object in the format {x, y, width, height}
15664 * @returns {Roo.BoxComponent} this
15666 updateBox : function(box){
15667 this.setSize(box.width, box.height);
15668 this.setPagePosition(box.x, box.y);
15673 getResizeEl : function(){
15674 return this.resizeEl || this.el;
15678 getPositionEl : function(){
15679 return this.positionEl || this.el;
15683 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15684 * This method fires the move event.
15685 * @param {Number} left The new left
15686 * @param {Number} top The new top
15687 * @returns {Roo.BoxComponent} this
15689 setPosition : function(x, y){
15692 if(!this.boxReady){
15695 var adj = this.adjustPosition(x, y);
15696 var ax = adj.x, ay = adj.y;
15698 var el = this.getPositionEl();
15699 if(ax !== undefined || ay !== undefined){
15700 if(ax !== undefined && ay !== undefined){
15701 el.setLeftTop(ax, ay);
15702 }else if(ax !== undefined){
15704 }else if(ay !== undefined){
15707 this.onPosition(ax, ay);
15708 this.fireEvent('move', this, ax, ay);
15714 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15715 * This method fires the move event.
15716 * @param {Number} x The new x position
15717 * @param {Number} y The new y position
15718 * @returns {Roo.BoxComponent} this
15720 setPagePosition : function(x, y){
15723 if(!this.boxReady){
15726 if(x === undefined || y === undefined){ // cannot translate undefined points
15729 var p = this.el.translatePoints(x, y);
15730 this.setPosition(p.left, p.top);
15735 onRender : function(ct, position){
15736 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15738 this.resizeEl = Roo.get(this.resizeEl);
15740 if(this.positionEl){
15741 this.positionEl = Roo.get(this.positionEl);
15746 afterRender : function(){
15747 Roo.BoxComponent.superclass.afterRender.call(this);
15748 this.boxReady = true;
15749 this.setSize(this.width, this.height);
15750 if(this.x || this.y){
15751 this.setPosition(this.x, this.y);
15753 if(this.pageX || this.pageY){
15754 this.setPagePosition(this.pageX, this.pageY);
15759 * Force the component's size to recalculate based on the underlying element's current height and width.
15760 * @returns {Roo.BoxComponent} this
15762 syncSize : function(){
15763 delete this.lastSize;
15764 this.setSize(this.el.getWidth(), this.el.getHeight());
15769 * Called after the component is resized, this method is empty by default but can be implemented by any
15770 * subclass that needs to perform custom logic after a resize occurs.
15771 * @param {Number} adjWidth The box-adjusted width that was set
15772 * @param {Number} adjHeight The box-adjusted height that was set
15773 * @param {Number} rawWidth The width that was originally specified
15774 * @param {Number} rawHeight The height that was originally specified
15776 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15781 * Called after the component is moved, this method is empty by default but can be implemented by any
15782 * subclass that needs to perform custom logic after a move occurs.
15783 * @param {Number} x The new x position
15784 * @param {Number} y The new y position
15786 onPosition : function(x, y){
15791 adjustSize : function(w, h){
15792 if(this.autoWidth){
15795 if(this.autoHeight){
15798 return {width : w, height: h};
15802 adjustPosition : function(x, y){
15803 return {x : x, y: y};
15806 * Original code for Roojs - LGPL
15807 * <script type="text/javascript">
15811 * @class Roo.XComponent
15812 * A delayed Element creator...
15813 * Or a way to group chunks of interface together.
15814 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15815 * used in conjunction with XComponent.build() it will create an instance of each element,
15816 * then call addxtype() to build the User interface.
15818 * Mypart.xyx = new Roo.XComponent({
15820 parent : 'Mypart.xyz', // empty == document.element.!!
15824 disabled : function() {}
15826 tree : function() { // return an tree of xtype declared components
15830 xtype : 'NestedLayoutPanel',
15837 * It can be used to build a big heiracy, with parent etc.
15838 * or you can just use this to render a single compoent to a dom element
15839 * MYPART.render(Roo.Element | String(id) | dom_element )
15846 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15847 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15849 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15851 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15852 * - if mulitple topModules exist, the last one is defined as the top module.
15856 * When the top level or multiple modules are to embedded into a existing HTML page,
15857 * the parent element can container '#id' of the element where the module will be drawn.
15861 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15862 * it relies more on a include mechanism, where sub modules are included into an outer page.
15863 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15865 * Bootstrap Roo Included elements
15867 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15868 * hence confusing the component builder as it thinks there are multiple top level elements.
15872 * @extends Roo.util.Observable
15874 * @param cfg {Object} configuration of component
15877 Roo.XComponent = function(cfg) {
15878 Roo.apply(this, cfg);
15882 * Fires when this the componnt is built
15883 * @param {Roo.XComponent} c the component
15888 this.region = this.region || 'center'; // default..
15889 Roo.XComponent.register(this);
15890 this.modules = false;
15891 this.el = false; // where the layout goes..
15895 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15898 * The created element (with Roo.factory())
15899 * @type {Roo.Layout}
15905 * for BC - use el in new code
15906 * @type {Roo.Layout}
15912 * for BC - use el in new code
15913 * @type {Roo.Layout}
15918 * @cfg {Function|boolean} disabled
15919 * If this module is disabled by some rule, return true from the funtion
15924 * @cfg {String} parent
15925 * Name of parent element which it get xtype added to..
15930 * @cfg {String} order
15931 * Used to set the order in which elements are created (usefull for multiple tabs)
15936 * @cfg {String} name
15937 * String to display while loading.
15941 * @cfg {String} region
15942 * Region to render component to (defaults to center)
15947 * @cfg {Array} items
15948 * A single item array - the first element is the root of the tree..
15949 * It's done this way to stay compatible with the Xtype system...
15955 * The method that retuns the tree of parts that make up this compoennt
15962 * render element to dom or tree
15963 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15966 render : function(el)
15970 var hp = this.parent ? 1 : 0;
15971 Roo.debug && Roo.log(this);
15973 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15974 // if parent is a '#.....' string, then let's use that..
15975 var ename = this.parent.substr(1);
15976 this.parent = false;
15977 Roo.debug && Roo.log(ename);
15979 case 'bootstrap-body' :
15980 if (typeof(Roo.bootstrap.Body) != 'undefined') {
15981 this.parent = { el : new Roo.bootstrap.Body() };
15982 Roo.debug && Roo.log("setting el to doc body");
15985 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15989 this.parent = { el : true};
15992 el = Roo.get(ename);
15997 if (!el && !this.parent) {
15998 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16002 Roo.debug && Roo.log("EL:");
16003 Roo.debug && Roo.log(el);
16004 Roo.debug && Roo.log("this.parent.el:");
16005 Roo.debug && Roo.log(this.parent.el);
16007 var tree = this._tree ? this._tree() : this.tree();
16009 // altertive root elements ??? - we need a better way to indicate these.
16010 var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16011 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16013 if (!this.parent && is_alt) {
16014 //el = Roo.get(document.body);
16015 this.parent = { el : true };
16020 if (!this.parent) {
16022 Roo.debug && Roo.log("no parent - creating one");
16024 el = el ? Roo.get(el) : false;
16026 // it's a top level one..
16028 el : new Roo.BorderLayout(el || document.body, {
16034 tabPosition: 'top',
16035 //resizeTabs: true,
16036 alwaysShowTabs: el && hp? false : true,
16037 hideTabs: el || !hp ? true : false,
16044 if (!this.parent.el) {
16045 // probably an old style ctor, which has been disabled.
16049 // The 'tree' method is '_tree now'
16051 tree.region = tree.region || this.region;
16053 if (this.parent.el === true) {
16054 // bootstrap... - body..
16055 this.parent.el = Roo.factory(tree);
16058 this.el = this.parent.el.addxtype(tree);
16059 this.fireEvent('built', this);
16061 this.panel = this.el;
16062 this.layout = this.panel.layout;
16063 this.parentLayout = this.parent.layout || false;
16069 Roo.apply(Roo.XComponent, {
16071 * @property hideProgress
16072 * true to disable the building progress bar.. usefull on single page renders.
16075 hideProgress : false,
16077 * @property buildCompleted
16078 * True when the builder has completed building the interface.
16081 buildCompleted : false,
16084 * @property topModule
16085 * the upper most module - uses document.element as it's constructor.
16092 * @property modules
16093 * array of modules to be created by registration system.
16094 * @type {Array} of Roo.XComponent
16099 * @property elmodules
16100 * array of modules to be created by which use #ID
16101 * @type {Array} of Roo.XComponent
16107 * @property build_from_html
16108 * Build elements from html - used by bootstrap HTML stuff
16109 * - this is cleared after build is completed
16110 * @type {boolean} true (default false)
16113 build_from_html : false,
16116 * Register components to be built later.
16118 * This solves the following issues
16119 * - Building is not done on page load, but after an authentication process has occured.
16120 * - Interface elements are registered on page load
16121 * - Parent Interface elements may not be loaded before child, so this handles that..
16128 module : 'Pman.Tab.projectMgr',
16130 parent : 'Pman.layout',
16131 disabled : false, // or use a function..
16134 * * @param {Object} details about module
16136 register : function(obj) {
16138 Roo.XComponent.event.fireEvent('register', obj);
16139 switch(typeof(obj.disabled) ) {
16145 if ( obj.disabled() ) {
16151 if (obj.disabled) {
16157 this.modules.push(obj);
16161 * convert a string to an object..
16162 * eg. 'AAA.BBB' -> finds AAA.BBB
16166 toObject : function(str)
16168 if (!str || typeof(str) == 'object') {
16171 if (str.substring(0,1) == '#') {
16175 var ar = str.split('.');
16180 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16182 throw "Module not found : " + str;
16186 throw "Module not found : " + str;
16188 Roo.each(ar, function(e) {
16189 if (typeof(o[e]) == 'undefined') {
16190 throw "Module not found : " + str;
16201 * move modules into their correct place in the tree..
16204 preBuild : function ()
16207 Roo.each(this.modules , function (obj)
16209 Roo.XComponent.event.fireEvent('beforebuild', obj);
16211 var opar = obj.parent;
16213 obj.parent = this.toObject(opar);
16215 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16220 Roo.debug && Roo.log("GOT top level module");
16221 Roo.debug && Roo.log(obj);
16222 obj.modules = new Roo.util.MixedCollection(false,
16223 function(o) { return o.order + '' }
16225 this.topModule = obj;
16228 // parent is a string (usually a dom element name..)
16229 if (typeof(obj.parent) == 'string') {
16230 this.elmodules.push(obj);
16233 if (obj.parent.constructor != Roo.XComponent) {
16234 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16236 if (!obj.parent.modules) {
16237 obj.parent.modules = new Roo.util.MixedCollection(false,
16238 function(o) { return o.order + '' }
16241 if (obj.parent.disabled) {
16242 obj.disabled = true;
16244 obj.parent.modules.add(obj);
16249 * make a list of modules to build.
16250 * @return {Array} list of modules.
16253 buildOrder : function()
16256 var cmp = function(a,b) {
16257 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16259 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16260 throw "No top level modules to build";
16263 // make a flat list in order of modules to build.
16264 var mods = this.topModule ? [ this.topModule ] : [];
16267 // elmodules (is a list of DOM based modules )
16268 Roo.each(this.elmodules, function(e) {
16270 if (!this.topModule &&
16271 typeof(e.parent) == 'string' &&
16272 e.parent.substring(0,1) == '#' &&
16273 Roo.get(e.parent.substr(1))
16276 _this.topModule = e;
16282 // add modules to their parents..
16283 var addMod = function(m) {
16284 Roo.debug && Roo.log("build Order: add: " + m.name);
16287 if (m.modules && !m.disabled) {
16288 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16289 m.modules.keySort('ASC', cmp );
16290 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16292 m.modules.each(addMod);
16294 Roo.debug && Roo.log("build Order: no child modules");
16296 // not sure if this is used any more..
16298 m.finalize.name = m.name + " (clean up) ";
16299 mods.push(m.finalize);
16303 if (this.topModule && this.topModule.modules) {
16304 this.topModule.modules.keySort('ASC', cmp );
16305 this.topModule.modules.each(addMod);
16311 * Build the registered modules.
16312 * @param {Object} parent element.
16313 * @param {Function} optional method to call after module has been added.
16317 build : function(opts)
16320 if (typeof(opts) != 'undefined') {
16321 Roo.apply(this,opts);
16325 var mods = this.buildOrder();
16327 //this.allmods = mods;
16328 //Roo.debug && Roo.log(mods);
16330 if (!mods.length) { // should not happen
16331 throw "NO modules!!!";
16335 var msg = "Building Interface...";
16336 // flash it up as modal - so we store the mask!?
16337 if (!this.hideProgress && Roo.MessageBox) {
16338 Roo.MessageBox.show({ title: 'loading' });
16339 Roo.MessageBox.show({
16340 title: "Please wait...",
16349 var total = mods.length;
16352 var progressRun = function() {
16353 if (!mods.length) {
16354 Roo.debug && Roo.log('hide?');
16355 if (!this.hideProgress && Roo.MessageBox) {
16356 Roo.MessageBox.hide();
16358 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16360 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16366 var m = mods.shift();
16369 Roo.debug && Roo.log(m);
16370 // not sure if this is supported any more.. - modules that are are just function
16371 if (typeof(m) == 'function') {
16373 return progressRun.defer(10, _this);
16377 msg = "Building Interface " + (total - mods.length) +
16379 (m.name ? (' - ' + m.name) : '');
16380 Roo.debug && Roo.log(msg);
16381 if (!this.hideProgress && Roo.MessageBox) {
16382 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16386 // is the module disabled?
16387 var disabled = (typeof(m.disabled) == 'function') ?
16388 m.disabled.call(m.module.disabled) : m.disabled;
16392 return progressRun(); // we do not update the display!
16400 // it's 10 on top level, and 1 on others??? why...
16401 return progressRun.defer(10, _this);
16404 progressRun.defer(1, _this);
16418 * wrapper for event.on - aliased later..
16419 * Typically use to register a event handler for register:
16421 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16430 Roo.XComponent.event = new Roo.util.Observable({
16434 * Fires when an Component is registered,
16435 * set the disable property on the Component to stop registration.
16436 * @param {Roo.XComponent} c the component being registerd.
16441 * @event beforebuild
16442 * Fires before each Component is built
16443 * can be used to apply permissions.
16444 * @param {Roo.XComponent} c the component being registerd.
16447 'beforebuild' : true,
16449 * @event buildcomplete
16450 * Fires on the top level element when all elements have been built
16451 * @param {Roo.XComponent} the top level component.
16453 'buildcomplete' : true
16458 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16461 * Ext JS Library 1.1.1
16462 * Copyright(c) 2006-2007, Ext JS, LLC.
16464 * Originally Released Under LGPL - original licence link has changed is not relivant.
16467 * <script type="text/javascript">
16473 * These classes are derivatives of the similarly named classes in the YUI Library.
16474 * The original license:
16475 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16476 * Code licensed under the BSD License:
16477 * http://developer.yahoo.net/yui/license.txt
16482 var Event=Roo.EventManager;
16483 var Dom=Roo.lib.Dom;
16486 * @class Roo.dd.DragDrop
16487 * @extends Roo.util.Observable
16488 * Defines the interface and base operation of items that that can be
16489 * dragged or can be drop targets. It was designed to be extended, overriding
16490 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16491 * Up to three html elements can be associated with a DragDrop instance:
16493 * <li>linked element: the element that is passed into the constructor.
16494 * This is the element which defines the boundaries for interaction with
16495 * other DragDrop objects.</li>
16496 * <li>handle element(s): The drag operation only occurs if the element that
16497 * was clicked matches a handle element. By default this is the linked
16498 * element, but there are times that you will want only a portion of the
16499 * linked element to initiate the drag operation, and the setHandleElId()
16500 * method provides a way to define this.</li>
16501 * <li>drag element: this represents the element that would be moved along
16502 * with the cursor during a drag operation. By default, this is the linked
16503 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16504 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16507 * This class should not be instantiated until the onload event to ensure that
16508 * the associated elements are available.
16509 * The following would define a DragDrop obj that would interact with any
16510 * other DragDrop obj in the "group1" group:
16512 * dd = new Roo.dd.DragDrop("div1", "group1");
16514 * Since none of the event handlers have been implemented, nothing would
16515 * actually happen if you were to run the code above. Normally you would
16516 * override this class or one of the default implementations, but you can
16517 * also override the methods you want on an instance of the class...
16519 * dd.onDragDrop = function(e, id) {
16520 * alert("dd was dropped on " + id);
16524 * @param {String} id of the element that is linked to this instance
16525 * @param {String} sGroup the group of related DragDrop objects
16526 * @param {object} config an object containing configurable attributes
16527 * Valid properties for DragDrop:
16528 * padding, isTarget, maintainOffset, primaryButtonOnly
16530 Roo.dd.DragDrop = function(id, sGroup, config) {
16532 this.init(id, sGroup, config);
16537 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16540 * The id of the element associated with this object. This is what we
16541 * refer to as the "linked element" because the size and position of
16542 * this element is used to determine when the drag and drop objects have
16550 * Configuration attributes passed into the constructor
16557 * The id of the element that will be dragged. By default this is same
16558 * as the linked element , but could be changed to another element. Ex:
16560 * @property dragElId
16567 * the id of the element that initiates the drag operation. By default
16568 * this is the linked element, but could be changed to be a child of this
16569 * element. This lets us do things like only starting the drag when the
16570 * header element within the linked html element is clicked.
16571 * @property handleElId
16578 * An associative array of HTML tags that will be ignored if clicked.
16579 * @property invalidHandleTypes
16580 * @type {string: string}
16582 invalidHandleTypes: null,
16585 * An associative array of ids for elements that will be ignored if clicked
16586 * @property invalidHandleIds
16587 * @type {string: string}
16589 invalidHandleIds: null,
16592 * An indexted array of css class names for elements that will be ignored
16594 * @property invalidHandleClasses
16597 invalidHandleClasses: null,
16600 * The linked element's absolute X position at the time the drag was
16602 * @property startPageX
16609 * The linked element's absolute X position at the time the drag was
16611 * @property startPageY
16618 * The group defines a logical collection of DragDrop objects that are
16619 * related. Instances only get events when interacting with other
16620 * DragDrop object in the same group. This lets us define multiple
16621 * groups using a single DragDrop subclass if we want.
16623 * @type {string: string}
16628 * Individual drag/drop instances can be locked. This will prevent
16629 * onmousedown start drag.
16637 * Lock this instance
16640 lock: function() { this.locked = true; },
16643 * Unlock this instace
16646 unlock: function() { this.locked = false; },
16649 * By default, all insances can be a drop target. This can be disabled by
16650 * setting isTarget to false.
16657 * The padding configured for this drag and drop object for calculating
16658 * the drop zone intersection with this object.
16665 * Cached reference to the linked element
16666 * @property _domRef
16672 * Internal typeof flag
16673 * @property __ygDragDrop
16676 __ygDragDrop: true,
16679 * Set to true when horizontal contraints are applied
16680 * @property constrainX
16687 * Set to true when vertical contraints are applied
16688 * @property constrainY
16695 * The left constraint
16703 * The right constraint
16711 * The up constraint
16720 * The down constraint
16728 * Maintain offsets when we resetconstraints. Set to true when you want
16729 * the position of the element relative to its parent to stay the same
16730 * when the page changes
16732 * @property maintainOffset
16735 maintainOffset: false,
16738 * Array of pixel locations the element will snap to if we specified a
16739 * horizontal graduation/interval. This array is generated automatically
16740 * when you define a tick interval.
16747 * Array of pixel locations the element will snap to if we specified a
16748 * vertical graduation/interval. This array is generated automatically
16749 * when you define a tick interval.
16756 * By default the drag and drop instance will only respond to the primary
16757 * button click (left button for a right-handed mouse). Set to true to
16758 * allow drag and drop to start with any mouse click that is propogated
16760 * @property primaryButtonOnly
16763 primaryButtonOnly: true,
16766 * The availabe property is false until the linked dom element is accessible.
16767 * @property available
16773 * By default, drags can only be initiated if the mousedown occurs in the
16774 * region the linked element is. This is done in part to work around a
16775 * bug in some browsers that mis-report the mousedown if the previous
16776 * mouseup happened outside of the window. This property is set to true
16777 * if outer handles are defined.
16779 * @property hasOuterHandles
16783 hasOuterHandles: false,
16786 * Code that executes immediately before the startDrag event
16787 * @method b4StartDrag
16790 b4StartDrag: function(x, y) { },
16793 * Abstract method called after a drag/drop object is clicked
16794 * and the drag or mousedown time thresholds have beeen met.
16795 * @method startDrag
16796 * @param {int} X click location
16797 * @param {int} Y click location
16799 startDrag: function(x, y) { /* override this */ },
16802 * Code that executes immediately before the onDrag event
16806 b4Drag: function(e) { },
16809 * Abstract method called during the onMouseMove event while dragging an
16812 * @param {Event} e the mousemove event
16814 onDrag: function(e) { /* override this */ },
16817 * Abstract method called when this element fist begins hovering over
16818 * another DragDrop obj
16819 * @method onDragEnter
16820 * @param {Event} e the mousemove event
16821 * @param {String|DragDrop[]} id In POINT mode, the element
16822 * id this is hovering over. In INTERSECT mode, an array of one or more
16823 * dragdrop items being hovered over.
16825 onDragEnter: function(e, id) { /* override this */ },
16828 * Code that executes immediately before the onDragOver event
16829 * @method b4DragOver
16832 b4DragOver: function(e) { },
16835 * Abstract method called when this element is hovering over another
16837 * @method onDragOver
16838 * @param {Event} e the mousemove event
16839 * @param {String|DragDrop[]} id In POINT mode, the element
16840 * id this is hovering over. In INTERSECT mode, an array of dd items
16841 * being hovered over.
16843 onDragOver: function(e, id) { /* override this */ },
16846 * Code that executes immediately before the onDragOut event
16847 * @method b4DragOut
16850 b4DragOut: function(e) { },
16853 * Abstract method called when we are no longer hovering over an element
16854 * @method onDragOut
16855 * @param {Event} e the mousemove event
16856 * @param {String|DragDrop[]} id In POINT mode, the element
16857 * id this was hovering over. In INTERSECT mode, an array of dd items
16858 * that the mouse is no longer over.
16860 onDragOut: function(e, id) { /* override this */ },
16863 * Code that executes immediately before the onDragDrop event
16864 * @method b4DragDrop
16867 b4DragDrop: function(e) { },
16870 * Abstract method called when this item is dropped on another DragDrop
16872 * @method onDragDrop
16873 * @param {Event} e the mouseup event
16874 * @param {String|DragDrop[]} id In POINT mode, the element
16875 * id this was dropped on. In INTERSECT mode, an array of dd items this
16878 onDragDrop: function(e, id) { /* override this */ },
16881 * Abstract method called when this item is dropped on an area with no
16883 * @method onInvalidDrop
16884 * @param {Event} e the mouseup event
16886 onInvalidDrop: function(e) { /* override this */ },
16889 * Code that executes immediately before the endDrag event
16890 * @method b4EndDrag
16893 b4EndDrag: function(e) { },
16896 * Fired when we are done dragging the object
16898 * @param {Event} e the mouseup event
16900 endDrag: function(e) { /* override this */ },
16903 * Code executed immediately before the onMouseDown event
16904 * @method b4MouseDown
16905 * @param {Event} e the mousedown event
16908 b4MouseDown: function(e) { },
16911 * Event handler that fires when a drag/drop obj gets a mousedown
16912 * @method onMouseDown
16913 * @param {Event} e the mousedown event
16915 onMouseDown: function(e) { /* override this */ },
16918 * Event handler that fires when a drag/drop obj gets a mouseup
16919 * @method onMouseUp
16920 * @param {Event} e the mouseup event
16922 onMouseUp: function(e) { /* override this */ },
16925 * Override the onAvailable method to do what is needed after the initial
16926 * position was determined.
16927 * @method onAvailable
16929 onAvailable: function () {
16933 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16936 defaultPadding : {left:0, right:0, top:0, bottom:0},
16939 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16943 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16944 { dragElId: "existingProxyDiv" });
16945 dd.startDrag = function(){
16946 this.constrainTo("parent-id");
16949 * Or you can initalize it using the {@link Roo.Element} object:
16951 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16952 startDrag : function(){
16953 this.constrainTo("parent-id");
16957 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16958 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16959 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16960 * an object containing the sides to pad. For example: {right:10, bottom:10}
16961 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16963 constrainTo : function(constrainTo, pad, inContent){
16964 if(typeof pad == "number"){
16965 pad = {left: pad, right:pad, top:pad, bottom:pad};
16967 pad = pad || this.defaultPadding;
16968 var b = Roo.get(this.getEl()).getBox();
16969 var ce = Roo.get(constrainTo);
16970 var s = ce.getScroll();
16971 var c, cd = ce.dom;
16972 if(cd == document.body){
16973 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16976 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16980 var topSpace = b.y - c.y;
16981 var leftSpace = b.x - c.x;
16983 this.resetConstraints();
16984 this.setXConstraint(leftSpace - (pad.left||0), // left
16985 c.width - leftSpace - b.width - (pad.right||0) //right
16987 this.setYConstraint(topSpace - (pad.top||0), //top
16988 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16993 * Returns a reference to the linked element
16995 * @return {HTMLElement} the html element
16997 getEl: function() {
16998 if (!this._domRef) {
16999 this._domRef = Roo.getDom(this.id);
17002 return this._domRef;
17006 * Returns a reference to the actual element to drag. By default this is
17007 * the same as the html element, but it can be assigned to another
17008 * element. An example of this can be found in Roo.dd.DDProxy
17009 * @method getDragEl
17010 * @return {HTMLElement} the html element
17012 getDragEl: function() {
17013 return Roo.getDom(this.dragElId);
17017 * Sets up the DragDrop object. Must be called in the constructor of any
17018 * Roo.dd.DragDrop subclass
17020 * @param id the id of the linked element
17021 * @param {String} sGroup the group of related items
17022 * @param {object} config configuration attributes
17024 init: function(id, sGroup, config) {
17025 this.initTarget(id, sGroup, config);
17026 if (!Roo.isTouch) {
17027 Event.on(this.id, "mousedown", this.handleMouseDown, this);
17029 Event.on(this.id, "touchstart", this.handleMouseDown, this);
17030 // Event.on(this.id, "selectstart", Event.preventDefault);
17034 * Initializes Targeting functionality only... the object does not
17035 * get a mousedown handler.
17036 * @method initTarget
17037 * @param id the id of the linked element
17038 * @param {String} sGroup the group of related items
17039 * @param {object} config configuration attributes
17041 initTarget: function(id, sGroup, config) {
17043 // configuration attributes
17044 this.config = config || {};
17046 // create a local reference to the drag and drop manager
17047 this.DDM = Roo.dd.DDM;
17048 // initialize the groups array
17051 // assume that we have an element reference instead of an id if the
17052 // parameter is not a string
17053 if (typeof id !== "string") {
17060 // add to an interaction group
17061 this.addToGroup((sGroup) ? sGroup : "default");
17063 // We don't want to register this as the handle with the manager
17064 // so we just set the id rather than calling the setter.
17065 this.handleElId = id;
17067 // the linked element is the element that gets dragged by default
17068 this.setDragElId(id);
17070 // by default, clicked anchors will not start drag operations.
17071 this.invalidHandleTypes = { A: "A" };
17072 this.invalidHandleIds = {};
17073 this.invalidHandleClasses = [];
17075 this.applyConfig();
17077 this.handleOnAvailable();
17081 * Applies the configuration parameters that were passed into the constructor.
17082 * This is supposed to happen at each level through the inheritance chain. So
17083 * a DDProxy implentation will execute apply config on DDProxy, DD, and
17084 * DragDrop in order to get all of the parameters that are available in
17086 * @method applyConfig
17088 applyConfig: function() {
17090 // configurable properties:
17091 // padding, isTarget, maintainOffset, primaryButtonOnly
17092 this.padding = this.config.padding || [0, 0, 0, 0];
17093 this.isTarget = (this.config.isTarget !== false);
17094 this.maintainOffset = (this.config.maintainOffset);
17095 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
17100 * Executed when the linked element is available
17101 * @method handleOnAvailable
17104 handleOnAvailable: function() {
17105 this.available = true;
17106 this.resetConstraints();
17107 this.onAvailable();
17111 * Configures the padding for the target zone in px. Effectively expands
17112 * (or reduces) the virtual object size for targeting calculations.
17113 * Supports css-style shorthand; if only one parameter is passed, all sides
17114 * will have that padding, and if only two are passed, the top and bottom
17115 * will have the first param, the left and right the second.
17116 * @method setPadding
17117 * @param {int} iTop Top pad
17118 * @param {int} iRight Right pad
17119 * @param {int} iBot Bot pad
17120 * @param {int} iLeft Left pad
17122 setPadding: function(iTop, iRight, iBot, iLeft) {
17123 // this.padding = [iLeft, iRight, iTop, iBot];
17124 if (!iRight && 0 !== iRight) {
17125 this.padding = [iTop, iTop, iTop, iTop];
17126 } else if (!iBot && 0 !== iBot) {
17127 this.padding = [iTop, iRight, iTop, iRight];
17129 this.padding = [iTop, iRight, iBot, iLeft];
17134 * Stores the initial placement of the linked element.
17135 * @method setInitialPosition
17136 * @param {int} diffX the X offset, default 0
17137 * @param {int} diffY the Y offset, default 0
17139 setInitPosition: function(diffX, diffY) {
17140 var el = this.getEl();
17142 if (!this.DDM.verifyEl(el)) {
17146 var dx = diffX || 0;
17147 var dy = diffY || 0;
17149 var p = Dom.getXY( el );
17151 this.initPageX = p[0] - dx;
17152 this.initPageY = p[1] - dy;
17154 this.lastPageX = p[0];
17155 this.lastPageY = p[1];
17158 this.setStartPosition(p);
17162 * Sets the start position of the element. This is set when the obj
17163 * is initialized, the reset when a drag is started.
17164 * @method setStartPosition
17165 * @param pos current position (from previous lookup)
17168 setStartPosition: function(pos) {
17169 var p = pos || Dom.getXY( this.getEl() );
17170 this.deltaSetXY = null;
17172 this.startPageX = p[0];
17173 this.startPageY = p[1];
17177 * Add this instance to a group of related drag/drop objects. All
17178 * instances belong to at least one group, and can belong to as many
17179 * groups as needed.
17180 * @method addToGroup
17181 * @param sGroup {string} the name of the group
17183 addToGroup: function(sGroup) {
17184 this.groups[sGroup] = true;
17185 this.DDM.regDragDrop(this, sGroup);
17189 * Remove's this instance from the supplied interaction group
17190 * @method removeFromGroup
17191 * @param {string} sGroup The group to drop
17193 removeFromGroup: function(sGroup) {
17194 if (this.groups[sGroup]) {
17195 delete this.groups[sGroup];
17198 this.DDM.removeDDFromGroup(this, sGroup);
17202 * Allows you to specify that an element other than the linked element
17203 * will be moved with the cursor during a drag
17204 * @method setDragElId
17205 * @param id {string} the id of the element that will be used to initiate the drag
17207 setDragElId: function(id) {
17208 this.dragElId = id;
17212 * Allows you to specify a child of the linked element that should be
17213 * used to initiate the drag operation. An example of this would be if
17214 * you have a content div with text and links. Clicking anywhere in the
17215 * content area would normally start the drag operation. Use this method
17216 * to specify that an element inside of the content div is the element
17217 * that starts the drag operation.
17218 * @method setHandleElId
17219 * @param id {string} the id of the element that will be used to
17220 * initiate the drag.
17222 setHandleElId: function(id) {
17223 if (typeof id !== "string") {
17226 this.handleElId = id;
17227 this.DDM.regHandle(this.id, id);
17231 * Allows you to set an element outside of the linked element as a drag
17233 * @method setOuterHandleElId
17234 * @param id the id of the element that will be used to initiate the drag
17236 setOuterHandleElId: function(id) {
17237 if (typeof id !== "string") {
17240 Event.on(id, "mousedown",
17241 this.handleMouseDown, this);
17242 this.setHandleElId(id);
17244 this.hasOuterHandles = true;
17248 * Remove all drag and drop hooks for this element
17251 unreg: function() {
17252 Event.un(this.id, "mousedown",
17253 this.handleMouseDown);
17254 Event.un(this.id, "touchstart",
17255 this.handleMouseDown);
17256 this._domRef = null;
17257 this.DDM._remove(this);
17260 destroy : function(){
17265 * Returns true if this instance is locked, or the drag drop mgr is locked
17266 * (meaning that all drag/drop is disabled on the page.)
17268 * @return {boolean} true if this obj or all drag/drop is locked, else
17271 isLocked: function() {
17272 return (this.DDM.isLocked() || this.locked);
17276 * Fired when this object is clicked
17277 * @method handleMouseDown
17279 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17282 handleMouseDown: function(e, oDD){
17284 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17285 //Roo.log('not touch/ button !=0');
17288 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17289 return; // double touch..
17293 if (this.isLocked()) {
17294 //Roo.log('locked');
17298 this.DDM.refreshCache(this.groups);
17299 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17300 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17301 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17302 //Roo.log('no outer handes or not over target');
17305 // Roo.log('check validator');
17306 if (this.clickValidator(e)) {
17307 // Roo.log('validate success');
17308 // set the initial element position
17309 this.setStartPosition();
17312 this.b4MouseDown(e);
17313 this.onMouseDown(e);
17315 this.DDM.handleMouseDown(e, this);
17317 this.DDM.stopEvent(e);
17325 clickValidator: function(e) {
17326 var target = e.getTarget();
17327 return ( this.isValidHandleChild(target) &&
17328 (this.id == this.handleElId ||
17329 this.DDM.handleWasClicked(target, this.id)) );
17333 * Allows you to specify a tag name that should not start a drag operation
17334 * when clicked. This is designed to facilitate embedding links within a
17335 * drag handle that do something other than start the drag.
17336 * @method addInvalidHandleType
17337 * @param {string} tagName the type of element to exclude
17339 addInvalidHandleType: function(tagName) {
17340 var type = tagName.toUpperCase();
17341 this.invalidHandleTypes[type] = type;
17345 * Lets you to specify an element id for a child of a drag handle
17346 * that should not initiate a drag
17347 * @method addInvalidHandleId
17348 * @param {string} id the element id of the element you wish to ignore
17350 addInvalidHandleId: function(id) {
17351 if (typeof id !== "string") {
17354 this.invalidHandleIds[id] = id;
17358 * Lets you specify a css class of elements that will not initiate a drag
17359 * @method addInvalidHandleClass
17360 * @param {string} cssClass the class of the elements you wish to ignore
17362 addInvalidHandleClass: function(cssClass) {
17363 this.invalidHandleClasses.push(cssClass);
17367 * Unsets an excluded tag name set by addInvalidHandleType
17368 * @method removeInvalidHandleType
17369 * @param {string} tagName the type of element to unexclude
17371 removeInvalidHandleType: function(tagName) {
17372 var type = tagName.toUpperCase();
17373 // this.invalidHandleTypes[type] = null;
17374 delete this.invalidHandleTypes[type];
17378 * Unsets an invalid handle id
17379 * @method removeInvalidHandleId
17380 * @param {string} id the id of the element to re-enable
17382 removeInvalidHandleId: function(id) {
17383 if (typeof id !== "string") {
17386 delete this.invalidHandleIds[id];
17390 * Unsets an invalid css class
17391 * @method removeInvalidHandleClass
17392 * @param {string} cssClass the class of the element(s) you wish to
17395 removeInvalidHandleClass: function(cssClass) {
17396 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17397 if (this.invalidHandleClasses[i] == cssClass) {
17398 delete this.invalidHandleClasses[i];
17404 * Checks the tag exclusion list to see if this click should be ignored
17405 * @method isValidHandleChild
17406 * @param {HTMLElement} node the HTMLElement to evaluate
17407 * @return {boolean} true if this is a valid tag type, false if not
17409 isValidHandleChild: function(node) {
17412 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17415 nodeName = node.nodeName.toUpperCase();
17417 nodeName = node.nodeName;
17419 valid = valid && !this.invalidHandleTypes[nodeName];
17420 valid = valid && !this.invalidHandleIds[node.id];
17422 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17423 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17432 * Create the array of horizontal tick marks if an interval was specified
17433 * in setXConstraint().
17434 * @method setXTicks
17437 setXTicks: function(iStartX, iTickSize) {
17439 this.xTickSize = iTickSize;
17443 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17445 this.xTicks[this.xTicks.length] = i;
17450 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17452 this.xTicks[this.xTicks.length] = i;
17457 this.xTicks.sort(this.DDM.numericSort) ;
17461 * Create the array of vertical tick marks if an interval was specified in
17462 * setYConstraint().
17463 * @method setYTicks
17466 setYTicks: function(iStartY, iTickSize) {
17468 this.yTickSize = iTickSize;
17472 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17474 this.yTicks[this.yTicks.length] = i;
17479 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17481 this.yTicks[this.yTicks.length] = i;
17486 this.yTicks.sort(this.DDM.numericSort) ;
17490 * By default, the element can be dragged any place on the screen. Use
17491 * this method to limit the horizontal travel of the element. Pass in
17492 * 0,0 for the parameters if you want to lock the drag to the y axis.
17493 * @method setXConstraint
17494 * @param {int} iLeft the number of pixels the element can move to the left
17495 * @param {int} iRight the number of pixels the element can move to the
17497 * @param {int} iTickSize optional parameter for specifying that the
17499 * should move iTickSize pixels at a time.
17501 setXConstraint: function(iLeft, iRight, iTickSize) {
17502 this.leftConstraint = iLeft;
17503 this.rightConstraint = iRight;
17505 this.minX = this.initPageX - iLeft;
17506 this.maxX = this.initPageX + iRight;
17507 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17509 this.constrainX = true;
17513 * Clears any constraints applied to this instance. Also clears ticks
17514 * since they can't exist independent of a constraint at this time.
17515 * @method clearConstraints
17517 clearConstraints: function() {
17518 this.constrainX = false;
17519 this.constrainY = false;
17524 * Clears any tick interval defined for this instance
17525 * @method clearTicks
17527 clearTicks: function() {
17528 this.xTicks = null;
17529 this.yTicks = null;
17530 this.xTickSize = 0;
17531 this.yTickSize = 0;
17535 * By default, the element can be dragged any place on the screen. Set
17536 * this to limit the vertical travel of the element. Pass in 0,0 for the
17537 * parameters if you want to lock the drag to the x axis.
17538 * @method setYConstraint
17539 * @param {int} iUp the number of pixels the element can move up
17540 * @param {int} iDown the number of pixels the element can move down
17541 * @param {int} iTickSize optional parameter for specifying that the
17542 * element should move iTickSize pixels at a time.
17544 setYConstraint: function(iUp, iDown, iTickSize) {
17545 this.topConstraint = iUp;
17546 this.bottomConstraint = iDown;
17548 this.minY = this.initPageY - iUp;
17549 this.maxY = this.initPageY + iDown;
17550 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17552 this.constrainY = true;
17557 * resetConstraints must be called if you manually reposition a dd element.
17558 * @method resetConstraints
17559 * @param {boolean} maintainOffset
17561 resetConstraints: function() {
17564 // Maintain offsets if necessary
17565 if (this.initPageX || this.initPageX === 0) {
17566 // figure out how much this thing has moved
17567 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17568 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17570 this.setInitPosition(dx, dy);
17572 // This is the first time we have detected the element's position
17574 this.setInitPosition();
17577 if (this.constrainX) {
17578 this.setXConstraint( this.leftConstraint,
17579 this.rightConstraint,
17583 if (this.constrainY) {
17584 this.setYConstraint( this.topConstraint,
17585 this.bottomConstraint,
17591 * Normally the drag element is moved pixel by pixel, but we can specify
17592 * that it move a number of pixels at a time. This method resolves the
17593 * location when we have it set up like this.
17595 * @param {int} val where we want to place the object
17596 * @param {int[]} tickArray sorted array of valid points
17597 * @return {int} the closest tick
17600 getTick: function(val, tickArray) {
17603 // If tick interval is not defined, it is effectively 1 pixel,
17604 // so we return the value passed to us.
17606 } else if (tickArray[0] >= val) {
17607 // The value is lower than the first tick, so we return the first
17609 return tickArray[0];
17611 for (var i=0, len=tickArray.length; i<len; ++i) {
17613 if (tickArray[next] && tickArray[next] >= val) {
17614 var diff1 = val - tickArray[i];
17615 var diff2 = tickArray[next] - val;
17616 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17620 // The value is larger than the last tick, so we return the last
17622 return tickArray[tickArray.length - 1];
17629 * @return {string} string representation of the dd obj
17631 toString: function() {
17632 return ("DragDrop " + this.id);
17640 * Ext JS Library 1.1.1
17641 * Copyright(c) 2006-2007, Ext JS, LLC.
17643 * Originally Released Under LGPL - original licence link has changed is not relivant.
17646 * <script type="text/javascript">
17651 * The drag and drop utility provides a framework for building drag and drop
17652 * applications. In addition to enabling drag and drop for specific elements,
17653 * the drag and drop elements are tracked by the manager class, and the
17654 * interactions between the various elements are tracked during the drag and
17655 * the implementing code is notified about these important moments.
17658 // Only load the library once. Rewriting the manager class would orphan
17659 // existing drag and drop instances.
17660 if (!Roo.dd.DragDropMgr) {
17663 * @class Roo.dd.DragDropMgr
17664 * DragDropMgr is a singleton that tracks the element interaction for
17665 * all DragDrop items in the window. Generally, you will not call
17666 * this class directly, but it does have helper methods that could
17667 * be useful in your DragDrop implementations.
17670 Roo.dd.DragDropMgr = function() {
17672 var Event = Roo.EventManager;
17677 * Two dimensional Array of registered DragDrop objects. The first
17678 * dimension is the DragDrop item group, the second the DragDrop
17681 * @type {string: string}
17688 * Array of element ids defined as drag handles. Used to determine
17689 * if the element that generated the mousedown event is actually the
17690 * handle and not the html element itself.
17691 * @property handleIds
17692 * @type {string: string}
17699 * the DragDrop object that is currently being dragged
17700 * @property dragCurrent
17708 * the DragDrop object(s) that are being hovered over
17709 * @property dragOvers
17717 * the X distance between the cursor and the object being dragged
17726 * the Y distance between the cursor and the object being dragged
17735 * Flag to determine if we should prevent the default behavior of the
17736 * events we define. By default this is true, but this can be set to
17737 * false if you need the default behavior (not recommended)
17738 * @property preventDefault
17742 preventDefault: true,
17745 * Flag to determine if we should stop the propagation of the events
17746 * we generate. This is true by default but you may want to set it to
17747 * false if the html element contains other features that require the
17749 * @property stopPropagation
17753 stopPropagation: true,
17756 * Internal flag that is set to true when drag and drop has been
17758 * @property initialized
17765 * All drag and drop can be disabled.
17773 * Called the first time an element is registered.
17779 this.initialized = true;
17783 * In point mode, drag and drop interaction is defined by the
17784 * location of the cursor during the drag/drop
17792 * In intersect mode, drag and drop interactio nis defined by the
17793 * overlap of two or more drag and drop objects.
17794 * @property INTERSECT
17801 * The current drag and drop mode. Default: POINT
17809 * Runs method on all drag and drop objects
17810 * @method _execOnAll
17814 _execOnAll: function(sMethod, args) {
17815 for (var i in this.ids) {
17816 for (var j in this.ids[i]) {
17817 var oDD = this.ids[i][j];
17818 if (! this.isTypeOfDD(oDD)) {
17821 oDD[sMethod].apply(oDD, args);
17827 * Drag and drop initialization. Sets up the global event handlers
17832 _onLoad: function() {
17836 if (!Roo.isTouch) {
17837 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17838 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17840 Event.on(document, "touchend", this.handleMouseUp, this, true);
17841 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17843 Event.on(window, "unload", this._onUnload, this, true);
17844 Event.on(window, "resize", this._onResize, this, true);
17845 // Event.on(window, "mouseout", this._test);
17850 * Reset constraints on all drag and drop objs
17851 * @method _onResize
17855 _onResize: function(e) {
17856 this._execOnAll("resetConstraints", []);
17860 * Lock all drag and drop functionality
17864 lock: function() { this.locked = true; },
17867 * Unlock all drag and drop functionality
17871 unlock: function() { this.locked = false; },
17874 * Is drag and drop locked?
17876 * @return {boolean} True if drag and drop is locked, false otherwise.
17879 isLocked: function() { return this.locked; },
17882 * Location cache that is set for all drag drop objects when a drag is
17883 * initiated, cleared when the drag is finished.
17884 * @property locationCache
17891 * Set useCache to false if you want to force object the lookup of each
17892 * drag and drop linked element constantly during a drag.
17893 * @property useCache
17900 * The number of pixels that the mouse needs to move after the
17901 * mousedown before the drag is initiated. Default=3;
17902 * @property clickPixelThresh
17906 clickPixelThresh: 3,
17909 * The number of milliseconds after the mousedown event to initiate the
17910 * drag if we don't get a mouseup event. Default=1000
17911 * @property clickTimeThresh
17915 clickTimeThresh: 350,
17918 * Flag that indicates that either the drag pixel threshold or the
17919 * mousdown time threshold has been met
17920 * @property dragThreshMet
17925 dragThreshMet: false,
17928 * Timeout used for the click time threshold
17929 * @property clickTimeout
17934 clickTimeout: null,
17937 * The X position of the mousedown event stored for later use when a
17938 * drag threshold is met.
17947 * The Y position of the mousedown event stored for later use when a
17948 * drag threshold is met.
17957 * Each DragDrop instance must be registered with the DragDropMgr.
17958 * This is executed in DragDrop.init()
17959 * @method regDragDrop
17960 * @param {DragDrop} oDD the DragDrop object to register
17961 * @param {String} sGroup the name of the group this element belongs to
17964 regDragDrop: function(oDD, sGroup) {
17965 if (!this.initialized) { this.init(); }
17967 if (!this.ids[sGroup]) {
17968 this.ids[sGroup] = {};
17970 this.ids[sGroup][oDD.id] = oDD;
17974 * Removes the supplied dd instance from the supplied group. Executed
17975 * by DragDrop.removeFromGroup, so don't call this function directly.
17976 * @method removeDDFromGroup
17980 removeDDFromGroup: function(oDD, sGroup) {
17981 if (!this.ids[sGroup]) {
17982 this.ids[sGroup] = {};
17985 var obj = this.ids[sGroup];
17986 if (obj && obj[oDD.id]) {
17987 delete obj[oDD.id];
17992 * Unregisters a drag and drop item. This is executed in
17993 * DragDrop.unreg, use that method instead of calling this directly.
17998 _remove: function(oDD) {
17999 for (var g in oDD.groups) {
18000 if (g && this.ids[g][oDD.id]) {
18001 delete this.ids[g][oDD.id];
18004 delete this.handleIds[oDD.id];
18008 * Each DragDrop handle element must be registered. This is done
18009 * automatically when executing DragDrop.setHandleElId()
18010 * @method regHandle
18011 * @param {String} sDDId the DragDrop id this element is a handle for
18012 * @param {String} sHandleId the id of the element that is the drag
18016 regHandle: function(sDDId, sHandleId) {
18017 if (!this.handleIds[sDDId]) {
18018 this.handleIds[sDDId] = {};
18020 this.handleIds[sDDId][sHandleId] = sHandleId;
18024 * Utility function to determine if a given element has been
18025 * registered as a drag drop item.
18026 * @method isDragDrop
18027 * @param {String} id the element id to check
18028 * @return {boolean} true if this element is a DragDrop item,
18032 isDragDrop: function(id) {
18033 return ( this.getDDById(id) ) ? true : false;
18037 * Returns the drag and drop instances that are in all groups the
18038 * passed in instance belongs to.
18039 * @method getRelated
18040 * @param {DragDrop} p_oDD the obj to get related data for
18041 * @param {boolean} bTargetsOnly if true, only return targetable objs
18042 * @return {DragDrop[]} the related instances
18045 getRelated: function(p_oDD, bTargetsOnly) {
18047 for (var i in p_oDD.groups) {
18048 for (j in this.ids[i]) {
18049 var dd = this.ids[i][j];
18050 if (! this.isTypeOfDD(dd)) {
18053 if (!bTargetsOnly || dd.isTarget) {
18054 oDDs[oDDs.length] = dd;
18063 * Returns true if the specified dd target is a legal target for
18064 * the specifice drag obj
18065 * @method isLegalTarget
18066 * @param {DragDrop} the drag obj
18067 * @param {DragDrop} the target
18068 * @return {boolean} true if the target is a legal target for the
18072 isLegalTarget: function (oDD, oTargetDD) {
18073 var targets = this.getRelated(oDD, true);
18074 for (var i=0, len=targets.length;i<len;++i) {
18075 if (targets[i].id == oTargetDD.id) {
18084 * My goal is to be able to transparently determine if an object is
18085 * typeof DragDrop, and the exact subclass of DragDrop. typeof
18086 * returns "object", oDD.constructor.toString() always returns
18087 * "DragDrop" and not the name of the subclass. So for now it just
18088 * evaluates a well-known variable in DragDrop.
18089 * @method isTypeOfDD
18090 * @param {Object} the object to evaluate
18091 * @return {boolean} true if typeof oDD = DragDrop
18094 isTypeOfDD: function (oDD) {
18095 return (oDD && oDD.__ygDragDrop);
18099 * Utility function to determine if a given element has been
18100 * registered as a drag drop handle for the given Drag Drop object.
18102 * @param {String} id the element id to check
18103 * @return {boolean} true if this element is a DragDrop handle, false
18107 isHandle: function(sDDId, sHandleId) {
18108 return ( this.handleIds[sDDId] &&
18109 this.handleIds[sDDId][sHandleId] );
18113 * Returns the DragDrop instance for a given id
18114 * @method getDDById
18115 * @param {String} id the id of the DragDrop object
18116 * @return {DragDrop} the drag drop object, null if it is not found
18119 getDDById: function(id) {
18120 for (var i in this.ids) {
18121 if (this.ids[i][id]) {
18122 return this.ids[i][id];
18129 * Fired after a registered DragDrop object gets the mousedown event.
18130 * Sets up the events required to track the object being dragged
18131 * @method handleMouseDown
18132 * @param {Event} e the event
18133 * @param oDD the DragDrop object being dragged
18137 handleMouseDown: function(e, oDD) {
18139 Roo.QuickTips.disable();
18141 this.currentTarget = e.getTarget();
18143 this.dragCurrent = oDD;
18145 var el = oDD.getEl();
18147 // track start position
18148 this.startX = e.getPageX();
18149 this.startY = e.getPageY();
18151 this.deltaX = this.startX - el.offsetLeft;
18152 this.deltaY = this.startY - el.offsetTop;
18154 this.dragThreshMet = false;
18156 this.clickTimeout = setTimeout(
18158 var DDM = Roo.dd.DDM;
18159 DDM.startDrag(DDM.startX, DDM.startY);
18161 this.clickTimeThresh );
18165 * Fired when either the drag pixel threshol or the mousedown hold
18166 * time threshold has been met.
18167 * @method startDrag
18168 * @param x {int} the X position of the original mousedown
18169 * @param y {int} the Y position of the original mousedown
18172 startDrag: function(x, y) {
18173 clearTimeout(this.clickTimeout);
18174 if (this.dragCurrent) {
18175 this.dragCurrent.b4StartDrag(x, y);
18176 this.dragCurrent.startDrag(x, y);
18178 this.dragThreshMet = true;
18182 * Internal function to handle the mouseup event. Will be invoked
18183 * from the context of the document.
18184 * @method handleMouseUp
18185 * @param {Event} e the event
18189 handleMouseUp: function(e) {
18192 Roo.QuickTips.enable();
18194 if (! this.dragCurrent) {
18198 clearTimeout(this.clickTimeout);
18200 if (this.dragThreshMet) {
18201 this.fireEvents(e, true);
18211 * Utility to stop event propagation and event default, if these
18212 * features are turned on.
18213 * @method stopEvent
18214 * @param {Event} e the event as returned by this.getEvent()
18217 stopEvent: function(e){
18218 if(this.stopPropagation) {
18219 e.stopPropagation();
18222 if (this.preventDefault) {
18223 e.preventDefault();
18228 * Internal function to clean up event handlers after the drag
18229 * operation is complete
18231 * @param {Event} e the event
18235 stopDrag: function(e) {
18236 // Fire the drag end event for the item that was dragged
18237 if (this.dragCurrent) {
18238 if (this.dragThreshMet) {
18239 this.dragCurrent.b4EndDrag(e);
18240 this.dragCurrent.endDrag(e);
18243 this.dragCurrent.onMouseUp(e);
18246 this.dragCurrent = null;
18247 this.dragOvers = {};
18251 * Internal function to handle the mousemove event. Will be invoked
18252 * from the context of the html element.
18254 * @TODO figure out what we can do about mouse events lost when the
18255 * user drags objects beyond the window boundary. Currently we can
18256 * detect this in internet explorer by verifying that the mouse is
18257 * down during the mousemove event. Firefox doesn't give us the
18258 * button state on the mousemove event.
18259 * @method handleMouseMove
18260 * @param {Event} e the event
18264 handleMouseMove: function(e) {
18265 if (! this.dragCurrent) {
18269 // var button = e.which || e.button;
18271 // check for IE mouseup outside of page boundary
18272 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18274 return this.handleMouseUp(e);
18277 if (!this.dragThreshMet) {
18278 var diffX = Math.abs(this.startX - e.getPageX());
18279 var diffY = Math.abs(this.startY - e.getPageY());
18280 if (diffX > this.clickPixelThresh ||
18281 diffY > this.clickPixelThresh) {
18282 this.startDrag(this.startX, this.startY);
18286 if (this.dragThreshMet) {
18287 this.dragCurrent.b4Drag(e);
18288 this.dragCurrent.onDrag(e);
18289 if(!this.dragCurrent.moveOnly){
18290 this.fireEvents(e, false);
18300 * Iterates over all of the DragDrop elements to find ones we are
18301 * hovering over or dropping on
18302 * @method fireEvents
18303 * @param {Event} e the event
18304 * @param {boolean} isDrop is this a drop op or a mouseover op?
18308 fireEvents: function(e, isDrop) {
18309 var dc = this.dragCurrent;
18311 // If the user did the mouse up outside of the window, we could
18312 // get here even though we have ended the drag.
18313 if (!dc || dc.isLocked()) {
18317 var pt = e.getPoint();
18319 // cache the previous dragOver array
18325 var enterEvts = [];
18327 // Check to see if the object(s) we were hovering over is no longer
18328 // being hovered over so we can fire the onDragOut event
18329 for (var i in this.dragOvers) {
18331 var ddo = this.dragOvers[i];
18333 if (! this.isTypeOfDD(ddo)) {
18337 if (! this.isOverTarget(pt, ddo, this.mode)) {
18338 outEvts.push( ddo );
18341 oldOvers[i] = true;
18342 delete this.dragOvers[i];
18345 for (var sGroup in dc.groups) {
18347 if ("string" != typeof sGroup) {
18351 for (i in this.ids[sGroup]) {
18352 var oDD = this.ids[sGroup][i];
18353 if (! this.isTypeOfDD(oDD)) {
18357 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18358 if (this.isOverTarget(pt, oDD, this.mode)) {
18359 // look for drop interactions
18361 dropEvts.push( oDD );
18362 // look for drag enter and drag over interactions
18365 // initial drag over: dragEnter fires
18366 if (!oldOvers[oDD.id]) {
18367 enterEvts.push( oDD );
18368 // subsequent drag overs: dragOver fires
18370 overEvts.push( oDD );
18373 this.dragOvers[oDD.id] = oDD;
18381 if (outEvts.length) {
18382 dc.b4DragOut(e, outEvts);
18383 dc.onDragOut(e, outEvts);
18386 if (enterEvts.length) {
18387 dc.onDragEnter(e, enterEvts);
18390 if (overEvts.length) {
18391 dc.b4DragOver(e, overEvts);
18392 dc.onDragOver(e, overEvts);
18395 if (dropEvts.length) {
18396 dc.b4DragDrop(e, dropEvts);
18397 dc.onDragDrop(e, dropEvts);
18401 // fire dragout events
18403 for (i=0, len=outEvts.length; i<len; ++i) {
18404 dc.b4DragOut(e, outEvts[i].id);
18405 dc.onDragOut(e, outEvts[i].id);
18408 // fire enter events
18409 for (i=0,len=enterEvts.length; i<len; ++i) {
18410 // dc.b4DragEnter(e, oDD.id);
18411 dc.onDragEnter(e, enterEvts[i].id);
18414 // fire over events
18415 for (i=0,len=overEvts.length; i<len; ++i) {
18416 dc.b4DragOver(e, overEvts[i].id);
18417 dc.onDragOver(e, overEvts[i].id);
18420 // fire drop events
18421 for (i=0, len=dropEvts.length; i<len; ++i) {
18422 dc.b4DragDrop(e, dropEvts[i].id);
18423 dc.onDragDrop(e, dropEvts[i].id);
18428 // notify about a drop that did not find a target
18429 if (isDrop && !dropEvts.length) {
18430 dc.onInvalidDrop(e);
18436 * Helper function for getting the best match from the list of drag
18437 * and drop objects returned by the drag and drop events when we are
18438 * in INTERSECT mode. It returns either the first object that the
18439 * cursor is over, or the object that has the greatest overlap with
18440 * the dragged element.
18441 * @method getBestMatch
18442 * @param {DragDrop[]} dds The array of drag and drop objects
18444 * @return {DragDrop} The best single match
18447 getBestMatch: function(dds) {
18449 // Return null if the input is not what we expect
18450 //if (!dds || !dds.length || dds.length == 0) {
18452 // If there is only one item, it wins
18453 //} else if (dds.length == 1) {
18455 var len = dds.length;
18460 // Loop through the targeted items
18461 for (var i=0; i<len; ++i) {
18463 // If the cursor is over the object, it wins. If the
18464 // cursor is over multiple matches, the first one we come
18466 if (dd.cursorIsOver) {
18469 // Otherwise the object with the most overlap wins
18472 winner.overlap.getArea() < dd.overlap.getArea()) {
18483 * Refreshes the cache of the top-left and bottom-right points of the
18484 * drag and drop objects in the specified group(s). This is in the
18485 * format that is stored in the drag and drop instance, so typical
18488 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18492 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18494 * @TODO this really should be an indexed array. Alternatively this
18495 * method could accept both.
18496 * @method refreshCache
18497 * @param {Object} groups an associative array of groups to refresh
18500 refreshCache: function(groups) {
18501 for (var sGroup in groups) {
18502 if ("string" != typeof sGroup) {
18505 for (var i in this.ids[sGroup]) {
18506 var oDD = this.ids[sGroup][i];
18508 if (this.isTypeOfDD(oDD)) {
18509 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18510 var loc = this.getLocation(oDD);
18512 this.locationCache[oDD.id] = loc;
18514 delete this.locationCache[oDD.id];
18515 // this will unregister the drag and drop object if
18516 // the element is not in a usable state
18525 * This checks to make sure an element exists and is in the DOM. The
18526 * main purpose is to handle cases where innerHTML is used to remove
18527 * drag and drop objects from the DOM. IE provides an 'unspecified
18528 * error' when trying to access the offsetParent of such an element
18530 * @param {HTMLElement} el the element to check
18531 * @return {boolean} true if the element looks usable
18534 verifyEl: function(el) {
18539 parent = el.offsetParent;
18542 parent = el.offsetParent;
18553 * Returns a Region object containing the drag and drop element's position
18554 * and size, including the padding configured for it
18555 * @method getLocation
18556 * @param {DragDrop} oDD the drag and drop object to get the
18558 * @return {Roo.lib.Region} a Region object representing the total area
18559 * the element occupies, including any padding
18560 * the instance is configured for.
18563 getLocation: function(oDD) {
18564 if (! this.isTypeOfDD(oDD)) {
18568 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18571 pos= Roo.lib.Dom.getXY(el);
18579 x2 = x1 + el.offsetWidth;
18581 y2 = y1 + el.offsetHeight;
18583 t = y1 - oDD.padding[0];
18584 r = x2 + oDD.padding[1];
18585 b = y2 + oDD.padding[2];
18586 l = x1 - oDD.padding[3];
18588 return new Roo.lib.Region( t, r, b, l );
18592 * Checks the cursor location to see if it over the target
18593 * @method isOverTarget
18594 * @param {Roo.lib.Point} pt The point to evaluate
18595 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18596 * @return {boolean} true if the mouse is over the target
18600 isOverTarget: function(pt, oTarget, intersect) {
18601 // use cache if available
18602 var loc = this.locationCache[oTarget.id];
18603 if (!loc || !this.useCache) {
18604 loc = this.getLocation(oTarget);
18605 this.locationCache[oTarget.id] = loc;
18613 oTarget.cursorIsOver = loc.contains( pt );
18615 // DragDrop is using this as a sanity check for the initial mousedown
18616 // in this case we are done. In POINT mode, if the drag obj has no
18617 // contraints, we are also done. Otherwise we need to evaluate the
18618 // location of the target as related to the actual location of the
18619 // dragged element.
18620 var dc = this.dragCurrent;
18621 if (!dc || !dc.getTargetCoord ||
18622 (!intersect && !dc.constrainX && !dc.constrainY)) {
18623 return oTarget.cursorIsOver;
18626 oTarget.overlap = null;
18628 // Get the current location of the drag element, this is the
18629 // location of the mouse event less the delta that represents
18630 // where the original mousedown happened on the element. We
18631 // need to consider constraints and ticks as well.
18632 var pos = dc.getTargetCoord(pt.x, pt.y);
18634 var el = dc.getDragEl();
18635 var curRegion = new Roo.lib.Region( pos.y,
18636 pos.x + el.offsetWidth,
18637 pos.y + el.offsetHeight,
18640 var overlap = curRegion.intersect(loc);
18643 oTarget.overlap = overlap;
18644 return (intersect) ? true : oTarget.cursorIsOver;
18651 * unload event handler
18652 * @method _onUnload
18656 _onUnload: function(e, me) {
18657 Roo.dd.DragDropMgr.unregAll();
18661 * Cleans up the drag and drop events and objects.
18666 unregAll: function() {
18668 if (this.dragCurrent) {
18670 this.dragCurrent = null;
18673 this._execOnAll("unreg", []);
18675 for (i in this.elementCache) {
18676 delete this.elementCache[i];
18679 this.elementCache = {};
18684 * A cache of DOM elements
18685 * @property elementCache
18692 * Get the wrapper for the DOM element specified
18693 * @method getElWrapper
18694 * @param {String} id the id of the element to get
18695 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18697 * @deprecated This wrapper isn't that useful
18700 getElWrapper: function(id) {
18701 var oWrapper = this.elementCache[id];
18702 if (!oWrapper || !oWrapper.el) {
18703 oWrapper = this.elementCache[id] =
18704 new this.ElementWrapper(Roo.getDom(id));
18710 * Returns the actual DOM element
18711 * @method getElement
18712 * @param {String} id the id of the elment to get
18713 * @return {Object} The element
18714 * @deprecated use Roo.getDom instead
18717 getElement: function(id) {
18718 return Roo.getDom(id);
18722 * Returns the style property for the DOM element (i.e.,
18723 * document.getElById(id).style)
18725 * @param {String} id the id of the elment to get
18726 * @return {Object} The style property of the element
18727 * @deprecated use Roo.getDom instead
18730 getCss: function(id) {
18731 var el = Roo.getDom(id);
18732 return (el) ? el.style : null;
18736 * Inner class for cached elements
18737 * @class DragDropMgr.ElementWrapper
18742 ElementWrapper: function(el) {
18747 this.el = el || null;
18752 this.id = this.el && el.id;
18754 * A reference to the style property
18757 this.css = this.el && el.style;
18761 * Returns the X position of an html element
18763 * @param el the element for which to get the position
18764 * @return {int} the X coordinate
18766 * @deprecated use Roo.lib.Dom.getX instead
18769 getPosX: function(el) {
18770 return Roo.lib.Dom.getX(el);
18774 * Returns the Y position of an html element
18776 * @param el the element for which to get the position
18777 * @return {int} the Y coordinate
18778 * @deprecated use Roo.lib.Dom.getY instead
18781 getPosY: function(el) {
18782 return Roo.lib.Dom.getY(el);
18786 * Swap two nodes. In IE, we use the native method, for others we
18787 * emulate the IE behavior
18789 * @param n1 the first node to swap
18790 * @param n2 the other node to swap
18793 swapNode: function(n1, n2) {
18797 var p = n2.parentNode;
18798 var s = n2.nextSibling;
18801 p.insertBefore(n1, n2);
18802 } else if (n2 == n1.nextSibling) {
18803 p.insertBefore(n2, n1);
18805 n1.parentNode.replaceChild(n2, n1);
18806 p.insertBefore(n1, s);
18812 * Returns the current scroll position
18813 * @method getScroll
18817 getScroll: function () {
18818 var t, l, dde=document.documentElement, db=document.body;
18819 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18821 l = dde.scrollLeft;
18828 return { top: t, left: l };
18832 * Returns the specified element style property
18834 * @param {HTMLElement} el the element
18835 * @param {string} styleProp the style property
18836 * @return {string} The value of the style property
18837 * @deprecated use Roo.lib.Dom.getStyle
18840 getStyle: function(el, styleProp) {
18841 return Roo.fly(el).getStyle(styleProp);
18845 * Gets the scrollTop
18846 * @method getScrollTop
18847 * @return {int} the document's scrollTop
18850 getScrollTop: function () { return this.getScroll().top; },
18853 * Gets the scrollLeft
18854 * @method getScrollLeft
18855 * @return {int} the document's scrollTop
18858 getScrollLeft: function () { return this.getScroll().left; },
18861 * Sets the x/y position of an element to the location of the
18864 * @param {HTMLElement} moveEl The element to move
18865 * @param {HTMLElement} targetEl The position reference element
18868 moveToEl: function (moveEl, targetEl) {
18869 var aCoord = Roo.lib.Dom.getXY(targetEl);
18870 Roo.lib.Dom.setXY(moveEl, aCoord);
18874 * Numeric array sort function
18875 * @method numericSort
18878 numericSort: function(a, b) { return (a - b); },
18882 * @property _timeoutCount
18889 * Trying to make the load order less important. Without this we get
18890 * an error if this file is loaded before the Event Utility.
18891 * @method _addListeners
18895 _addListeners: function() {
18896 var DDM = Roo.dd.DDM;
18897 if ( Roo.lib.Event && document ) {
18900 if (DDM._timeoutCount > 2000) {
18902 setTimeout(DDM._addListeners, 10);
18903 if (document && document.body) {
18904 DDM._timeoutCount += 1;
18911 * Recursively searches the immediate parent and all child nodes for
18912 * the handle element in order to determine wheter or not it was
18914 * @method handleWasClicked
18915 * @param node the html element to inspect
18918 handleWasClicked: function(node, id) {
18919 if (this.isHandle(id, node.id)) {
18922 // check to see if this is a text node child of the one we want
18923 var p = node.parentNode;
18926 if (this.isHandle(id, p.id)) {
18941 // shorter alias, save a few bytes
18942 Roo.dd.DDM = Roo.dd.DragDropMgr;
18943 Roo.dd.DDM._addListeners();
18947 * Ext JS Library 1.1.1
18948 * Copyright(c) 2006-2007, Ext JS, LLC.
18950 * Originally Released Under LGPL - original licence link has changed is not relivant.
18953 * <script type="text/javascript">
18958 * A DragDrop implementation where the linked element follows the
18959 * mouse cursor during a drag.
18960 * @extends Roo.dd.DragDrop
18962 * @param {String} id the id of the linked element
18963 * @param {String} sGroup the group of related DragDrop items
18964 * @param {object} config an object containing configurable attributes
18965 * Valid properties for DD:
18968 Roo.dd.DD = function(id, sGroup, config) {
18970 this.init(id, sGroup, config);
18974 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18977 * When set to true, the utility automatically tries to scroll the browser
18978 * window wehn a drag and drop element is dragged near the viewport boundary.
18979 * Defaults to true.
18986 * Sets the pointer offset to the distance between the linked element's top
18987 * left corner and the location the element was clicked
18988 * @method autoOffset
18989 * @param {int} iPageX the X coordinate of the click
18990 * @param {int} iPageY the Y coordinate of the click
18992 autoOffset: function(iPageX, iPageY) {
18993 var x = iPageX - this.startPageX;
18994 var y = iPageY - this.startPageY;
18995 this.setDelta(x, y);
18999 * Sets the pointer offset. You can call this directly to force the
19000 * offset to be in a particular location (e.g., pass in 0,0 to set it
19001 * to the center of the object)
19003 * @param {int} iDeltaX the distance from the left
19004 * @param {int} iDeltaY the distance from the top
19006 setDelta: function(iDeltaX, iDeltaY) {
19007 this.deltaX = iDeltaX;
19008 this.deltaY = iDeltaY;
19012 * Sets the drag element to the location of the mousedown or click event,
19013 * maintaining the cursor location relative to the location on the element
19014 * that was clicked. Override this if you want to place the element in a
19015 * location other than where the cursor is.
19016 * @method setDragElPos
19017 * @param {int} iPageX the X coordinate of the mousedown or drag event
19018 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19020 setDragElPos: function(iPageX, iPageY) {
19021 // the first time we do this, we are going to check to make sure
19022 // the element has css positioning
19024 var el = this.getDragEl();
19025 this.alignElWithMouse(el, iPageX, iPageY);
19029 * Sets the element to the location of the mousedown or click event,
19030 * maintaining the cursor location relative to the location on the element
19031 * that was clicked. Override this if you want to place the element in a
19032 * location other than where the cursor is.
19033 * @method alignElWithMouse
19034 * @param {HTMLElement} el the element to move
19035 * @param {int} iPageX the X coordinate of the mousedown or drag event
19036 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19038 alignElWithMouse: function(el, iPageX, iPageY) {
19039 var oCoord = this.getTargetCoord(iPageX, iPageY);
19040 var fly = el.dom ? el : Roo.fly(el);
19041 if (!this.deltaSetXY) {
19042 var aCoord = [oCoord.x, oCoord.y];
19044 var newLeft = fly.getLeft(true);
19045 var newTop = fly.getTop(true);
19046 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
19048 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
19051 this.cachePosition(oCoord.x, oCoord.y);
19052 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
19057 * Saves the most recent position so that we can reset the constraints and
19058 * tick marks on-demand. We need to know this so that we can calculate the
19059 * number of pixels the element is offset from its original position.
19060 * @method cachePosition
19061 * @param iPageX the current x position (optional, this just makes it so we
19062 * don't have to look it up again)
19063 * @param iPageY the current y position (optional, this just makes it so we
19064 * don't have to look it up again)
19066 cachePosition: function(iPageX, iPageY) {
19068 this.lastPageX = iPageX;
19069 this.lastPageY = iPageY;
19071 var aCoord = Roo.lib.Dom.getXY(this.getEl());
19072 this.lastPageX = aCoord[0];
19073 this.lastPageY = aCoord[1];
19078 * Auto-scroll the window if the dragged object has been moved beyond the
19079 * visible window boundary.
19080 * @method autoScroll
19081 * @param {int} x the drag element's x position
19082 * @param {int} y the drag element's y position
19083 * @param {int} h the height of the drag element
19084 * @param {int} w the width of the drag element
19087 autoScroll: function(x, y, h, w) {
19090 // The client height
19091 var clientH = Roo.lib.Dom.getViewWidth();
19093 // The client width
19094 var clientW = Roo.lib.Dom.getViewHeight();
19096 // The amt scrolled down
19097 var st = this.DDM.getScrollTop();
19099 // The amt scrolled right
19100 var sl = this.DDM.getScrollLeft();
19102 // Location of the bottom of the element
19105 // Location of the right of the element
19108 // The distance from the cursor to the bottom of the visible area,
19109 // adjusted so that we don't scroll if the cursor is beyond the
19110 // element drag constraints
19111 var toBot = (clientH + st - y - this.deltaY);
19113 // The distance from the cursor to the right of the visible area
19114 var toRight = (clientW + sl - x - this.deltaX);
19117 // How close to the edge the cursor must be before we scroll
19118 // var thresh = (document.all) ? 100 : 40;
19121 // How many pixels to scroll per autoscroll op. This helps to reduce
19122 // clunky scrolling. IE is more sensitive about this ... it needs this
19123 // value to be higher.
19124 var scrAmt = (document.all) ? 80 : 30;
19126 // Scroll down if we are near the bottom of the visible page and the
19127 // obj extends below the crease
19128 if ( bot > clientH && toBot < thresh ) {
19129 window.scrollTo(sl, st + scrAmt);
19132 // Scroll up if the window is scrolled down and the top of the object
19133 // goes above the top border
19134 if ( y < st && st > 0 && y - st < thresh ) {
19135 window.scrollTo(sl, st - scrAmt);
19138 // Scroll right if the obj is beyond the right border and the cursor is
19139 // near the border.
19140 if ( right > clientW && toRight < thresh ) {
19141 window.scrollTo(sl + scrAmt, st);
19144 // Scroll left if the window has been scrolled to the right and the obj
19145 // extends past the left border
19146 if ( x < sl && sl > 0 && x - sl < thresh ) {
19147 window.scrollTo(sl - scrAmt, st);
19153 * Finds the location the element should be placed if we want to move
19154 * it to where the mouse location less the click offset would place us.
19155 * @method getTargetCoord
19156 * @param {int} iPageX the X coordinate of the click
19157 * @param {int} iPageY the Y coordinate of the click
19158 * @return an object that contains the coordinates (Object.x and Object.y)
19161 getTargetCoord: function(iPageX, iPageY) {
19164 var x = iPageX - this.deltaX;
19165 var y = iPageY - this.deltaY;
19167 if (this.constrainX) {
19168 if (x < this.minX) { x = this.minX; }
19169 if (x > this.maxX) { x = this.maxX; }
19172 if (this.constrainY) {
19173 if (y < this.minY) { y = this.minY; }
19174 if (y > this.maxY) { y = this.maxY; }
19177 x = this.getTick(x, this.xTicks);
19178 y = this.getTick(y, this.yTicks);
19185 * Sets up config options specific to this class. Overrides
19186 * Roo.dd.DragDrop, but all versions of this method through the
19187 * inheritance chain are called
19189 applyConfig: function() {
19190 Roo.dd.DD.superclass.applyConfig.call(this);
19191 this.scroll = (this.config.scroll !== false);
19195 * Event that fires prior to the onMouseDown event. Overrides
19198 b4MouseDown: function(e) {
19199 // this.resetConstraints();
19200 this.autoOffset(e.getPageX(),
19205 * Event that fires prior to the onDrag event. Overrides
19208 b4Drag: function(e) {
19209 this.setDragElPos(e.getPageX(),
19213 toString: function() {
19214 return ("DD " + this.id);
19217 //////////////////////////////////////////////////////////////////////////
19218 // Debugging ygDragDrop events that can be overridden
19219 //////////////////////////////////////////////////////////////////////////
19221 startDrag: function(x, y) {
19224 onDrag: function(e) {
19227 onDragEnter: function(e, id) {
19230 onDragOver: function(e, id) {
19233 onDragOut: function(e, id) {
19236 onDragDrop: function(e, id) {
19239 endDrag: function(e) {
19246 * Ext JS Library 1.1.1
19247 * Copyright(c) 2006-2007, Ext JS, LLC.
19249 * Originally Released Under LGPL - original licence link has changed is not relivant.
19252 * <script type="text/javascript">
19256 * @class Roo.dd.DDProxy
19257 * A DragDrop implementation that inserts an empty, bordered div into
19258 * the document that follows the cursor during drag operations. At the time of
19259 * the click, the frame div is resized to the dimensions of the linked html
19260 * element, and moved to the exact location of the linked element.
19262 * References to the "frame" element refer to the single proxy element that
19263 * was created to be dragged in place of all DDProxy elements on the
19266 * @extends Roo.dd.DD
19268 * @param {String} id the id of the linked html element
19269 * @param {String} sGroup the group of related DragDrop objects
19270 * @param {object} config an object containing configurable attributes
19271 * Valid properties for DDProxy in addition to those in DragDrop:
19272 * resizeFrame, centerFrame, dragElId
19274 Roo.dd.DDProxy = function(id, sGroup, config) {
19276 this.init(id, sGroup, config);
19282 * The default drag frame div id
19283 * @property Roo.dd.DDProxy.dragElId
19287 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19289 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19292 * By default we resize the drag frame to be the same size as the element
19293 * we want to drag (this is to get the frame effect). We can turn it off
19294 * if we want a different behavior.
19295 * @property resizeFrame
19301 * By default the frame is positioned exactly where the drag element is, so
19302 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19303 * you do not have constraints on the obj is to have the drag frame centered
19304 * around the cursor. Set centerFrame to true for this effect.
19305 * @property centerFrame
19308 centerFrame: false,
19311 * Creates the proxy element if it does not yet exist
19312 * @method createFrame
19314 createFrame: function() {
19316 var body = document.body;
19318 if (!body || !body.firstChild) {
19319 setTimeout( function() { self.createFrame(); }, 50 );
19323 var div = this.getDragEl();
19326 div = document.createElement("div");
19327 div.id = this.dragElId;
19330 s.position = "absolute";
19331 s.visibility = "hidden";
19333 s.border = "2px solid #aaa";
19336 // appendChild can blow up IE if invoked prior to the window load event
19337 // while rendering a table. It is possible there are other scenarios
19338 // that would cause this to happen as well.
19339 body.insertBefore(div, body.firstChild);
19344 * Initialization for the drag frame element. Must be called in the
19345 * constructor of all subclasses
19346 * @method initFrame
19348 initFrame: function() {
19349 this.createFrame();
19352 applyConfig: function() {
19353 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19355 this.resizeFrame = (this.config.resizeFrame !== false);
19356 this.centerFrame = (this.config.centerFrame);
19357 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19361 * Resizes the drag frame to the dimensions of the clicked object, positions
19362 * it over the object, and finally displays it
19363 * @method showFrame
19364 * @param {int} iPageX X click position
19365 * @param {int} iPageY Y click position
19368 showFrame: function(iPageX, iPageY) {
19369 var el = this.getEl();
19370 var dragEl = this.getDragEl();
19371 var s = dragEl.style;
19373 this._resizeProxy();
19375 if (this.centerFrame) {
19376 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19377 Math.round(parseInt(s.height, 10)/2) );
19380 this.setDragElPos(iPageX, iPageY);
19382 Roo.fly(dragEl).show();
19386 * The proxy is automatically resized to the dimensions of the linked
19387 * element when a drag is initiated, unless resizeFrame is set to false
19388 * @method _resizeProxy
19391 _resizeProxy: function() {
19392 if (this.resizeFrame) {
19393 var el = this.getEl();
19394 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19398 // overrides Roo.dd.DragDrop
19399 b4MouseDown: function(e) {
19400 var x = e.getPageX();
19401 var y = e.getPageY();
19402 this.autoOffset(x, y);
19403 this.setDragElPos(x, y);
19406 // overrides Roo.dd.DragDrop
19407 b4StartDrag: function(x, y) {
19408 // show the drag frame
19409 this.showFrame(x, y);
19412 // overrides Roo.dd.DragDrop
19413 b4EndDrag: function(e) {
19414 Roo.fly(this.getDragEl()).hide();
19417 // overrides Roo.dd.DragDrop
19418 // By default we try to move the element to the last location of the frame.
19419 // This is so that the default behavior mirrors that of Roo.dd.DD.
19420 endDrag: function(e) {
19422 var lel = this.getEl();
19423 var del = this.getDragEl();
19425 // Show the drag frame briefly so we can get its position
19426 del.style.visibility = "";
19429 // Hide the linked element before the move to get around a Safari
19431 lel.style.visibility = "hidden";
19432 Roo.dd.DDM.moveToEl(lel, del);
19433 del.style.visibility = "hidden";
19434 lel.style.visibility = "";
19439 beforeMove : function(){
19443 afterDrag : function(){
19447 toString: function() {
19448 return ("DDProxy " + this.id);
19454 * Ext JS Library 1.1.1
19455 * Copyright(c) 2006-2007, Ext JS, LLC.
19457 * Originally Released Under LGPL - original licence link has changed is not relivant.
19460 * <script type="text/javascript">
19464 * @class Roo.dd.DDTarget
19465 * A DragDrop implementation that does not move, but can be a drop
19466 * target. You would get the same result by simply omitting implementation
19467 * for the event callbacks, but this way we reduce the processing cost of the
19468 * event listener and the callbacks.
19469 * @extends Roo.dd.DragDrop
19471 * @param {String} id the id of the element that is a drop target
19472 * @param {String} sGroup the group of related DragDrop objects
19473 * @param {object} config an object containing configurable attributes
19474 * Valid properties for DDTarget in addition to those in
19478 Roo.dd.DDTarget = function(id, sGroup, config) {
19480 this.initTarget(id, sGroup, config);
19482 if (config.listeners || config.events) {
19483 Roo.dd.DragDrop.superclass.constructor.call(this, {
19484 listeners : config.listeners || {},
19485 events : config.events || {}
19490 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19491 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19492 toString: function() {
19493 return ("DDTarget " + this.id);
19498 * Ext JS Library 1.1.1
19499 * Copyright(c) 2006-2007, Ext JS, LLC.
19501 * Originally Released Under LGPL - original licence link has changed is not relivant.
19504 * <script type="text/javascript">
19509 * @class Roo.dd.ScrollManager
19510 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19511 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19514 Roo.dd.ScrollManager = function(){
19515 var ddm = Roo.dd.DragDropMgr;
19522 var onStop = function(e){
19527 var triggerRefresh = function(){
19528 if(ddm.dragCurrent){
19529 ddm.refreshCache(ddm.dragCurrent.groups);
19533 var doScroll = function(){
19534 if(ddm.dragCurrent){
19535 var dds = Roo.dd.ScrollManager;
19537 if(proc.el.scroll(proc.dir, dds.increment)){
19541 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19546 var clearProc = function(){
19548 clearInterval(proc.id);
19555 var startProc = function(el, dir){
19556 Roo.log('scroll startproc');
19560 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19563 var onFire = function(e, isDrop){
19565 if(isDrop || !ddm.dragCurrent){ return; }
19566 var dds = Roo.dd.ScrollManager;
19567 if(!dragEl || dragEl != ddm.dragCurrent){
19568 dragEl = ddm.dragCurrent;
19569 // refresh regions on drag start
19570 dds.refreshCache();
19573 var xy = Roo.lib.Event.getXY(e);
19574 var pt = new Roo.lib.Point(xy[0], xy[1]);
19575 for(var id in els){
19576 var el = els[id], r = el._region;
19577 if(r && r.contains(pt) && el.isScrollable()){
19578 if(r.bottom - pt.y <= dds.thresh){
19580 startProc(el, "down");
19583 }else if(r.right - pt.x <= dds.thresh){
19585 startProc(el, "left");
19588 }else if(pt.y - r.top <= dds.thresh){
19590 startProc(el, "up");
19593 }else if(pt.x - r.left <= dds.thresh){
19595 startProc(el, "right");
19604 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19605 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19609 * Registers new overflow element(s) to auto scroll
19610 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19612 register : function(el){
19613 if(el instanceof Array){
19614 for(var i = 0, len = el.length; i < len; i++) {
19615 this.register(el[i]);
19621 Roo.dd.ScrollManager.els = els;
19625 * Unregisters overflow element(s) so they are no longer scrolled
19626 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19628 unregister : function(el){
19629 if(el instanceof Array){
19630 for(var i = 0, len = el.length; i < len; i++) {
19631 this.unregister(el[i]);
19640 * The number of pixels from the edge of a container the pointer needs to be to
19641 * trigger scrolling (defaults to 25)
19647 * The number of pixels to scroll in each scroll increment (defaults to 50)
19653 * The frequency of scrolls in milliseconds (defaults to 500)
19659 * True to animate the scroll (defaults to true)
19665 * The animation duration in seconds -
19666 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19672 * Manually trigger a cache refresh.
19674 refreshCache : function(){
19675 for(var id in els){
19676 if(typeof els[id] == 'object'){ // for people extending the object prototype
19677 els[id]._region = els[id].getRegion();
19684 * Ext JS Library 1.1.1
19685 * Copyright(c) 2006-2007, Ext JS, LLC.
19687 * Originally Released Under LGPL - original licence link has changed is not relivant.
19690 * <script type="text/javascript">
19695 * @class Roo.dd.Registry
19696 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19697 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19700 Roo.dd.Registry = function(){
19703 var autoIdSeed = 0;
19705 var getId = function(el, autogen){
19706 if(typeof el == "string"){
19710 if(!id && autogen !== false){
19711 id = "roodd-" + (++autoIdSeed);
19719 * Register a drag drop element
19720 * @param {String|HTMLElement} element The id or DOM node to register
19721 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19722 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19723 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19724 * populated in the data object (if applicable):
19726 Value Description<br />
19727 --------- ------------------------------------------<br />
19728 handles Array of DOM nodes that trigger dragging<br />
19729 for the element being registered<br />
19730 isHandle True if the element passed in triggers<br />
19731 dragging itself, else false
19734 register : function(el, data){
19736 if(typeof el == "string"){
19737 el = document.getElementById(el);
19740 elements[getId(el)] = data;
19741 if(data.isHandle !== false){
19742 handles[data.ddel.id] = data;
19745 var hs = data.handles;
19746 for(var i = 0, len = hs.length; i < len; i++){
19747 handles[getId(hs[i])] = data;
19753 * Unregister a drag drop element
19754 * @param {String|HTMLElement} element The id or DOM node to unregister
19756 unregister : function(el){
19757 var id = getId(el, false);
19758 var data = elements[id];
19760 delete elements[id];
19762 var hs = data.handles;
19763 for(var i = 0, len = hs.length; i < len; i++){
19764 delete handles[getId(hs[i], false)];
19771 * Returns the handle registered for a DOM Node by id
19772 * @param {String|HTMLElement} id The DOM node or id to look up
19773 * @return {Object} handle The custom handle data
19775 getHandle : function(id){
19776 if(typeof id != "string"){ // must be element?
19779 return handles[id];
19783 * Returns the handle that is registered for the DOM node that is the target of the event
19784 * @param {Event} e The event
19785 * @return {Object} handle The custom handle data
19787 getHandleFromEvent : function(e){
19788 var t = Roo.lib.Event.getTarget(e);
19789 return t ? handles[t.id] : null;
19793 * Returns a custom data object that is registered for a DOM node by id
19794 * @param {String|HTMLElement} id The DOM node or id to look up
19795 * @return {Object} data The custom data
19797 getTarget : function(id){
19798 if(typeof id != "string"){ // must be element?
19801 return elements[id];
19805 * Returns a custom data object that is registered for the DOM node that is the target of the event
19806 * @param {Event} e The event
19807 * @return {Object} data The custom data
19809 getTargetFromEvent : function(e){
19810 var t = Roo.lib.Event.getTarget(e);
19811 return t ? elements[t.id] || handles[t.id] : null;
19816 * Ext JS Library 1.1.1
19817 * Copyright(c) 2006-2007, Ext JS, LLC.
19819 * Originally Released Under LGPL - original licence link has changed is not relivant.
19822 * <script type="text/javascript">
19827 * @class Roo.dd.StatusProxy
19828 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19829 * default drag proxy used by all Roo.dd components.
19831 * @param {Object} config
19833 Roo.dd.StatusProxy = function(config){
19834 Roo.apply(this, config);
19835 this.id = this.id || Roo.id();
19836 this.el = new Roo.Layer({
19838 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19839 {tag: "div", cls: "x-dd-drop-icon"},
19840 {tag: "div", cls: "x-dd-drag-ghost"}
19843 shadow: !config || config.shadow !== false
19845 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19846 this.dropStatus = this.dropNotAllowed;
19849 Roo.dd.StatusProxy.prototype = {
19851 * @cfg {String} dropAllowed
19852 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19854 dropAllowed : "x-dd-drop-ok",
19856 * @cfg {String} dropNotAllowed
19857 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19859 dropNotAllowed : "x-dd-drop-nodrop",
19862 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19863 * over the current target element.
19864 * @param {String} cssClass The css class for the new drop status indicator image
19866 setStatus : function(cssClass){
19867 cssClass = cssClass || this.dropNotAllowed;
19868 if(this.dropStatus != cssClass){
19869 this.el.replaceClass(this.dropStatus, cssClass);
19870 this.dropStatus = cssClass;
19875 * Resets the status indicator to the default dropNotAllowed value
19876 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19878 reset : function(clearGhost){
19879 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19880 this.dropStatus = this.dropNotAllowed;
19882 this.ghost.update("");
19887 * Updates the contents of the ghost element
19888 * @param {String} html The html that will replace the current innerHTML of the ghost element
19890 update : function(html){
19891 if(typeof html == "string"){
19892 this.ghost.update(html);
19894 this.ghost.update("");
19895 html.style.margin = "0";
19896 this.ghost.dom.appendChild(html);
19898 // ensure float = none set?? cant remember why though.
19899 var el = this.ghost.dom.firstChild;
19901 Roo.fly(el).setStyle('float', 'none');
19906 * Returns the underlying proxy {@link Roo.Layer}
19907 * @return {Roo.Layer} el
19909 getEl : function(){
19914 * Returns the ghost element
19915 * @return {Roo.Element} el
19917 getGhost : function(){
19923 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19925 hide : function(clear){
19933 * Stops the repair animation if it's currently running
19936 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19942 * Displays this proxy
19949 * Force the Layer to sync its shadow and shim positions to the element
19956 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19957 * invalid drop operation by the item being dragged.
19958 * @param {Array} xy The XY position of the element ([x, y])
19959 * @param {Function} callback The function to call after the repair is complete
19960 * @param {Object} scope The scope in which to execute the callback
19962 repair : function(xy, callback, scope){
19963 this.callback = callback;
19964 this.scope = scope;
19965 if(xy && this.animRepair !== false){
19966 this.el.addClass("x-dd-drag-repair");
19967 this.el.hideUnders(true);
19968 this.anim = this.el.shift({
19969 duration: this.repairDuration || .5,
19973 callback: this.afterRepair,
19977 this.afterRepair();
19982 afterRepair : function(){
19984 if(typeof this.callback == "function"){
19985 this.callback.call(this.scope || this);
19987 this.callback = null;
19992 * Ext JS Library 1.1.1
19993 * Copyright(c) 2006-2007, Ext JS, LLC.
19995 * Originally Released Under LGPL - original licence link has changed is not relivant.
19998 * <script type="text/javascript">
20002 * @class Roo.dd.DragSource
20003 * @extends Roo.dd.DDProxy
20004 * A simple class that provides the basic implementation needed to make any element draggable.
20006 * @param {String/HTMLElement/Element} el The container element
20007 * @param {Object} config
20009 Roo.dd.DragSource = function(el, config){
20010 this.el = Roo.get(el);
20011 this.dragData = {};
20013 Roo.apply(this, config);
20016 this.proxy = new Roo.dd.StatusProxy();
20019 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
20020 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
20022 this.dragging = false;
20025 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
20027 * @cfg {String} dropAllowed
20028 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20030 dropAllowed : "x-dd-drop-ok",
20032 * @cfg {String} dropNotAllowed
20033 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20035 dropNotAllowed : "x-dd-drop-nodrop",
20038 * Returns the data object associated with this drag source
20039 * @return {Object} data An object containing arbitrary data
20041 getDragData : function(e){
20042 return this.dragData;
20046 onDragEnter : function(e, id){
20047 var target = Roo.dd.DragDropMgr.getDDById(id);
20048 this.cachedTarget = target;
20049 if(this.beforeDragEnter(target, e, id) !== false){
20050 if(target.isNotifyTarget){
20051 var status = target.notifyEnter(this, e, this.dragData);
20052 this.proxy.setStatus(status);
20054 this.proxy.setStatus(this.dropAllowed);
20057 if(this.afterDragEnter){
20059 * An empty function by default, but provided so that you can perform a custom action
20060 * when the dragged item enters the drop target by providing an implementation.
20061 * @param {Roo.dd.DragDrop} target The drop target
20062 * @param {Event} e The event object
20063 * @param {String} id The id of the dragged element
20064 * @method afterDragEnter
20066 this.afterDragEnter(target, e, id);
20072 * An empty function by default, but provided so that you can perform a custom action
20073 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
20074 * @param {Roo.dd.DragDrop} target The drop target
20075 * @param {Event} e The event object
20076 * @param {String} id The id of the dragged element
20077 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20079 beforeDragEnter : function(target, e, id){
20084 alignElWithMouse: function() {
20085 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
20090 onDragOver : function(e, id){
20091 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20092 if(this.beforeDragOver(target, e, id) !== false){
20093 if(target.isNotifyTarget){
20094 var status = target.notifyOver(this, e, this.dragData);
20095 this.proxy.setStatus(status);
20098 if(this.afterDragOver){
20100 * An empty function by default, but provided so that you can perform a custom action
20101 * while the dragged item is over the drop target by providing an implementation.
20102 * @param {Roo.dd.DragDrop} target The drop target
20103 * @param {Event} e The event object
20104 * @param {String} id The id of the dragged element
20105 * @method afterDragOver
20107 this.afterDragOver(target, e, id);
20113 * An empty function by default, but provided so that you can perform a custom action
20114 * while the dragged item is over the drop target and optionally cancel the onDragOver.
20115 * @param {Roo.dd.DragDrop} target The drop target
20116 * @param {Event} e The event object
20117 * @param {String} id The id of the dragged element
20118 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20120 beforeDragOver : function(target, e, id){
20125 onDragOut : function(e, id){
20126 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20127 if(this.beforeDragOut(target, e, id) !== false){
20128 if(target.isNotifyTarget){
20129 target.notifyOut(this, e, this.dragData);
20131 this.proxy.reset();
20132 if(this.afterDragOut){
20134 * An empty function by default, but provided so that you can perform a custom action
20135 * after the dragged item is dragged out of the target without dropping.
20136 * @param {Roo.dd.DragDrop} target The drop target
20137 * @param {Event} e The event object
20138 * @param {String} id The id of the dragged element
20139 * @method afterDragOut
20141 this.afterDragOut(target, e, id);
20144 this.cachedTarget = null;
20148 * An empty function by default, but provided so that you can perform a custom action before the dragged
20149 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20150 * @param {Roo.dd.DragDrop} target The drop target
20151 * @param {Event} e The event object
20152 * @param {String} id The id of the dragged element
20153 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20155 beforeDragOut : function(target, e, id){
20160 onDragDrop : function(e, id){
20161 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20162 if(this.beforeDragDrop(target, e, id) !== false){
20163 if(target.isNotifyTarget){
20164 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20165 this.onValidDrop(target, e, id);
20167 this.onInvalidDrop(target, e, id);
20170 this.onValidDrop(target, e, id);
20173 if(this.afterDragDrop){
20175 * An empty function by default, but provided so that you can perform a custom action
20176 * after a valid drag drop has occurred by providing an implementation.
20177 * @param {Roo.dd.DragDrop} target The drop target
20178 * @param {Event} e The event object
20179 * @param {String} id The id of the dropped element
20180 * @method afterDragDrop
20182 this.afterDragDrop(target, e, id);
20185 delete this.cachedTarget;
20189 * An empty function by default, but provided so that you can perform a custom action before the dragged
20190 * item is dropped onto the target and optionally cancel the onDragDrop.
20191 * @param {Roo.dd.DragDrop} target The drop target
20192 * @param {Event} e The event object
20193 * @param {String} id The id of the dragged element
20194 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20196 beforeDragDrop : function(target, e, id){
20201 onValidDrop : function(target, e, id){
20203 if(this.afterValidDrop){
20205 * An empty function by default, but provided so that you can perform a custom action
20206 * after a valid drop has occurred by providing an implementation.
20207 * @param {Object} target The target DD
20208 * @param {Event} e The event object
20209 * @param {String} id The id of the dropped element
20210 * @method afterInvalidDrop
20212 this.afterValidDrop(target, e, id);
20217 getRepairXY : function(e, data){
20218 return this.el.getXY();
20222 onInvalidDrop : function(target, e, id){
20223 this.beforeInvalidDrop(target, e, id);
20224 if(this.cachedTarget){
20225 if(this.cachedTarget.isNotifyTarget){
20226 this.cachedTarget.notifyOut(this, e, this.dragData);
20228 this.cacheTarget = null;
20230 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20232 if(this.afterInvalidDrop){
20234 * An empty function by default, but provided so that you can perform a custom action
20235 * after an invalid drop has occurred by providing an implementation.
20236 * @param {Event} e The event object
20237 * @param {String} id The id of the dropped element
20238 * @method afterInvalidDrop
20240 this.afterInvalidDrop(e, id);
20245 afterRepair : function(){
20247 this.el.highlight(this.hlColor || "c3daf9");
20249 this.dragging = false;
20253 * An empty function by default, but provided so that you can perform a custom action after an invalid
20254 * drop has occurred.
20255 * @param {Roo.dd.DragDrop} target The drop target
20256 * @param {Event} e The event object
20257 * @param {String} id The id of the dragged element
20258 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20260 beforeInvalidDrop : function(target, e, id){
20265 handleMouseDown : function(e){
20266 if(this.dragging) {
20269 var data = this.getDragData(e);
20270 if(data && this.onBeforeDrag(data, e) !== false){
20271 this.dragData = data;
20273 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20278 * An empty function by default, but provided so that you can perform a custom action before the initial
20279 * drag event begins and optionally cancel it.
20280 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20281 * @param {Event} e The event object
20282 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20284 onBeforeDrag : function(data, e){
20289 * An empty function by default, but provided so that you can perform a custom action once the initial
20290 * drag event has begun. The drag cannot be canceled from this function.
20291 * @param {Number} x The x position of the click on the dragged object
20292 * @param {Number} y The y position of the click on the dragged object
20294 onStartDrag : Roo.emptyFn,
20296 // private - YUI override
20297 startDrag : function(x, y){
20298 this.proxy.reset();
20299 this.dragging = true;
20300 this.proxy.update("");
20301 this.onInitDrag(x, y);
20306 onInitDrag : function(x, y){
20307 var clone = this.el.dom.cloneNode(true);
20308 clone.id = Roo.id(); // prevent duplicate ids
20309 this.proxy.update(clone);
20310 this.onStartDrag(x, y);
20315 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20316 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20318 getProxy : function(){
20323 * Hides the drag source's {@link Roo.dd.StatusProxy}
20325 hideProxy : function(){
20327 this.proxy.reset(true);
20328 this.dragging = false;
20332 triggerCacheRefresh : function(){
20333 Roo.dd.DDM.refreshCache(this.groups);
20336 // private - override to prevent hiding
20337 b4EndDrag: function(e) {
20340 // private - override to prevent moving
20341 endDrag : function(e){
20342 this.onEndDrag(this.dragData, e);
20346 onEndDrag : function(data, e){
20349 // private - pin to cursor
20350 autoOffset : function(x, y) {
20351 this.setDelta(-12, -20);
20355 * Ext JS Library 1.1.1
20356 * Copyright(c) 2006-2007, Ext JS, LLC.
20358 * Originally Released Under LGPL - original licence link has changed is not relivant.
20361 * <script type="text/javascript">
20366 * @class Roo.dd.DropTarget
20367 * @extends Roo.dd.DDTarget
20368 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20369 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20371 * @param {String/HTMLElement/Element} el The container element
20372 * @param {Object} config
20374 Roo.dd.DropTarget = function(el, config){
20375 this.el = Roo.get(el);
20377 var listeners = false; ;
20378 if (config && config.listeners) {
20379 listeners= config.listeners;
20380 delete config.listeners;
20382 Roo.apply(this, config);
20384 if(this.containerScroll){
20385 Roo.dd.ScrollManager.register(this.el);
20389 * @scope Roo.dd.DropTarget
20394 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20395 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20396 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20398 * IMPORTANT : it should set this.overClass and this.dropAllowed
20400 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20401 * @param {Event} e The event
20402 * @param {Object} data An object containing arbitrary data supplied by the drag source
20408 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20409 * This method will be called on every mouse movement while the drag source is over the drop target.
20410 * This default implementation simply returns the dropAllowed config value.
20412 * IMPORTANT : it should set this.dropAllowed
20414 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20415 * @param {Event} e The event
20416 * @param {Object} data An object containing arbitrary data supplied by the drag source
20422 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20423 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20424 * overClass (if any) from the drop element.
20426 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20427 * @param {Event} e The event
20428 * @param {Object} data An object containing arbitrary data supplied by the drag source
20434 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20435 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20436 * implementation that does something to process the drop event and returns true so that the drag source's
20437 * repair action does not run.
20439 * IMPORTANT : it should set this.success
20441 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20442 * @param {Event} e The event
20443 * @param {Object} data An object containing arbitrary data supplied by the drag source
20449 Roo.dd.DropTarget.superclass.constructor.call( this,
20451 this.ddGroup || this.group,
20454 listeners : listeners || {}
20462 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20464 * @cfg {String} overClass
20465 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20468 * @cfg {String} ddGroup
20469 * The drag drop group to handle drop events for
20473 * @cfg {String} dropAllowed
20474 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20476 dropAllowed : "x-dd-drop-ok",
20478 * @cfg {String} dropNotAllowed
20479 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20481 dropNotAllowed : "x-dd-drop-nodrop",
20483 * @cfg {boolean} success
20484 * set this after drop listener..
20488 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20489 * if the drop point is valid for over/enter..
20496 isNotifyTarget : true,
20501 notifyEnter : function(dd, e, data)
20504 this.fireEvent('enter', dd, e, data);
20505 if(this.overClass){
20506 this.el.addClass(this.overClass);
20508 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20509 this.valid ? this.dropAllowed : this.dropNotAllowed
20516 notifyOver : function(dd, e, data)
20519 this.fireEvent('over', dd, e, data);
20520 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20521 this.valid ? this.dropAllowed : this.dropNotAllowed
20528 notifyOut : function(dd, e, data)
20530 this.fireEvent('out', dd, e, data);
20531 if(this.overClass){
20532 this.el.removeClass(this.overClass);
20539 notifyDrop : function(dd, e, data)
20541 this.success = false;
20542 this.fireEvent('drop', dd, e, data);
20543 return this.success;
20547 * Ext JS Library 1.1.1
20548 * Copyright(c) 2006-2007, Ext JS, LLC.
20550 * Originally Released Under LGPL - original licence link has changed is not relivant.
20553 * <script type="text/javascript">
20558 * @class Roo.dd.DragZone
20559 * @extends Roo.dd.DragSource
20560 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20561 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20563 * @param {String/HTMLElement/Element} el The container element
20564 * @param {Object} config
20566 Roo.dd.DragZone = function(el, config){
20567 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20568 if(this.containerScroll){
20569 Roo.dd.ScrollManager.register(this.el);
20573 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20575 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20576 * for auto scrolling during drag operations.
20579 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20580 * method after a failed drop (defaults to "c3daf9" - light blue)
20584 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20585 * for a valid target to drag based on the mouse down. Override this method
20586 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20587 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20588 * @param {EventObject} e The mouse down event
20589 * @return {Object} The dragData
20591 getDragData : function(e){
20592 return Roo.dd.Registry.getHandleFromEvent(e);
20596 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20597 * this.dragData.ddel
20598 * @param {Number} x The x position of the click on the dragged object
20599 * @param {Number} y The y position of the click on the dragged object
20600 * @return {Boolean} true to continue the drag, false to cancel
20602 onInitDrag : function(x, y){
20603 this.proxy.update(this.dragData.ddel.cloneNode(true));
20604 this.onStartDrag(x, y);
20609 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20611 afterRepair : function(){
20613 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20615 this.dragging = false;
20619 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20620 * the XY of this.dragData.ddel
20621 * @param {EventObject} e The mouse up event
20622 * @return {Array} The xy location (e.g. [100, 200])
20624 getRepairXY : function(e){
20625 return Roo.Element.fly(this.dragData.ddel).getXY();
20629 * Ext JS Library 1.1.1
20630 * Copyright(c) 2006-2007, Ext JS, LLC.
20632 * Originally Released Under LGPL - original licence link has changed is not relivant.
20635 * <script type="text/javascript">
20638 * @class Roo.dd.DropZone
20639 * @extends Roo.dd.DropTarget
20640 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20641 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20643 * @param {String/HTMLElement/Element} el The container element
20644 * @param {Object} config
20646 Roo.dd.DropZone = function(el, config){
20647 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20650 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20652 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20653 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20654 * provide your own custom lookup.
20655 * @param {Event} e The event
20656 * @return {Object} data The custom data
20658 getTargetFromEvent : function(e){
20659 return Roo.dd.Registry.getTargetFromEvent(e);
20663 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20664 * that it has registered. This method has no default implementation and should be overridden to provide
20665 * node-specific processing if necessary.
20666 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20667 * {@link #getTargetFromEvent} for this node)
20668 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20669 * @param {Event} e The event
20670 * @param {Object} data An object containing arbitrary data supplied by the drag source
20672 onNodeEnter : function(n, dd, e, data){
20677 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20678 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20679 * overridden to provide the proper feedback.
20680 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20681 * {@link #getTargetFromEvent} for this node)
20682 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20683 * @param {Event} e The event
20684 * @param {Object} data An object containing arbitrary data supplied by the drag source
20685 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20686 * underlying {@link Roo.dd.StatusProxy} can be updated
20688 onNodeOver : function(n, dd, e, data){
20689 return this.dropAllowed;
20693 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20694 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20695 * node-specific processing if necessary.
20696 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20697 * {@link #getTargetFromEvent} for this node)
20698 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20699 * @param {Event} e The event
20700 * @param {Object} data An object containing arbitrary data supplied by the drag source
20702 onNodeOut : function(n, dd, e, data){
20707 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20708 * the drop node. The default implementation returns false, so it should be overridden to provide the
20709 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20710 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20711 * {@link #getTargetFromEvent} for this node)
20712 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20713 * @param {Event} e The event
20714 * @param {Object} data An object containing arbitrary data supplied by the drag source
20715 * @return {Boolean} True if the drop was valid, else false
20717 onNodeDrop : function(n, dd, e, data){
20722 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20723 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20724 * it should be overridden to provide the proper feedback if necessary.
20725 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20726 * @param {Event} e The event
20727 * @param {Object} data An object containing arbitrary data supplied by the drag source
20728 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20729 * underlying {@link Roo.dd.StatusProxy} can be updated
20731 onContainerOver : function(dd, e, data){
20732 return this.dropNotAllowed;
20736 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20737 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20738 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20739 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20740 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20741 * @param {Event} e The event
20742 * @param {Object} data An object containing arbitrary data supplied by the drag source
20743 * @return {Boolean} True if the drop was valid, else false
20745 onContainerDrop : function(dd, e, data){
20750 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20751 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20752 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20753 * you should override this method and provide a custom implementation.
20754 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20755 * @param {Event} e The event
20756 * @param {Object} data An object containing arbitrary data supplied by the drag source
20757 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20758 * underlying {@link Roo.dd.StatusProxy} can be updated
20760 notifyEnter : function(dd, e, data){
20761 return this.dropNotAllowed;
20765 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20766 * This method will be called on every mouse movement while the drag source is over the drop zone.
20767 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20768 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20769 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20770 * registered node, it will call {@link #onContainerOver}.
20771 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20772 * @param {Event} e The event
20773 * @param {Object} data An object containing arbitrary data supplied by the drag source
20774 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20775 * underlying {@link Roo.dd.StatusProxy} can be updated
20777 notifyOver : function(dd, e, data){
20778 var n = this.getTargetFromEvent(e);
20779 if(!n){ // not over valid drop target
20780 if(this.lastOverNode){
20781 this.onNodeOut(this.lastOverNode, dd, e, data);
20782 this.lastOverNode = null;
20784 return this.onContainerOver(dd, e, data);
20786 if(this.lastOverNode != n){
20787 if(this.lastOverNode){
20788 this.onNodeOut(this.lastOverNode, dd, e, data);
20790 this.onNodeEnter(n, dd, e, data);
20791 this.lastOverNode = n;
20793 return this.onNodeOver(n, dd, e, data);
20797 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20798 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20799 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20800 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20801 * @param {Event} e The event
20802 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20804 notifyOut : function(dd, e, data){
20805 if(this.lastOverNode){
20806 this.onNodeOut(this.lastOverNode, dd, e, data);
20807 this.lastOverNode = null;
20812 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20813 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20814 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20815 * otherwise it will call {@link #onContainerDrop}.
20816 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20817 * @param {Event} e The event
20818 * @param {Object} data An object containing arbitrary data supplied by the drag source
20819 * @return {Boolean} True if the drop was valid, else false
20821 notifyDrop : function(dd, e, data){
20822 if(this.lastOverNode){
20823 this.onNodeOut(this.lastOverNode, dd, e, data);
20824 this.lastOverNode = null;
20826 var n = this.getTargetFromEvent(e);
20828 this.onNodeDrop(n, dd, e, data) :
20829 this.onContainerDrop(dd, e, data);
20833 triggerCacheRefresh : function(){
20834 Roo.dd.DDM.refreshCache(this.groups);
20838 * Ext JS Library 1.1.1
20839 * Copyright(c) 2006-2007, Ext JS, LLC.
20841 * Originally Released Under LGPL - original licence link has changed is not relivant.
20844 * <script type="text/javascript">
20849 * @class Roo.data.SortTypes
20851 * Defines the default sorting (casting?) comparison functions used when sorting data.
20853 Roo.data.SortTypes = {
20855 * Default sort that does nothing
20856 * @param {Mixed} s The value being converted
20857 * @return {Mixed} The comparison value
20859 none : function(s){
20864 * The regular expression used to strip tags
20868 stripTagsRE : /<\/?[^>]+>/gi,
20871 * Strips all HTML tags to sort on text only
20872 * @param {Mixed} s The value being converted
20873 * @return {String} The comparison value
20875 asText : function(s){
20876 return String(s).replace(this.stripTagsRE, "");
20880 * Strips all HTML tags to sort on text only - Case insensitive
20881 * @param {Mixed} s The value being converted
20882 * @return {String} The comparison value
20884 asUCText : function(s){
20885 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20889 * Case insensitive string
20890 * @param {Mixed} s The value being converted
20891 * @return {String} The comparison value
20893 asUCString : function(s) {
20894 return String(s).toUpperCase();
20899 * @param {Mixed} s The value being converted
20900 * @return {Number} The comparison value
20902 asDate : function(s) {
20906 if(s instanceof Date){
20907 return s.getTime();
20909 return Date.parse(String(s));
20914 * @param {Mixed} s The value being converted
20915 * @return {Float} The comparison value
20917 asFloat : function(s) {
20918 var val = parseFloat(String(s).replace(/,/g, ""));
20927 * @param {Mixed} s The value being converted
20928 * @return {Number} The comparison value
20930 asInt : function(s) {
20931 var val = parseInt(String(s).replace(/,/g, ""));
20939 * Ext JS Library 1.1.1
20940 * Copyright(c) 2006-2007, Ext JS, LLC.
20942 * Originally Released Under LGPL - original licence link has changed is not relivant.
20945 * <script type="text/javascript">
20949 * @class Roo.data.Record
20950 * Instances of this class encapsulate both record <em>definition</em> information, and record
20951 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20952 * to access Records cached in an {@link Roo.data.Store} object.<br>
20954 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20955 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20958 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20960 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20961 * {@link #create}. The parameters are the same.
20962 * @param {Array} data An associative Array of data values keyed by the field name.
20963 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20964 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20965 * not specified an integer id is generated.
20967 Roo.data.Record = function(data, id){
20968 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20973 * Generate a constructor for a specific record layout.
20974 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20975 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20976 * Each field definition object may contain the following properties: <ul>
20977 * <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,
20978 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20979 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20980 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20981 * is being used, then this is a string containing the javascript expression to reference the data relative to
20982 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20983 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20984 * this may be omitted.</p></li>
20985 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20986 * <ul><li>auto (Default, implies no conversion)</li>
20991 * <li>date</li></ul></p></li>
20992 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20993 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20994 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20995 * by the Reader into an object that will be stored in the Record. It is passed the
20996 * following parameters:<ul>
20997 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20999 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
21001 * <br>usage:<br><pre><code>
21002 var TopicRecord = Roo.data.Record.create(
21003 {name: 'title', mapping: 'topic_title'},
21004 {name: 'author', mapping: 'username'},
21005 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
21006 {name: 'lastPost', mapping: 'post_time', type: 'date'},
21007 {name: 'lastPoster', mapping: 'user2'},
21008 {name: 'excerpt', mapping: 'post_text'}
21011 var myNewRecord = new TopicRecord({
21012 title: 'Do my job please',
21015 lastPost: new Date(),
21016 lastPoster: 'Animal',
21017 excerpt: 'No way dude!'
21019 myStore.add(myNewRecord);
21024 Roo.data.Record.create = function(o){
21025 var f = function(){
21026 f.superclass.constructor.apply(this, arguments);
21028 Roo.extend(f, Roo.data.Record);
21029 var p = f.prototype;
21030 p.fields = new Roo.util.MixedCollection(false, function(field){
21033 for(var i = 0, len = o.length; i < len; i++){
21034 p.fields.add(new Roo.data.Field(o[i]));
21036 f.getField = function(name){
21037 return p.fields.get(name);
21042 Roo.data.Record.AUTO_ID = 1000;
21043 Roo.data.Record.EDIT = 'edit';
21044 Roo.data.Record.REJECT = 'reject';
21045 Roo.data.Record.COMMIT = 'commit';
21047 Roo.data.Record.prototype = {
21049 * Readonly flag - true if this record has been modified.
21058 join : function(store){
21059 this.store = store;
21063 * Set the named field to the specified value.
21064 * @param {String} name The name of the field to set.
21065 * @param {Object} value The value to set the field to.
21067 set : function(name, value){
21068 if(this.data[name] == value){
21072 if(!this.modified){
21073 this.modified = {};
21075 if(typeof this.modified[name] == 'undefined'){
21076 this.modified[name] = this.data[name];
21078 this.data[name] = value;
21079 if(!this.editing && this.store){
21080 this.store.afterEdit(this);
21085 * Get the value of the named field.
21086 * @param {String} name The name of the field to get the value of.
21087 * @return {Object} The value of the field.
21089 get : function(name){
21090 return this.data[name];
21094 beginEdit : function(){
21095 this.editing = true;
21096 this.modified = {};
21100 cancelEdit : function(){
21101 this.editing = false;
21102 delete this.modified;
21106 endEdit : function(){
21107 this.editing = false;
21108 if(this.dirty && this.store){
21109 this.store.afterEdit(this);
21114 * Usually called by the {@link Roo.data.Store} which owns the Record.
21115 * Rejects all changes made to the Record since either creation, or the last commit operation.
21116 * Modified fields are reverted to their original values.
21118 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21119 * of reject operations.
21121 reject : function(){
21122 var m = this.modified;
21124 if(typeof m[n] != "function"){
21125 this.data[n] = m[n];
21128 this.dirty = false;
21129 delete this.modified;
21130 this.editing = false;
21132 this.store.afterReject(this);
21137 * Usually called by the {@link Roo.data.Store} which owns the Record.
21138 * Commits all changes made to the Record since either creation, or the last commit operation.
21140 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21141 * of commit operations.
21143 commit : function(){
21144 this.dirty = false;
21145 delete this.modified;
21146 this.editing = false;
21148 this.store.afterCommit(this);
21153 hasError : function(){
21154 return this.error != null;
21158 clearError : function(){
21163 * Creates a copy of this record.
21164 * @param {String} id (optional) A new record id if you don't want to use this record's id
21167 copy : function(newId) {
21168 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21172 * Ext JS Library 1.1.1
21173 * Copyright(c) 2006-2007, Ext JS, LLC.
21175 * Originally Released Under LGPL - original licence link has changed is not relivant.
21178 * <script type="text/javascript">
21184 * @class Roo.data.Store
21185 * @extends Roo.util.Observable
21186 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21187 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21189 * 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
21190 * has no knowledge of the format of the data returned by the Proxy.<br>
21192 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21193 * instances from the data object. These records are cached and made available through accessor functions.
21195 * Creates a new Store.
21196 * @param {Object} config A config object containing the objects needed for the Store to access data,
21197 * and read the data into Records.
21199 Roo.data.Store = function(config){
21200 this.data = new Roo.util.MixedCollection(false);
21201 this.data.getKey = function(o){
21204 this.baseParams = {};
21206 this.paramNames = {
21211 "multisort" : "_multisort"
21214 if(config && config.data){
21215 this.inlineData = config.data;
21216 delete config.data;
21219 Roo.apply(this, config);
21221 if(this.reader){ // reader passed
21222 this.reader = Roo.factory(this.reader, Roo.data);
21223 this.reader.xmodule = this.xmodule || false;
21224 if(!this.recordType){
21225 this.recordType = this.reader.recordType;
21227 if(this.reader.onMetaChange){
21228 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21232 if(this.recordType){
21233 this.fields = this.recordType.prototype.fields;
21235 this.modified = [];
21239 * @event datachanged
21240 * Fires when the data cache has changed, and a widget which is using this Store
21241 * as a Record cache should refresh its view.
21242 * @param {Store} this
21244 datachanged : true,
21246 * @event metachange
21247 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21248 * @param {Store} this
21249 * @param {Object} meta The JSON metadata
21254 * Fires when Records have been added to the Store
21255 * @param {Store} this
21256 * @param {Roo.data.Record[]} records The array of Records added
21257 * @param {Number} index The index at which the record(s) were added
21262 * Fires when a Record has been removed from the Store
21263 * @param {Store} this
21264 * @param {Roo.data.Record} record The Record that was removed
21265 * @param {Number} index The index at which the record was removed
21270 * Fires when a Record has been updated
21271 * @param {Store} this
21272 * @param {Roo.data.Record} record The Record that was updated
21273 * @param {String} operation The update operation being performed. Value may be one of:
21275 Roo.data.Record.EDIT
21276 Roo.data.Record.REJECT
21277 Roo.data.Record.COMMIT
21283 * Fires when the data cache has been cleared.
21284 * @param {Store} this
21288 * @event beforeload
21289 * Fires before a request is made for a new data object. If the beforeload handler returns false
21290 * the load action will be canceled.
21291 * @param {Store} this
21292 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21296 * @event beforeloadadd
21297 * Fires after a new set of Records has been loaded.
21298 * @param {Store} this
21299 * @param {Roo.data.Record[]} records The Records that were loaded
21300 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21302 beforeloadadd : true,
21305 * Fires after a new set of Records has been loaded, before they are added to the store.
21306 * @param {Store} this
21307 * @param {Roo.data.Record[]} records The Records that were loaded
21308 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21309 * @params {Object} return from reader
21313 * @event loadexception
21314 * Fires if an exception occurs in the Proxy during loading.
21315 * Called with the signature of the Proxy's "loadexception" event.
21316 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21319 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21320 * @param {Object} load options
21321 * @param {Object} jsonData from your request (normally this contains the Exception)
21323 loadexception : true
21327 this.proxy = Roo.factory(this.proxy, Roo.data);
21328 this.proxy.xmodule = this.xmodule || false;
21329 this.relayEvents(this.proxy, ["loadexception"]);
21331 this.sortToggle = {};
21332 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21334 Roo.data.Store.superclass.constructor.call(this);
21336 if(this.inlineData){
21337 this.loadData(this.inlineData);
21338 delete this.inlineData;
21342 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21344 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21345 * without a remote query - used by combo/forms at present.
21349 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21352 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21355 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21356 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21359 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21360 * on any HTTP request
21363 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21366 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21370 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21371 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21373 remoteSort : false,
21376 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21377 * loaded or when a record is removed. (defaults to false).
21379 pruneModifiedRecords : false,
21382 lastOptions : null,
21385 * Add Records to the Store and fires the add event.
21386 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21388 add : function(records){
21389 records = [].concat(records);
21390 for(var i = 0, len = records.length; i < len; i++){
21391 records[i].join(this);
21393 var index = this.data.length;
21394 this.data.addAll(records);
21395 this.fireEvent("add", this, records, index);
21399 * Remove a Record from the Store and fires the remove event.
21400 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21402 remove : function(record){
21403 var index = this.data.indexOf(record);
21404 this.data.removeAt(index);
21405 if(this.pruneModifiedRecords){
21406 this.modified.remove(record);
21408 this.fireEvent("remove", this, record, index);
21412 * Remove all Records from the Store and fires the clear event.
21414 removeAll : function(){
21416 if(this.pruneModifiedRecords){
21417 this.modified = [];
21419 this.fireEvent("clear", this);
21423 * Inserts Records to the Store at the given index and fires the add event.
21424 * @param {Number} index The start index at which to insert the passed Records.
21425 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21427 insert : function(index, records){
21428 records = [].concat(records);
21429 for(var i = 0, len = records.length; i < len; i++){
21430 this.data.insert(index, records[i]);
21431 records[i].join(this);
21433 this.fireEvent("add", this, records, index);
21437 * Get the index within the cache of the passed Record.
21438 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21439 * @return {Number} The index of the passed Record. Returns -1 if not found.
21441 indexOf : function(record){
21442 return this.data.indexOf(record);
21446 * Get the index within the cache of the Record with the passed id.
21447 * @param {String} id The id of the Record to find.
21448 * @return {Number} The index of the Record. Returns -1 if not found.
21450 indexOfId : function(id){
21451 return this.data.indexOfKey(id);
21455 * Get the Record with the specified id.
21456 * @param {String} id The id of the Record to find.
21457 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21459 getById : function(id){
21460 return this.data.key(id);
21464 * Get the Record at the specified index.
21465 * @param {Number} index The index of the Record to find.
21466 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21468 getAt : function(index){
21469 return this.data.itemAt(index);
21473 * Returns a range of Records between specified indices.
21474 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21475 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21476 * @return {Roo.data.Record[]} An array of Records
21478 getRange : function(start, end){
21479 return this.data.getRange(start, end);
21483 storeOptions : function(o){
21484 o = Roo.apply({}, o);
21487 this.lastOptions = o;
21491 * Loads the Record cache from the configured Proxy using the configured Reader.
21493 * If using remote paging, then the first load call must specify the <em>start</em>
21494 * and <em>limit</em> properties in the options.params property to establish the initial
21495 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21497 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21498 * and this call will return before the new data has been loaded. Perform any post-processing
21499 * in a callback function, or in a "load" event handler.</strong>
21501 * @param {Object} options An object containing properties which control loading options:<ul>
21502 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21503 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21504 * passed the following arguments:<ul>
21505 * <li>r : Roo.data.Record[]</li>
21506 * <li>options: Options object from the load call</li>
21507 * <li>success: Boolean success indicator</li></ul></li>
21508 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21509 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21512 load : function(options){
21513 options = options || {};
21514 if(this.fireEvent("beforeload", this, options) !== false){
21515 this.storeOptions(options);
21516 var p = Roo.apply(options.params || {}, this.baseParams);
21517 // if meta was not loaded from remote source.. try requesting it.
21518 if (!this.reader.metaFromRemote) {
21519 p._requestMeta = 1;
21521 if(this.sortInfo && this.remoteSort){
21522 var pn = this.paramNames;
21523 p[pn["sort"]] = this.sortInfo.field;
21524 p[pn["dir"]] = this.sortInfo.direction;
21526 if (this.multiSort) {
21527 var pn = this.paramNames;
21528 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21531 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21536 * Reloads the Record cache from the configured Proxy using the configured Reader and
21537 * the options from the last load operation performed.
21538 * @param {Object} options (optional) An object containing properties which may override the options
21539 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21540 * the most recently used options are reused).
21542 reload : function(options){
21543 this.load(Roo.applyIf(options||{}, this.lastOptions));
21547 // Called as a callback by the Reader during a load operation.
21548 loadRecords : function(o, options, success){
21549 if(!o || success === false){
21550 if(success !== false){
21551 this.fireEvent("load", this, [], options, o);
21553 if(options.callback){
21554 options.callback.call(options.scope || this, [], options, false);
21558 // if data returned failure - throw an exception.
21559 if (o.success === false) {
21560 // show a message if no listener is registered.
21561 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21562 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21564 // loadmask wil be hooked into this..
21565 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21568 var r = o.records, t = o.totalRecords || r.length;
21570 this.fireEvent("beforeloadadd", this, r, options, o);
21572 if(!options || options.add !== true){
21573 if(this.pruneModifiedRecords){
21574 this.modified = [];
21576 for(var i = 0, len = r.length; i < len; i++){
21580 this.data = this.snapshot;
21581 delete this.snapshot;
21584 this.data.addAll(r);
21585 this.totalLength = t;
21587 this.fireEvent("datachanged", this);
21589 this.totalLength = Math.max(t, this.data.length+r.length);
21592 this.fireEvent("load", this, r, options, o);
21593 if(options.callback){
21594 options.callback.call(options.scope || this, r, options, true);
21600 * Loads data from a passed data block. A Reader which understands the format of the data
21601 * must have been configured in the constructor.
21602 * @param {Object} data The data block from which to read the Records. The format of the data expected
21603 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21604 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21606 loadData : function(o, append){
21607 var r = this.reader.readRecords(o);
21608 this.loadRecords(r, {add: append}, true);
21612 * Gets the number of cached records.
21614 * <em>If using paging, this may not be the total size of the dataset. If the data object
21615 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21616 * the data set size</em>
21618 getCount : function(){
21619 return this.data.length || 0;
21623 * Gets the total number of records in the dataset as returned by the server.
21625 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21626 * the dataset size</em>
21628 getTotalCount : function(){
21629 return this.totalLength || 0;
21633 * Returns the sort state of the Store as an object with two properties:
21635 field {String} The name of the field by which the Records are sorted
21636 direction {String} The sort order, "ASC" or "DESC"
21639 getSortState : function(){
21640 return this.sortInfo;
21644 applySort : function(){
21645 if(this.sortInfo && !this.remoteSort){
21646 var s = this.sortInfo, f = s.field;
21647 var st = this.fields.get(f).sortType;
21648 var fn = function(r1, r2){
21649 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21650 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21652 this.data.sort(s.direction, fn);
21653 if(this.snapshot && this.snapshot != this.data){
21654 this.snapshot.sort(s.direction, fn);
21660 * Sets the default sort column and order to be used by the next load operation.
21661 * @param {String} fieldName The name of the field to sort by.
21662 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21664 setDefaultSort : function(field, dir){
21665 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21669 * Sort the Records.
21670 * If remote sorting is used, the sort is performed on the server, and the cache is
21671 * reloaded. If local sorting is used, the cache is sorted internally.
21672 * @param {String} fieldName The name of the field to sort by.
21673 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21675 sort : function(fieldName, dir){
21676 var f = this.fields.get(fieldName);
21678 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21680 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21681 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21686 this.sortToggle[f.name] = dir;
21687 this.sortInfo = {field: f.name, direction: dir};
21688 if(!this.remoteSort){
21690 this.fireEvent("datachanged", this);
21692 this.load(this.lastOptions);
21697 * Calls the specified function for each of the Records in the cache.
21698 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21699 * Returning <em>false</em> aborts and exits the iteration.
21700 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21702 each : function(fn, scope){
21703 this.data.each(fn, scope);
21707 * Gets all records modified since the last commit. Modified records are persisted across load operations
21708 * (e.g., during paging).
21709 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21711 getModifiedRecords : function(){
21712 return this.modified;
21716 createFilterFn : function(property, value, anyMatch){
21717 if(!value.exec){ // not a regex
21718 value = String(value);
21719 if(value.length == 0){
21722 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21724 return function(r){
21725 return value.test(r.data[property]);
21730 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21731 * @param {String} property A field on your records
21732 * @param {Number} start The record index to start at (defaults to 0)
21733 * @param {Number} end The last record index to include (defaults to length - 1)
21734 * @return {Number} The sum
21736 sum : function(property, start, end){
21737 var rs = this.data.items, v = 0;
21738 start = start || 0;
21739 end = (end || end === 0) ? end : rs.length-1;
21741 for(var i = start; i <= end; i++){
21742 v += (rs[i].data[property] || 0);
21748 * Filter the records by a specified property.
21749 * @param {String} field A field on your records
21750 * @param {String/RegExp} value Either a string that the field
21751 * should start with or a RegExp to test against the field
21752 * @param {Boolean} anyMatch True to match any part not just the beginning
21754 filter : function(property, value, anyMatch){
21755 var fn = this.createFilterFn(property, value, anyMatch);
21756 return fn ? this.filterBy(fn) : this.clearFilter();
21760 * Filter by a function. The specified function will be called with each
21761 * record in this data source. If the function returns true the record is included,
21762 * otherwise it is filtered.
21763 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21764 * @param {Object} scope (optional) The scope of the function (defaults to this)
21766 filterBy : function(fn, scope){
21767 this.snapshot = this.snapshot || this.data;
21768 this.data = this.queryBy(fn, scope||this);
21769 this.fireEvent("datachanged", this);
21773 * Query the records by a specified property.
21774 * @param {String} field A field on your records
21775 * @param {String/RegExp} value Either a string that the field
21776 * should start with or a RegExp to test against the field
21777 * @param {Boolean} anyMatch True to match any part not just the beginning
21778 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21780 query : function(property, value, anyMatch){
21781 var fn = this.createFilterFn(property, value, anyMatch);
21782 return fn ? this.queryBy(fn) : this.data.clone();
21786 * Query by a function. The specified function will be called with each
21787 * record in this data source. If the function returns true the record is included
21789 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21790 * @param {Object} scope (optional) The scope of the function (defaults to this)
21791 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21793 queryBy : function(fn, scope){
21794 var data = this.snapshot || this.data;
21795 return data.filterBy(fn, scope||this);
21799 * Collects unique values for a particular dataIndex from this store.
21800 * @param {String} dataIndex The property to collect
21801 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21802 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21803 * @return {Array} An array of the unique values
21805 collect : function(dataIndex, allowNull, bypassFilter){
21806 var d = (bypassFilter === true && this.snapshot) ?
21807 this.snapshot.items : this.data.items;
21808 var v, sv, r = [], l = {};
21809 for(var i = 0, len = d.length; i < len; i++){
21810 v = d[i].data[dataIndex];
21812 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21821 * Revert to a view of the Record cache with no filtering applied.
21822 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21824 clearFilter : function(suppressEvent){
21825 if(this.snapshot && this.snapshot != this.data){
21826 this.data = this.snapshot;
21827 delete this.snapshot;
21828 if(suppressEvent !== true){
21829 this.fireEvent("datachanged", this);
21835 afterEdit : function(record){
21836 if(this.modified.indexOf(record) == -1){
21837 this.modified.push(record);
21839 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21843 afterReject : function(record){
21844 this.modified.remove(record);
21845 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21849 afterCommit : function(record){
21850 this.modified.remove(record);
21851 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21855 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21856 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21858 commitChanges : function(){
21859 var m = this.modified.slice(0);
21860 this.modified = [];
21861 for(var i = 0, len = m.length; i < len; i++){
21867 * Cancel outstanding changes on all changed records.
21869 rejectChanges : function(){
21870 var m = this.modified.slice(0);
21871 this.modified = [];
21872 for(var i = 0, len = m.length; i < len; i++){
21877 onMetaChange : function(meta, rtype, o){
21878 this.recordType = rtype;
21879 this.fields = rtype.prototype.fields;
21880 delete this.snapshot;
21881 this.sortInfo = meta.sortInfo || this.sortInfo;
21882 this.modified = [];
21883 this.fireEvent('metachange', this, this.reader.meta);
21886 moveIndex : function(data, type)
21888 var index = this.indexOf(data);
21890 var newIndex = index + type;
21894 this.insert(newIndex, data);
21899 * Ext JS Library 1.1.1
21900 * Copyright(c) 2006-2007, Ext JS, LLC.
21902 * Originally Released Under LGPL - original licence link has changed is not relivant.
21905 * <script type="text/javascript">
21909 * @class Roo.data.SimpleStore
21910 * @extends Roo.data.Store
21911 * Small helper class to make creating Stores from Array data easier.
21912 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21913 * @cfg {Array} fields An array of field definition objects, or field name strings.
21914 * @cfg {Array} data The multi-dimensional array of data
21916 * @param {Object} config
21918 Roo.data.SimpleStore = function(config){
21919 Roo.data.SimpleStore.superclass.constructor.call(this, {
21921 reader: new Roo.data.ArrayReader({
21924 Roo.data.Record.create(config.fields)
21926 proxy : new Roo.data.MemoryProxy(config.data)
21930 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21932 * Ext JS Library 1.1.1
21933 * Copyright(c) 2006-2007, Ext JS, LLC.
21935 * Originally Released Under LGPL - original licence link has changed is not relivant.
21938 * <script type="text/javascript">
21943 * @extends Roo.data.Store
21944 * @class Roo.data.JsonStore
21945 * Small helper class to make creating Stores for JSON data easier. <br/>
21947 var store = new Roo.data.JsonStore({
21948 url: 'get-images.php',
21950 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21953 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21954 * JsonReader and HttpProxy (unless inline data is provided).</b>
21955 * @cfg {Array} fields An array of field definition objects, or field name strings.
21957 * @param {Object} config
21959 Roo.data.JsonStore = function(c){
21960 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21961 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21962 reader: new Roo.data.JsonReader(c, c.fields)
21965 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21967 * Ext JS Library 1.1.1
21968 * Copyright(c) 2006-2007, Ext JS, LLC.
21970 * Originally Released Under LGPL - original licence link has changed is not relivant.
21973 * <script type="text/javascript">
21977 Roo.data.Field = function(config){
21978 if(typeof config == "string"){
21979 config = {name: config};
21981 Roo.apply(this, config);
21984 this.type = "auto";
21987 var st = Roo.data.SortTypes;
21988 // named sortTypes are supported, here we look them up
21989 if(typeof this.sortType == "string"){
21990 this.sortType = st[this.sortType];
21993 // set default sortType for strings and dates
21994 if(!this.sortType){
21997 this.sortType = st.asUCString;
22000 this.sortType = st.asDate;
22003 this.sortType = st.none;
22008 var stripRe = /[\$,%]/g;
22010 // prebuilt conversion function for this field, instead of
22011 // switching every time we're reading a value
22013 var cv, dateFormat = this.dateFormat;
22018 cv = function(v){ return v; };
22021 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
22025 return v !== undefined && v !== null && v !== '' ?
22026 parseInt(String(v).replace(stripRe, ""), 10) : '';
22031 return v !== undefined && v !== null && v !== '' ?
22032 parseFloat(String(v).replace(stripRe, ""), 10) : '';
22037 cv = function(v){ return v === true || v === "true" || v == 1; };
22044 if(v instanceof Date){
22048 if(dateFormat == "timestamp"){
22049 return new Date(v*1000);
22051 return Date.parseDate(v, dateFormat);
22053 var parsed = Date.parse(v);
22054 return parsed ? new Date(parsed) : null;
22063 Roo.data.Field.prototype = {
22071 * Ext JS Library 1.1.1
22072 * Copyright(c) 2006-2007, Ext JS, LLC.
22074 * Originally Released Under LGPL - original licence link has changed is not relivant.
22077 * <script type="text/javascript">
22080 // Base class for reading structured data from a data source. This class is intended to be
22081 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
22084 * @class Roo.data.DataReader
22085 * Base class for reading structured data from a data source. This class is intended to be
22086 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
22089 Roo.data.DataReader = function(meta, recordType){
22093 this.recordType = recordType instanceof Array ?
22094 Roo.data.Record.create(recordType) : recordType;
22097 Roo.data.DataReader.prototype = {
22099 * Create an empty record
22100 * @param {Object} data (optional) - overlay some values
22101 * @return {Roo.data.Record} record created.
22103 newRow : function(d) {
22105 this.recordType.prototype.fields.each(function(c) {
22107 case 'int' : da[c.name] = 0; break;
22108 case 'date' : da[c.name] = new Date(); break;
22109 case 'float' : da[c.name] = 0.0; break;
22110 case 'boolean' : da[c.name] = false; break;
22111 default : da[c.name] = ""; break;
22115 return new this.recordType(Roo.apply(da, d));
22120 * Ext JS Library 1.1.1
22121 * Copyright(c) 2006-2007, Ext JS, LLC.
22123 * Originally Released Under LGPL - original licence link has changed is not relivant.
22126 * <script type="text/javascript">
22130 * @class Roo.data.DataProxy
22131 * @extends Roo.data.Observable
22132 * This class is an abstract base class for implementations which provide retrieval of
22133 * unformatted data objects.<br>
22135 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
22136 * (of the appropriate type which knows how to parse the data object) to provide a block of
22137 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
22139 * Custom implementations must implement the load method as described in
22140 * {@link Roo.data.HttpProxy#load}.
22142 Roo.data.DataProxy = function(){
22145 * @event beforeload
22146 * Fires before a network request is made to retrieve a data object.
22147 * @param {Object} This DataProxy object.
22148 * @param {Object} params The params parameter to the load function.
22153 * Fires before the load method's callback is called.
22154 * @param {Object} This DataProxy object.
22155 * @param {Object} o The data object.
22156 * @param {Object} arg The callback argument object passed to the load function.
22160 * @event loadexception
22161 * Fires if an Exception occurs during data retrieval.
22162 * @param {Object} This DataProxy object.
22163 * @param {Object} o The data object.
22164 * @param {Object} arg The callback argument object passed to the load function.
22165 * @param {Object} e The Exception.
22167 loadexception : true
22169 Roo.data.DataProxy.superclass.constructor.call(this);
22172 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22175 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22179 * Ext JS Library 1.1.1
22180 * Copyright(c) 2006-2007, Ext JS, LLC.
22182 * Originally Released Under LGPL - original licence link has changed is not relivant.
22185 * <script type="text/javascript">
22188 * @class Roo.data.MemoryProxy
22189 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22190 * to the Reader when its load method is called.
22192 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22194 Roo.data.MemoryProxy = function(data){
22198 Roo.data.MemoryProxy.superclass.constructor.call(this);
22202 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22204 * Load data from the requested source (in this case an in-memory
22205 * data object passed to the constructor), read the data object into
22206 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22207 * process that block using the passed callback.
22208 * @param {Object} params This parameter is not used by the MemoryProxy class.
22209 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22210 * object into a block of Roo.data.Records.
22211 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22212 * The function must be passed <ul>
22213 * <li>The Record block object</li>
22214 * <li>The "arg" argument from the load function</li>
22215 * <li>A boolean success indicator</li>
22217 * @param {Object} scope The scope in which to call the callback
22218 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22220 load : function(params, reader, callback, scope, arg){
22221 params = params || {};
22224 result = reader.readRecords(this.data);
22226 this.fireEvent("loadexception", this, arg, null, e);
22227 callback.call(scope, null, arg, false);
22230 callback.call(scope, result, arg, true);
22234 update : function(params, records){
22239 * Ext JS Library 1.1.1
22240 * Copyright(c) 2006-2007, Ext JS, LLC.
22242 * Originally Released Under LGPL - original licence link has changed is not relivant.
22245 * <script type="text/javascript">
22248 * @class Roo.data.HttpProxy
22249 * @extends Roo.data.DataProxy
22250 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22251 * configured to reference a certain URL.<br><br>
22253 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22254 * from which the running page was served.<br><br>
22256 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22258 * Be aware that to enable the browser to parse an XML document, the server must set
22259 * the Content-Type header in the HTTP response to "text/xml".
22261 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22262 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22263 * will be used to make the request.
22265 Roo.data.HttpProxy = function(conn){
22266 Roo.data.HttpProxy.superclass.constructor.call(this);
22267 // is conn a conn config or a real conn?
22269 this.useAjax = !conn || !conn.events;
22273 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22274 // thse are take from connection...
22277 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22280 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22281 * extra parameters to each request made by this object. (defaults to undefined)
22284 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22285 * to each request made by this object. (defaults to undefined)
22288 * @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)
22291 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22294 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22300 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22304 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22305 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22306 * a finer-grained basis than the DataProxy events.
22308 getConnection : function(){
22309 return this.useAjax ? Roo.Ajax : this.conn;
22313 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22314 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22315 * process that block using the passed callback.
22316 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22317 * for the request to the remote server.
22318 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22319 * object into a block of Roo.data.Records.
22320 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22321 * The function must be passed <ul>
22322 * <li>The Record block object</li>
22323 * <li>The "arg" argument from the load function</li>
22324 * <li>A boolean success indicator</li>
22326 * @param {Object} scope The scope in which to call the callback
22327 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22329 load : function(params, reader, callback, scope, arg){
22330 if(this.fireEvent("beforeload", this, params) !== false){
22332 params : params || {},
22334 callback : callback,
22339 callback : this.loadResponse,
22343 Roo.applyIf(o, this.conn);
22344 if(this.activeRequest){
22345 Roo.Ajax.abort(this.activeRequest);
22347 this.activeRequest = Roo.Ajax.request(o);
22349 this.conn.request(o);
22352 callback.call(scope||this, null, arg, false);
22357 loadResponse : function(o, success, response){
22358 delete this.activeRequest;
22360 this.fireEvent("loadexception", this, o, response);
22361 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22366 result = o.reader.read(response);
22368 this.fireEvent("loadexception", this, o, response, e);
22369 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22373 this.fireEvent("load", this, o, o.request.arg);
22374 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22378 update : function(dataSet){
22383 updateResponse : function(dataSet){
22388 * Ext JS Library 1.1.1
22389 * Copyright(c) 2006-2007, Ext JS, LLC.
22391 * Originally Released Under LGPL - original licence link has changed is not relivant.
22394 * <script type="text/javascript">
22398 * @class Roo.data.ScriptTagProxy
22399 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22400 * other than the originating domain of the running page.<br><br>
22402 * <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
22403 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22405 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22406 * source code that is used as the source inside a <script> tag.<br><br>
22408 * In order for the browser to process the returned data, the server must wrap the data object
22409 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22410 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22411 * depending on whether the callback name was passed:
22414 boolean scriptTag = false;
22415 String cb = request.getParameter("callback");
22418 response.setContentType("text/javascript");
22420 response.setContentType("application/x-json");
22422 Writer out = response.getWriter();
22424 out.write(cb + "(");
22426 out.print(dataBlock.toJsonString());
22433 * @param {Object} config A configuration object.
22435 Roo.data.ScriptTagProxy = function(config){
22436 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22437 Roo.apply(this, config);
22438 this.head = document.getElementsByTagName("head")[0];
22441 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22443 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22445 * @cfg {String} url The URL from which to request the data object.
22448 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22452 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22453 * the server the name of the callback function set up by the load call to process the returned data object.
22454 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22455 * javascript output which calls this named function passing the data object as its only parameter.
22457 callbackParam : "callback",
22459 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22460 * name to the request.
22465 * Load data from the configured URL, read the data object into
22466 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22467 * process that block using the passed callback.
22468 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22469 * for the request to the remote server.
22470 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22471 * object into a block of Roo.data.Records.
22472 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22473 * The function must be passed <ul>
22474 * <li>The Record block object</li>
22475 * <li>The "arg" argument from the load function</li>
22476 * <li>A boolean success indicator</li>
22478 * @param {Object} scope The scope in which to call the callback
22479 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22481 load : function(params, reader, callback, scope, arg){
22482 if(this.fireEvent("beforeload", this, params) !== false){
22484 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22486 var url = this.url;
22487 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22489 url += "&_dc=" + (new Date().getTime());
22491 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22494 cb : "stcCallback"+transId,
22495 scriptId : "stcScript"+transId,
22499 callback : callback,
22505 window[trans.cb] = function(o){
22506 conn.handleResponse(o, trans);
22509 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22511 if(this.autoAbort !== false){
22515 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22517 var script = document.createElement("script");
22518 script.setAttribute("src", url);
22519 script.setAttribute("type", "text/javascript");
22520 script.setAttribute("id", trans.scriptId);
22521 this.head.appendChild(script);
22523 this.trans = trans;
22525 callback.call(scope||this, null, arg, false);
22530 isLoading : function(){
22531 return this.trans ? true : false;
22535 * Abort the current server request.
22537 abort : function(){
22538 if(this.isLoading()){
22539 this.destroyTrans(this.trans);
22544 destroyTrans : function(trans, isLoaded){
22545 this.head.removeChild(document.getElementById(trans.scriptId));
22546 clearTimeout(trans.timeoutId);
22548 window[trans.cb] = undefined;
22550 delete window[trans.cb];
22553 // if hasn't been loaded, wait for load to remove it to prevent script error
22554 window[trans.cb] = function(){
22555 window[trans.cb] = undefined;
22557 delete window[trans.cb];
22564 handleResponse : function(o, trans){
22565 this.trans = false;
22566 this.destroyTrans(trans, true);
22569 result = trans.reader.readRecords(o);
22571 this.fireEvent("loadexception", this, o, trans.arg, e);
22572 trans.callback.call(trans.scope||window, null, trans.arg, false);
22575 this.fireEvent("load", this, o, trans.arg);
22576 trans.callback.call(trans.scope||window, result, trans.arg, true);
22580 handleFailure : function(trans){
22581 this.trans = false;
22582 this.destroyTrans(trans, false);
22583 this.fireEvent("loadexception", this, null, trans.arg);
22584 trans.callback.call(trans.scope||window, null, trans.arg, false);
22588 * Ext JS Library 1.1.1
22589 * Copyright(c) 2006-2007, Ext JS, LLC.
22591 * Originally Released Under LGPL - original licence link has changed is not relivant.
22594 * <script type="text/javascript">
22598 * @class Roo.data.JsonReader
22599 * @extends Roo.data.DataReader
22600 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22601 * based on mappings in a provided Roo.data.Record constructor.
22603 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22604 * in the reply previously.
22609 var RecordDef = Roo.data.Record.create([
22610 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22611 {name: 'occupation'} // This field will use "occupation" as the mapping.
22613 var myReader = new Roo.data.JsonReader({
22614 totalProperty: "results", // The property which contains the total dataset size (optional)
22615 root: "rows", // The property which contains an Array of row objects
22616 id: "id" // The property within each row object that provides an ID for the record (optional)
22620 * This would consume a JSON file like this:
22622 { 'results': 2, 'rows': [
22623 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22624 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22627 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22628 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22629 * paged from the remote server.
22630 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22631 * @cfg {String} root name of the property which contains the Array of row objects.
22632 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22633 * @cfg {Array} fields Array of field definition objects
22635 * Create a new JsonReader
22636 * @param {Object} meta Metadata configuration options
22637 * @param {Object} recordType Either an Array of field definition objects,
22638 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22640 Roo.data.JsonReader = function(meta, recordType){
22643 // set some defaults:
22644 Roo.applyIf(meta, {
22645 totalProperty: 'total',
22646 successProperty : 'success',
22651 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22653 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22656 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22657 * Used by Store query builder to append _requestMeta to params.
22660 metaFromRemote : false,
22662 * This method is only used by a DataProxy which has retrieved data from a remote server.
22663 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22664 * @return {Object} data A data block which is used by an Roo.data.Store object as
22665 * a cache of Roo.data.Records.
22667 read : function(response){
22668 var json = response.responseText;
22670 var o = /* eval:var:o */ eval("("+json+")");
22672 throw {message: "JsonReader.read: Json object not found"};
22678 this.metaFromRemote = true;
22679 this.meta = o.metaData;
22680 this.recordType = Roo.data.Record.create(o.metaData.fields);
22681 this.onMetaChange(this.meta, this.recordType, o);
22683 return this.readRecords(o);
22686 // private function a store will implement
22687 onMetaChange : function(meta, recordType, o){
22694 simpleAccess: function(obj, subsc) {
22701 getJsonAccessor: function(){
22703 return function(expr) {
22705 return(re.test(expr))
22706 ? new Function("obj", "return obj." + expr)
22711 return Roo.emptyFn;
22716 * Create a data block containing Roo.data.Records from an XML document.
22717 * @param {Object} o An object which contains an Array of row objects in the property specified
22718 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22719 * which contains the total size of the dataset.
22720 * @return {Object} data A data block which is used by an Roo.data.Store object as
22721 * a cache of Roo.data.Records.
22723 readRecords : function(o){
22725 * After any data loads, the raw JSON data is available for further custom processing.
22729 var s = this.meta, Record = this.recordType,
22730 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
22732 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22734 if(s.totalProperty) {
22735 this.getTotal = this.getJsonAccessor(s.totalProperty);
22737 if(s.successProperty) {
22738 this.getSuccess = this.getJsonAccessor(s.successProperty);
22740 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22742 var g = this.getJsonAccessor(s.id);
22743 this.getId = function(rec) {
22745 return (r === undefined || r === "") ? null : r;
22748 this.getId = function(){return null;};
22751 for(var jj = 0; jj < fl; jj++){
22753 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22754 this.ef[jj] = this.getJsonAccessor(map);
22758 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22759 if(s.totalProperty){
22760 var vt = parseInt(this.getTotal(o), 10);
22765 if(s.successProperty){
22766 var vs = this.getSuccess(o);
22767 if(vs === false || vs === 'false'){
22772 for(var i = 0; i < c; i++){
22775 var id = this.getId(n);
22776 for(var j = 0; j < fl; j++){
22778 var v = this.ef[j](n);
22780 Roo.log('missing convert for ' + f.name);
22784 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22786 var record = new Record(values, id);
22788 records[i] = record;
22794 totalRecords : totalRecords
22799 * Ext JS Library 1.1.1
22800 * Copyright(c) 2006-2007, Ext JS, LLC.
22802 * Originally Released Under LGPL - original licence link has changed is not relivant.
22805 * <script type="text/javascript">
22809 * @class Roo.data.XmlReader
22810 * @extends Roo.data.DataReader
22811 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22812 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22814 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22815 * header in the HTTP response must be set to "text/xml".</em>
22819 var RecordDef = Roo.data.Record.create([
22820 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22821 {name: 'occupation'} // This field will use "occupation" as the mapping.
22823 var myReader = new Roo.data.XmlReader({
22824 totalRecords: "results", // The element which contains the total dataset size (optional)
22825 record: "row", // The repeated element which contains row information
22826 id: "id" // The element within the row that provides an ID for the record (optional)
22830 * This would consume an XML file like this:
22834 <results>2</results>
22837 <name>Bill</name>
22838 <occupation>Gardener</occupation>
22842 <name>Ben</name>
22843 <occupation>Horticulturalist</occupation>
22847 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22848 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22849 * paged from the remote server.
22850 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22851 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22852 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22853 * a record identifier value.
22855 * Create a new XmlReader
22856 * @param {Object} meta Metadata configuration options
22857 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22858 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22859 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22861 Roo.data.XmlReader = function(meta, recordType){
22863 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22865 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22867 * This method is only used by a DataProxy which has retrieved data from a remote server.
22868 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22869 * to contain a method called 'responseXML' that returns an XML document object.
22870 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22871 * a cache of Roo.data.Records.
22873 read : function(response){
22874 var doc = response.responseXML;
22876 throw {message: "XmlReader.read: XML Document not available"};
22878 return this.readRecords(doc);
22882 * Create a data block containing Roo.data.Records from an XML document.
22883 * @param {Object} doc A parsed XML document.
22884 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22885 * a cache of Roo.data.Records.
22887 readRecords : function(doc){
22889 * After any data loads/reads, the raw XML Document is available for further custom processing.
22890 * @type XMLDocument
22892 this.xmlData = doc;
22893 var root = doc.documentElement || doc;
22894 var q = Roo.DomQuery;
22895 var recordType = this.recordType, fields = recordType.prototype.fields;
22896 var sid = this.meta.id;
22897 var totalRecords = 0, success = true;
22898 if(this.meta.totalRecords){
22899 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22902 if(this.meta.success){
22903 var sv = q.selectValue(this.meta.success, root, true);
22904 success = sv !== false && sv !== 'false';
22907 var ns = q.select(this.meta.record, root);
22908 for(var i = 0, len = ns.length; i < len; i++) {
22911 var id = sid ? q.selectValue(sid, n) : undefined;
22912 for(var j = 0, jlen = fields.length; j < jlen; j++){
22913 var f = fields.items[j];
22914 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22916 values[f.name] = v;
22918 var record = new recordType(values, id);
22920 records[records.length] = record;
22926 totalRecords : totalRecords || records.length
22931 * Ext JS Library 1.1.1
22932 * Copyright(c) 2006-2007, Ext JS, LLC.
22934 * Originally Released Under LGPL - original licence link has changed is not relivant.
22937 * <script type="text/javascript">
22941 * @class Roo.data.ArrayReader
22942 * @extends Roo.data.DataReader
22943 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22944 * Each element of that Array represents a row of data fields. The
22945 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22946 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22950 var RecordDef = Roo.data.Record.create([
22951 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22952 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22954 var myReader = new Roo.data.ArrayReader({
22955 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22959 * This would consume an Array like this:
22961 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22963 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22965 * Create a new JsonReader
22966 * @param {Object} meta Metadata configuration options.
22967 * @param {Object} recordType Either an Array of field definition objects
22968 * as specified to {@link Roo.data.Record#create},
22969 * or an {@link Roo.data.Record} object
22970 * created using {@link Roo.data.Record#create}.
22972 Roo.data.ArrayReader = function(meta, recordType){
22973 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22976 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22978 * Create a data block containing Roo.data.Records from an XML document.
22979 * @param {Object} o An Array of row objects which represents the dataset.
22980 * @return {Object} data A data block which is used by an Roo.data.Store object as
22981 * a cache of Roo.data.Records.
22983 readRecords : function(o){
22984 var sid = this.meta ? this.meta.id : null;
22985 var recordType = this.recordType, fields = recordType.prototype.fields;
22988 for(var i = 0; i < root.length; i++){
22991 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22992 for(var j = 0, jlen = fields.length; j < jlen; j++){
22993 var f = fields.items[j];
22994 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22995 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22997 values[f.name] = v;
22999 var record = new recordType(values, id);
23001 records[records.length] = record;
23005 totalRecords : records.length
23010 * Ext JS Library 1.1.1
23011 * Copyright(c) 2006-2007, Ext JS, LLC.
23013 * Originally Released Under LGPL - original licence link has changed is not relivant.
23016 * <script type="text/javascript">
23021 * @class Roo.data.Tree
23022 * @extends Roo.util.Observable
23023 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
23024 * in the tree have most standard DOM functionality.
23026 * @param {Node} root (optional) The root node
23028 Roo.data.Tree = function(root){
23029 this.nodeHash = {};
23031 * The root node for this tree
23036 this.setRootNode(root);
23041 * Fires when a new child node is appended to a node in this tree.
23042 * @param {Tree} tree The owner tree
23043 * @param {Node} parent The parent node
23044 * @param {Node} node The newly appended node
23045 * @param {Number} index The index of the newly appended node
23050 * Fires when a child node is removed from a node in this tree.
23051 * @param {Tree} tree The owner tree
23052 * @param {Node} parent The parent node
23053 * @param {Node} node The child node removed
23058 * Fires when a node is moved to a new location in the tree
23059 * @param {Tree} tree The owner tree
23060 * @param {Node} node The node moved
23061 * @param {Node} oldParent The old parent of this node
23062 * @param {Node} newParent The new parent of this node
23063 * @param {Number} index The index it was moved to
23068 * Fires when a new child node is inserted in a node in this tree.
23069 * @param {Tree} tree The owner tree
23070 * @param {Node} parent The parent node
23071 * @param {Node} node The child node inserted
23072 * @param {Node} refNode The child node the node was inserted before
23076 * @event beforeappend
23077 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
23078 * @param {Tree} tree The owner tree
23079 * @param {Node} parent The parent node
23080 * @param {Node} node The child node to be appended
23082 "beforeappend" : true,
23084 * @event beforeremove
23085 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
23086 * @param {Tree} tree The owner tree
23087 * @param {Node} parent The parent node
23088 * @param {Node} node The child node to be removed
23090 "beforeremove" : true,
23092 * @event beforemove
23093 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
23094 * @param {Tree} tree The owner tree
23095 * @param {Node} node The node being moved
23096 * @param {Node} oldParent The parent of the node
23097 * @param {Node} newParent The new parent the node is moving to
23098 * @param {Number} index The index it is being moved to
23100 "beforemove" : true,
23102 * @event beforeinsert
23103 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
23104 * @param {Tree} tree The owner tree
23105 * @param {Node} parent The parent node
23106 * @param {Node} node The child node to be inserted
23107 * @param {Node} refNode The child node the node is being inserted before
23109 "beforeinsert" : true
23112 Roo.data.Tree.superclass.constructor.call(this);
23115 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
23116 pathSeparator: "/",
23118 proxyNodeEvent : function(){
23119 return this.fireEvent.apply(this, arguments);
23123 * Returns the root node for this tree.
23126 getRootNode : function(){
23131 * Sets the root node for this tree.
23132 * @param {Node} node
23135 setRootNode : function(node){
23137 node.ownerTree = this;
23138 node.isRoot = true;
23139 this.registerNode(node);
23144 * Gets a node in this tree by its id.
23145 * @param {String} id
23148 getNodeById : function(id){
23149 return this.nodeHash[id];
23152 registerNode : function(node){
23153 this.nodeHash[node.id] = node;
23156 unregisterNode : function(node){
23157 delete this.nodeHash[node.id];
23160 toString : function(){
23161 return "[Tree"+(this.id?" "+this.id:"")+"]";
23166 * @class Roo.data.Node
23167 * @extends Roo.util.Observable
23168 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23169 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23171 * @param {Object} attributes The attributes/config for the node
23173 Roo.data.Node = function(attributes){
23175 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23178 this.attributes = attributes || {};
23179 this.leaf = this.attributes.leaf;
23181 * The node id. @type String
23183 this.id = this.attributes.id;
23185 this.id = Roo.id(null, "ynode-");
23186 this.attributes.id = this.id;
23191 * All child nodes of this node. @type Array
23193 this.childNodes = [];
23194 if(!this.childNodes.indexOf){ // indexOf is a must
23195 this.childNodes.indexOf = function(o){
23196 for(var i = 0, len = this.length; i < len; i++){
23205 * The parent node for this node. @type Node
23207 this.parentNode = null;
23209 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23211 this.firstChild = null;
23213 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23215 this.lastChild = null;
23217 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23219 this.previousSibling = null;
23221 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23223 this.nextSibling = null;
23228 * Fires when a new child node is appended
23229 * @param {Tree} tree The owner tree
23230 * @param {Node} this This node
23231 * @param {Node} node The newly appended node
23232 * @param {Number} index The index of the newly appended node
23237 * Fires when a child node is removed
23238 * @param {Tree} tree The owner tree
23239 * @param {Node} this This node
23240 * @param {Node} node The removed node
23245 * Fires when this node is moved to a new location in the tree
23246 * @param {Tree} tree The owner tree
23247 * @param {Node} this This node
23248 * @param {Node} oldParent The old parent of this node
23249 * @param {Node} newParent The new parent of this node
23250 * @param {Number} index The index it was moved to
23255 * Fires when a new child node is inserted.
23256 * @param {Tree} tree The owner tree
23257 * @param {Node} this This node
23258 * @param {Node} node The child node inserted
23259 * @param {Node} refNode The child node the node was inserted before
23263 * @event beforeappend
23264 * Fires before a new child is appended, return false to cancel the append.
23265 * @param {Tree} tree The owner tree
23266 * @param {Node} this This node
23267 * @param {Node} node The child node to be appended
23269 "beforeappend" : true,
23271 * @event beforeremove
23272 * Fires before a child is removed, return false to cancel the remove.
23273 * @param {Tree} tree The owner tree
23274 * @param {Node} this This node
23275 * @param {Node} node The child node to be removed
23277 "beforeremove" : true,
23279 * @event beforemove
23280 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23281 * @param {Tree} tree The owner tree
23282 * @param {Node} this This node
23283 * @param {Node} oldParent The parent of this node
23284 * @param {Node} newParent The new parent this node is moving to
23285 * @param {Number} index The index it is being moved to
23287 "beforemove" : true,
23289 * @event beforeinsert
23290 * Fires before a new child is inserted, return false to cancel the insert.
23291 * @param {Tree} tree The owner tree
23292 * @param {Node} this This node
23293 * @param {Node} node The child node to be inserted
23294 * @param {Node} refNode The child node the node is being inserted before
23296 "beforeinsert" : true
23298 this.listeners = this.attributes.listeners;
23299 Roo.data.Node.superclass.constructor.call(this);
23302 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23303 fireEvent : function(evtName){
23304 // first do standard event for this node
23305 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23308 // then bubble it up to the tree if the event wasn't cancelled
23309 var ot = this.getOwnerTree();
23311 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23319 * Returns true if this node is a leaf
23320 * @return {Boolean}
23322 isLeaf : function(){
23323 return this.leaf === true;
23327 setFirstChild : function(node){
23328 this.firstChild = node;
23332 setLastChild : function(node){
23333 this.lastChild = node;
23338 * Returns true if this node is the last child of its parent
23339 * @return {Boolean}
23341 isLast : function(){
23342 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23346 * Returns true if this node is the first child of its parent
23347 * @return {Boolean}
23349 isFirst : function(){
23350 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23353 hasChildNodes : function(){
23354 return !this.isLeaf() && this.childNodes.length > 0;
23358 * Insert node(s) as the last child node of this node.
23359 * @param {Node/Array} node The node or Array of nodes to append
23360 * @return {Node} The appended node if single append, or null if an array was passed
23362 appendChild : function(node){
23364 if(node instanceof Array){
23366 }else if(arguments.length > 1){
23369 // if passed an array or multiple args do them one by one
23371 for(var i = 0, len = multi.length; i < len; i++) {
23372 this.appendChild(multi[i]);
23375 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23378 var index = this.childNodes.length;
23379 var oldParent = node.parentNode;
23380 // it's a move, make sure we move it cleanly
23382 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23385 oldParent.removeChild(node);
23387 index = this.childNodes.length;
23389 this.setFirstChild(node);
23391 this.childNodes.push(node);
23392 node.parentNode = this;
23393 var ps = this.childNodes[index-1];
23395 node.previousSibling = ps;
23396 ps.nextSibling = node;
23398 node.previousSibling = null;
23400 node.nextSibling = null;
23401 this.setLastChild(node);
23402 node.setOwnerTree(this.getOwnerTree());
23403 this.fireEvent("append", this.ownerTree, this, node, index);
23405 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23412 * Removes a child node from this node.
23413 * @param {Node} node The node to remove
23414 * @return {Node} The removed node
23416 removeChild : function(node){
23417 var index = this.childNodes.indexOf(node);
23421 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23425 // remove it from childNodes collection
23426 this.childNodes.splice(index, 1);
23429 if(node.previousSibling){
23430 node.previousSibling.nextSibling = node.nextSibling;
23432 if(node.nextSibling){
23433 node.nextSibling.previousSibling = node.previousSibling;
23436 // update child refs
23437 if(this.firstChild == node){
23438 this.setFirstChild(node.nextSibling);
23440 if(this.lastChild == node){
23441 this.setLastChild(node.previousSibling);
23444 node.setOwnerTree(null);
23445 // clear any references from the node
23446 node.parentNode = null;
23447 node.previousSibling = null;
23448 node.nextSibling = null;
23449 this.fireEvent("remove", this.ownerTree, this, node);
23454 * Inserts the first node before the second node in this nodes childNodes collection.
23455 * @param {Node} node The node to insert
23456 * @param {Node} refNode The node to insert before (if null the node is appended)
23457 * @return {Node} The inserted node
23459 insertBefore : function(node, refNode){
23460 if(!refNode){ // like standard Dom, refNode can be null for append
23461 return this.appendChild(node);
23464 if(node == refNode){
23468 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23471 var index = this.childNodes.indexOf(refNode);
23472 var oldParent = node.parentNode;
23473 var refIndex = index;
23475 // when moving internally, indexes will change after remove
23476 if(oldParent == this && this.childNodes.indexOf(node) < index){
23480 // it's a move, make sure we move it cleanly
23482 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23485 oldParent.removeChild(node);
23488 this.setFirstChild(node);
23490 this.childNodes.splice(refIndex, 0, node);
23491 node.parentNode = this;
23492 var ps = this.childNodes[refIndex-1];
23494 node.previousSibling = ps;
23495 ps.nextSibling = node;
23497 node.previousSibling = null;
23499 node.nextSibling = refNode;
23500 refNode.previousSibling = node;
23501 node.setOwnerTree(this.getOwnerTree());
23502 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23504 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23510 * Returns the child node at the specified index.
23511 * @param {Number} index
23514 item : function(index){
23515 return this.childNodes[index];
23519 * Replaces one child node in this node with another.
23520 * @param {Node} newChild The replacement node
23521 * @param {Node} oldChild The node to replace
23522 * @return {Node} The replaced node
23524 replaceChild : function(newChild, oldChild){
23525 this.insertBefore(newChild, oldChild);
23526 this.removeChild(oldChild);
23531 * Returns the index of a child node
23532 * @param {Node} node
23533 * @return {Number} The index of the node or -1 if it was not found
23535 indexOf : function(child){
23536 return this.childNodes.indexOf(child);
23540 * Returns the tree this node is in.
23543 getOwnerTree : function(){
23544 // if it doesn't have one, look for one
23545 if(!this.ownerTree){
23549 this.ownerTree = p.ownerTree;
23555 return this.ownerTree;
23559 * Returns depth of this node (the root node has a depth of 0)
23562 getDepth : function(){
23565 while(p.parentNode){
23573 setOwnerTree : function(tree){
23574 // if it's move, we need to update everyone
23575 if(tree != this.ownerTree){
23576 if(this.ownerTree){
23577 this.ownerTree.unregisterNode(this);
23579 this.ownerTree = tree;
23580 var cs = this.childNodes;
23581 for(var i = 0, len = cs.length; i < len; i++) {
23582 cs[i].setOwnerTree(tree);
23585 tree.registerNode(this);
23591 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23592 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23593 * @return {String} The path
23595 getPath : function(attr){
23596 attr = attr || "id";
23597 var p = this.parentNode;
23598 var b = [this.attributes[attr]];
23600 b.unshift(p.attributes[attr]);
23603 var sep = this.getOwnerTree().pathSeparator;
23604 return sep + b.join(sep);
23608 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23609 * function call will be the scope provided or the current node. The arguments to the function
23610 * will be the args provided or the current node. If the function returns false at any point,
23611 * the bubble is stopped.
23612 * @param {Function} fn The function to call
23613 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23614 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23616 bubble : function(fn, scope, args){
23619 if(fn.call(scope || p, args || p) === false){
23627 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23628 * function call will be the scope provided or the current node. The arguments to the function
23629 * will be the args provided or the current node. If the function returns false at any point,
23630 * the cascade is stopped on that branch.
23631 * @param {Function} fn The function to call
23632 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23633 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23635 cascade : function(fn, scope, args){
23636 if(fn.call(scope || this, args || this) !== false){
23637 var cs = this.childNodes;
23638 for(var i = 0, len = cs.length; i < len; i++) {
23639 cs[i].cascade(fn, scope, args);
23645 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23646 * function call will be the scope provided or the current node. The arguments to the function
23647 * will be the args provided or the current node. If the function returns false at any point,
23648 * the iteration stops.
23649 * @param {Function} fn The function to call
23650 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23651 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23653 eachChild : function(fn, scope, args){
23654 var cs = this.childNodes;
23655 for(var i = 0, len = cs.length; i < len; i++) {
23656 if(fn.call(scope || this, args || cs[i]) === false){
23663 * Finds the first child that has the attribute with the specified value.
23664 * @param {String} attribute The attribute name
23665 * @param {Mixed} value The value to search for
23666 * @return {Node} The found child or null if none was found
23668 findChild : function(attribute, value){
23669 var cs = this.childNodes;
23670 for(var i = 0, len = cs.length; i < len; i++) {
23671 if(cs[i].attributes[attribute] == value){
23679 * Finds the first child by a custom function. The child matches if the function passed
23681 * @param {Function} fn
23682 * @param {Object} scope (optional)
23683 * @return {Node} The found child or null if none was found
23685 findChildBy : function(fn, scope){
23686 var cs = this.childNodes;
23687 for(var i = 0, len = cs.length; i < len; i++) {
23688 if(fn.call(scope||cs[i], cs[i]) === true){
23696 * Sorts this nodes children using the supplied sort function
23697 * @param {Function} fn
23698 * @param {Object} scope (optional)
23700 sort : function(fn, scope){
23701 var cs = this.childNodes;
23702 var len = cs.length;
23704 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23706 for(var i = 0; i < len; i++){
23708 n.previousSibling = cs[i-1];
23709 n.nextSibling = cs[i+1];
23711 this.setFirstChild(n);
23714 this.setLastChild(n);
23721 * Returns true if this node is an ancestor (at any point) of the passed node.
23722 * @param {Node} node
23723 * @return {Boolean}
23725 contains : function(node){
23726 return node.isAncestor(this);
23730 * Returns true if the passed node is an ancestor (at any point) of this node.
23731 * @param {Node} node
23732 * @return {Boolean}
23734 isAncestor : function(node){
23735 var p = this.parentNode;
23745 toString : function(){
23746 return "[Node"+(this.id?" "+this.id:"")+"]";
23750 * Ext JS Library 1.1.1
23751 * Copyright(c) 2006-2007, Ext JS, LLC.
23753 * Originally Released Under LGPL - original licence link has changed is not relivant.
23756 * <script type="text/javascript">
23761 * @extends Roo.Element
23762 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23763 * automatic maintaining of shadow/shim positions.
23764 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23765 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23766 * you can pass a string with a CSS class name. False turns off the shadow.
23767 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23768 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23769 * @cfg {String} cls CSS class to add to the element
23770 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23771 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23773 * @param {Object} config An object with config options.
23774 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23777 Roo.Layer = function(config, existingEl){
23778 config = config || {};
23779 var dh = Roo.DomHelper;
23780 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23782 this.dom = Roo.getDom(existingEl);
23785 var o = config.dh || {tag: "div", cls: "x-layer"};
23786 this.dom = dh.append(pel, o);
23789 this.addClass(config.cls);
23791 this.constrain = config.constrain !== false;
23792 this.visibilityMode = Roo.Element.VISIBILITY;
23794 this.id = this.dom.id = config.id;
23796 this.id = Roo.id(this.dom);
23798 this.zindex = config.zindex || this.getZIndex();
23799 this.position("absolute", this.zindex);
23801 this.shadowOffset = config.shadowOffset || 4;
23802 this.shadow = new Roo.Shadow({
23803 offset : this.shadowOffset,
23804 mode : config.shadow
23807 this.shadowOffset = 0;
23809 this.useShim = config.shim !== false && Roo.useShims;
23810 this.useDisplay = config.useDisplay;
23814 var supr = Roo.Element.prototype;
23816 // shims are shared among layer to keep from having 100 iframes
23819 Roo.extend(Roo.Layer, Roo.Element, {
23821 getZIndex : function(){
23822 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23825 getShim : function(){
23832 var shim = shims.shift();
23834 shim = this.createShim();
23835 shim.enableDisplayMode('block');
23836 shim.dom.style.display = 'none';
23837 shim.dom.style.visibility = 'visible';
23839 var pn = this.dom.parentNode;
23840 if(shim.dom.parentNode != pn){
23841 pn.insertBefore(shim.dom, this.dom);
23843 shim.setStyle('z-index', this.getZIndex()-2);
23848 hideShim : function(){
23850 this.shim.setDisplayed(false);
23851 shims.push(this.shim);
23856 disableShadow : function(){
23858 this.shadowDisabled = true;
23859 this.shadow.hide();
23860 this.lastShadowOffset = this.shadowOffset;
23861 this.shadowOffset = 0;
23865 enableShadow : function(show){
23867 this.shadowDisabled = false;
23868 this.shadowOffset = this.lastShadowOffset;
23869 delete this.lastShadowOffset;
23877 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23878 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23879 sync : function(doShow){
23880 var sw = this.shadow;
23881 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23882 var sh = this.getShim();
23884 var w = this.getWidth(),
23885 h = this.getHeight();
23887 var l = this.getLeft(true),
23888 t = this.getTop(true);
23890 if(sw && !this.shadowDisabled){
23891 if(doShow && !sw.isVisible()){
23894 sw.realign(l, t, w, h);
23900 // fit the shim behind the shadow, so it is shimmed too
23901 var a = sw.adjusts, s = sh.dom.style;
23902 s.left = (Math.min(l, l+a.l))+"px";
23903 s.top = (Math.min(t, t+a.t))+"px";
23904 s.width = (w+a.w)+"px";
23905 s.height = (h+a.h)+"px";
23912 sh.setLeftTop(l, t);
23919 destroy : function(){
23922 this.shadow.hide();
23924 this.removeAllListeners();
23925 var pn = this.dom.parentNode;
23927 pn.removeChild(this.dom);
23929 Roo.Element.uncache(this.id);
23932 remove : function(){
23937 beginUpdate : function(){
23938 this.updating = true;
23942 endUpdate : function(){
23943 this.updating = false;
23948 hideUnders : function(negOffset){
23950 this.shadow.hide();
23956 constrainXY : function(){
23957 if(this.constrain){
23958 var vw = Roo.lib.Dom.getViewWidth(),
23959 vh = Roo.lib.Dom.getViewHeight();
23960 var s = Roo.get(document).getScroll();
23962 var xy = this.getXY();
23963 var x = xy[0], y = xy[1];
23964 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23965 // only move it if it needs it
23967 // first validate right/bottom
23968 if((x + w) > vw+s.left){
23969 x = vw - w - this.shadowOffset;
23972 if((y + h) > vh+s.top){
23973 y = vh - h - this.shadowOffset;
23976 // then make sure top/left isn't negative
23987 var ay = this.avoidY;
23988 if(y <= ay && (y+h) >= ay){
23994 supr.setXY.call(this, xy);
24000 isVisible : function(){
24001 return this.visible;
24005 showAction : function(){
24006 this.visible = true; // track visibility to prevent getStyle calls
24007 if(this.useDisplay === true){
24008 this.setDisplayed("");
24009 }else if(this.lastXY){
24010 supr.setXY.call(this, this.lastXY);
24011 }else if(this.lastLT){
24012 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
24017 hideAction : function(){
24018 this.visible = false;
24019 if(this.useDisplay === true){
24020 this.setDisplayed(false);
24022 this.setLeftTop(-10000,-10000);
24026 // overridden Element method
24027 setVisible : function(v, a, d, c, e){
24032 var cb = function(){
24037 }.createDelegate(this);
24038 supr.setVisible.call(this, true, true, d, cb, e);
24041 this.hideUnders(true);
24050 }.createDelegate(this);
24052 supr.setVisible.call(this, v, a, d, cb, e);
24061 storeXY : function(xy){
24062 delete this.lastLT;
24066 storeLeftTop : function(left, top){
24067 delete this.lastXY;
24068 this.lastLT = [left, top];
24072 beforeFx : function(){
24073 this.beforeAction();
24074 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
24078 afterFx : function(){
24079 Roo.Layer.superclass.afterFx.apply(this, arguments);
24080 this.sync(this.isVisible());
24084 beforeAction : function(){
24085 if(!this.updating && this.shadow){
24086 this.shadow.hide();
24090 // overridden Element method
24091 setLeft : function(left){
24092 this.storeLeftTop(left, this.getTop(true));
24093 supr.setLeft.apply(this, arguments);
24097 setTop : function(top){
24098 this.storeLeftTop(this.getLeft(true), top);
24099 supr.setTop.apply(this, arguments);
24103 setLeftTop : function(left, top){
24104 this.storeLeftTop(left, top);
24105 supr.setLeftTop.apply(this, arguments);
24109 setXY : function(xy, a, d, c, e){
24111 this.beforeAction();
24113 var cb = this.createCB(c);
24114 supr.setXY.call(this, xy, a, d, cb, e);
24121 createCB : function(c){
24132 // overridden Element method
24133 setX : function(x, a, d, c, e){
24134 this.setXY([x, this.getY()], a, d, c, e);
24137 // overridden Element method
24138 setY : function(y, a, d, c, e){
24139 this.setXY([this.getX(), y], a, d, c, e);
24142 // overridden Element method
24143 setSize : function(w, h, a, d, c, e){
24144 this.beforeAction();
24145 var cb = this.createCB(c);
24146 supr.setSize.call(this, w, h, a, d, cb, e);
24152 // overridden Element method
24153 setWidth : function(w, a, d, c, e){
24154 this.beforeAction();
24155 var cb = this.createCB(c);
24156 supr.setWidth.call(this, w, a, d, cb, e);
24162 // overridden Element method
24163 setHeight : function(h, a, d, c, e){
24164 this.beforeAction();
24165 var cb = this.createCB(c);
24166 supr.setHeight.call(this, h, a, d, cb, e);
24172 // overridden Element method
24173 setBounds : function(x, y, w, h, a, d, c, e){
24174 this.beforeAction();
24175 var cb = this.createCB(c);
24177 this.storeXY([x, y]);
24178 supr.setXY.call(this, [x, y]);
24179 supr.setSize.call(this, w, h, a, d, cb, e);
24182 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24188 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24189 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24190 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24191 * @param {Number} zindex The new z-index to set
24192 * @return {this} The Layer
24194 setZIndex : function(zindex){
24195 this.zindex = zindex;
24196 this.setStyle("z-index", zindex + 2);
24198 this.shadow.setZIndex(zindex + 1);
24201 this.shim.setStyle("z-index", zindex);
24207 * Ext JS Library 1.1.1
24208 * Copyright(c) 2006-2007, Ext JS, LLC.
24210 * Originally Released Under LGPL - original licence link has changed is not relivant.
24213 * <script type="text/javascript">
24218 * @class Roo.Shadow
24219 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24220 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24221 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24223 * Create a new Shadow
24224 * @param {Object} config The config object
24226 Roo.Shadow = function(config){
24227 Roo.apply(this, config);
24228 if(typeof this.mode != "string"){
24229 this.mode = this.defaultMode;
24231 var o = this.offset, a = {h: 0};
24232 var rad = Math.floor(this.offset/2);
24233 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24239 a.l -= this.offset + rad;
24240 a.t -= this.offset + rad;
24251 a.l -= (this.offset - rad);
24252 a.t -= this.offset + rad;
24254 a.w -= (this.offset - rad)*2;
24265 a.l -= (this.offset - rad);
24266 a.t -= (this.offset - rad);
24268 a.w -= (this.offset + rad + 1);
24269 a.h -= (this.offset + rad);
24278 Roo.Shadow.prototype = {
24280 * @cfg {String} mode
24281 * The shadow display mode. Supports the following options:<br />
24282 * sides: Shadow displays on both sides and bottom only<br />
24283 * frame: Shadow displays equally on all four sides<br />
24284 * drop: Traditional bottom-right drop shadow (default)
24287 * @cfg {String} offset
24288 * The number of pixels to offset the shadow from the element (defaults to 4)
24293 defaultMode: "drop",
24296 * Displays the shadow under the target element
24297 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24299 show : function(target){
24300 target = Roo.get(target);
24302 this.el = Roo.Shadow.Pool.pull();
24303 if(this.el.dom.nextSibling != target.dom){
24304 this.el.insertBefore(target);
24307 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24309 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24312 target.getLeft(true),
24313 target.getTop(true),
24317 this.el.dom.style.display = "block";
24321 * Returns true if the shadow is visible, else false
24323 isVisible : function(){
24324 return this.el ? true : false;
24328 * Direct alignment when values are already available. Show must be called at least once before
24329 * calling this method to ensure it is initialized.
24330 * @param {Number} left The target element left position
24331 * @param {Number} top The target element top position
24332 * @param {Number} width The target element width
24333 * @param {Number} height The target element height
24335 realign : function(l, t, w, h){
24339 var a = this.adjusts, d = this.el.dom, s = d.style;
24341 s.left = (l+a.l)+"px";
24342 s.top = (t+a.t)+"px";
24343 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24345 if(s.width != sws || s.height != shs){
24349 var cn = d.childNodes;
24350 var sww = Math.max(0, (sw-12))+"px";
24351 cn[0].childNodes[1].style.width = sww;
24352 cn[1].childNodes[1].style.width = sww;
24353 cn[2].childNodes[1].style.width = sww;
24354 cn[1].style.height = Math.max(0, (sh-12))+"px";
24360 * Hides this shadow
24364 this.el.dom.style.display = "none";
24365 Roo.Shadow.Pool.push(this.el);
24371 * Adjust the z-index of this shadow
24372 * @param {Number} zindex The new z-index
24374 setZIndex : function(z){
24377 this.el.setStyle("z-index", z);
24382 // Private utility class that manages the internal Shadow cache
24383 Roo.Shadow.Pool = function(){
24385 var markup = Roo.isIE ?
24386 '<div class="x-ie-shadow"></div>' :
24387 '<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>';
24390 var sh = p.shift();
24392 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24393 sh.autoBoxAdjust = false;
24398 push : function(sh){
24404 * Ext JS Library 1.1.1
24405 * Copyright(c) 2006-2007, Ext JS, LLC.
24407 * Originally Released Under LGPL - original licence link has changed is not relivant.
24410 * <script type="text/javascript">
24415 * @class Roo.SplitBar
24416 * @extends Roo.util.Observable
24417 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24421 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24422 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24423 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24424 split.minSize = 100;
24425 split.maxSize = 600;
24426 split.animate = true;
24427 split.on('moved', splitterMoved);
24430 * Create a new SplitBar
24431 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24432 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24433 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24434 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24435 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24436 position of the SplitBar).
24438 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24441 this.el = Roo.get(dragElement, true);
24442 this.el.dom.unselectable = "on";
24444 this.resizingEl = Roo.get(resizingElement, true);
24448 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24449 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24452 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24455 * The minimum size of the resizing element. (Defaults to 0)
24461 * The maximum size of the resizing element. (Defaults to 2000)
24464 this.maxSize = 2000;
24467 * Whether to animate the transition to the new size
24470 this.animate = false;
24473 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24476 this.useShim = false;
24481 if(!existingProxy){
24483 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24485 this.proxy = Roo.get(existingProxy).dom;
24488 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24491 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24494 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24497 this.dragSpecs = {};
24500 * @private The adapter to use to positon and resize elements
24502 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24503 this.adapter.init(this);
24505 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24507 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24508 this.el.addClass("x-splitbar-h");
24511 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24512 this.el.addClass("x-splitbar-v");
24518 * Fires when the splitter is moved (alias for {@link #event-moved})
24519 * @param {Roo.SplitBar} this
24520 * @param {Number} newSize the new width or height
24525 * Fires when the splitter is moved
24526 * @param {Roo.SplitBar} this
24527 * @param {Number} newSize the new width or height
24531 * @event beforeresize
24532 * Fires before the splitter is dragged
24533 * @param {Roo.SplitBar} this
24535 "beforeresize" : true,
24537 "beforeapply" : true
24540 Roo.util.Observable.call(this);
24543 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24544 onStartProxyDrag : function(x, y){
24545 this.fireEvent("beforeresize", this);
24547 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24549 o.enableDisplayMode("block");
24550 // all splitbars share the same overlay
24551 Roo.SplitBar.prototype.overlay = o;
24553 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24554 this.overlay.show();
24555 Roo.get(this.proxy).setDisplayed("block");
24556 var size = this.adapter.getElementSize(this);
24557 this.activeMinSize = this.getMinimumSize();;
24558 this.activeMaxSize = this.getMaximumSize();;
24559 var c1 = size - this.activeMinSize;
24560 var c2 = Math.max(this.activeMaxSize - size, 0);
24561 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24562 this.dd.resetConstraints();
24563 this.dd.setXConstraint(
24564 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24565 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24567 this.dd.setYConstraint(0, 0);
24569 this.dd.resetConstraints();
24570 this.dd.setXConstraint(0, 0);
24571 this.dd.setYConstraint(
24572 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24573 this.placement == Roo.SplitBar.TOP ? c2 : c1
24576 this.dragSpecs.startSize = size;
24577 this.dragSpecs.startPoint = [x, y];
24578 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24582 * @private Called after the drag operation by the DDProxy
24584 onEndProxyDrag : function(e){
24585 Roo.get(this.proxy).setDisplayed(false);
24586 var endPoint = Roo.lib.Event.getXY(e);
24588 this.overlay.hide();
24591 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24592 newSize = this.dragSpecs.startSize +
24593 (this.placement == Roo.SplitBar.LEFT ?
24594 endPoint[0] - this.dragSpecs.startPoint[0] :
24595 this.dragSpecs.startPoint[0] - endPoint[0]
24598 newSize = this.dragSpecs.startSize +
24599 (this.placement == Roo.SplitBar.TOP ?
24600 endPoint[1] - this.dragSpecs.startPoint[1] :
24601 this.dragSpecs.startPoint[1] - endPoint[1]
24604 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24605 if(newSize != this.dragSpecs.startSize){
24606 if(this.fireEvent('beforeapply', this, newSize) !== false){
24607 this.adapter.setElementSize(this, newSize);
24608 this.fireEvent("moved", this, newSize);
24609 this.fireEvent("resize", this, newSize);
24615 * Get the adapter this SplitBar uses
24616 * @return The adapter object
24618 getAdapter : function(){
24619 return this.adapter;
24623 * Set the adapter this SplitBar uses
24624 * @param {Object} adapter A SplitBar adapter object
24626 setAdapter : function(adapter){
24627 this.adapter = adapter;
24628 this.adapter.init(this);
24632 * Gets the minimum size for the resizing element
24633 * @return {Number} The minimum size
24635 getMinimumSize : function(){
24636 return this.minSize;
24640 * Sets the minimum size for the resizing element
24641 * @param {Number} minSize The minimum size
24643 setMinimumSize : function(minSize){
24644 this.minSize = minSize;
24648 * Gets the maximum size for the resizing element
24649 * @return {Number} The maximum size
24651 getMaximumSize : function(){
24652 return this.maxSize;
24656 * Sets the maximum size for the resizing element
24657 * @param {Number} maxSize The maximum size
24659 setMaximumSize : function(maxSize){
24660 this.maxSize = maxSize;
24664 * Sets the initialize size for the resizing element
24665 * @param {Number} size The initial size
24667 setCurrentSize : function(size){
24668 var oldAnimate = this.animate;
24669 this.animate = false;
24670 this.adapter.setElementSize(this, size);
24671 this.animate = oldAnimate;
24675 * Destroy this splitbar.
24676 * @param {Boolean} removeEl True to remove the element
24678 destroy : function(removeEl){
24680 this.shim.remove();
24683 this.proxy.parentNode.removeChild(this.proxy);
24691 * @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.
24693 Roo.SplitBar.createProxy = function(dir){
24694 var proxy = new Roo.Element(document.createElement("div"));
24695 proxy.unselectable();
24696 var cls = 'x-splitbar-proxy';
24697 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24698 document.body.appendChild(proxy.dom);
24703 * @class Roo.SplitBar.BasicLayoutAdapter
24704 * Default Adapter. It assumes the splitter and resizing element are not positioned
24705 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24707 Roo.SplitBar.BasicLayoutAdapter = function(){
24710 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24711 // do nothing for now
24712 init : function(s){
24716 * Called before drag operations to get the current size of the resizing element.
24717 * @param {Roo.SplitBar} s The SplitBar using this adapter
24719 getElementSize : function(s){
24720 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24721 return s.resizingEl.getWidth();
24723 return s.resizingEl.getHeight();
24728 * Called after drag operations to set the size of the resizing element.
24729 * @param {Roo.SplitBar} s The SplitBar using this adapter
24730 * @param {Number} newSize The new size to set
24731 * @param {Function} onComplete A function to be invoked when resizing is complete
24733 setElementSize : function(s, newSize, onComplete){
24734 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24736 s.resizingEl.setWidth(newSize);
24738 onComplete(s, newSize);
24741 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24746 s.resizingEl.setHeight(newSize);
24748 onComplete(s, newSize);
24751 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24758 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24759 * @extends Roo.SplitBar.BasicLayoutAdapter
24760 * Adapter that moves the splitter element to align with the resized sizing element.
24761 * Used with an absolute positioned SplitBar.
24762 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24763 * document.body, make sure you assign an id to the body element.
24765 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24766 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24767 this.container = Roo.get(container);
24770 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24771 init : function(s){
24772 this.basic.init(s);
24775 getElementSize : function(s){
24776 return this.basic.getElementSize(s);
24779 setElementSize : function(s, newSize, onComplete){
24780 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24783 moveSplitter : function(s){
24784 var yes = Roo.SplitBar;
24785 switch(s.placement){
24787 s.el.setX(s.resizingEl.getRight());
24790 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24793 s.el.setY(s.resizingEl.getBottom());
24796 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24803 * Orientation constant - Create a vertical SplitBar
24807 Roo.SplitBar.VERTICAL = 1;
24810 * Orientation constant - Create a horizontal SplitBar
24814 Roo.SplitBar.HORIZONTAL = 2;
24817 * Placement constant - The resizing element is to the left of the splitter element
24821 Roo.SplitBar.LEFT = 1;
24824 * Placement constant - The resizing element is to the right of the splitter element
24828 Roo.SplitBar.RIGHT = 2;
24831 * Placement constant - The resizing element is positioned above the splitter element
24835 Roo.SplitBar.TOP = 3;
24838 * Placement constant - The resizing element is positioned under splitter element
24842 Roo.SplitBar.BOTTOM = 4;
24845 * Ext JS Library 1.1.1
24846 * Copyright(c) 2006-2007, Ext JS, LLC.
24848 * Originally Released Under LGPL - original licence link has changed is not relivant.
24851 * <script type="text/javascript">
24856 * @extends Roo.util.Observable
24857 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24858 * This class also supports single and multi selection modes. <br>
24859 * Create a data model bound view:
24861 var store = new Roo.data.Store(...);
24863 var view = new Roo.View({
24865 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24867 singleSelect: true,
24868 selectedClass: "ydataview-selected",
24872 // listen for node click?
24873 view.on("click", function(vw, index, node, e){
24874 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24878 dataModel.load("foobar.xml");
24880 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24882 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24883 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24885 * Note: old style constructor is still suported (container, template, config)
24888 * Create a new View
24889 * @param {Object} config The config object
24892 Roo.View = function(config, depreciated_tpl, depreciated_config){
24894 this.parent = false;
24896 if (typeof(depreciated_tpl) == 'undefined') {
24897 // new way.. - universal constructor.
24898 Roo.apply(this, config);
24899 this.el = Roo.get(this.el);
24902 this.el = Roo.get(config);
24903 this.tpl = depreciated_tpl;
24904 Roo.apply(this, depreciated_config);
24906 this.wrapEl = this.el.wrap().wrap();
24907 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24910 if(typeof(this.tpl) == "string"){
24911 this.tpl = new Roo.Template(this.tpl);
24913 // support xtype ctors..
24914 this.tpl = new Roo.factory(this.tpl, Roo);
24918 this.tpl.compile();
24923 * @event beforeclick
24924 * Fires before a click is processed. Returns false to cancel the default action.
24925 * @param {Roo.View} this
24926 * @param {Number} index The index of the target node
24927 * @param {HTMLElement} node The target node
24928 * @param {Roo.EventObject} e The raw event object
24930 "beforeclick" : true,
24933 * Fires when a template node is clicked.
24934 * @param {Roo.View} this
24935 * @param {Number} index The index of the target node
24936 * @param {HTMLElement} node The target node
24937 * @param {Roo.EventObject} e The raw event object
24942 * Fires when a template node is double clicked.
24943 * @param {Roo.View} this
24944 * @param {Number} index The index of the target node
24945 * @param {HTMLElement} node The target node
24946 * @param {Roo.EventObject} e The raw event object
24950 * @event contextmenu
24951 * Fires when a template node is right clicked.
24952 * @param {Roo.View} this
24953 * @param {Number} index The index of the target node
24954 * @param {HTMLElement} node The target node
24955 * @param {Roo.EventObject} e The raw event object
24957 "contextmenu" : true,
24959 * @event selectionchange
24960 * Fires when the selected nodes change.
24961 * @param {Roo.View} this
24962 * @param {Array} selections Array of the selected nodes
24964 "selectionchange" : true,
24967 * @event beforeselect
24968 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24969 * @param {Roo.View} this
24970 * @param {HTMLElement} node The node to be selected
24971 * @param {Array} selections Array of currently selected nodes
24973 "beforeselect" : true,
24975 * @event preparedata
24976 * Fires on every row to render, to allow you to change the data.
24977 * @param {Roo.View} this
24978 * @param {Object} data to be rendered (change this)
24980 "preparedata" : true
24988 "click": this.onClick,
24989 "dblclick": this.onDblClick,
24990 "contextmenu": this.onContextMenu,
24994 this.selections = [];
24996 this.cmp = new Roo.CompositeElementLite([]);
24998 this.store = Roo.factory(this.store, Roo.data);
24999 this.setStore(this.store, true);
25002 if ( this.footer && this.footer.xtype) {
25004 var fctr = this.wrapEl.appendChild(document.createElement("div"));
25006 this.footer.dataSource = this.store;
25007 this.footer.container = fctr;
25008 this.footer = Roo.factory(this.footer, Roo);
25009 fctr.insertFirst(this.el);
25011 // this is a bit insane - as the paging toolbar seems to detach the el..
25012 // dom.parentNode.parentNode.parentNode
25013 // they get detached?
25017 Roo.View.superclass.constructor.call(this);
25022 Roo.extend(Roo.View, Roo.util.Observable, {
25025 * @cfg {Roo.data.Store} store Data store to load data from.
25030 * @cfg {String|Roo.Element} el The container element.
25035 * @cfg {String|Roo.Template} tpl The template used by this View
25039 * @cfg {String} dataName the named area of the template to use as the data area
25040 * Works with domtemplates roo-name="name"
25044 * @cfg {String} selectedClass The css class to add to selected nodes
25046 selectedClass : "x-view-selected",
25048 * @cfg {String} emptyText The empty text to show when nothing is loaded.
25053 * @cfg {String} text to display on mask (default Loading)
25057 * @cfg {Boolean} multiSelect Allow multiple selection
25059 multiSelect : false,
25061 * @cfg {Boolean} singleSelect Allow single selection
25063 singleSelect: false,
25066 * @cfg {Boolean} toggleSelect - selecting
25068 toggleSelect : false,
25071 * @cfg {Boolean} tickable - selecting
25076 * Returns the element this view is bound to.
25077 * @return {Roo.Element}
25079 getEl : function(){
25080 return this.wrapEl;
25086 * Refreshes the view. - called by datachanged on the store. - do not call directly.
25088 refresh : function(){
25089 //Roo.log('refresh');
25092 // if we are using something like 'domtemplate', then
25093 // the what gets used is:
25094 // t.applySubtemplate(NAME, data, wrapping data..)
25095 // the outer template then get' applied with
25096 // the store 'extra data'
25097 // and the body get's added to the
25098 // roo-name="data" node?
25099 // <span class='roo-tpl-{name}'></span> ?????
25103 this.clearSelections();
25104 this.el.update("");
25106 var records = this.store.getRange();
25107 if(records.length < 1) {
25109 // is this valid?? = should it render a template??
25111 this.el.update(this.emptyText);
25115 if (this.dataName) {
25116 this.el.update(t.apply(this.store.meta)); //????
25117 el = this.el.child('.roo-tpl-' + this.dataName);
25120 for(var i = 0, len = records.length; i < len; i++){
25121 var data = this.prepareData(records[i].data, i, records[i]);
25122 this.fireEvent("preparedata", this, data, i, records[i]);
25124 var d = Roo.apply({}, data);
25127 Roo.apply(d, {'roo-id' : Roo.id()});
25131 Roo.each(this.parent.item, function(item){
25132 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
25135 Roo.apply(d, {'roo-data-checked' : 'checked'});
25139 html[html.length] = Roo.util.Format.trim(
25141 t.applySubtemplate(this.dataName, d, this.store.meta) :
25148 el.update(html.join(""));
25149 this.nodes = el.dom.childNodes;
25150 this.updateIndexes(0);
25155 * Function to override to reformat the data that is sent to
25156 * the template for each node.
25157 * DEPRICATED - use the preparedata event handler.
25158 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25159 * a JSON object for an UpdateManager bound view).
25161 prepareData : function(data, index, record)
25163 this.fireEvent("preparedata", this, data, index, record);
25167 onUpdate : function(ds, record){
25168 // Roo.log('on update');
25169 this.clearSelections();
25170 var index = this.store.indexOf(record);
25171 var n = this.nodes[index];
25172 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25173 n.parentNode.removeChild(n);
25174 this.updateIndexes(index, index);
25180 onAdd : function(ds, records, index)
25182 //Roo.log(['on Add', ds, records, index] );
25183 this.clearSelections();
25184 if(this.nodes.length == 0){
25188 var n = this.nodes[index];
25189 for(var i = 0, len = records.length; i < len; i++){
25190 var d = this.prepareData(records[i].data, i, records[i]);
25192 this.tpl.insertBefore(n, d);
25195 this.tpl.append(this.el, d);
25198 this.updateIndexes(index);
25201 onRemove : function(ds, record, index){
25202 // Roo.log('onRemove');
25203 this.clearSelections();
25204 var el = this.dataName ?
25205 this.el.child('.roo-tpl-' + this.dataName) :
25208 el.dom.removeChild(this.nodes[index]);
25209 this.updateIndexes(index);
25213 * Refresh an individual node.
25214 * @param {Number} index
25216 refreshNode : function(index){
25217 this.onUpdate(this.store, this.store.getAt(index));
25220 updateIndexes : function(startIndex, endIndex){
25221 var ns = this.nodes;
25222 startIndex = startIndex || 0;
25223 endIndex = endIndex || ns.length - 1;
25224 for(var i = startIndex; i <= endIndex; i++){
25225 ns[i].nodeIndex = i;
25230 * Changes the data store this view uses and refresh the view.
25231 * @param {Store} store
25233 setStore : function(store, initial){
25234 if(!initial && this.store){
25235 this.store.un("datachanged", this.refresh);
25236 this.store.un("add", this.onAdd);
25237 this.store.un("remove", this.onRemove);
25238 this.store.un("update", this.onUpdate);
25239 this.store.un("clear", this.refresh);
25240 this.store.un("beforeload", this.onBeforeLoad);
25241 this.store.un("load", this.onLoad);
25242 this.store.un("loadexception", this.onLoad);
25246 store.on("datachanged", this.refresh, this);
25247 store.on("add", this.onAdd, this);
25248 store.on("remove", this.onRemove, this);
25249 store.on("update", this.onUpdate, this);
25250 store.on("clear", this.refresh, this);
25251 store.on("beforeload", this.onBeforeLoad, this);
25252 store.on("load", this.onLoad, this);
25253 store.on("loadexception", this.onLoad, this);
25261 * onbeforeLoad - masks the loading area.
25264 onBeforeLoad : function(store,opts)
25266 //Roo.log('onBeforeLoad');
25268 this.el.update("");
25270 this.el.mask(this.mask ? this.mask : "Loading" );
25272 onLoad : function ()
25279 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25280 * @param {HTMLElement} node
25281 * @return {HTMLElement} The template node
25283 findItemFromChild : function(node){
25284 var el = this.dataName ?
25285 this.el.child('.roo-tpl-' + this.dataName,true) :
25288 if(!node || node.parentNode == el){
25291 var p = node.parentNode;
25292 while(p && p != el){
25293 if(p.parentNode == el){
25302 onClick : function(e){
25303 var item = this.findItemFromChild(e.getTarget());
25305 var index = this.indexOf(item);
25306 if(this.onItemClick(item, index, e) !== false){
25307 this.fireEvent("click", this, index, item, e);
25310 this.clearSelections();
25315 onContextMenu : function(e){
25316 var item = this.findItemFromChild(e.getTarget());
25318 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25323 onDblClick : function(e){
25324 var item = this.findItemFromChild(e.getTarget());
25326 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25330 onItemClick : function(item, index, e)
25332 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25335 if (this.toggleSelect) {
25336 var m = this.isSelected(item) ? 'unselect' : 'select';
25339 _t[m](item, true, false);
25342 if(this.multiSelect || this.singleSelect){
25343 if(this.multiSelect && e.shiftKey && this.lastSelection){
25344 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25346 this.select(item, this.multiSelect && e.ctrlKey);
25347 this.lastSelection = item;
25350 if(!this.tickable){
25351 e.preventDefault();
25359 * Get the number of selected nodes.
25362 getSelectionCount : function(){
25363 return this.selections.length;
25367 * Get the currently selected nodes.
25368 * @return {Array} An array of HTMLElements
25370 getSelectedNodes : function(){
25371 return this.selections;
25375 * Get the indexes of the selected nodes.
25378 getSelectedIndexes : function(){
25379 var indexes = [], s = this.selections;
25380 for(var i = 0, len = s.length; i < len; i++){
25381 indexes.push(s[i].nodeIndex);
25387 * Clear all selections
25388 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25390 clearSelections : function(suppressEvent){
25391 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25392 this.cmp.elements = this.selections;
25393 this.cmp.removeClass(this.selectedClass);
25394 this.selections = [];
25395 if(!suppressEvent){
25396 this.fireEvent("selectionchange", this, this.selections);
25402 * Returns true if the passed node is selected
25403 * @param {HTMLElement/Number} node The node or node index
25404 * @return {Boolean}
25406 isSelected : function(node){
25407 var s = this.selections;
25411 node = this.getNode(node);
25412 return s.indexOf(node) !== -1;
25417 * @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
25418 * @param {Boolean} keepExisting (optional) true to keep existing selections
25419 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25421 select : function(nodeInfo, keepExisting, suppressEvent){
25422 if(nodeInfo instanceof Array){
25424 this.clearSelections(true);
25426 for(var i = 0, len = nodeInfo.length; i < len; i++){
25427 this.select(nodeInfo[i], true, true);
25431 var node = this.getNode(nodeInfo);
25432 if(!node || this.isSelected(node)){
25433 return; // already selected.
25436 this.clearSelections(true);
25439 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25440 Roo.fly(node).addClass(this.selectedClass);
25441 this.selections.push(node);
25442 if(!suppressEvent){
25443 this.fireEvent("selectionchange", this, this.selections);
25451 * @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
25452 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25453 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25455 unselect : function(nodeInfo, keepExisting, suppressEvent)
25457 if(nodeInfo instanceof Array){
25458 Roo.each(this.selections, function(s) {
25459 this.unselect(s, nodeInfo);
25463 var node = this.getNode(nodeInfo);
25464 if(!node || !this.isSelected(node)){
25465 //Roo.log("not selected");
25466 return; // not selected.
25470 Roo.each(this.selections, function(s) {
25472 Roo.fly(node).removeClass(this.selectedClass);
25479 this.selections= ns;
25480 this.fireEvent("selectionchange", this, this.selections);
25484 * Gets a template node.
25485 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25486 * @return {HTMLElement} The node or null if it wasn't found
25488 getNode : function(nodeInfo){
25489 if(typeof nodeInfo == "string"){
25490 return document.getElementById(nodeInfo);
25491 }else if(typeof nodeInfo == "number"){
25492 return this.nodes[nodeInfo];
25498 * Gets a range template nodes.
25499 * @param {Number} startIndex
25500 * @param {Number} endIndex
25501 * @return {Array} An array of nodes
25503 getNodes : function(start, end){
25504 var ns = this.nodes;
25505 start = start || 0;
25506 end = typeof end == "undefined" ? ns.length - 1 : end;
25509 for(var i = start; i <= end; i++){
25513 for(var i = start; i >= end; i--){
25521 * Finds the index of the passed node
25522 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25523 * @return {Number} The index of the node or -1
25525 indexOf : function(node){
25526 node = this.getNode(node);
25527 if(typeof node.nodeIndex == "number"){
25528 return node.nodeIndex;
25530 var ns = this.nodes;
25531 for(var i = 0, len = ns.length; i < len; i++){
25541 * Ext JS Library 1.1.1
25542 * Copyright(c) 2006-2007, Ext JS, LLC.
25544 * Originally Released Under LGPL - original licence link has changed is not relivant.
25547 * <script type="text/javascript">
25551 * @class Roo.JsonView
25552 * @extends Roo.View
25553 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25555 var view = new Roo.JsonView({
25556 container: "my-element",
25557 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25562 // listen for node click?
25563 view.on("click", function(vw, index, node, e){
25564 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25567 // direct load of JSON data
25568 view.load("foobar.php");
25570 // Example from my blog list
25571 var tpl = new Roo.Template(
25572 '<div class="entry">' +
25573 '<a class="entry-title" href="{link}">{title}</a>' +
25574 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25575 "</div><hr />"
25578 var moreView = new Roo.JsonView({
25579 container : "entry-list",
25583 moreView.on("beforerender", this.sortEntries, this);
25585 url: "/blog/get-posts.php",
25586 params: "allposts=true",
25587 text: "Loading Blog Entries..."
25591 * Note: old code is supported with arguments : (container, template, config)
25595 * Create a new JsonView
25597 * @param {Object} config The config object
25600 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25603 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25605 var um = this.el.getUpdateManager();
25606 um.setRenderer(this);
25607 um.on("update", this.onLoad, this);
25608 um.on("failure", this.onLoadException, this);
25611 * @event beforerender
25612 * Fires before rendering of the downloaded JSON data.
25613 * @param {Roo.JsonView} this
25614 * @param {Object} data The JSON data loaded
25618 * Fires when data is loaded.
25619 * @param {Roo.JsonView} this
25620 * @param {Object} data The JSON data loaded
25621 * @param {Object} response The raw Connect response object
25624 * @event loadexception
25625 * Fires when loading fails.
25626 * @param {Roo.JsonView} this
25627 * @param {Object} response The raw Connect response object
25630 'beforerender' : true,
25632 'loadexception' : true
25635 Roo.extend(Roo.JsonView, Roo.View, {
25637 * @type {String} The root property in the loaded JSON object that contains the data
25642 * Refreshes the view.
25644 refresh : function(){
25645 this.clearSelections();
25646 this.el.update("");
25648 var o = this.jsonData;
25649 if(o && o.length > 0){
25650 for(var i = 0, len = o.length; i < len; i++){
25651 var data = this.prepareData(o[i], i, o);
25652 html[html.length] = this.tpl.apply(data);
25655 html.push(this.emptyText);
25657 this.el.update(html.join(""));
25658 this.nodes = this.el.dom.childNodes;
25659 this.updateIndexes(0);
25663 * 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.
25664 * @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:
25667 url: "your-url.php",
25668 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25669 callback: yourFunction,
25670 scope: yourObject, //(optional scope)
25673 text: "Loading...",
25678 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25679 * 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.
25680 * @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}
25681 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25682 * @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.
25685 var um = this.el.getUpdateManager();
25686 um.update.apply(um, arguments);
25689 render : function(el, response){
25690 this.clearSelections();
25691 this.el.update("");
25694 o = Roo.util.JSON.decode(response.responseText);
25697 o = o[this.jsonRoot];
25702 * The current JSON data or null
25705 this.beforeRender();
25710 * Get the number of records in the current JSON dataset
25713 getCount : function(){
25714 return this.jsonData ? this.jsonData.length : 0;
25718 * Returns the JSON object for the specified node(s)
25719 * @param {HTMLElement/Array} node The node or an array of nodes
25720 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25721 * you get the JSON object for the node
25723 getNodeData : function(node){
25724 if(node instanceof Array){
25726 for(var i = 0, len = node.length; i < len; i++){
25727 data.push(this.getNodeData(node[i]));
25731 return this.jsonData[this.indexOf(node)] || null;
25734 beforeRender : function(){
25735 this.snapshot = this.jsonData;
25737 this.sort.apply(this, this.sortInfo);
25739 this.fireEvent("beforerender", this, this.jsonData);
25742 onLoad : function(el, o){
25743 this.fireEvent("load", this, this.jsonData, o);
25746 onLoadException : function(el, o){
25747 this.fireEvent("loadexception", this, o);
25751 * Filter the data by a specific property.
25752 * @param {String} property A property on your JSON objects
25753 * @param {String/RegExp} value Either string that the property values
25754 * should start with, or a RegExp to test against the property
25756 filter : function(property, value){
25759 var ss = this.snapshot;
25760 if(typeof value == "string"){
25761 var vlen = value.length;
25763 this.clearFilter();
25766 value = value.toLowerCase();
25767 for(var i = 0, len = ss.length; i < len; i++){
25769 if(o[property].substr(0, vlen).toLowerCase() == value){
25773 } else if(value.exec){ // regex?
25774 for(var i = 0, len = ss.length; i < len; i++){
25776 if(value.test(o[property])){
25783 this.jsonData = data;
25789 * Filter by a function. The passed function will be called with each
25790 * object in the current dataset. If the function returns true the value is kept,
25791 * otherwise it is filtered.
25792 * @param {Function} fn
25793 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25795 filterBy : function(fn, scope){
25798 var ss = this.snapshot;
25799 for(var i = 0, len = ss.length; i < len; i++){
25801 if(fn.call(scope || this, o)){
25805 this.jsonData = data;
25811 * Clears the current filter.
25813 clearFilter : function(){
25814 if(this.snapshot && this.jsonData != this.snapshot){
25815 this.jsonData = this.snapshot;
25822 * Sorts the data for this view and refreshes it.
25823 * @param {String} property A property on your JSON objects to sort on
25824 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25825 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25827 sort : function(property, dir, sortType){
25828 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25831 var dsc = dir && dir.toLowerCase() == "desc";
25832 var f = function(o1, o2){
25833 var v1 = sortType ? sortType(o1[p]) : o1[p];
25834 var v2 = sortType ? sortType(o2[p]) : o2[p];
25837 return dsc ? +1 : -1;
25838 } else if(v1 > v2){
25839 return dsc ? -1 : +1;
25844 this.jsonData.sort(f);
25846 if(this.jsonData != this.snapshot){
25847 this.snapshot.sort(f);
25853 * Ext JS Library 1.1.1
25854 * Copyright(c) 2006-2007, Ext JS, LLC.
25856 * Originally Released Under LGPL - original licence link has changed is not relivant.
25859 * <script type="text/javascript">
25864 * @class Roo.ColorPalette
25865 * @extends Roo.Component
25866 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25867 * Here's an example of typical usage:
25869 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25870 cp.render('my-div');
25872 cp.on('select', function(palette, selColor){
25873 // do something with selColor
25877 * Create a new ColorPalette
25878 * @param {Object} config The config object
25880 Roo.ColorPalette = function(config){
25881 Roo.ColorPalette.superclass.constructor.call(this, config);
25885 * Fires when a color is selected
25886 * @param {ColorPalette} this
25887 * @param {String} color The 6-digit color hex code (without the # symbol)
25893 this.on("select", this.handler, this.scope, true);
25896 Roo.extend(Roo.ColorPalette, Roo.Component, {
25898 * @cfg {String} itemCls
25899 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25901 itemCls : "x-color-palette",
25903 * @cfg {String} value
25904 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25905 * the hex codes are case-sensitive.
25908 clickEvent:'click',
25910 ctype: "Roo.ColorPalette",
25913 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25915 allowReselect : false,
25918 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25919 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25920 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25921 * of colors with the width setting until the box is symmetrical.</p>
25922 * <p>You can override individual colors if needed:</p>
25924 var cp = new Roo.ColorPalette();
25925 cp.colors[0] = "FF0000"; // change the first box to red
25928 Or you can provide a custom array of your own for complete control:
25930 var cp = new Roo.ColorPalette();
25931 cp.colors = ["000000", "993300", "333300"];
25936 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25937 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25938 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25939 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25940 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25944 onRender : function(container, position){
25945 var t = new Roo.MasterTemplate(
25946 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25948 var c = this.colors;
25949 for(var i = 0, len = c.length; i < len; i++){
25952 var el = document.createElement("div");
25953 el.className = this.itemCls;
25955 container.dom.insertBefore(el, position);
25956 this.el = Roo.get(el);
25957 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25958 if(this.clickEvent != 'click'){
25959 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25964 afterRender : function(){
25965 Roo.ColorPalette.superclass.afterRender.call(this);
25967 var s = this.value;
25974 handleClick : function(e, t){
25975 e.preventDefault();
25976 if(!this.disabled){
25977 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25978 this.select(c.toUpperCase());
25983 * Selects the specified color in the palette (fires the select event)
25984 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25986 select : function(color){
25987 color = color.replace("#", "");
25988 if(color != this.value || this.allowReselect){
25991 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25993 el.child("a.color-"+color).addClass("x-color-palette-sel");
25994 this.value = color;
25995 this.fireEvent("select", this, color);
26000 * Ext JS Library 1.1.1
26001 * Copyright(c) 2006-2007, Ext JS, LLC.
26003 * Originally Released Under LGPL - original licence link has changed is not relivant.
26006 * <script type="text/javascript">
26010 * @class Roo.DatePicker
26011 * @extends Roo.Component
26012 * Simple date picker class.
26014 * Create a new DatePicker
26015 * @param {Object} config The config object
26017 Roo.DatePicker = function(config){
26018 Roo.DatePicker.superclass.constructor.call(this, config);
26020 this.value = config && config.value ?
26021 config.value.clearTime() : new Date().clearTime();
26026 * Fires when a date is selected
26027 * @param {DatePicker} this
26028 * @param {Date} date The selected date
26032 * @event monthchange
26033 * Fires when the displayed month changes
26034 * @param {DatePicker} this
26035 * @param {Date} date The selected month
26037 'monthchange': true
26041 this.on("select", this.handler, this.scope || this);
26043 // build the disabledDatesRE
26044 if(!this.disabledDatesRE && this.disabledDates){
26045 var dd = this.disabledDates;
26047 for(var i = 0; i < dd.length; i++){
26049 if(i != dd.length-1) {
26053 this.disabledDatesRE = new RegExp(re + ")");
26057 Roo.extend(Roo.DatePicker, Roo.Component, {
26059 * @cfg {String} todayText
26060 * The text to display on the button that selects the current date (defaults to "Today")
26062 todayText : "Today",
26064 * @cfg {String} okText
26065 * The text to display on the ok button
26067 okText : " OK ", //   to give the user extra clicking room
26069 * @cfg {String} cancelText
26070 * The text to display on the cancel button
26072 cancelText : "Cancel",
26074 * @cfg {String} todayTip
26075 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
26077 todayTip : "{0} (Spacebar)",
26079 * @cfg {Date} minDate
26080 * Minimum allowable date (JavaScript date object, defaults to null)
26084 * @cfg {Date} maxDate
26085 * Maximum allowable date (JavaScript date object, defaults to null)
26089 * @cfg {String} minText
26090 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
26092 minText : "This date is before the minimum date",
26094 * @cfg {String} maxText
26095 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
26097 maxText : "This date is after the maximum date",
26099 * @cfg {String} format
26100 * The default date format string which can be overriden for localization support. The format must be
26101 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
26105 * @cfg {Array} disabledDays
26106 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
26108 disabledDays : null,
26110 * @cfg {String} disabledDaysText
26111 * The tooltip to display when the date falls on a disabled day (defaults to "")
26113 disabledDaysText : "",
26115 * @cfg {RegExp} disabledDatesRE
26116 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
26118 disabledDatesRE : null,
26120 * @cfg {String} disabledDatesText
26121 * The tooltip text to display when the date falls on a disabled date (defaults to "")
26123 disabledDatesText : "",
26125 * @cfg {Boolean} constrainToViewport
26126 * True to constrain the date picker to the viewport (defaults to true)
26128 constrainToViewport : true,
26130 * @cfg {Array} monthNames
26131 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
26133 monthNames : Date.monthNames,
26135 * @cfg {Array} dayNames
26136 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
26138 dayNames : Date.dayNames,
26140 * @cfg {String} nextText
26141 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
26143 nextText: 'Next Month (Control+Right)',
26145 * @cfg {String} prevText
26146 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
26148 prevText: 'Previous Month (Control+Left)',
26150 * @cfg {String} monthYearText
26151 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
26153 monthYearText: 'Choose a month (Control+Up/Down to move years)',
26155 * @cfg {Number} startDay
26156 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
26160 * @cfg {Bool} showClear
26161 * Show a clear button (usefull for date form elements that can be blank.)
26167 * Sets the value of the date field
26168 * @param {Date} value The date to set
26170 setValue : function(value){
26171 var old = this.value;
26173 if (typeof(value) == 'string') {
26175 value = Date.parseDate(value, this.format);
26178 value = new Date();
26181 this.value = value.clearTime(true);
26183 this.update(this.value);
26188 * Gets the current selected value of the date field
26189 * @return {Date} The selected date
26191 getValue : function(){
26196 focus : function(){
26198 this.update(this.activeDate);
26203 onRender : function(container, position){
26206 '<table cellspacing="0">',
26207 '<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>',
26208 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26209 var dn = this.dayNames;
26210 for(var i = 0; i < 7; i++){
26211 var d = this.startDay+i;
26215 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26217 m[m.length] = "</tr></thead><tbody><tr>";
26218 for(var i = 0; i < 42; i++) {
26219 if(i % 7 == 0 && i != 0){
26220 m[m.length] = "</tr><tr>";
26222 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26224 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26225 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26227 var el = document.createElement("div");
26228 el.className = "x-date-picker";
26229 el.innerHTML = m.join("");
26231 container.dom.insertBefore(el, position);
26233 this.el = Roo.get(el);
26234 this.eventEl = Roo.get(el.firstChild);
26236 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26237 handler: this.showPrevMonth,
26239 preventDefault:true,
26243 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26244 handler: this.showNextMonth,
26246 preventDefault:true,
26250 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26252 this.monthPicker = this.el.down('div.x-date-mp');
26253 this.monthPicker.enableDisplayMode('block');
26255 var kn = new Roo.KeyNav(this.eventEl, {
26256 "left" : function(e){
26258 this.showPrevMonth() :
26259 this.update(this.activeDate.add("d", -1));
26262 "right" : function(e){
26264 this.showNextMonth() :
26265 this.update(this.activeDate.add("d", 1));
26268 "up" : function(e){
26270 this.showNextYear() :
26271 this.update(this.activeDate.add("d", -7));
26274 "down" : function(e){
26276 this.showPrevYear() :
26277 this.update(this.activeDate.add("d", 7));
26280 "pageUp" : function(e){
26281 this.showNextMonth();
26284 "pageDown" : function(e){
26285 this.showPrevMonth();
26288 "enter" : function(e){
26289 e.stopPropagation();
26296 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26298 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26300 this.el.unselectable();
26302 this.cells = this.el.select("table.x-date-inner tbody td");
26303 this.textNodes = this.el.query("table.x-date-inner tbody span");
26305 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26307 tooltip: this.monthYearText
26310 this.mbtn.on('click', this.showMonthPicker, this);
26311 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26314 var today = (new Date()).dateFormat(this.format);
26316 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26317 if (this.showClear) {
26318 baseTb.add( new Roo.Toolbar.Fill());
26321 text: String.format(this.todayText, today),
26322 tooltip: String.format(this.todayTip, today),
26323 handler: this.selectToday,
26327 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26330 if (this.showClear) {
26332 baseTb.add( new Roo.Toolbar.Fill());
26335 cls: 'x-btn-icon x-btn-clear',
26336 handler: function() {
26338 this.fireEvent("select", this, '');
26348 this.update(this.value);
26351 createMonthPicker : function(){
26352 if(!this.monthPicker.dom.firstChild){
26353 var buf = ['<table border="0" cellspacing="0">'];
26354 for(var i = 0; i < 6; i++){
26356 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26357 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26359 '<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>' :
26360 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26364 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26366 '</button><button type="button" class="x-date-mp-cancel">',
26368 '</button></td></tr>',
26371 this.monthPicker.update(buf.join(''));
26372 this.monthPicker.on('click', this.onMonthClick, this);
26373 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26375 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26376 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26378 this.mpMonths.each(function(m, a, i){
26381 m.dom.xmonth = 5 + Math.round(i * .5);
26383 m.dom.xmonth = Math.round((i-1) * .5);
26389 showMonthPicker : function(){
26390 this.createMonthPicker();
26391 var size = this.el.getSize();
26392 this.monthPicker.setSize(size);
26393 this.monthPicker.child('table').setSize(size);
26395 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26396 this.updateMPMonth(this.mpSelMonth);
26397 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26398 this.updateMPYear(this.mpSelYear);
26400 this.monthPicker.slideIn('t', {duration:.2});
26403 updateMPYear : function(y){
26405 var ys = this.mpYears.elements;
26406 for(var i = 1; i <= 10; i++){
26407 var td = ys[i-1], y2;
26409 y2 = y + Math.round(i * .5);
26410 td.firstChild.innerHTML = y2;
26413 y2 = y - (5-Math.round(i * .5));
26414 td.firstChild.innerHTML = y2;
26417 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26421 updateMPMonth : function(sm){
26422 this.mpMonths.each(function(m, a, i){
26423 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26427 selectMPMonth: function(m){
26431 onMonthClick : function(e, t){
26433 var el = new Roo.Element(t), pn;
26434 if(el.is('button.x-date-mp-cancel')){
26435 this.hideMonthPicker();
26437 else if(el.is('button.x-date-mp-ok')){
26438 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26439 this.hideMonthPicker();
26441 else if(pn = el.up('td.x-date-mp-month', 2)){
26442 this.mpMonths.removeClass('x-date-mp-sel');
26443 pn.addClass('x-date-mp-sel');
26444 this.mpSelMonth = pn.dom.xmonth;
26446 else if(pn = el.up('td.x-date-mp-year', 2)){
26447 this.mpYears.removeClass('x-date-mp-sel');
26448 pn.addClass('x-date-mp-sel');
26449 this.mpSelYear = pn.dom.xyear;
26451 else if(el.is('a.x-date-mp-prev')){
26452 this.updateMPYear(this.mpyear-10);
26454 else if(el.is('a.x-date-mp-next')){
26455 this.updateMPYear(this.mpyear+10);
26459 onMonthDblClick : function(e, t){
26461 var el = new Roo.Element(t), pn;
26462 if(pn = el.up('td.x-date-mp-month', 2)){
26463 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26464 this.hideMonthPicker();
26466 else if(pn = el.up('td.x-date-mp-year', 2)){
26467 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26468 this.hideMonthPicker();
26472 hideMonthPicker : function(disableAnim){
26473 if(this.monthPicker){
26474 if(disableAnim === true){
26475 this.monthPicker.hide();
26477 this.monthPicker.slideOut('t', {duration:.2});
26483 showPrevMonth : function(e){
26484 this.update(this.activeDate.add("mo", -1));
26488 showNextMonth : function(e){
26489 this.update(this.activeDate.add("mo", 1));
26493 showPrevYear : function(){
26494 this.update(this.activeDate.add("y", -1));
26498 showNextYear : function(){
26499 this.update(this.activeDate.add("y", 1));
26503 handleMouseWheel : function(e){
26504 var delta = e.getWheelDelta();
26506 this.showPrevMonth();
26508 } else if(delta < 0){
26509 this.showNextMonth();
26515 handleDateClick : function(e, t){
26517 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26518 this.setValue(new Date(t.dateValue));
26519 this.fireEvent("select", this, this.value);
26524 selectToday : function(){
26525 this.setValue(new Date().clearTime());
26526 this.fireEvent("select", this, this.value);
26530 update : function(date)
26532 var vd = this.activeDate;
26533 this.activeDate = date;
26535 var t = date.getTime();
26536 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26537 this.cells.removeClass("x-date-selected");
26538 this.cells.each(function(c){
26539 if(c.dom.firstChild.dateValue == t){
26540 c.addClass("x-date-selected");
26541 setTimeout(function(){
26542 try{c.dom.firstChild.focus();}catch(e){}
26551 var days = date.getDaysInMonth();
26552 var firstOfMonth = date.getFirstDateOfMonth();
26553 var startingPos = firstOfMonth.getDay()-this.startDay;
26555 if(startingPos <= this.startDay){
26559 var pm = date.add("mo", -1);
26560 var prevStart = pm.getDaysInMonth()-startingPos;
26562 var cells = this.cells.elements;
26563 var textEls = this.textNodes;
26564 days += startingPos;
26566 // convert everything to numbers so it's fast
26567 var day = 86400000;
26568 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26569 var today = new Date().clearTime().getTime();
26570 var sel = date.clearTime().getTime();
26571 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26572 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26573 var ddMatch = this.disabledDatesRE;
26574 var ddText = this.disabledDatesText;
26575 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26576 var ddaysText = this.disabledDaysText;
26577 var format = this.format;
26579 var setCellClass = function(cal, cell){
26581 var t = d.getTime();
26582 cell.firstChild.dateValue = t;
26584 cell.className += " x-date-today";
26585 cell.title = cal.todayText;
26588 cell.className += " x-date-selected";
26589 setTimeout(function(){
26590 try{cell.firstChild.focus();}catch(e){}
26595 cell.className = " x-date-disabled";
26596 cell.title = cal.minText;
26600 cell.className = " x-date-disabled";
26601 cell.title = cal.maxText;
26605 if(ddays.indexOf(d.getDay()) != -1){
26606 cell.title = ddaysText;
26607 cell.className = " x-date-disabled";
26610 if(ddMatch && format){
26611 var fvalue = d.dateFormat(format);
26612 if(ddMatch.test(fvalue)){
26613 cell.title = ddText.replace("%0", fvalue);
26614 cell.className = " x-date-disabled";
26620 for(; i < startingPos; i++) {
26621 textEls[i].innerHTML = (++prevStart);
26622 d.setDate(d.getDate()+1);
26623 cells[i].className = "x-date-prevday";
26624 setCellClass(this, cells[i]);
26626 for(; i < days; i++){
26627 intDay = i - startingPos + 1;
26628 textEls[i].innerHTML = (intDay);
26629 d.setDate(d.getDate()+1);
26630 cells[i].className = "x-date-active";
26631 setCellClass(this, cells[i]);
26634 for(; i < 42; i++) {
26635 textEls[i].innerHTML = (++extraDays);
26636 d.setDate(d.getDate()+1);
26637 cells[i].className = "x-date-nextday";
26638 setCellClass(this, cells[i]);
26641 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26642 this.fireEvent('monthchange', this, date);
26644 if(!this.internalRender){
26645 var main = this.el.dom.firstChild;
26646 var w = main.offsetWidth;
26647 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26648 Roo.fly(main).setWidth(w);
26649 this.internalRender = true;
26650 // opera does not respect the auto grow header center column
26651 // then, after it gets a width opera refuses to recalculate
26652 // without a second pass
26653 if(Roo.isOpera && !this.secondPass){
26654 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26655 this.secondPass = true;
26656 this.update.defer(10, this, [date]);
26664 * Ext JS Library 1.1.1
26665 * Copyright(c) 2006-2007, Ext JS, LLC.
26667 * Originally Released Under LGPL - original licence link has changed is not relivant.
26670 * <script type="text/javascript">
26673 * @class Roo.TabPanel
26674 * @extends Roo.util.Observable
26675 * A lightweight tab container.
26679 // basic tabs 1, built from existing content
26680 var tabs = new Roo.TabPanel("tabs1");
26681 tabs.addTab("script", "View Script");
26682 tabs.addTab("markup", "View Markup");
26683 tabs.activate("script");
26685 // more advanced tabs, built from javascript
26686 var jtabs = new Roo.TabPanel("jtabs");
26687 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26689 // set up the UpdateManager
26690 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26691 var updater = tab2.getUpdateManager();
26692 updater.setDefaultUrl("ajax1.htm");
26693 tab2.on('activate', updater.refresh, updater, true);
26695 // Use setUrl for Ajax loading
26696 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26697 tab3.setUrl("ajax2.htm", null, true);
26700 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26703 jtabs.activate("jtabs-1");
26706 * Create a new TabPanel.
26707 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26708 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26710 Roo.TabPanel = function(container, config){
26712 * The container element for this TabPanel.
26713 * @type Roo.Element
26715 this.el = Roo.get(container, true);
26717 if(typeof config == "boolean"){
26718 this.tabPosition = config ? "bottom" : "top";
26720 Roo.apply(this, config);
26723 if(this.tabPosition == "bottom"){
26724 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26725 this.el.addClass("x-tabs-bottom");
26727 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26728 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26729 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26731 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26733 if(this.tabPosition != "bottom"){
26734 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26735 * @type Roo.Element
26737 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26738 this.el.addClass("x-tabs-top");
26742 this.bodyEl.setStyle("position", "relative");
26744 this.active = null;
26745 this.activateDelegate = this.activate.createDelegate(this);
26750 * Fires when the active tab changes
26751 * @param {Roo.TabPanel} this
26752 * @param {Roo.TabPanelItem} activePanel The new active tab
26756 * @event beforetabchange
26757 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26758 * @param {Roo.TabPanel} this
26759 * @param {Object} e Set cancel to true on this object to cancel the tab change
26760 * @param {Roo.TabPanelItem} tab The tab being changed to
26762 "beforetabchange" : true
26765 Roo.EventManager.onWindowResize(this.onResize, this);
26766 this.cpad = this.el.getPadding("lr");
26767 this.hiddenCount = 0;
26770 // toolbar on the tabbar support...
26771 if (this.toolbar) {
26772 var tcfg = this.toolbar;
26773 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26774 this.toolbar = new Roo.Toolbar(tcfg);
26775 if (Roo.isSafari) {
26776 var tbl = tcfg.container.child('table', true);
26777 tbl.setAttribute('width', '100%');
26784 Roo.TabPanel.superclass.constructor.call(this);
26787 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26789 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26791 tabPosition : "top",
26793 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26795 currentTabWidth : 0,
26797 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26801 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26805 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26807 preferredTabWidth : 175,
26809 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26811 resizeTabs : false,
26813 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26815 monitorResize : true,
26817 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26822 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26823 * @param {String} id The id of the div to use <b>or create</b>
26824 * @param {String} text The text for the tab
26825 * @param {String} content (optional) Content to put in the TabPanelItem body
26826 * @param {Boolean} closable (optional) True to create a close icon on the tab
26827 * @return {Roo.TabPanelItem} The created TabPanelItem
26829 addTab : function(id, text, content, closable){
26830 var item = new Roo.TabPanelItem(this, id, text, closable);
26831 this.addTabItem(item);
26833 item.setContent(content);
26839 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26840 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26841 * @return {Roo.TabPanelItem}
26843 getTab : function(id){
26844 return this.items[id];
26848 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26849 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26851 hideTab : function(id){
26852 var t = this.items[id];
26855 this.hiddenCount++;
26856 this.autoSizeTabs();
26861 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26862 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26864 unhideTab : function(id){
26865 var t = this.items[id];
26867 t.setHidden(false);
26868 this.hiddenCount--;
26869 this.autoSizeTabs();
26874 * Adds an existing {@link Roo.TabPanelItem}.
26875 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26877 addTabItem : function(item){
26878 this.items[item.id] = item;
26879 this.items.push(item);
26880 if(this.resizeTabs){
26881 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26882 this.autoSizeTabs();
26889 * Removes a {@link Roo.TabPanelItem}.
26890 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26892 removeTab : function(id){
26893 var items = this.items;
26894 var tab = items[id];
26895 if(!tab) { return; }
26896 var index = items.indexOf(tab);
26897 if(this.active == tab && items.length > 1){
26898 var newTab = this.getNextAvailable(index);
26903 this.stripEl.dom.removeChild(tab.pnode.dom);
26904 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26905 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26907 items.splice(index, 1);
26908 delete this.items[tab.id];
26909 tab.fireEvent("close", tab);
26910 tab.purgeListeners();
26911 this.autoSizeTabs();
26914 getNextAvailable : function(start){
26915 var items = this.items;
26917 // look for a next tab that will slide over to
26918 // replace the one being removed
26919 while(index < items.length){
26920 var item = items[++index];
26921 if(item && !item.isHidden()){
26925 // if one isn't found select the previous tab (on the left)
26928 var item = items[--index];
26929 if(item && !item.isHidden()){
26937 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26938 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26940 disableTab : function(id){
26941 var tab = this.items[id];
26942 if(tab && this.active != tab){
26948 * Enables a {@link Roo.TabPanelItem} that is disabled.
26949 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26951 enableTab : function(id){
26952 var tab = this.items[id];
26957 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26958 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26959 * @return {Roo.TabPanelItem} The TabPanelItem.
26961 activate : function(id){
26962 var tab = this.items[id];
26966 if(tab == this.active || tab.disabled){
26970 this.fireEvent("beforetabchange", this, e, tab);
26971 if(e.cancel !== true && !tab.disabled){
26973 this.active.hide();
26975 this.active = this.items[id];
26976 this.active.show();
26977 this.fireEvent("tabchange", this, this.active);
26983 * Gets the active {@link Roo.TabPanelItem}.
26984 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26986 getActiveTab : function(){
26987 return this.active;
26991 * Updates the tab body element to fit the height of the container element
26992 * for overflow scrolling
26993 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26995 syncHeight : function(targetHeight){
26996 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26997 var bm = this.bodyEl.getMargins();
26998 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26999 this.bodyEl.setHeight(newHeight);
27003 onResize : function(){
27004 if(this.monitorResize){
27005 this.autoSizeTabs();
27010 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
27012 beginUpdate : function(){
27013 this.updating = true;
27017 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
27019 endUpdate : function(){
27020 this.updating = false;
27021 this.autoSizeTabs();
27025 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
27027 autoSizeTabs : function(){
27028 var count = this.items.length;
27029 var vcount = count - this.hiddenCount;
27030 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
27033 var w = Math.max(this.el.getWidth() - this.cpad, 10);
27034 var availWidth = Math.floor(w / vcount);
27035 var b = this.stripBody;
27036 if(b.getWidth() > w){
27037 var tabs = this.items;
27038 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
27039 if(availWidth < this.minTabWidth){
27040 /*if(!this.sleft){ // incomplete scrolling code
27041 this.createScrollButtons();
27044 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
27047 if(this.currentTabWidth < this.preferredTabWidth){
27048 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
27054 * Returns the number of tabs in this TabPanel.
27057 getCount : function(){
27058 return this.items.length;
27062 * Resizes all the tabs to the passed width
27063 * @param {Number} The new width
27065 setTabWidth : function(width){
27066 this.currentTabWidth = width;
27067 for(var i = 0, len = this.items.length; i < len; i++) {
27068 if(!this.items[i].isHidden()) {
27069 this.items[i].setWidth(width);
27075 * Destroys this TabPanel
27076 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
27078 destroy : function(removeEl){
27079 Roo.EventManager.removeResizeListener(this.onResize, this);
27080 for(var i = 0, len = this.items.length; i < len; i++){
27081 this.items[i].purgeListeners();
27083 if(removeEl === true){
27084 this.el.update("");
27091 * @class Roo.TabPanelItem
27092 * @extends Roo.util.Observable
27093 * Represents an individual item (tab plus body) in a TabPanel.
27094 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
27095 * @param {String} id The id of this TabPanelItem
27096 * @param {String} text The text for the tab of this TabPanelItem
27097 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
27099 Roo.TabPanelItem = function(tabPanel, id, text, closable){
27101 * The {@link Roo.TabPanel} this TabPanelItem belongs to
27102 * @type Roo.TabPanel
27104 this.tabPanel = tabPanel;
27106 * The id for this TabPanelItem
27111 this.disabled = false;
27115 this.loaded = false;
27116 this.closable = closable;
27119 * The body element for this TabPanelItem.
27120 * @type Roo.Element
27122 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
27123 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
27124 this.bodyEl.setStyle("display", "block");
27125 this.bodyEl.setStyle("zoom", "1");
27128 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
27130 this.el = Roo.get(els.el, true);
27131 this.inner = Roo.get(els.inner, true);
27132 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
27133 this.pnode = Roo.get(els.el.parentNode, true);
27134 this.el.on("mousedown", this.onTabMouseDown, this);
27135 this.el.on("click", this.onTabClick, this);
27138 var c = Roo.get(els.close, true);
27139 c.dom.title = this.closeText;
27140 c.addClassOnOver("close-over");
27141 c.on("click", this.closeClick, this);
27147 * Fires when this tab becomes the active tab.
27148 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27149 * @param {Roo.TabPanelItem} this
27153 * @event beforeclose
27154 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
27155 * @param {Roo.TabPanelItem} this
27156 * @param {Object} e Set cancel to true on this object to cancel the close.
27158 "beforeclose": true,
27161 * Fires when this tab is closed.
27162 * @param {Roo.TabPanelItem} this
27166 * @event deactivate
27167 * Fires when this tab is no longer the active tab.
27168 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27169 * @param {Roo.TabPanelItem} this
27171 "deactivate" : true
27173 this.hidden = false;
27175 Roo.TabPanelItem.superclass.constructor.call(this);
27178 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27179 purgeListeners : function(){
27180 Roo.util.Observable.prototype.purgeListeners.call(this);
27181 this.el.removeAllListeners();
27184 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27187 this.pnode.addClass("on");
27190 this.tabPanel.stripWrap.repaint();
27192 this.fireEvent("activate", this.tabPanel, this);
27196 * Returns true if this tab is the active tab.
27197 * @return {Boolean}
27199 isActive : function(){
27200 return this.tabPanel.getActiveTab() == this;
27204 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27207 this.pnode.removeClass("on");
27209 this.fireEvent("deactivate", this.tabPanel, this);
27212 hideAction : function(){
27213 this.bodyEl.hide();
27214 this.bodyEl.setStyle("position", "absolute");
27215 this.bodyEl.setLeft("-20000px");
27216 this.bodyEl.setTop("-20000px");
27219 showAction : function(){
27220 this.bodyEl.setStyle("position", "relative");
27221 this.bodyEl.setTop("");
27222 this.bodyEl.setLeft("");
27223 this.bodyEl.show();
27227 * Set the tooltip for the tab.
27228 * @param {String} tooltip The tab's tooltip
27230 setTooltip : function(text){
27231 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27232 this.textEl.dom.qtip = text;
27233 this.textEl.dom.removeAttribute('title');
27235 this.textEl.dom.title = text;
27239 onTabClick : function(e){
27240 e.preventDefault();
27241 this.tabPanel.activate(this.id);
27244 onTabMouseDown : function(e){
27245 e.preventDefault();
27246 this.tabPanel.activate(this.id);
27249 getWidth : function(){
27250 return this.inner.getWidth();
27253 setWidth : function(width){
27254 var iwidth = width - this.pnode.getPadding("lr");
27255 this.inner.setWidth(iwidth);
27256 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27257 this.pnode.setWidth(width);
27261 * Show or hide the tab
27262 * @param {Boolean} hidden True to hide or false to show.
27264 setHidden : function(hidden){
27265 this.hidden = hidden;
27266 this.pnode.setStyle("display", hidden ? "none" : "");
27270 * Returns true if this tab is "hidden"
27271 * @return {Boolean}
27273 isHidden : function(){
27274 return this.hidden;
27278 * Returns the text for this tab
27281 getText : function(){
27285 autoSize : function(){
27286 //this.el.beginMeasure();
27287 this.textEl.setWidth(1);
27289 * #2804 [new] Tabs in Roojs
27290 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
27292 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
27293 //this.el.endMeasure();
27297 * Sets the text for the tab (Note: this also sets the tooltip text)
27298 * @param {String} text The tab's text and tooltip
27300 setText : function(text){
27302 this.textEl.update(text);
27303 this.setTooltip(text);
27304 if(!this.tabPanel.resizeTabs){
27309 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27311 activate : function(){
27312 this.tabPanel.activate(this.id);
27316 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27318 disable : function(){
27319 if(this.tabPanel.active != this){
27320 this.disabled = true;
27321 this.pnode.addClass("disabled");
27326 * Enables this TabPanelItem if it was previously disabled.
27328 enable : function(){
27329 this.disabled = false;
27330 this.pnode.removeClass("disabled");
27334 * Sets the content for this TabPanelItem.
27335 * @param {String} content The content
27336 * @param {Boolean} loadScripts true to look for and load scripts
27338 setContent : function(content, loadScripts){
27339 this.bodyEl.update(content, loadScripts);
27343 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27344 * @return {Roo.UpdateManager} The UpdateManager
27346 getUpdateManager : function(){
27347 return this.bodyEl.getUpdateManager();
27351 * Set a URL to be used to load the content for this TabPanelItem.
27352 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27353 * @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)
27354 * @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)
27355 * @return {Roo.UpdateManager} The UpdateManager
27357 setUrl : function(url, params, loadOnce){
27358 if(this.refreshDelegate){
27359 this.un('activate', this.refreshDelegate);
27361 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27362 this.on("activate", this.refreshDelegate);
27363 return this.bodyEl.getUpdateManager();
27367 _handleRefresh : function(url, params, loadOnce){
27368 if(!loadOnce || !this.loaded){
27369 var updater = this.bodyEl.getUpdateManager();
27370 updater.update(url, params, this._setLoaded.createDelegate(this));
27375 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27376 * Will fail silently if the setUrl method has not been called.
27377 * This does not activate the panel, just updates its content.
27379 refresh : function(){
27380 if(this.refreshDelegate){
27381 this.loaded = false;
27382 this.refreshDelegate();
27387 _setLoaded : function(){
27388 this.loaded = true;
27392 closeClick : function(e){
27395 this.fireEvent("beforeclose", this, o);
27396 if(o.cancel !== true){
27397 this.tabPanel.removeTab(this.id);
27401 * The text displayed in the tooltip for the close icon.
27404 closeText : "Close this tab"
27408 Roo.TabPanel.prototype.createStrip = function(container){
27409 var strip = document.createElement("div");
27410 strip.className = "x-tabs-wrap";
27411 container.appendChild(strip);
27415 Roo.TabPanel.prototype.createStripList = function(strip){
27416 // div wrapper for retard IE
27417 // returns the "tr" element.
27418 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27419 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27420 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27421 return strip.firstChild.firstChild.firstChild.firstChild;
27424 Roo.TabPanel.prototype.createBody = function(container){
27425 var body = document.createElement("div");
27426 Roo.id(body, "tab-body");
27427 Roo.fly(body).addClass("x-tabs-body");
27428 container.appendChild(body);
27432 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27433 var body = Roo.getDom(id);
27435 body = document.createElement("div");
27438 Roo.fly(body).addClass("x-tabs-item-body");
27439 bodyEl.insertBefore(body, bodyEl.firstChild);
27443 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27444 var td = document.createElement("td");
27445 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27446 //stripEl.appendChild(td);
27448 td.className = "x-tabs-closable";
27449 if(!this.closeTpl){
27450 this.closeTpl = new Roo.Template(
27451 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27452 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27453 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27456 var el = this.closeTpl.overwrite(td, {"text": text});
27457 var close = el.getElementsByTagName("div")[0];
27458 var inner = el.getElementsByTagName("em")[0];
27459 return {"el": el, "close": close, "inner": inner};
27462 this.tabTpl = new Roo.Template(
27463 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27464 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27467 var el = this.tabTpl.overwrite(td, {"text": text});
27468 var inner = el.getElementsByTagName("em")[0];
27469 return {"el": el, "inner": inner};
27473 * Ext JS Library 1.1.1
27474 * Copyright(c) 2006-2007, Ext JS, LLC.
27476 * Originally Released Under LGPL - original licence link has changed is not relivant.
27479 * <script type="text/javascript">
27483 * @class Roo.Button
27484 * @extends Roo.util.Observable
27485 * Simple Button class
27486 * @cfg {String} text The button text
27487 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27488 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27489 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27490 * @cfg {Object} scope The scope of the handler
27491 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27492 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27493 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27494 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27495 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27496 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27497 applies if enableToggle = true)
27498 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27499 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27500 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27502 * Create a new button
27503 * @param {Object} config The config object
27505 Roo.Button = function(renderTo, config)
27509 renderTo = config.renderTo || false;
27512 Roo.apply(this, config);
27516 * Fires when this button is clicked
27517 * @param {Button} this
27518 * @param {EventObject} e The click event
27523 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27524 * @param {Button} this
27525 * @param {Boolean} pressed
27530 * Fires when the mouse hovers over the button
27531 * @param {Button} this
27532 * @param {Event} e The event object
27534 'mouseover' : true,
27537 * Fires when the mouse exits the button
27538 * @param {Button} this
27539 * @param {Event} e The event object
27544 * Fires when the button is rendered
27545 * @param {Button} this
27550 this.menu = Roo.menu.MenuMgr.get(this.menu);
27552 // register listeners first!! - so render can be captured..
27553 Roo.util.Observable.call(this);
27555 this.render(renderTo);
27561 Roo.extend(Roo.Button, Roo.util.Observable, {
27567 * Read-only. True if this button is hidden
27572 * Read-only. True if this button is disabled
27577 * Read-only. True if this button is pressed (only if enableToggle = true)
27583 * @cfg {Number} tabIndex
27584 * The DOM tabIndex for this button (defaults to undefined)
27586 tabIndex : undefined,
27589 * @cfg {Boolean} enableToggle
27590 * True to enable pressed/not pressed toggling (defaults to false)
27592 enableToggle: false,
27594 * @cfg {Mixed} menu
27595 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27599 * @cfg {String} menuAlign
27600 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27602 menuAlign : "tl-bl?",
27605 * @cfg {String} iconCls
27606 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27608 iconCls : undefined,
27610 * @cfg {String} type
27611 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27616 menuClassTarget: 'tr',
27619 * @cfg {String} clickEvent
27620 * The type of event to map to the button's event handler (defaults to 'click')
27622 clickEvent : 'click',
27625 * @cfg {Boolean} handleMouseEvents
27626 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27628 handleMouseEvents : true,
27631 * @cfg {String} tooltipType
27632 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27634 tooltipType : 'qtip',
27637 * @cfg {String} cls
27638 * A CSS class to apply to the button's main element.
27642 * @cfg {Roo.Template} template (Optional)
27643 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27644 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27645 * require code modifications if required elements (e.g. a button) aren't present.
27649 render : function(renderTo){
27651 if(this.hideParent){
27652 this.parentEl = Roo.get(renderTo);
27654 if(!this.dhconfig){
27655 if(!this.template){
27656 if(!Roo.Button.buttonTemplate){
27657 // hideous table template
27658 Roo.Button.buttonTemplate = new Roo.Template(
27659 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27660 '<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>',
27661 "</tr></tbody></table>");
27663 this.template = Roo.Button.buttonTemplate;
27665 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27666 var btnEl = btn.child("button:first");
27667 btnEl.on('focus', this.onFocus, this);
27668 btnEl.on('blur', this.onBlur, this);
27670 btn.addClass(this.cls);
27673 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27676 btnEl.addClass(this.iconCls);
27678 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27681 if(this.tabIndex !== undefined){
27682 btnEl.dom.tabIndex = this.tabIndex;
27685 if(typeof this.tooltip == 'object'){
27686 Roo.QuickTips.tips(Roo.apply({
27690 btnEl.dom[this.tooltipType] = this.tooltip;
27694 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27698 this.el.dom.id = this.el.id = this.id;
27701 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27702 this.menu.on("show", this.onMenuShow, this);
27703 this.menu.on("hide", this.onMenuHide, this);
27705 btn.addClass("x-btn");
27706 if(Roo.isIE && !Roo.isIE7){
27707 this.autoWidth.defer(1, this);
27711 if(this.handleMouseEvents){
27712 btn.on("mouseover", this.onMouseOver, this);
27713 btn.on("mouseout", this.onMouseOut, this);
27714 btn.on("mousedown", this.onMouseDown, this);
27716 btn.on(this.clickEvent, this.onClick, this);
27717 //btn.on("mouseup", this.onMouseUp, this);
27724 Roo.ButtonToggleMgr.register(this);
27726 this.el.addClass("x-btn-pressed");
27729 var repeater = new Roo.util.ClickRepeater(btn,
27730 typeof this.repeat == "object" ? this.repeat : {}
27732 repeater.on("click", this.onClick, this);
27735 this.fireEvent('render', this);
27739 * Returns the button's underlying element
27740 * @return {Roo.Element} The element
27742 getEl : function(){
27747 * Destroys this Button and removes any listeners.
27749 destroy : function(){
27750 Roo.ButtonToggleMgr.unregister(this);
27751 this.el.removeAllListeners();
27752 this.purgeListeners();
27757 autoWidth : function(){
27759 this.el.setWidth("auto");
27760 if(Roo.isIE7 && Roo.isStrict){
27761 var ib = this.el.child('button');
27762 if(ib && ib.getWidth() > 20){
27764 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27769 this.el.beginMeasure();
27771 if(this.el.getWidth() < this.minWidth){
27772 this.el.setWidth(this.minWidth);
27775 this.el.endMeasure();
27782 * Assigns this button's click handler
27783 * @param {Function} handler The function to call when the button is clicked
27784 * @param {Object} scope (optional) Scope for the function passed in
27786 setHandler : function(handler, scope){
27787 this.handler = handler;
27788 this.scope = scope;
27792 * Sets this button's text
27793 * @param {String} text The button text
27795 setText : function(text){
27798 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27804 * Gets the text for this button
27805 * @return {String} The button text
27807 getText : function(){
27815 this.hidden = false;
27817 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27825 this.hidden = true;
27827 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27832 * Convenience function for boolean show/hide
27833 * @param {Boolean} visible True to show, false to hide
27835 setVisible: function(visible){
27844 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27845 * @param {Boolean} state (optional) Force a particular state
27847 toggle : function(state){
27848 state = state === undefined ? !this.pressed : state;
27849 if(state != this.pressed){
27851 this.el.addClass("x-btn-pressed");
27852 this.pressed = true;
27853 this.fireEvent("toggle", this, true);
27855 this.el.removeClass("x-btn-pressed");
27856 this.pressed = false;
27857 this.fireEvent("toggle", this, false);
27859 if(this.toggleHandler){
27860 this.toggleHandler.call(this.scope || this, this, state);
27868 focus : function(){
27869 this.el.child('button:first').focus();
27873 * Disable this button
27875 disable : function(){
27877 this.el.addClass("x-btn-disabled");
27879 this.disabled = true;
27883 * Enable this button
27885 enable : function(){
27887 this.el.removeClass("x-btn-disabled");
27889 this.disabled = false;
27893 * Convenience function for boolean enable/disable
27894 * @param {Boolean} enabled True to enable, false to disable
27896 setDisabled : function(v){
27897 this[v !== true ? "enable" : "disable"]();
27901 onClick : function(e)
27904 e.preventDefault();
27909 if(!this.disabled){
27910 if(this.enableToggle){
27913 if(this.menu && !this.menu.isVisible()){
27914 this.menu.show(this.el, this.menuAlign);
27916 this.fireEvent("click", this, e);
27918 this.el.removeClass("x-btn-over");
27919 this.handler.call(this.scope || this, this, e);
27924 onMouseOver : function(e){
27925 if(!this.disabled){
27926 this.el.addClass("x-btn-over");
27927 this.fireEvent('mouseover', this, e);
27931 onMouseOut : function(e){
27932 if(!e.within(this.el, true)){
27933 this.el.removeClass("x-btn-over");
27934 this.fireEvent('mouseout', this, e);
27938 onFocus : function(e){
27939 if(!this.disabled){
27940 this.el.addClass("x-btn-focus");
27944 onBlur : function(e){
27945 this.el.removeClass("x-btn-focus");
27948 onMouseDown : function(e){
27949 if(!this.disabled && e.button == 0){
27950 this.el.addClass("x-btn-click");
27951 Roo.get(document).on('mouseup', this.onMouseUp, this);
27955 onMouseUp : function(e){
27957 this.el.removeClass("x-btn-click");
27958 Roo.get(document).un('mouseup', this.onMouseUp, this);
27962 onMenuShow : function(e){
27963 this.el.addClass("x-btn-menu-active");
27966 onMenuHide : function(e){
27967 this.el.removeClass("x-btn-menu-active");
27971 // Private utility class used by Button
27972 Roo.ButtonToggleMgr = function(){
27975 function toggleGroup(btn, state){
27977 var g = groups[btn.toggleGroup];
27978 for(var i = 0, l = g.length; i < l; i++){
27980 g[i].toggle(false);
27987 register : function(btn){
27988 if(!btn.toggleGroup){
27991 var g = groups[btn.toggleGroup];
27993 g = groups[btn.toggleGroup] = [];
27996 btn.on("toggle", toggleGroup);
27999 unregister : function(btn){
28000 if(!btn.toggleGroup){
28003 var g = groups[btn.toggleGroup];
28006 btn.un("toggle", toggleGroup);
28012 * Ext JS Library 1.1.1
28013 * Copyright(c) 2006-2007, Ext JS, LLC.
28015 * Originally Released Under LGPL - original licence link has changed is not relivant.
28018 * <script type="text/javascript">
28022 * @class Roo.SplitButton
28023 * @extends Roo.Button
28024 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
28025 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
28026 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
28027 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
28028 * @cfg {String} arrowTooltip The title attribute of the arrow
28030 * Create a new menu button
28031 * @param {String/HTMLElement/Element} renderTo The element to append the button to
28032 * @param {Object} config The config object
28034 Roo.SplitButton = function(renderTo, config){
28035 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
28037 * @event arrowclick
28038 * Fires when this button's arrow is clicked
28039 * @param {SplitButton} this
28040 * @param {EventObject} e The click event
28042 this.addEvents({"arrowclick":true});
28045 Roo.extend(Roo.SplitButton, Roo.Button, {
28046 render : function(renderTo){
28047 // this is one sweet looking template!
28048 var tpl = new Roo.Template(
28049 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
28050 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
28051 '<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>',
28052 "</tbody></table></td><td>",
28053 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
28054 '<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>',
28055 "</tbody></table></td></tr></table>"
28057 var btn = tpl.append(renderTo, [this.text, this.type], true);
28058 var btnEl = btn.child("button");
28060 btn.addClass(this.cls);
28063 btnEl.setStyle('background-image', 'url(' +this.icon +')');
28066 btnEl.addClass(this.iconCls);
28068 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
28072 if(this.handleMouseEvents){
28073 btn.on("mouseover", this.onMouseOver, this);
28074 btn.on("mouseout", this.onMouseOut, this);
28075 btn.on("mousedown", this.onMouseDown, this);
28076 btn.on("mouseup", this.onMouseUp, this);
28078 btn.on(this.clickEvent, this.onClick, this);
28080 if(typeof this.tooltip == 'object'){
28081 Roo.QuickTips.tips(Roo.apply({
28085 btnEl.dom[this.tooltipType] = this.tooltip;
28088 if(this.arrowTooltip){
28089 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
28098 this.el.addClass("x-btn-pressed");
28100 if(Roo.isIE && !Roo.isIE7){
28101 this.autoWidth.defer(1, this);
28106 this.menu.on("show", this.onMenuShow, this);
28107 this.menu.on("hide", this.onMenuHide, this);
28109 this.fireEvent('render', this);
28113 autoWidth : function(){
28115 var tbl = this.el.child("table:first");
28116 var tbl2 = this.el.child("table:last");
28117 this.el.setWidth("auto");
28118 tbl.setWidth("auto");
28119 if(Roo.isIE7 && Roo.isStrict){
28120 var ib = this.el.child('button:first');
28121 if(ib && ib.getWidth() > 20){
28123 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
28128 this.el.beginMeasure();
28130 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
28131 tbl.setWidth(this.minWidth-tbl2.getWidth());
28134 this.el.endMeasure();
28137 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
28141 * Sets this button's click handler
28142 * @param {Function} handler The function to call when the button is clicked
28143 * @param {Object} scope (optional) Scope for the function passed above
28145 setHandler : function(handler, scope){
28146 this.handler = handler;
28147 this.scope = scope;
28151 * Sets this button's arrow click handler
28152 * @param {Function} handler The function to call when the arrow is clicked
28153 * @param {Object} scope (optional) Scope for the function passed above
28155 setArrowHandler : function(handler, scope){
28156 this.arrowHandler = handler;
28157 this.scope = scope;
28163 focus : function(){
28165 this.el.child("button:first").focus();
28170 onClick : function(e){
28171 e.preventDefault();
28172 if(!this.disabled){
28173 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28174 if(this.menu && !this.menu.isVisible()){
28175 this.menu.show(this.el, this.menuAlign);
28177 this.fireEvent("arrowclick", this, e);
28178 if(this.arrowHandler){
28179 this.arrowHandler.call(this.scope || this, this, e);
28182 this.fireEvent("click", this, e);
28184 this.handler.call(this.scope || this, this, e);
28190 onMouseDown : function(e){
28191 if(!this.disabled){
28192 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28196 onMouseUp : function(e){
28197 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28202 // backwards compat
28203 Roo.MenuButton = Roo.SplitButton;/*
28205 * Ext JS Library 1.1.1
28206 * Copyright(c) 2006-2007, Ext JS, LLC.
28208 * Originally Released Under LGPL - original licence link has changed is not relivant.
28211 * <script type="text/javascript">
28215 * @class Roo.Toolbar
28216 * Basic Toolbar class.
28218 * Creates a new Toolbar
28219 * @param {Object} container The config object
28221 Roo.Toolbar = function(container, buttons, config)
28223 /// old consturctor format still supported..
28224 if(container instanceof Array){ // omit the container for later rendering
28225 buttons = container;
28229 if (typeof(container) == 'object' && container.xtype) {
28230 config = container;
28231 container = config.container;
28232 buttons = config.buttons || []; // not really - use items!!
28235 if (config && config.items) {
28236 xitems = config.items;
28237 delete config.items;
28239 Roo.apply(this, config);
28240 this.buttons = buttons;
28243 this.render(container);
28245 this.xitems = xitems;
28246 Roo.each(xitems, function(b) {
28252 Roo.Toolbar.prototype = {
28254 * @cfg {Array} items
28255 * array of button configs or elements to add (will be converted to a MixedCollection)
28259 * @cfg {String/HTMLElement/Element} container
28260 * The id or element that will contain the toolbar
28263 render : function(ct){
28264 this.el = Roo.get(ct);
28266 this.el.addClass(this.cls);
28268 // using a table allows for vertical alignment
28269 // 100% width is needed by Safari...
28270 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28271 this.tr = this.el.child("tr", true);
28273 this.items = new Roo.util.MixedCollection(false, function(o){
28274 return o.id || ("item" + (++autoId));
28277 this.add.apply(this, this.buttons);
28278 delete this.buttons;
28283 * Adds element(s) to the toolbar -- this function takes a variable number of
28284 * arguments of mixed type and adds them to the toolbar.
28285 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28287 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28288 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28289 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28290 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28291 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28292 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28293 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28294 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28295 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28297 * @param {Mixed} arg2
28298 * @param {Mixed} etc.
28301 var a = arguments, l = a.length;
28302 for(var i = 0; i < l; i++){
28307 _add : function(el) {
28310 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28313 if (el.applyTo){ // some kind of form field
28314 return this.addField(el);
28316 if (el.render){ // some kind of Toolbar.Item
28317 return this.addItem(el);
28319 if (typeof el == "string"){ // string
28320 if(el == "separator" || el == "-"){
28321 return this.addSeparator();
28324 return this.addSpacer();
28327 return this.addFill();
28329 return this.addText(el);
28332 if(el.tagName){ // element
28333 return this.addElement(el);
28335 if(typeof el == "object"){ // must be button config?
28336 return this.addButton(el);
28338 // and now what?!?!
28344 * Add an Xtype element
28345 * @param {Object} xtype Xtype Object
28346 * @return {Object} created Object
28348 addxtype : function(e){
28349 return this.add(e);
28353 * Returns the Element for this toolbar.
28354 * @return {Roo.Element}
28356 getEl : function(){
28362 * @return {Roo.Toolbar.Item} The separator item
28364 addSeparator : function(){
28365 return this.addItem(new Roo.Toolbar.Separator());
28369 * Adds a spacer element
28370 * @return {Roo.Toolbar.Spacer} The spacer item
28372 addSpacer : function(){
28373 return this.addItem(new Roo.Toolbar.Spacer());
28377 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28378 * @return {Roo.Toolbar.Fill} The fill item
28380 addFill : function(){
28381 return this.addItem(new Roo.Toolbar.Fill());
28385 * Adds any standard HTML element to the toolbar
28386 * @param {String/HTMLElement/Element} el The element or id of the element to add
28387 * @return {Roo.Toolbar.Item} The element's item
28389 addElement : function(el){
28390 return this.addItem(new Roo.Toolbar.Item(el));
28393 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28394 * @type Roo.util.MixedCollection
28399 * Adds any Toolbar.Item or subclass
28400 * @param {Roo.Toolbar.Item} item
28401 * @return {Roo.Toolbar.Item} The item
28403 addItem : function(item){
28404 var td = this.nextBlock();
28406 this.items.add(item);
28411 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28412 * @param {Object/Array} config A button config or array of configs
28413 * @return {Roo.Toolbar.Button/Array}
28415 addButton : function(config){
28416 if(config instanceof Array){
28418 for(var i = 0, len = config.length; i < len; i++) {
28419 buttons.push(this.addButton(config[i]));
28424 if(!(config instanceof Roo.Toolbar.Button)){
28426 new Roo.Toolbar.SplitButton(config) :
28427 new Roo.Toolbar.Button(config);
28429 var td = this.nextBlock();
28436 * Adds text to the toolbar
28437 * @param {String} text The text to add
28438 * @return {Roo.Toolbar.Item} The element's item
28440 addText : function(text){
28441 return this.addItem(new Roo.Toolbar.TextItem(text));
28445 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28446 * @param {Number} index The index where the item is to be inserted
28447 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28448 * @return {Roo.Toolbar.Button/Item}
28450 insertButton : function(index, item){
28451 if(item instanceof Array){
28453 for(var i = 0, len = item.length; i < len; i++) {
28454 buttons.push(this.insertButton(index + i, item[i]));
28458 if (!(item instanceof Roo.Toolbar.Button)){
28459 item = new Roo.Toolbar.Button(item);
28461 var td = document.createElement("td");
28462 this.tr.insertBefore(td, this.tr.childNodes[index]);
28464 this.items.insert(index, item);
28469 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28470 * @param {Object} config
28471 * @return {Roo.Toolbar.Item} The element's item
28473 addDom : function(config, returnEl){
28474 var td = this.nextBlock();
28475 Roo.DomHelper.overwrite(td, config);
28476 var ti = new Roo.Toolbar.Item(td.firstChild);
28478 this.items.add(ti);
28483 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28484 * @type Roo.util.MixedCollection
28489 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28490 * Note: the field should not have been rendered yet. For a field that has already been
28491 * rendered, use {@link #addElement}.
28492 * @param {Roo.form.Field} field
28493 * @return {Roo.ToolbarItem}
28497 addField : function(field) {
28498 if (!this.fields) {
28500 this.fields = new Roo.util.MixedCollection(false, function(o){
28501 return o.id || ("item" + (++autoId));
28506 var td = this.nextBlock();
28508 var ti = new Roo.Toolbar.Item(td.firstChild);
28510 this.items.add(ti);
28511 this.fields.add(field);
28522 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28523 this.el.child('div').hide();
28531 this.el.child('div').show();
28535 nextBlock : function(){
28536 var td = document.createElement("td");
28537 this.tr.appendChild(td);
28542 destroy : function(){
28543 if(this.items){ // rendered?
28544 Roo.destroy.apply(Roo, this.items.items);
28546 if(this.fields){ // rendered?
28547 Roo.destroy.apply(Roo, this.fields.items);
28549 Roo.Element.uncache(this.el, this.tr);
28554 * @class Roo.Toolbar.Item
28555 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28557 * Creates a new Item
28558 * @param {HTMLElement} el
28560 Roo.Toolbar.Item = function(el){
28562 if (typeof (el.xtype) != 'undefined') {
28567 this.el = Roo.getDom(el);
28568 this.id = Roo.id(this.el);
28569 this.hidden = false;
28574 * Fires when the button is rendered
28575 * @param {Button} this
28579 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
28581 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
28582 //Roo.Toolbar.Item.prototype = {
28585 * Get this item's HTML Element
28586 * @return {HTMLElement}
28588 getEl : function(){
28593 render : function(td){
28596 td.appendChild(this.el);
28598 this.fireEvent('render', this);
28602 * Removes and destroys this item.
28604 destroy : function(){
28605 this.td.parentNode.removeChild(this.td);
28612 this.hidden = false;
28613 this.td.style.display = "";
28620 this.hidden = true;
28621 this.td.style.display = "none";
28625 * Convenience function for boolean show/hide.
28626 * @param {Boolean} visible true to show/false to hide
28628 setVisible: function(visible){
28637 * Try to focus this item.
28639 focus : function(){
28640 Roo.fly(this.el).focus();
28644 * Disables this item.
28646 disable : function(){
28647 Roo.fly(this.td).addClass("x-item-disabled");
28648 this.disabled = true;
28649 this.el.disabled = true;
28653 * Enables this item.
28655 enable : function(){
28656 Roo.fly(this.td).removeClass("x-item-disabled");
28657 this.disabled = false;
28658 this.el.disabled = false;
28664 * @class Roo.Toolbar.Separator
28665 * @extends Roo.Toolbar.Item
28666 * A simple toolbar separator class
28668 * Creates a new Separator
28670 Roo.Toolbar.Separator = function(cfg){
28672 var s = document.createElement("span");
28673 s.className = "ytb-sep";
28678 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
28680 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28681 enable:Roo.emptyFn,
28682 disable:Roo.emptyFn,
28687 * @class Roo.Toolbar.Spacer
28688 * @extends Roo.Toolbar.Item
28689 * A simple element that adds extra horizontal space to a toolbar.
28691 * Creates a new Spacer
28693 Roo.Toolbar.Spacer = function(cfg){
28694 var s = document.createElement("div");
28695 s.className = "ytb-spacer";
28699 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
28701 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28702 enable:Roo.emptyFn,
28703 disable:Roo.emptyFn,
28708 * @class Roo.Toolbar.Fill
28709 * @extends Roo.Toolbar.Spacer
28710 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28712 * Creates a new Spacer
28714 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28716 render : function(td){
28717 td.style.width = '100%';
28718 Roo.Toolbar.Fill.superclass.render.call(this, td);
28723 * @class Roo.Toolbar.TextItem
28724 * @extends Roo.Toolbar.Item
28725 * A simple class that renders text directly into a toolbar.
28727 * Creates a new TextItem
28728 * @param {String} text
28730 Roo.Toolbar.TextItem = function(cfg){
28731 var text = cfg || "";
28732 if (typeof(cfg) == 'object') {
28733 text = cfg.text || "";
28737 var s = document.createElement("span");
28738 s.className = "ytb-text";
28739 s.innerHTML = text;
28744 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
28746 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28749 enable:Roo.emptyFn,
28750 disable:Roo.emptyFn,
28755 * @class Roo.Toolbar.Button
28756 * @extends Roo.Button
28757 * A button that renders into a toolbar.
28759 * Creates a new Button
28760 * @param {Object} config A standard {@link Roo.Button} config object
28762 Roo.Toolbar.Button = function(config){
28763 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28765 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28766 render : function(td){
28768 Roo.Toolbar.Button.superclass.render.call(this, td);
28772 * Removes and destroys this button
28774 destroy : function(){
28775 Roo.Toolbar.Button.superclass.destroy.call(this);
28776 this.td.parentNode.removeChild(this.td);
28780 * Shows this button
28783 this.hidden = false;
28784 this.td.style.display = "";
28788 * Hides this button
28791 this.hidden = true;
28792 this.td.style.display = "none";
28796 * Disables this item
28798 disable : function(){
28799 Roo.fly(this.td).addClass("x-item-disabled");
28800 this.disabled = true;
28804 * Enables this item
28806 enable : function(){
28807 Roo.fly(this.td).removeClass("x-item-disabled");
28808 this.disabled = false;
28811 // backwards compat
28812 Roo.ToolbarButton = Roo.Toolbar.Button;
28815 * @class Roo.Toolbar.SplitButton
28816 * @extends Roo.SplitButton
28817 * A menu button that renders into a toolbar.
28819 * Creates a new SplitButton
28820 * @param {Object} config A standard {@link Roo.SplitButton} config object
28822 Roo.Toolbar.SplitButton = function(config){
28823 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28825 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28826 render : function(td){
28828 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28832 * Removes and destroys this button
28834 destroy : function(){
28835 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28836 this.td.parentNode.removeChild(this.td);
28840 * Shows this button
28843 this.hidden = false;
28844 this.td.style.display = "";
28848 * Hides this button
28851 this.hidden = true;
28852 this.td.style.display = "none";
28856 // backwards compat
28857 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28859 * Ext JS Library 1.1.1
28860 * Copyright(c) 2006-2007, Ext JS, LLC.
28862 * Originally Released Under LGPL - original licence link has changed is not relivant.
28865 * <script type="text/javascript">
28869 * @class Roo.PagingToolbar
28870 * @extends Roo.Toolbar
28871 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28873 * Create a new PagingToolbar
28874 * @param {Object} config The config object
28876 Roo.PagingToolbar = function(el, ds, config)
28878 // old args format still supported... - xtype is prefered..
28879 if (typeof(el) == 'object' && el.xtype) {
28880 // created from xtype...
28882 ds = el.dataSource;
28883 el = config.container;
28886 if (config.items) {
28887 items = config.items;
28891 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28894 this.renderButtons(this.el);
28897 // supprot items array.
28899 Roo.each(items, function(e) {
28900 this.add(Roo.factory(e));
28905 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28907 * @cfg {Roo.data.Store} dataSource
28908 * The underlying data store providing the paged data
28911 * @cfg {String/HTMLElement/Element} container
28912 * container The id or element that will contain the toolbar
28915 * @cfg {Boolean} displayInfo
28916 * True to display the displayMsg (defaults to false)
28919 * @cfg {Number} pageSize
28920 * The number of records to display per page (defaults to 20)
28924 * @cfg {String} displayMsg
28925 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28927 displayMsg : 'Displaying {0} - {1} of {2}',
28929 * @cfg {String} emptyMsg
28930 * The message to display when no records are found (defaults to "No data to display")
28932 emptyMsg : 'No data to display',
28934 * Customizable piece of the default paging text (defaults to "Page")
28937 beforePageText : "Page",
28939 * Customizable piece of the default paging text (defaults to "of %0")
28942 afterPageText : "of {0}",
28944 * Customizable piece of the default paging text (defaults to "First Page")
28947 firstText : "First Page",
28949 * Customizable piece of the default paging text (defaults to "Previous Page")
28952 prevText : "Previous Page",
28954 * Customizable piece of the default paging text (defaults to "Next Page")
28957 nextText : "Next Page",
28959 * Customizable piece of the default paging text (defaults to "Last Page")
28962 lastText : "Last Page",
28964 * Customizable piece of the default paging text (defaults to "Refresh")
28967 refreshText : "Refresh",
28970 renderButtons : function(el){
28971 Roo.PagingToolbar.superclass.render.call(this, el);
28972 this.first = this.addButton({
28973 tooltip: this.firstText,
28974 cls: "x-btn-icon x-grid-page-first",
28976 handler: this.onClick.createDelegate(this, ["first"])
28978 this.prev = this.addButton({
28979 tooltip: this.prevText,
28980 cls: "x-btn-icon x-grid-page-prev",
28982 handler: this.onClick.createDelegate(this, ["prev"])
28984 //this.addSeparator();
28985 this.add(this.beforePageText);
28986 this.field = Roo.get(this.addDom({
28991 cls: "x-grid-page-number"
28993 this.field.on("keydown", this.onPagingKeydown, this);
28994 this.field.on("focus", function(){this.dom.select();});
28995 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28996 this.field.setHeight(18);
28997 //this.addSeparator();
28998 this.next = this.addButton({
28999 tooltip: this.nextText,
29000 cls: "x-btn-icon x-grid-page-next",
29002 handler: this.onClick.createDelegate(this, ["next"])
29004 this.last = this.addButton({
29005 tooltip: this.lastText,
29006 cls: "x-btn-icon x-grid-page-last",
29008 handler: this.onClick.createDelegate(this, ["last"])
29010 //this.addSeparator();
29011 this.loading = this.addButton({
29012 tooltip: this.refreshText,
29013 cls: "x-btn-icon x-grid-loading",
29014 handler: this.onClick.createDelegate(this, ["refresh"])
29017 if(this.displayInfo){
29018 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
29023 updateInfo : function(){
29024 if(this.displayEl){
29025 var count = this.ds.getCount();
29026 var msg = count == 0 ?
29030 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
29032 this.displayEl.update(msg);
29037 onLoad : function(ds, r, o){
29038 this.cursor = o.params ? o.params.start : 0;
29039 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
29041 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
29042 this.field.dom.value = ap;
29043 this.first.setDisabled(ap == 1);
29044 this.prev.setDisabled(ap == 1);
29045 this.next.setDisabled(ap == ps);
29046 this.last.setDisabled(ap == ps);
29047 this.loading.enable();
29052 getPageData : function(){
29053 var total = this.ds.getTotalCount();
29056 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
29057 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
29062 onLoadError : function(){
29063 this.loading.enable();
29067 onPagingKeydown : function(e){
29068 var k = e.getKey();
29069 var d = this.getPageData();
29071 var v = this.field.dom.value, pageNum;
29072 if(!v || isNaN(pageNum = parseInt(v, 10))){
29073 this.field.dom.value = d.activePage;
29076 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
29077 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29080 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))
29082 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
29083 this.field.dom.value = pageNum;
29084 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
29087 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29089 var v = this.field.dom.value, pageNum;
29090 var increment = (e.shiftKey) ? 10 : 1;
29091 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
29094 if(!v || isNaN(pageNum = parseInt(v, 10))) {
29095 this.field.dom.value = d.activePage;
29098 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
29100 this.field.dom.value = parseInt(v, 10) + increment;
29101 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
29102 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29109 beforeLoad : function(){
29111 this.loading.disable();
29116 onClick : function(which){
29120 ds.load({params:{start: 0, limit: this.pageSize}});
29123 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
29126 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
29129 var total = ds.getTotalCount();
29130 var extra = total % this.pageSize;
29131 var lastStart = extra ? (total - extra) : total-this.pageSize;
29132 ds.load({params:{start: lastStart, limit: this.pageSize}});
29135 ds.load({params:{start: this.cursor, limit: this.pageSize}});
29141 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
29142 * @param {Roo.data.Store} store The data store to unbind
29144 unbind : function(ds){
29145 ds.un("beforeload", this.beforeLoad, this);
29146 ds.un("load", this.onLoad, this);
29147 ds.un("loadexception", this.onLoadError, this);
29148 ds.un("remove", this.updateInfo, this);
29149 ds.un("add", this.updateInfo, this);
29150 this.ds = undefined;
29154 * Binds the paging toolbar to the specified {@link Roo.data.Store}
29155 * @param {Roo.data.Store} store The data store to bind
29157 bind : function(ds){
29158 ds.on("beforeload", this.beforeLoad, this);
29159 ds.on("load", this.onLoad, this);
29160 ds.on("loadexception", this.onLoadError, this);
29161 ds.on("remove", this.updateInfo, this);
29162 ds.on("add", this.updateInfo, this);
29167 * Ext JS Library 1.1.1
29168 * Copyright(c) 2006-2007, Ext JS, LLC.
29170 * Originally Released Under LGPL - original licence link has changed is not relivant.
29173 * <script type="text/javascript">
29177 * @class Roo.Resizable
29178 * @extends Roo.util.Observable
29179 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
29180 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
29181 * 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
29182 * the element will be wrapped for you automatically.</p>
29183 * <p>Here is the list of valid resize handles:</p>
29186 ------ -------------------
29195 'hd' horizontal drag
29198 * <p>Here's an example showing the creation of a typical Resizable:</p>
29200 var resizer = new Roo.Resizable("element-id", {
29208 resizer.on("resize", myHandler);
29210 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29211 * resizer.east.setDisplayed(false);</p>
29212 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29213 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29214 * resize operation's new size (defaults to [0, 0])
29215 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29216 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29217 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29218 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29219 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29220 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29221 * @cfg {Number} width The width of the element in pixels (defaults to null)
29222 * @cfg {Number} height The height of the element in pixels (defaults to null)
29223 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29224 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29225 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29226 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29227 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29228 * in favor of the handles config option (defaults to false)
29229 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29230 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29231 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29232 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29233 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29234 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29235 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29236 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29237 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29238 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29239 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29241 * Create a new resizable component
29242 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29243 * @param {Object} config configuration options
29245 Roo.Resizable = function(el, config)
29247 this.el = Roo.get(el);
29249 if(config && config.wrap){
29250 config.resizeChild = this.el;
29251 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29252 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29253 this.el.setStyle("overflow", "hidden");
29254 this.el.setPositioning(config.resizeChild.getPositioning());
29255 config.resizeChild.clearPositioning();
29256 if(!config.width || !config.height){
29257 var csize = config.resizeChild.getSize();
29258 this.el.setSize(csize.width, csize.height);
29260 if(config.pinned && !config.adjustments){
29261 config.adjustments = "auto";
29265 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29266 this.proxy.unselectable();
29267 this.proxy.enableDisplayMode('block');
29269 Roo.apply(this, config);
29272 this.disableTrackOver = true;
29273 this.el.addClass("x-resizable-pinned");
29275 // if the element isn't positioned, make it relative
29276 var position = this.el.getStyle("position");
29277 if(position != "absolute" && position != "fixed"){
29278 this.el.setStyle("position", "relative");
29280 if(!this.handles){ // no handles passed, must be legacy style
29281 this.handles = 's,e,se';
29282 if(this.multiDirectional){
29283 this.handles += ',n,w';
29286 if(this.handles == "all"){
29287 this.handles = "n s e w ne nw se sw";
29289 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29290 var ps = Roo.Resizable.positions;
29291 for(var i = 0, len = hs.length; i < len; i++){
29292 if(hs[i] && ps[hs[i]]){
29293 var pos = ps[hs[i]];
29294 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29298 this.corner = this.southeast;
29300 // updateBox = the box can move..
29301 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29302 this.updateBox = true;
29305 this.activeHandle = null;
29307 if(this.resizeChild){
29308 if(typeof this.resizeChild == "boolean"){
29309 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29311 this.resizeChild = Roo.get(this.resizeChild, true);
29315 if(this.adjustments == "auto"){
29316 var rc = this.resizeChild;
29317 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29318 if(rc && (hw || hn)){
29319 rc.position("relative");
29320 rc.setLeft(hw ? hw.el.getWidth() : 0);
29321 rc.setTop(hn ? hn.el.getHeight() : 0);
29323 this.adjustments = [
29324 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29325 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29329 if(this.draggable){
29330 this.dd = this.dynamic ?
29331 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29332 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29338 * @event beforeresize
29339 * Fired before resize is allowed. Set enabled to false to cancel resize.
29340 * @param {Roo.Resizable} this
29341 * @param {Roo.EventObject} e The mousedown event
29343 "beforeresize" : true,
29346 * Fired a resizing.
29347 * @param {Roo.Resizable} this
29348 * @param {Number} x The new x position
29349 * @param {Number} y The new y position
29350 * @param {Number} w The new w width
29351 * @param {Number} h The new h hight
29352 * @param {Roo.EventObject} e The mouseup event
29357 * Fired after a resize.
29358 * @param {Roo.Resizable} this
29359 * @param {Number} width The new width
29360 * @param {Number} height The new height
29361 * @param {Roo.EventObject} e The mouseup event
29366 if(this.width !== null && this.height !== null){
29367 this.resizeTo(this.width, this.height);
29369 this.updateChildSize();
29372 this.el.dom.style.zoom = 1;
29374 Roo.Resizable.superclass.constructor.call(this);
29377 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29378 resizeChild : false,
29379 adjustments : [0, 0],
29389 multiDirectional : false,
29390 disableTrackOver : false,
29391 easing : 'easeOutStrong',
29392 widthIncrement : 0,
29393 heightIncrement : 0,
29397 preserveRatio : false,
29398 transparent: false,
29404 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29406 constrainTo: undefined,
29408 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29410 resizeRegion: undefined,
29414 * Perform a manual resize
29415 * @param {Number} width
29416 * @param {Number} height
29418 resizeTo : function(width, height){
29419 this.el.setSize(width, height);
29420 this.updateChildSize();
29421 this.fireEvent("resize", this, width, height, null);
29425 startSizing : function(e, handle){
29426 this.fireEvent("beforeresize", this, e);
29427 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29430 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29431 this.overlay.unselectable();
29432 this.overlay.enableDisplayMode("block");
29433 this.overlay.on("mousemove", this.onMouseMove, this);
29434 this.overlay.on("mouseup", this.onMouseUp, this);
29436 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29438 this.resizing = true;
29439 this.startBox = this.el.getBox();
29440 this.startPoint = e.getXY();
29441 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29442 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29444 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29445 this.overlay.show();
29447 if(this.constrainTo) {
29448 var ct = Roo.get(this.constrainTo);
29449 this.resizeRegion = ct.getRegion().adjust(
29450 ct.getFrameWidth('t'),
29451 ct.getFrameWidth('l'),
29452 -ct.getFrameWidth('b'),
29453 -ct.getFrameWidth('r')
29457 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29459 this.proxy.setBox(this.startBox);
29461 this.proxy.setStyle('visibility', 'visible');
29467 onMouseDown : function(handle, e){
29470 this.activeHandle = handle;
29471 this.startSizing(e, handle);
29476 onMouseUp : function(e){
29477 var size = this.resizeElement();
29478 this.resizing = false;
29480 this.overlay.hide();
29482 this.fireEvent("resize", this, size.width, size.height, e);
29486 updateChildSize : function(){
29488 if(this.resizeChild){
29490 var child = this.resizeChild;
29491 var adj = this.adjustments;
29492 if(el.dom.offsetWidth){
29493 var b = el.getSize(true);
29494 child.setSize(b.width+adj[0], b.height+adj[1]);
29496 // Second call here for IE
29497 // The first call enables instant resizing and
29498 // the second call corrects scroll bars if they
29501 setTimeout(function(){
29502 if(el.dom.offsetWidth){
29503 var b = el.getSize(true);
29504 child.setSize(b.width+adj[0], b.height+adj[1]);
29512 snap : function(value, inc, min){
29513 if(!inc || !value) {
29516 var newValue = value;
29517 var m = value % inc;
29520 newValue = value + (inc-m);
29522 newValue = value - m;
29525 return Math.max(min, newValue);
29529 resizeElement : function(){
29530 var box = this.proxy.getBox();
29531 if(this.updateBox){
29532 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29534 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29536 this.updateChildSize();
29544 constrain : function(v, diff, m, mx){
29547 }else if(v - diff > mx){
29554 onMouseMove : function(e){
29557 try{// try catch so if something goes wrong the user doesn't get hung
29559 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29563 //var curXY = this.startPoint;
29564 var curSize = this.curSize || this.startBox;
29565 var x = this.startBox.x, y = this.startBox.y;
29566 var ox = x, oy = y;
29567 var w = curSize.width, h = curSize.height;
29568 var ow = w, oh = h;
29569 var mw = this.minWidth, mh = this.minHeight;
29570 var mxw = this.maxWidth, mxh = this.maxHeight;
29571 var wi = this.widthIncrement;
29572 var hi = this.heightIncrement;
29574 var eventXY = e.getXY();
29575 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29576 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29578 var pos = this.activeHandle.position;
29583 w = Math.min(Math.max(mw, w), mxw);
29588 h = Math.min(Math.max(mh, h), mxh);
29593 w = Math.min(Math.max(mw, w), mxw);
29594 h = Math.min(Math.max(mh, h), mxh);
29597 diffY = this.constrain(h, diffY, mh, mxh);
29604 var adiffX = Math.abs(diffX);
29605 var sub = (adiffX % wi); // how much
29606 if (sub > (wi/2)) { // far enough to snap
29607 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29609 // remove difference..
29610 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29614 x = Math.max(this.minX, x);
29617 diffX = this.constrain(w, diffX, mw, mxw);
29623 w = Math.min(Math.max(mw, w), mxw);
29624 diffY = this.constrain(h, diffY, mh, mxh);
29629 diffX = this.constrain(w, diffX, mw, mxw);
29630 diffY = this.constrain(h, diffY, mh, mxh);
29637 diffX = this.constrain(w, diffX, mw, mxw);
29639 h = Math.min(Math.max(mh, h), mxh);
29645 var sw = this.snap(w, wi, mw);
29646 var sh = this.snap(h, hi, mh);
29647 if(sw != w || sh != h){
29670 if(this.preserveRatio){
29675 h = Math.min(Math.max(mh, h), mxh);
29680 w = Math.min(Math.max(mw, w), mxw);
29685 w = Math.min(Math.max(mw, w), mxw);
29691 w = Math.min(Math.max(mw, w), mxw);
29697 h = Math.min(Math.max(mh, h), mxh);
29705 h = Math.min(Math.max(mh, h), mxh);
29715 h = Math.min(Math.max(mh, h), mxh);
29723 if (pos == 'hdrag') {
29726 this.proxy.setBounds(x, y, w, h);
29728 this.resizeElement();
29732 this.fireEvent("resizing", this, x, y, w, h, e);
29736 handleOver : function(){
29738 this.el.addClass("x-resizable-over");
29743 handleOut : function(){
29744 if(!this.resizing){
29745 this.el.removeClass("x-resizable-over");
29750 * Returns the element this component is bound to.
29751 * @return {Roo.Element}
29753 getEl : function(){
29758 * Returns the resizeChild element (or null).
29759 * @return {Roo.Element}
29761 getResizeChild : function(){
29762 return this.resizeChild;
29764 groupHandler : function()
29769 * Destroys this resizable. If the element was wrapped and
29770 * removeEl is not true then the element remains.
29771 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29773 destroy : function(removeEl){
29774 this.proxy.remove();
29776 this.overlay.removeAllListeners();
29777 this.overlay.remove();
29779 var ps = Roo.Resizable.positions;
29781 if(typeof ps[k] != "function" && this[ps[k]]){
29782 var h = this[ps[k]];
29783 h.el.removeAllListeners();
29788 this.el.update("");
29795 // hash to map config positions to true positions
29796 Roo.Resizable.positions = {
29797 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29802 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29804 // only initialize the template if resizable is used
29805 var tpl = Roo.DomHelper.createTemplate(
29806 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29809 Roo.Resizable.Handle.prototype.tpl = tpl;
29811 this.position = pos;
29813 // show north drag fro topdra
29814 var handlepos = pos == 'hdrag' ? 'north' : pos;
29816 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29817 if (pos == 'hdrag') {
29818 this.el.setStyle('cursor', 'pointer');
29820 this.el.unselectable();
29822 this.el.setOpacity(0);
29824 this.el.on("mousedown", this.onMouseDown, this);
29825 if(!disableTrackOver){
29826 this.el.on("mouseover", this.onMouseOver, this);
29827 this.el.on("mouseout", this.onMouseOut, this);
29832 Roo.Resizable.Handle.prototype = {
29833 afterResize : function(rz){
29838 onMouseDown : function(e){
29839 this.rz.onMouseDown(this, e);
29842 onMouseOver : function(e){
29843 this.rz.handleOver(this, e);
29846 onMouseOut : function(e){
29847 this.rz.handleOut(this, e);
29851 * Ext JS Library 1.1.1
29852 * Copyright(c) 2006-2007, Ext JS, LLC.
29854 * Originally Released Under LGPL - original licence link has changed is not relivant.
29857 * <script type="text/javascript">
29861 * @class Roo.Editor
29862 * @extends Roo.Component
29863 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29865 * Create a new Editor
29866 * @param {Roo.form.Field} field The Field object (or descendant)
29867 * @param {Object} config The config object
29869 Roo.Editor = function(field, config){
29870 Roo.Editor.superclass.constructor.call(this, config);
29871 this.field = field;
29874 * @event beforestartedit
29875 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29876 * false from the handler of this event.
29877 * @param {Editor} this
29878 * @param {Roo.Element} boundEl The underlying element bound to this editor
29879 * @param {Mixed} value The field value being set
29881 "beforestartedit" : true,
29884 * Fires when this editor is displayed
29885 * @param {Roo.Element} boundEl The underlying element bound to this editor
29886 * @param {Mixed} value The starting field value
29888 "startedit" : true,
29890 * @event beforecomplete
29891 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29892 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29893 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29894 * event will not fire since no edit actually occurred.
29895 * @param {Editor} this
29896 * @param {Mixed} value The current field value
29897 * @param {Mixed} startValue The original field value
29899 "beforecomplete" : true,
29902 * Fires after editing is complete and any changed value has been written to the underlying field.
29903 * @param {Editor} this
29904 * @param {Mixed} value The current field value
29905 * @param {Mixed} startValue The original field value
29909 * @event specialkey
29910 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29911 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29912 * @param {Roo.form.Field} this
29913 * @param {Roo.EventObject} e The event object
29915 "specialkey" : true
29919 Roo.extend(Roo.Editor, Roo.Component, {
29921 * @cfg {Boolean/String} autosize
29922 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29923 * or "height" to adopt the height only (defaults to false)
29926 * @cfg {Boolean} revertInvalid
29927 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29928 * validation fails (defaults to true)
29931 * @cfg {Boolean} ignoreNoChange
29932 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29933 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29934 * will never be ignored.
29937 * @cfg {Boolean} hideEl
29938 * False to keep the bound element visible while the editor is displayed (defaults to true)
29941 * @cfg {Mixed} value
29942 * The data value of the underlying field (defaults to "")
29946 * @cfg {String} alignment
29947 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29951 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29952 * for bottom-right shadow (defaults to "frame")
29956 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29960 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29962 completeOnEnter : false,
29964 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29966 cancelOnEsc : false,
29968 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29973 onRender : function(ct, position){
29974 this.el = new Roo.Layer({
29975 shadow: this.shadow,
29981 constrain: this.constrain
29983 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29984 if(this.field.msgTarget != 'title'){
29985 this.field.msgTarget = 'qtip';
29987 this.field.render(this.el);
29989 this.field.el.dom.setAttribute('autocomplete', 'off');
29991 this.field.on("specialkey", this.onSpecialKey, this);
29992 if(this.swallowKeys){
29993 this.field.el.swallowEvent(['keydown','keypress']);
29996 this.field.on("blur", this.onBlur, this);
29997 if(this.field.grow){
29998 this.field.on("autosize", this.el.sync, this.el, {delay:1});
30002 onSpecialKey : function(field, e)
30004 //Roo.log('editor onSpecialKey');
30005 if(this.completeOnEnter && e.getKey() == e.ENTER){
30007 this.completeEdit();
30010 // do not fire special key otherwise it might hide close the editor...
30011 if(e.getKey() == e.ENTER){
30014 if(this.cancelOnEsc && e.getKey() == e.ESC){
30018 this.fireEvent('specialkey', field, e);
30023 * Starts the editing process and shows the editor.
30024 * @param {String/HTMLElement/Element} el The element to edit
30025 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
30026 * to the innerHTML of el.
30028 startEdit : function(el, value){
30030 this.completeEdit();
30032 this.boundEl = Roo.get(el);
30033 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
30034 if(!this.rendered){
30035 this.render(this.parentEl || document.body);
30037 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
30040 this.startValue = v;
30041 this.field.setValue(v);
30043 var sz = this.boundEl.getSize();
30044 switch(this.autoSize){
30046 this.setSize(sz.width, "");
30049 this.setSize("", sz.height);
30052 this.setSize(sz.width, sz.height);
30055 this.el.alignTo(this.boundEl, this.alignment);
30056 this.editing = true;
30058 Roo.QuickTips.disable();
30064 * Sets the height and width of this editor.
30065 * @param {Number} width The new width
30066 * @param {Number} height The new height
30068 setSize : function(w, h){
30069 this.field.setSize(w, h);
30076 * Realigns the editor to the bound field based on the current alignment config value.
30078 realign : function(){
30079 this.el.alignTo(this.boundEl, this.alignment);
30083 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
30084 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
30086 completeEdit : function(remainVisible){
30090 var v = this.getValue();
30091 if(this.revertInvalid !== false && !this.field.isValid()){
30092 v = this.startValue;
30093 this.cancelEdit(true);
30095 if(String(v) === String(this.startValue) && this.ignoreNoChange){
30096 this.editing = false;
30100 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
30101 this.editing = false;
30102 if(this.updateEl && this.boundEl){
30103 this.boundEl.update(v);
30105 if(remainVisible !== true){
30108 this.fireEvent("complete", this, v, this.startValue);
30113 onShow : function(){
30115 if(this.hideEl !== false){
30116 this.boundEl.hide();
30119 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
30120 this.fixIEFocus = true;
30121 this.deferredFocus.defer(50, this);
30123 this.field.focus();
30125 this.fireEvent("startedit", this.boundEl, this.startValue);
30128 deferredFocus : function(){
30130 this.field.focus();
30135 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
30136 * reverted to the original starting value.
30137 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
30138 * cancel (defaults to false)
30140 cancelEdit : function(remainVisible){
30142 this.setValue(this.startValue);
30143 if(remainVisible !== true){
30150 onBlur : function(){
30151 if(this.allowBlur !== true && this.editing){
30152 this.completeEdit();
30157 onHide : function(){
30159 this.completeEdit();
30163 if(this.field.collapse){
30164 this.field.collapse();
30167 if(this.hideEl !== false){
30168 this.boundEl.show();
30171 Roo.QuickTips.enable();
30176 * Sets the data value of the editor
30177 * @param {Mixed} value Any valid value supported by the underlying field
30179 setValue : function(v){
30180 this.field.setValue(v);
30184 * Gets the data value of the editor
30185 * @return {Mixed} The data value
30187 getValue : function(){
30188 return this.field.getValue();
30192 * Ext JS Library 1.1.1
30193 * Copyright(c) 2006-2007, Ext JS, LLC.
30195 * Originally Released Under LGPL - original licence link has changed is not relivant.
30198 * <script type="text/javascript">
30202 * @class Roo.BasicDialog
30203 * @extends Roo.util.Observable
30204 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
30206 var dlg = new Roo.BasicDialog("my-dlg", {
30215 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30216 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30217 dlg.addButton('Cancel', dlg.hide, dlg);
30220 <b>A Dialog should always be a direct child of the body element.</b>
30221 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30222 * @cfg {String} title Default text to display in the title bar (defaults to null)
30223 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30224 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30225 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30226 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30227 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30228 * (defaults to null with no animation)
30229 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30230 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30231 * property for valid values (defaults to 'all')
30232 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30233 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30234 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30235 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30236 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30237 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30238 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30239 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30240 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30241 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30242 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30243 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30244 * draggable = true (defaults to false)
30245 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30246 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30247 * shadow (defaults to false)
30248 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30249 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30250 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30251 * @cfg {Array} buttons Array of buttons
30252 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30254 * Create a new BasicDialog.
30255 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30256 * @param {Object} config Configuration options
30258 Roo.BasicDialog = function(el, config){
30259 this.el = Roo.get(el);
30260 var dh = Roo.DomHelper;
30261 if(!this.el && config && config.autoCreate){
30262 if(typeof config.autoCreate == "object"){
30263 if(!config.autoCreate.id){
30264 config.autoCreate.id = el;
30266 this.el = dh.append(document.body,
30267 config.autoCreate, true);
30269 this.el = dh.append(document.body,
30270 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30274 el.setDisplayed(true);
30275 el.hide = this.hideAction;
30277 el.addClass("x-dlg");
30279 Roo.apply(this, config);
30281 this.proxy = el.createProxy("x-dlg-proxy");
30282 this.proxy.hide = this.hideAction;
30283 this.proxy.setOpacity(.5);
30287 el.setWidth(config.width);
30290 el.setHeight(config.height);
30292 this.size = el.getSize();
30293 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30294 this.xy = [config.x,config.y];
30296 this.xy = el.getCenterXY(true);
30298 /** The header element @type Roo.Element */
30299 this.header = el.child("> .x-dlg-hd");
30300 /** The body element @type Roo.Element */
30301 this.body = el.child("> .x-dlg-bd");
30302 /** The footer element @type Roo.Element */
30303 this.footer = el.child("> .x-dlg-ft");
30306 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30309 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30312 this.header.unselectable();
30314 this.header.update(this.title);
30316 // this element allows the dialog to be focused for keyboard event
30317 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30318 this.focusEl.swallowEvent("click", true);
30320 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30322 // wrap the body and footer for special rendering
30323 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30325 this.bwrap.dom.appendChild(this.footer.dom);
30328 this.bg = this.el.createChild({
30329 tag: "div", cls:"x-dlg-bg",
30330 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30332 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30335 if(this.autoScroll !== false && !this.autoTabs){
30336 this.body.setStyle("overflow", "auto");
30339 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30341 if(this.closable !== false){
30342 this.el.addClass("x-dlg-closable");
30343 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30344 this.close.on("click", this.closeClick, this);
30345 this.close.addClassOnOver("x-dlg-close-over");
30347 if(this.collapsible !== false){
30348 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30349 this.collapseBtn.on("click", this.collapseClick, this);
30350 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30351 this.header.on("dblclick", this.collapseClick, this);
30353 if(this.resizable !== false){
30354 this.el.addClass("x-dlg-resizable");
30355 this.resizer = new Roo.Resizable(el, {
30356 minWidth: this.minWidth || 80,
30357 minHeight:this.minHeight || 80,
30358 handles: this.resizeHandles || "all",
30361 this.resizer.on("beforeresize", this.beforeResize, this);
30362 this.resizer.on("resize", this.onResize, this);
30364 if(this.draggable !== false){
30365 el.addClass("x-dlg-draggable");
30366 if (!this.proxyDrag) {
30367 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30370 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30372 dd.setHandleElId(this.header.id);
30373 dd.endDrag = this.endMove.createDelegate(this);
30374 dd.startDrag = this.startMove.createDelegate(this);
30375 dd.onDrag = this.onDrag.createDelegate(this);
30380 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30381 this.mask.enableDisplayMode("block");
30383 this.el.addClass("x-dlg-modal");
30386 this.shadow = new Roo.Shadow({
30387 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30388 offset : this.shadowOffset
30391 this.shadowOffset = 0;
30393 if(Roo.useShims && this.shim !== false){
30394 this.shim = this.el.createShim();
30395 this.shim.hide = this.hideAction;
30403 if (this.buttons) {
30404 var bts= this.buttons;
30406 Roo.each(bts, function(b) {
30415 * Fires when a key is pressed
30416 * @param {Roo.BasicDialog} this
30417 * @param {Roo.EventObject} e
30422 * Fires when this dialog is moved by the user.
30423 * @param {Roo.BasicDialog} this
30424 * @param {Number} x The new page X
30425 * @param {Number} y The new page Y
30430 * Fires when this dialog is resized by the user.
30431 * @param {Roo.BasicDialog} this
30432 * @param {Number} width The new width
30433 * @param {Number} height The new height
30437 * @event beforehide
30438 * Fires before this dialog is hidden.
30439 * @param {Roo.BasicDialog} this
30441 "beforehide" : true,
30444 * Fires when this dialog is hidden.
30445 * @param {Roo.BasicDialog} this
30449 * @event beforeshow
30450 * Fires before this dialog is shown.
30451 * @param {Roo.BasicDialog} this
30453 "beforeshow" : true,
30456 * Fires when this dialog is shown.
30457 * @param {Roo.BasicDialog} this
30461 el.on("keydown", this.onKeyDown, this);
30462 el.on("mousedown", this.toFront, this);
30463 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30465 Roo.DialogManager.register(this);
30466 Roo.BasicDialog.superclass.constructor.call(this);
30469 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30470 shadowOffset: Roo.isIE ? 6 : 5,
30473 minButtonWidth: 75,
30474 defaultButton: null,
30475 buttonAlign: "right",
30480 * Sets the dialog title text
30481 * @param {String} text The title text to display
30482 * @return {Roo.BasicDialog} this
30484 setTitle : function(text){
30485 this.header.update(text);
30490 closeClick : function(){
30495 collapseClick : function(){
30496 this[this.collapsed ? "expand" : "collapse"]();
30500 * Collapses the dialog to its minimized state (only the title bar is visible).
30501 * Equivalent to the user clicking the collapse dialog button.
30503 collapse : function(){
30504 if(!this.collapsed){
30505 this.collapsed = true;
30506 this.el.addClass("x-dlg-collapsed");
30507 this.restoreHeight = this.el.getHeight();
30508 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30513 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30514 * clicking the expand dialog button.
30516 expand : function(){
30517 if(this.collapsed){
30518 this.collapsed = false;
30519 this.el.removeClass("x-dlg-collapsed");
30520 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30525 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30526 * @return {Roo.TabPanel} The tabs component
30528 initTabs : function(){
30529 var tabs = this.getTabs();
30530 while(tabs.getTab(0)){
30533 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30535 tabs.addTab(Roo.id(dom), dom.title);
30543 beforeResize : function(){
30544 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30548 onResize : function(){
30549 this.refreshSize();
30550 this.syncBodyHeight();
30551 this.adjustAssets();
30553 this.fireEvent("resize", this, this.size.width, this.size.height);
30557 onKeyDown : function(e){
30558 if(this.isVisible()){
30559 this.fireEvent("keydown", this, e);
30564 * Resizes the dialog.
30565 * @param {Number} width
30566 * @param {Number} height
30567 * @return {Roo.BasicDialog} this
30569 resizeTo : function(width, height){
30570 this.el.setSize(width, height);
30571 this.size = {width: width, height: height};
30572 this.syncBodyHeight();
30573 if(this.fixedcenter){
30576 if(this.isVisible()){
30577 this.constrainXY();
30578 this.adjustAssets();
30580 this.fireEvent("resize", this, width, height);
30586 * Resizes the dialog to fit the specified content size.
30587 * @param {Number} width
30588 * @param {Number} height
30589 * @return {Roo.BasicDialog} this
30591 setContentSize : function(w, h){
30592 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30593 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30594 //if(!this.el.isBorderBox()){
30595 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30596 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30599 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30600 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30602 this.resizeTo(w, h);
30607 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30608 * executed in response to a particular key being pressed while the dialog is active.
30609 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30610 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30611 * @param {Function} fn The function to call
30612 * @param {Object} scope (optional) The scope of the function
30613 * @return {Roo.BasicDialog} this
30615 addKeyListener : function(key, fn, scope){
30616 var keyCode, shift, ctrl, alt;
30617 if(typeof key == "object" && !(key instanceof Array)){
30618 keyCode = key["key"];
30619 shift = key["shift"];
30620 ctrl = key["ctrl"];
30625 var handler = function(dlg, e){
30626 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30627 var k = e.getKey();
30628 if(keyCode instanceof Array){
30629 for(var i = 0, len = keyCode.length; i < len; i++){
30630 if(keyCode[i] == k){
30631 fn.call(scope || window, dlg, k, e);
30637 fn.call(scope || window, dlg, k, e);
30642 this.on("keydown", handler);
30647 * Returns the TabPanel component (creates it if it doesn't exist).
30648 * Note: If you wish to simply check for the existence of tabs without creating them,
30649 * check for a null 'tabs' property.
30650 * @return {Roo.TabPanel} The tabs component
30652 getTabs : function(){
30654 this.el.addClass("x-dlg-auto-tabs");
30655 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30656 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30662 * Adds a button to the footer section of the dialog.
30663 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30664 * object or a valid Roo.DomHelper element config
30665 * @param {Function} handler The function called when the button is clicked
30666 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30667 * @return {Roo.Button} The new button
30669 addButton : function(config, handler, scope){
30670 var dh = Roo.DomHelper;
30672 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30674 if(!this.btnContainer){
30675 var tb = this.footer.createChild({
30677 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30678 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30680 this.btnContainer = tb.firstChild.firstChild.firstChild;
30685 minWidth: this.minButtonWidth,
30688 if(typeof config == "string"){
30689 bconfig.text = config;
30692 bconfig.dhconfig = config;
30694 Roo.apply(bconfig, config);
30698 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30699 bconfig.position = Math.max(0, bconfig.position);
30700 fc = this.btnContainer.childNodes[bconfig.position];
30703 var btn = new Roo.Button(
30705 this.btnContainer.insertBefore(document.createElement("td"),fc)
30706 : this.btnContainer.appendChild(document.createElement("td")),
30707 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30710 this.syncBodyHeight();
30713 * Array of all the buttons that have been added to this dialog via addButton
30718 this.buttons.push(btn);
30723 * Sets the default button to be focused when the dialog is displayed.
30724 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30725 * @return {Roo.BasicDialog} this
30727 setDefaultButton : function(btn){
30728 this.defaultButton = btn;
30733 getHeaderFooterHeight : function(safe){
30736 height += this.header.getHeight();
30739 var fm = this.footer.getMargins();
30740 height += (this.footer.getHeight()+fm.top+fm.bottom);
30742 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30743 height += this.centerBg.getPadding("tb");
30748 syncBodyHeight : function()
30750 var bd = this.body, // the text
30751 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30753 var height = this.size.height - this.getHeaderFooterHeight(false);
30754 bd.setHeight(height-bd.getMargins("tb"));
30755 var hh = this.header.getHeight();
30756 var h = this.size.height-hh;
30759 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30760 bw.setHeight(h-cb.getPadding("tb"));
30762 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30763 bd.setWidth(bw.getWidth(true));
30765 this.tabs.syncHeight();
30767 this.tabs.el.repaint();
30773 * Restores the previous state of the dialog if Roo.state is configured.
30774 * @return {Roo.BasicDialog} this
30776 restoreState : function(){
30777 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30778 if(box && box.width){
30779 this.xy = [box.x, box.y];
30780 this.resizeTo(box.width, box.height);
30786 beforeShow : function(){
30788 if(this.fixedcenter){
30789 this.xy = this.el.getCenterXY(true);
30792 Roo.get(document.body).addClass("x-body-masked");
30793 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30796 this.constrainXY();
30800 animShow : function(){
30801 var b = Roo.get(this.animateTarget).getBox();
30802 this.proxy.setSize(b.width, b.height);
30803 this.proxy.setLocation(b.x, b.y);
30805 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30806 true, .35, this.showEl.createDelegate(this));
30810 * Shows the dialog.
30811 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30812 * @return {Roo.BasicDialog} this
30814 show : function(animateTarget){
30815 if (this.fireEvent("beforeshow", this) === false){
30818 if(this.syncHeightBeforeShow){
30819 this.syncBodyHeight();
30820 }else if(this.firstShow){
30821 this.firstShow = false;
30822 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30824 this.animateTarget = animateTarget || this.animateTarget;
30825 if(!this.el.isVisible()){
30827 if(this.animateTarget && Roo.get(this.animateTarget)){
30837 showEl : function(){
30839 this.el.setXY(this.xy);
30841 this.adjustAssets(true);
30844 // IE peekaboo bug - fix found by Dave Fenwick
30848 this.fireEvent("show", this);
30852 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30853 * dialog itself will receive focus.
30855 focus : function(){
30856 if(this.defaultButton){
30857 this.defaultButton.focus();
30859 this.focusEl.focus();
30864 constrainXY : function(){
30865 if(this.constraintoviewport !== false){
30866 if(!this.viewSize){
30867 if(this.container){
30868 var s = this.container.getSize();
30869 this.viewSize = [s.width, s.height];
30871 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30874 var s = Roo.get(this.container||document).getScroll();
30876 var x = this.xy[0], y = this.xy[1];
30877 var w = this.size.width, h = this.size.height;
30878 var vw = this.viewSize[0], vh = this.viewSize[1];
30879 // only move it if it needs it
30881 // first validate right/bottom
30882 if(x + w > vw+s.left){
30886 if(y + h > vh+s.top){
30890 // then make sure top/left isn't negative
30902 if(this.isVisible()){
30903 this.el.setLocation(x, y);
30904 this.adjustAssets();
30911 onDrag : function(){
30912 if(!this.proxyDrag){
30913 this.xy = this.el.getXY();
30914 this.adjustAssets();
30919 adjustAssets : function(doShow){
30920 var x = this.xy[0], y = this.xy[1];
30921 var w = this.size.width, h = this.size.height;
30922 if(doShow === true){
30924 this.shadow.show(this.el);
30930 if(this.shadow && this.shadow.isVisible()){
30931 this.shadow.show(this.el);
30933 if(this.shim && this.shim.isVisible()){
30934 this.shim.setBounds(x, y, w, h);
30939 adjustViewport : function(w, h){
30941 w = Roo.lib.Dom.getViewWidth();
30942 h = Roo.lib.Dom.getViewHeight();
30945 this.viewSize = [w, h];
30946 if(this.modal && this.mask.isVisible()){
30947 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30948 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30950 if(this.isVisible()){
30951 this.constrainXY();
30956 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30957 * shadow, proxy, mask, etc.) Also removes all event listeners.
30958 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30960 destroy : function(removeEl){
30961 if(this.isVisible()){
30962 this.animateTarget = null;
30965 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30967 this.tabs.destroy(removeEl);
30980 for(var i = 0, len = this.buttons.length; i < len; i++){
30981 this.buttons[i].destroy();
30984 this.el.removeAllListeners();
30985 if(removeEl === true){
30986 this.el.update("");
30989 Roo.DialogManager.unregister(this);
30993 startMove : function(){
30994 if(this.proxyDrag){
30997 if(this.constraintoviewport !== false){
30998 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
31003 endMove : function(){
31004 if(!this.proxyDrag){
31005 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
31007 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
31010 this.refreshSize();
31011 this.adjustAssets();
31013 this.fireEvent("move", this, this.xy[0], this.xy[1]);
31017 * Brings this dialog to the front of any other visible dialogs
31018 * @return {Roo.BasicDialog} this
31020 toFront : function(){
31021 Roo.DialogManager.bringToFront(this);
31026 * Sends this dialog to the back (under) of any other visible dialogs
31027 * @return {Roo.BasicDialog} this
31029 toBack : function(){
31030 Roo.DialogManager.sendToBack(this);
31035 * Centers this dialog in the viewport
31036 * @return {Roo.BasicDialog} this
31038 center : function(){
31039 var xy = this.el.getCenterXY(true);
31040 this.moveTo(xy[0], xy[1]);
31045 * Moves the dialog's top-left corner to the specified point
31046 * @param {Number} x
31047 * @param {Number} y
31048 * @return {Roo.BasicDialog} this
31050 moveTo : function(x, y){
31052 if(this.isVisible()){
31053 this.el.setXY(this.xy);
31054 this.adjustAssets();
31060 * Aligns the dialog to the specified element
31061 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31062 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
31063 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31064 * @return {Roo.BasicDialog} this
31066 alignTo : function(element, position, offsets){
31067 this.xy = this.el.getAlignToXY(element, position, offsets);
31068 if(this.isVisible()){
31069 this.el.setXY(this.xy);
31070 this.adjustAssets();
31076 * Anchors an element to another element and realigns it when the window is resized.
31077 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31078 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
31079 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31080 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
31081 * is a number, it is used as the buffer delay (defaults to 50ms).
31082 * @return {Roo.BasicDialog} this
31084 anchorTo : function(el, alignment, offsets, monitorScroll){
31085 var action = function(){
31086 this.alignTo(el, alignment, offsets);
31088 Roo.EventManager.onWindowResize(action, this);
31089 var tm = typeof monitorScroll;
31090 if(tm != 'undefined'){
31091 Roo.EventManager.on(window, 'scroll', action, this,
31092 {buffer: tm == 'number' ? monitorScroll : 50});
31099 * Returns true if the dialog is visible
31100 * @return {Boolean}
31102 isVisible : function(){
31103 return this.el.isVisible();
31107 animHide : function(callback){
31108 var b = Roo.get(this.animateTarget).getBox();
31110 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
31112 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
31113 this.hideEl.createDelegate(this, [callback]));
31117 * Hides the dialog.
31118 * @param {Function} callback (optional) Function to call when the dialog is hidden
31119 * @return {Roo.BasicDialog} this
31121 hide : function(callback){
31122 if (this.fireEvent("beforehide", this) === false){
31126 this.shadow.hide();
31131 // sometimes animateTarget seems to get set.. causing problems...
31132 // this just double checks..
31133 if(this.animateTarget && Roo.get(this.animateTarget)) {
31134 this.animHide(callback);
31137 this.hideEl(callback);
31143 hideEl : function(callback){
31147 Roo.get(document.body).removeClass("x-body-masked");
31149 this.fireEvent("hide", this);
31150 if(typeof callback == "function"){
31156 hideAction : function(){
31157 this.setLeft("-10000px");
31158 this.setTop("-10000px");
31159 this.setStyle("visibility", "hidden");
31163 refreshSize : function(){
31164 this.size = this.el.getSize();
31165 this.xy = this.el.getXY();
31166 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
31170 // z-index is managed by the DialogManager and may be overwritten at any time
31171 setZIndex : function(index){
31173 this.mask.setStyle("z-index", index);
31176 this.shim.setStyle("z-index", ++index);
31179 this.shadow.setZIndex(++index);
31181 this.el.setStyle("z-index", ++index);
31183 this.proxy.setStyle("z-index", ++index);
31186 this.resizer.proxy.setStyle("z-index", ++index);
31189 this.lastZIndex = index;
31193 * Returns the element for this dialog
31194 * @return {Roo.Element} The underlying dialog Element
31196 getEl : function(){
31202 * @class Roo.DialogManager
31203 * Provides global access to BasicDialogs that have been created and
31204 * support for z-indexing (layering) multiple open dialogs.
31206 Roo.DialogManager = function(){
31208 var accessList = [];
31212 var sortDialogs = function(d1, d2){
31213 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31217 var orderDialogs = function(){
31218 accessList.sort(sortDialogs);
31219 var seed = Roo.DialogManager.zseed;
31220 for(var i = 0, len = accessList.length; i < len; i++){
31221 var dlg = accessList[i];
31223 dlg.setZIndex(seed + (i*10));
31230 * The starting z-index for BasicDialogs (defaults to 9000)
31231 * @type Number The z-index value
31236 register : function(dlg){
31237 list[dlg.id] = dlg;
31238 accessList.push(dlg);
31242 unregister : function(dlg){
31243 delete list[dlg.id];
31246 if(!accessList.indexOf){
31247 for( i = 0, len = accessList.length; i < len; i++){
31248 if(accessList[i] == dlg){
31249 accessList.splice(i, 1);
31254 i = accessList.indexOf(dlg);
31256 accessList.splice(i, 1);
31262 * Gets a registered dialog by id
31263 * @param {String/Object} id The id of the dialog or a dialog
31264 * @return {Roo.BasicDialog} this
31266 get : function(id){
31267 return typeof id == "object" ? id : list[id];
31271 * Brings the specified dialog to the front
31272 * @param {String/Object} dlg The id of the dialog or a dialog
31273 * @return {Roo.BasicDialog} this
31275 bringToFront : function(dlg){
31276 dlg = this.get(dlg);
31279 dlg._lastAccess = new Date().getTime();
31286 * Sends the specified dialog to the back
31287 * @param {String/Object} dlg The id of the dialog or a dialog
31288 * @return {Roo.BasicDialog} this
31290 sendToBack : function(dlg){
31291 dlg = this.get(dlg);
31292 dlg._lastAccess = -(new Date().getTime());
31298 * Hides all dialogs
31300 hideAll : function(){
31301 for(var id in list){
31302 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31311 * @class Roo.LayoutDialog
31312 * @extends Roo.BasicDialog
31313 * Dialog which provides adjustments for working with a layout in a Dialog.
31314 * Add your necessary layout config options to the dialog's config.<br>
31315 * Example usage (including a nested layout):
31318 dialog = new Roo.LayoutDialog("download-dlg", {
31327 // layout config merges with the dialog config
31329 tabPosition: "top",
31330 alwaysShowTabs: true
31333 dialog.addKeyListener(27, dialog.hide, dialog);
31334 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31335 dialog.addButton("Build It!", this.getDownload, this);
31337 // we can even add nested layouts
31338 var innerLayout = new Roo.BorderLayout("dl-inner", {
31348 innerLayout.beginUpdate();
31349 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31350 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31351 innerLayout.endUpdate(true);
31353 var layout = dialog.getLayout();
31354 layout.beginUpdate();
31355 layout.add("center", new Roo.ContentPanel("standard-panel",
31356 {title: "Download the Source", fitToFrame:true}));
31357 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31358 {title: "Build your own roo.js"}));
31359 layout.getRegion("center").showPanel(sp);
31360 layout.endUpdate();
31364 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31365 * @param {Object} config configuration options
31367 Roo.LayoutDialog = function(el, cfg){
31370 if (typeof(cfg) == 'undefined') {
31371 config = Roo.apply({}, el);
31372 // not sure why we use documentElement here.. - it should always be body.
31373 // IE7 borks horribly if we use documentElement.
31374 // webkit also does not like documentElement - it creates a body element...
31375 el = Roo.get( document.body || document.documentElement ).createChild();
31376 //config.autoCreate = true;
31380 config.autoTabs = false;
31381 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31382 this.body.setStyle({overflow:"hidden", position:"relative"});
31383 this.layout = new Roo.BorderLayout(this.body.dom, config);
31384 this.layout.monitorWindowResize = false;
31385 this.el.addClass("x-dlg-auto-layout");
31386 // fix case when center region overwrites center function
31387 this.center = Roo.BasicDialog.prototype.center;
31388 this.on("show", this.layout.layout, this.layout, true);
31389 if (config.items) {
31390 var xitems = config.items;
31391 delete config.items;
31392 Roo.each(xitems, this.addxtype, this);
31397 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31399 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31402 endUpdate : function(){
31403 this.layout.endUpdate();
31407 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31410 beginUpdate : function(){
31411 this.layout.beginUpdate();
31415 * Get the BorderLayout for this dialog
31416 * @return {Roo.BorderLayout}
31418 getLayout : function(){
31419 return this.layout;
31422 showEl : function(){
31423 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31425 this.layout.layout();
31430 // Use the syncHeightBeforeShow config option to control this automatically
31431 syncBodyHeight : function(){
31432 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31433 if(this.layout){this.layout.layout();}
31437 * Add an xtype element (actually adds to the layout.)
31438 * @return {Object} xdata xtype object data.
31441 addxtype : function(c) {
31442 return this.layout.addxtype(c);
31446 * Ext JS Library 1.1.1
31447 * Copyright(c) 2006-2007, Ext JS, LLC.
31449 * Originally Released Under LGPL - original licence link has changed is not relivant.
31452 * <script type="text/javascript">
31456 * @class Roo.MessageBox
31457 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31461 Roo.Msg.alert('Status', 'Changes saved successfully.');
31463 // Prompt for user data:
31464 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31466 // process text value...
31470 // Show a dialog using config options:
31472 title:'Save Changes?',
31473 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31474 buttons: Roo.Msg.YESNOCANCEL,
31481 Roo.MessageBox = function(){
31482 var dlg, opt, mask, waitTimer;
31483 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31484 var buttons, activeTextEl, bwidth;
31487 var handleButton = function(button){
31489 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31493 var handleHide = function(){
31494 if(opt && opt.cls){
31495 dlg.el.removeClass(opt.cls);
31498 Roo.TaskMgr.stop(waitTimer);
31504 var updateButtons = function(b){
31507 buttons["ok"].hide();
31508 buttons["cancel"].hide();
31509 buttons["yes"].hide();
31510 buttons["no"].hide();
31511 dlg.footer.dom.style.display = 'none';
31514 dlg.footer.dom.style.display = '';
31515 for(var k in buttons){
31516 if(typeof buttons[k] != "function"){
31519 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31520 width += buttons[k].el.getWidth()+15;
31530 var handleEsc = function(d, k, e){
31531 if(opt && opt.closable !== false){
31541 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31542 * @return {Roo.BasicDialog} The BasicDialog element
31544 getDialog : function(){
31546 dlg = new Roo.BasicDialog("x-msg-box", {
31551 constraintoviewport:false,
31553 collapsible : false,
31556 width:400, height:100,
31557 buttonAlign:"center",
31558 closeClick : function(){
31559 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31560 handleButton("no");
31562 handleButton("cancel");
31566 dlg.on("hide", handleHide);
31568 dlg.addKeyListener(27, handleEsc);
31570 var bt = this.buttonText;
31571 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31572 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31573 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31574 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31575 bodyEl = dlg.body.createChild({
31577 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>'
31579 msgEl = bodyEl.dom.firstChild;
31580 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31581 textboxEl.enableDisplayMode();
31582 textboxEl.addKeyListener([10,13], function(){
31583 if(dlg.isVisible() && opt && opt.buttons){
31584 if(opt.buttons.ok){
31585 handleButton("ok");
31586 }else if(opt.buttons.yes){
31587 handleButton("yes");
31591 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31592 textareaEl.enableDisplayMode();
31593 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31594 progressEl.enableDisplayMode();
31595 var pf = progressEl.dom.firstChild;
31597 pp = Roo.get(pf.firstChild);
31598 pp.setHeight(pf.offsetHeight);
31606 * Updates the message box body text
31607 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31608 * the XHTML-compliant non-breaking space character '&#160;')
31609 * @return {Roo.MessageBox} This message box
31611 updateText : function(text){
31612 if(!dlg.isVisible() && !opt.width){
31613 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31615 msgEl.innerHTML = text || ' ';
31617 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31618 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31620 Math.min(opt.width || cw , this.maxWidth),
31621 Math.max(opt.minWidth || this.minWidth, bwidth)
31624 activeTextEl.setWidth(w);
31626 if(dlg.isVisible()){
31627 dlg.fixedcenter = false;
31629 // to big, make it scroll. = But as usual stupid IE does not support
31632 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31633 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31634 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31636 bodyEl.dom.style.height = '';
31637 bodyEl.dom.style.overflowY = '';
31640 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31642 bodyEl.dom.style.overflowX = '';
31645 dlg.setContentSize(w, bodyEl.getHeight());
31646 if(dlg.isVisible()){
31647 dlg.fixedcenter = true;
31653 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31654 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31655 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31656 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31657 * @return {Roo.MessageBox} This message box
31659 updateProgress : function(value, text){
31661 this.updateText(text);
31663 if (pp) { // weird bug on my firefox - for some reason this is not defined
31664 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31670 * Returns true if the message box is currently displayed
31671 * @return {Boolean} True if the message box is visible, else false
31673 isVisible : function(){
31674 return dlg && dlg.isVisible();
31678 * Hides the message box if it is displayed
31681 if(this.isVisible()){
31687 * Displays a new message box, or reinitializes an existing message box, based on the config options
31688 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31689 * The following config object properties are supported:
31691 Property Type Description
31692 ---------- --------------- ------------------------------------------------------------------------------------
31693 animEl String/Element An id or Element from which the message box should animate as it opens and
31694 closes (defaults to undefined)
31695 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31696 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31697 closable Boolean False to hide the top-right close button (defaults to true). Note that
31698 progress and wait dialogs will ignore this property and always hide the
31699 close button as they can only be closed programmatically.
31700 cls String A custom CSS class to apply to the message box element
31701 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31702 displayed (defaults to 75)
31703 fn Function A callback function to execute after closing the dialog. The arguments to the
31704 function will be btn (the name of the button that was clicked, if applicable,
31705 e.g. "ok"), and text (the value of the active text field, if applicable).
31706 Progress and wait dialogs will ignore this option since they do not respond to
31707 user actions and can only be closed programmatically, so any required function
31708 should be called by the same code after it closes the dialog.
31709 icon String A CSS class that provides a background image to be used as an icon for
31710 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31711 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31712 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31713 modal Boolean False to allow user interaction with the page while the message box is
31714 displayed (defaults to true)
31715 msg String A string that will replace the existing message box body text (defaults
31716 to the XHTML-compliant non-breaking space character ' ')
31717 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31718 progress Boolean True to display a progress bar (defaults to false)
31719 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31720 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31721 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31722 title String The title text
31723 value String The string value to set into the active textbox element if displayed
31724 wait Boolean True to display a progress bar (defaults to false)
31725 width Number The width of the dialog in pixels
31732 msg: 'Please enter your address:',
31734 buttons: Roo.MessageBox.OKCANCEL,
31737 animEl: 'addAddressBtn'
31740 * @param {Object} config Configuration options
31741 * @return {Roo.MessageBox} This message box
31743 show : function(options)
31746 // this causes nightmares if you show one dialog after another
31747 // especially on callbacks..
31749 if(this.isVisible()){
31752 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31753 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31754 Roo.log("New Dialog Message:" + options.msg )
31755 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31756 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31759 var d = this.getDialog();
31761 d.setTitle(opt.title || " ");
31762 d.close.setDisplayed(opt.closable !== false);
31763 activeTextEl = textboxEl;
31764 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31769 textareaEl.setHeight(typeof opt.multiline == "number" ?
31770 opt.multiline : this.defaultTextHeight);
31771 activeTextEl = textareaEl;
31780 progressEl.setDisplayed(opt.progress === true);
31781 this.updateProgress(0);
31782 activeTextEl.dom.value = opt.value || "";
31784 dlg.setDefaultButton(activeTextEl);
31786 var bs = opt.buttons;
31789 db = buttons["ok"];
31790 }else if(bs && bs.yes){
31791 db = buttons["yes"];
31793 dlg.setDefaultButton(db);
31795 bwidth = updateButtons(opt.buttons);
31796 this.updateText(opt.msg);
31798 d.el.addClass(opt.cls);
31800 d.proxyDrag = opt.proxyDrag === true;
31801 d.modal = opt.modal !== false;
31802 d.mask = opt.modal !== false ? mask : false;
31803 if(!d.isVisible()){
31804 // force it to the end of the z-index stack so it gets a cursor in FF
31805 document.body.appendChild(dlg.el.dom);
31806 d.animateTarget = null;
31807 d.show(options.animEl);
31813 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31814 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31815 * and closing the message box when the process is complete.
31816 * @param {String} title The title bar text
31817 * @param {String} msg The message box body text
31818 * @return {Roo.MessageBox} This message box
31820 progress : function(title, msg){
31827 minWidth: this.minProgressWidth,
31834 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31835 * If a callback function is passed it will be called after the user clicks the button, and the
31836 * id of the button that was clicked will be passed as the only parameter to the callback
31837 * (could also be the top-right close button).
31838 * @param {String} title The title bar text
31839 * @param {String} msg The message box body text
31840 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31841 * @param {Object} scope (optional) The scope of the callback function
31842 * @return {Roo.MessageBox} This message box
31844 alert : function(title, msg, fn, scope){
31857 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31858 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31859 * You are responsible for closing the message box when the process is complete.
31860 * @param {String} msg The message box body text
31861 * @param {String} title (optional) The title bar text
31862 * @return {Roo.MessageBox} This message box
31864 wait : function(msg, title){
31875 waitTimer = Roo.TaskMgr.start({
31877 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31885 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31886 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31887 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31888 * @param {String} title The title bar text
31889 * @param {String} msg The message box body text
31890 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31891 * @param {Object} scope (optional) The scope of the callback function
31892 * @return {Roo.MessageBox} This message box
31894 confirm : function(title, msg, fn, scope){
31898 buttons: this.YESNO,
31907 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31908 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31909 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31910 * (could also be the top-right close button) and the text that was entered will be passed as the two
31911 * parameters to the callback.
31912 * @param {String} title The title bar text
31913 * @param {String} msg The message box body text
31914 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31915 * @param {Object} scope (optional) The scope of the callback function
31916 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31917 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31918 * @return {Roo.MessageBox} This message box
31920 prompt : function(title, msg, fn, scope, multiline){
31924 buttons: this.OKCANCEL,
31929 multiline: multiline,
31936 * Button config that displays a single OK button
31941 * Button config that displays Yes and No buttons
31944 YESNO : {yes:true, no:true},
31946 * Button config that displays OK and Cancel buttons
31949 OKCANCEL : {ok:true, cancel:true},
31951 * Button config that displays Yes, No and Cancel buttons
31954 YESNOCANCEL : {yes:true, no:true, cancel:true},
31957 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31960 defaultTextHeight : 75,
31962 * The maximum width in pixels of the message box (defaults to 600)
31967 * The minimum width in pixels of the message box (defaults to 100)
31972 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31973 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31976 minProgressWidth : 250,
31978 * An object containing the default button text strings that can be overriden for localized language support.
31979 * Supported properties are: ok, cancel, yes and no.
31980 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31993 * Shorthand for {@link Roo.MessageBox}
31995 Roo.Msg = Roo.MessageBox;/*
31997 * Ext JS Library 1.1.1
31998 * Copyright(c) 2006-2007, Ext JS, LLC.
32000 * Originally Released Under LGPL - original licence link has changed is not relivant.
32003 * <script type="text/javascript">
32006 * @class Roo.QuickTips
32007 * Provides attractive and customizable tooltips for any element.
32010 Roo.QuickTips = function(){
32011 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
32012 var ce, bd, xy, dd;
32013 var visible = false, disabled = true, inited = false;
32014 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
32016 var onOver = function(e){
32020 var t = e.getTarget();
32021 if(!t || t.nodeType !== 1 || t == document || t == document.body){
32024 if(ce && t == ce.el){
32025 clearTimeout(hideProc);
32028 if(t && tagEls[t.id]){
32029 tagEls[t.id].el = t;
32030 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
32033 var ttp, et = Roo.fly(t);
32034 var ns = cfg.namespace;
32035 if(tm.interceptTitles && t.title){
32038 t.removeAttribute("title");
32039 e.preventDefault();
32041 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
32044 showProc = show.defer(tm.showDelay, tm, [{
32047 width: et.getAttributeNS(ns, cfg.width),
32048 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
32049 title: et.getAttributeNS(ns, cfg.title),
32050 cls: et.getAttributeNS(ns, cfg.cls)
32055 var onOut = function(e){
32056 clearTimeout(showProc);
32057 var t = e.getTarget();
32058 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
32059 hideProc = setTimeout(hide, tm.hideDelay);
32063 var onMove = function(e){
32069 if(tm.trackMouse && ce){
32074 var onDown = function(e){
32075 clearTimeout(showProc);
32076 clearTimeout(hideProc);
32078 if(tm.hideOnClick){
32081 tm.enable.defer(100, tm);
32086 var getPad = function(){
32087 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
32090 var show = function(o){
32094 clearTimeout(dismissProc);
32096 if(removeCls){ // in case manually hidden
32097 el.removeClass(removeCls);
32101 el.addClass(ce.cls);
32102 removeCls = ce.cls;
32105 tipTitle.update(ce.title);
32108 tipTitle.update('');
32111 el.dom.style.width = tm.maxWidth+'px';
32112 //tipBody.dom.style.width = '';
32113 tipBodyText.update(o.text);
32114 var p = getPad(), w = ce.width;
32116 var td = tipBodyText.dom;
32117 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
32118 if(aw > tm.maxWidth){
32120 }else if(aw < tm.minWidth){
32126 //tipBody.setWidth(w);
32127 el.setWidth(parseInt(w, 10) + p);
32128 if(ce.autoHide === false){
32129 close.setDisplayed(true);
32134 close.setDisplayed(false);
32140 el.avoidY = xy[1]-18;
32145 el.setStyle("visibility", "visible");
32146 el.fadeIn({callback: afterShow});
32152 var afterShow = function(){
32156 if(tm.autoDismiss && ce.autoHide !== false){
32157 dismissProc = setTimeout(hide, tm.autoDismissDelay);
32162 var hide = function(noanim){
32163 clearTimeout(dismissProc);
32164 clearTimeout(hideProc);
32166 if(el.isVisible()){
32168 if(noanim !== true && tm.animate){
32169 el.fadeOut({callback: afterHide});
32176 var afterHide = function(){
32179 el.removeClass(removeCls);
32186 * @cfg {Number} minWidth
32187 * The minimum width of the quick tip (defaults to 40)
32191 * @cfg {Number} maxWidth
32192 * The maximum width of the quick tip (defaults to 300)
32196 * @cfg {Boolean} interceptTitles
32197 * True to automatically use the element's DOM title value if available (defaults to false)
32199 interceptTitles : false,
32201 * @cfg {Boolean} trackMouse
32202 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
32204 trackMouse : false,
32206 * @cfg {Boolean} hideOnClick
32207 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32209 hideOnClick : true,
32211 * @cfg {Number} showDelay
32212 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32216 * @cfg {Number} hideDelay
32217 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32221 * @cfg {Boolean} autoHide
32222 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32223 * Used in conjunction with hideDelay.
32228 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32229 * (defaults to true). Used in conjunction with autoDismissDelay.
32231 autoDismiss : true,
32234 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32236 autoDismissDelay : 5000,
32238 * @cfg {Boolean} animate
32239 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32244 * @cfg {String} title
32245 * Title text to display (defaults to ''). This can be any valid HTML markup.
32249 * @cfg {String} text
32250 * Body text to display (defaults to ''). This can be any valid HTML markup.
32254 * @cfg {String} cls
32255 * A CSS class to apply to the base quick tip element (defaults to '').
32259 * @cfg {Number} width
32260 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32261 * minWidth or maxWidth.
32266 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32267 * or display QuickTips in a page.
32270 tm = Roo.QuickTips;
32271 cfg = tm.tagConfig;
32273 if(!Roo.isReady){ // allow calling of init() before onReady
32274 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32277 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32278 el.fxDefaults = {stopFx: true};
32279 // maximum custom styling
32280 //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>');
32281 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>');
32282 tipTitle = el.child('h3');
32283 tipTitle.enableDisplayMode("block");
32284 tipBody = el.child('div.x-tip-bd');
32285 tipBodyText = el.child('div.x-tip-bd-inner');
32286 //bdLeft = el.child('div.x-tip-bd-left');
32287 //bdRight = el.child('div.x-tip-bd-right');
32288 close = el.child('div.x-tip-close');
32289 close.enableDisplayMode("block");
32290 close.on("click", hide);
32291 var d = Roo.get(document);
32292 d.on("mousedown", onDown);
32293 d.on("mouseover", onOver);
32294 d.on("mouseout", onOut);
32295 d.on("mousemove", onMove);
32296 esc = d.addKeyListener(27, hide);
32299 dd = el.initDD("default", null, {
32300 onDrag : function(){
32304 dd.setHandleElId(tipTitle.id);
32313 * Configures a new quick tip instance and assigns it to a target element. The following config options
32316 Property Type Description
32317 ---------- --------------------- ------------------------------------------------------------------------
32318 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32320 * @param {Object} config The config object
32322 register : function(config){
32323 var cs = config instanceof Array ? config : arguments;
32324 for(var i = 0, len = cs.length; i < len; i++) {
32326 var target = c.target;
32328 if(target instanceof Array){
32329 for(var j = 0, jlen = target.length; j < jlen; j++){
32330 tagEls[target[j]] = c;
32333 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32340 * Removes this quick tip from its element and destroys it.
32341 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32343 unregister : function(el){
32344 delete tagEls[Roo.id(el)];
32348 * Enable this quick tip.
32350 enable : function(){
32351 if(inited && disabled){
32353 if(locks.length < 1){
32360 * Disable this quick tip.
32362 disable : function(){
32364 clearTimeout(showProc);
32365 clearTimeout(hideProc);
32366 clearTimeout(dismissProc);
32374 * Returns true if the quick tip is enabled, else false.
32376 isEnabled : function(){
32383 attribute : "qtip",
32393 // backwards compat
32394 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32396 * Ext JS Library 1.1.1
32397 * Copyright(c) 2006-2007, Ext JS, LLC.
32399 * Originally Released Under LGPL - original licence link has changed is not relivant.
32402 * <script type="text/javascript">
32407 * @class Roo.tree.TreePanel
32408 * @extends Roo.data.Tree
32410 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32411 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32412 * @cfg {Boolean} enableDD true to enable drag and drop
32413 * @cfg {Boolean} enableDrag true to enable just drag
32414 * @cfg {Boolean} enableDrop true to enable just drop
32415 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32416 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32417 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32418 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32419 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32420 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32421 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32422 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32423 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32424 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32425 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32426 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32427 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32428 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32429 * @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>
32430 * @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>
32433 * @param {String/HTMLElement/Element} el The container element
32434 * @param {Object} config
32436 Roo.tree.TreePanel = function(el, config){
32438 var loader = false;
32440 root = config.root;
32441 delete config.root;
32443 if (config.loader) {
32444 loader = config.loader;
32445 delete config.loader;
32448 Roo.apply(this, config);
32449 Roo.tree.TreePanel.superclass.constructor.call(this);
32450 this.el = Roo.get(el);
32451 this.el.addClass('x-tree');
32452 //console.log(root);
32454 this.setRootNode( Roo.factory(root, Roo.tree));
32457 this.loader = Roo.factory(loader, Roo.tree);
32460 * Read-only. The id of the container element becomes this TreePanel's id.
32462 this.id = this.el.id;
32465 * @event beforeload
32466 * Fires before a node is loaded, return false to cancel
32467 * @param {Node} node The node being loaded
32469 "beforeload" : true,
32472 * Fires when a node is loaded
32473 * @param {Node} node The node that was loaded
32477 * @event textchange
32478 * Fires when the text for a node is changed
32479 * @param {Node} node The node
32480 * @param {String} text The new text
32481 * @param {String} oldText The old text
32483 "textchange" : true,
32485 * @event beforeexpand
32486 * Fires before a node is expanded, return false to cancel.
32487 * @param {Node} node The node
32488 * @param {Boolean} deep
32489 * @param {Boolean} anim
32491 "beforeexpand" : true,
32493 * @event beforecollapse
32494 * Fires before a node is collapsed, return false to cancel.
32495 * @param {Node} node The node
32496 * @param {Boolean} deep
32497 * @param {Boolean} anim
32499 "beforecollapse" : true,
32502 * Fires when a node is expanded
32503 * @param {Node} node The node
32507 * @event disabledchange
32508 * Fires when the disabled status of a node changes
32509 * @param {Node} node The node
32510 * @param {Boolean} disabled
32512 "disabledchange" : true,
32515 * Fires when a node is collapsed
32516 * @param {Node} node The node
32520 * @event beforeclick
32521 * Fires before click processing on a node. Return false to cancel the default action.
32522 * @param {Node} node The node
32523 * @param {Roo.EventObject} e The event object
32525 "beforeclick":true,
32527 * @event checkchange
32528 * Fires when a node with a checkbox's checked property changes
32529 * @param {Node} this This node
32530 * @param {Boolean} checked
32532 "checkchange":true,
32535 * Fires when a node is clicked
32536 * @param {Node} node The node
32537 * @param {Roo.EventObject} e The event object
32542 * Fires when a node is double clicked
32543 * @param {Node} node The node
32544 * @param {Roo.EventObject} e The event object
32548 * @event contextmenu
32549 * Fires when a node is right clicked
32550 * @param {Node} node The node
32551 * @param {Roo.EventObject} e The event object
32553 "contextmenu":true,
32555 * @event beforechildrenrendered
32556 * Fires right before the child nodes for a node are rendered
32557 * @param {Node} node The node
32559 "beforechildrenrendered":true,
32562 * Fires when a node starts being dragged
32563 * @param {Roo.tree.TreePanel} this
32564 * @param {Roo.tree.TreeNode} node
32565 * @param {event} e The raw browser event
32567 "startdrag" : true,
32570 * Fires when a drag operation is complete
32571 * @param {Roo.tree.TreePanel} this
32572 * @param {Roo.tree.TreeNode} node
32573 * @param {event} e The raw browser event
32578 * Fires when a dragged node is dropped on a valid DD target
32579 * @param {Roo.tree.TreePanel} this
32580 * @param {Roo.tree.TreeNode} node
32581 * @param {DD} dd The dd it was dropped on
32582 * @param {event} e The raw browser event
32586 * @event beforenodedrop
32587 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32588 * passed to handlers has the following properties:<br />
32589 * <ul style="padding:5px;padding-left:16px;">
32590 * <li>tree - The TreePanel</li>
32591 * <li>target - The node being targeted for the drop</li>
32592 * <li>data - The drag data from the drag source</li>
32593 * <li>point - The point of the drop - append, above or below</li>
32594 * <li>source - The drag source</li>
32595 * <li>rawEvent - Raw mouse event</li>
32596 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32597 * to be inserted by setting them on this object.</li>
32598 * <li>cancel - Set this to true to cancel the drop.</li>
32600 * @param {Object} dropEvent
32602 "beforenodedrop" : true,
32605 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32606 * passed to handlers has the following properties:<br />
32607 * <ul style="padding:5px;padding-left:16px;">
32608 * <li>tree - The TreePanel</li>
32609 * <li>target - The node being targeted for the drop</li>
32610 * <li>data - The drag data from the drag source</li>
32611 * <li>point - The point of the drop - append, above or below</li>
32612 * <li>source - The drag source</li>
32613 * <li>rawEvent - Raw mouse event</li>
32614 * <li>dropNode - Dropped node(s).</li>
32616 * @param {Object} dropEvent
32620 * @event nodedragover
32621 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32622 * passed to handlers has the following properties:<br />
32623 * <ul style="padding:5px;padding-left:16px;">
32624 * <li>tree - The TreePanel</li>
32625 * <li>target - The node being targeted for the drop</li>
32626 * <li>data - The drag data from the drag source</li>
32627 * <li>point - The point of the drop - append, above or below</li>
32628 * <li>source - The drag source</li>
32629 * <li>rawEvent - Raw mouse event</li>
32630 * <li>dropNode - Drop node(s) provided by the source.</li>
32631 * <li>cancel - Set this to true to signal drop not allowed.</li>
32633 * @param {Object} dragOverEvent
32635 "nodedragover" : true
32638 if(this.singleExpand){
32639 this.on("beforeexpand", this.restrictExpand, this);
32642 this.editor.tree = this;
32643 this.editor = Roo.factory(this.editor, Roo.tree);
32646 if (this.selModel) {
32647 this.selModel = Roo.factory(this.selModel, Roo.tree);
32651 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32652 rootVisible : true,
32653 animate: Roo.enableFx,
32656 hlDrop : Roo.enableFx,
32660 rendererTip: false,
32662 restrictExpand : function(node){
32663 var p = node.parentNode;
32665 if(p.expandedChild && p.expandedChild.parentNode == p){
32666 p.expandedChild.collapse();
32668 p.expandedChild = node;
32672 // private override
32673 setRootNode : function(node){
32674 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32675 if(!this.rootVisible){
32676 node.ui = new Roo.tree.RootTreeNodeUI(node);
32682 * Returns the container element for this TreePanel
32684 getEl : function(){
32689 * Returns the default TreeLoader for this TreePanel
32691 getLoader : function(){
32692 return this.loader;
32698 expandAll : function(){
32699 this.root.expand(true);
32703 * Collapse all nodes
32705 collapseAll : function(){
32706 this.root.collapse(true);
32710 * Returns the selection model used by this TreePanel
32712 getSelectionModel : function(){
32713 if(!this.selModel){
32714 this.selModel = new Roo.tree.DefaultSelectionModel();
32716 return this.selModel;
32720 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32721 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32722 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32725 getChecked : function(a, startNode){
32726 startNode = startNode || this.root;
32728 var f = function(){
32729 if(this.attributes.checked){
32730 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32733 startNode.cascade(f);
32738 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32739 * @param {String} path
32740 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32741 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32742 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32744 expandPath : function(path, attr, callback){
32745 attr = attr || "id";
32746 var keys = path.split(this.pathSeparator);
32747 var curNode = this.root;
32748 if(curNode.attributes[attr] != keys[1]){ // invalid root
32750 callback(false, null);
32755 var f = function(){
32756 if(++index == keys.length){
32758 callback(true, curNode);
32762 var c = curNode.findChild(attr, keys[index]);
32765 callback(false, curNode);
32770 c.expand(false, false, f);
32772 curNode.expand(false, false, f);
32776 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32777 * @param {String} path
32778 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32779 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32780 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32782 selectPath : function(path, attr, callback){
32783 attr = attr || "id";
32784 var keys = path.split(this.pathSeparator);
32785 var v = keys.pop();
32786 if(keys.length > 0){
32787 var f = function(success, node){
32788 if(success && node){
32789 var n = node.findChild(attr, v);
32795 }else if(callback){
32796 callback(false, n);
32800 callback(false, n);
32804 this.expandPath(keys.join(this.pathSeparator), attr, f);
32806 this.root.select();
32808 callback(true, this.root);
32813 getTreeEl : function(){
32818 * Trigger rendering of this TreePanel
32820 render : function(){
32821 if (this.innerCt) {
32822 return this; // stop it rendering more than once!!
32825 this.innerCt = this.el.createChild({tag:"ul",
32826 cls:"x-tree-root-ct " +
32827 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32829 if(this.containerScroll){
32830 Roo.dd.ScrollManager.register(this.el);
32832 if((this.enableDD || this.enableDrop) && !this.dropZone){
32834 * The dropZone used by this tree if drop is enabled
32835 * @type Roo.tree.TreeDropZone
32837 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32838 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32841 if((this.enableDD || this.enableDrag) && !this.dragZone){
32843 * The dragZone used by this tree if drag is enabled
32844 * @type Roo.tree.TreeDragZone
32846 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32847 ddGroup: this.ddGroup || "TreeDD",
32848 scroll: this.ddScroll
32851 this.getSelectionModel().init(this);
32853 Roo.log("ROOT not set in tree");
32856 this.root.render();
32857 if(!this.rootVisible){
32858 this.root.renderChildren();
32864 * Ext JS Library 1.1.1
32865 * Copyright(c) 2006-2007, Ext JS, LLC.
32867 * Originally Released Under LGPL - original licence link has changed is not relivant.
32870 * <script type="text/javascript">
32875 * @class Roo.tree.DefaultSelectionModel
32876 * @extends Roo.util.Observable
32877 * The default single selection for a TreePanel.
32878 * @param {Object} cfg Configuration
32880 Roo.tree.DefaultSelectionModel = function(cfg){
32881 this.selNode = null;
32887 * @event selectionchange
32888 * Fires when the selected node changes
32889 * @param {DefaultSelectionModel} this
32890 * @param {TreeNode} node the new selection
32892 "selectionchange" : true,
32895 * @event beforeselect
32896 * Fires before the selected node changes, return false to cancel the change
32897 * @param {DefaultSelectionModel} this
32898 * @param {TreeNode} node the new selection
32899 * @param {TreeNode} node the old selection
32901 "beforeselect" : true
32904 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32907 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32908 init : function(tree){
32910 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32911 tree.on("click", this.onNodeClick, this);
32914 onNodeClick : function(node, e){
32915 if (e.ctrlKey && this.selNode == node) {
32916 this.unselect(node);
32924 * @param {TreeNode} node The node to select
32925 * @return {TreeNode} The selected node
32927 select : function(node){
32928 var last = this.selNode;
32929 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32931 last.ui.onSelectedChange(false);
32933 this.selNode = node;
32934 node.ui.onSelectedChange(true);
32935 this.fireEvent("selectionchange", this, node, last);
32942 * @param {TreeNode} node The node to unselect
32944 unselect : function(node){
32945 if(this.selNode == node){
32946 this.clearSelections();
32951 * Clear all selections
32953 clearSelections : function(){
32954 var n = this.selNode;
32956 n.ui.onSelectedChange(false);
32957 this.selNode = null;
32958 this.fireEvent("selectionchange", this, null);
32964 * Get the selected node
32965 * @return {TreeNode} The selected node
32967 getSelectedNode : function(){
32968 return this.selNode;
32972 * Returns true if the node is selected
32973 * @param {TreeNode} node The node to check
32974 * @return {Boolean}
32976 isSelected : function(node){
32977 return this.selNode == node;
32981 * Selects the node above the selected node in the tree, intelligently walking the nodes
32982 * @return TreeNode The new selection
32984 selectPrevious : function(){
32985 var s = this.selNode || this.lastSelNode;
32989 var ps = s.previousSibling;
32991 if(!ps.isExpanded() || ps.childNodes.length < 1){
32992 return this.select(ps);
32994 var lc = ps.lastChild;
32995 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32998 return this.select(lc);
33000 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
33001 return this.select(s.parentNode);
33007 * Selects the node above the selected node in the tree, intelligently walking the nodes
33008 * @return TreeNode The new selection
33010 selectNext : function(){
33011 var s = this.selNode || this.lastSelNode;
33015 if(s.firstChild && s.isExpanded()){
33016 return this.select(s.firstChild);
33017 }else if(s.nextSibling){
33018 return this.select(s.nextSibling);
33019 }else if(s.parentNode){
33021 s.parentNode.bubble(function(){
33022 if(this.nextSibling){
33023 newS = this.getOwnerTree().selModel.select(this.nextSibling);
33032 onKeyDown : function(e){
33033 var s = this.selNode || this.lastSelNode;
33034 // undesirable, but required
33039 var k = e.getKey();
33047 this.selectPrevious();
33050 e.preventDefault();
33051 if(s.hasChildNodes()){
33052 if(!s.isExpanded()){
33054 }else if(s.firstChild){
33055 this.select(s.firstChild, e);
33060 e.preventDefault();
33061 if(s.hasChildNodes() && s.isExpanded()){
33063 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
33064 this.select(s.parentNode, e);
33072 * @class Roo.tree.MultiSelectionModel
33073 * @extends Roo.util.Observable
33074 * Multi selection for a TreePanel.
33075 * @param {Object} cfg Configuration
33077 Roo.tree.MultiSelectionModel = function(){
33078 this.selNodes = [];
33082 * @event selectionchange
33083 * Fires when the selected nodes change
33084 * @param {MultiSelectionModel} this
33085 * @param {Array} nodes Array of the selected nodes
33087 "selectionchange" : true
33089 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
33093 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
33094 init : function(tree){
33096 tree.getTreeEl().on("keydown", this.onKeyDown, this);
33097 tree.on("click", this.onNodeClick, this);
33100 onNodeClick : function(node, e){
33101 this.select(node, e, e.ctrlKey);
33106 * @param {TreeNode} node The node to select
33107 * @param {EventObject} e (optional) An event associated with the selection
33108 * @param {Boolean} keepExisting True to retain existing selections
33109 * @return {TreeNode} The selected node
33111 select : function(node, e, keepExisting){
33112 if(keepExisting !== true){
33113 this.clearSelections(true);
33115 if(this.isSelected(node)){
33116 this.lastSelNode = node;
33119 this.selNodes.push(node);
33120 this.selMap[node.id] = node;
33121 this.lastSelNode = node;
33122 node.ui.onSelectedChange(true);
33123 this.fireEvent("selectionchange", this, this.selNodes);
33129 * @param {TreeNode} node The node to unselect
33131 unselect : function(node){
33132 if(this.selMap[node.id]){
33133 node.ui.onSelectedChange(false);
33134 var sn = this.selNodes;
33137 index = sn.indexOf(node);
33139 for(var i = 0, len = sn.length; i < len; i++){
33147 this.selNodes.splice(index, 1);
33149 delete this.selMap[node.id];
33150 this.fireEvent("selectionchange", this, this.selNodes);
33155 * Clear all selections
33157 clearSelections : function(suppressEvent){
33158 var sn = this.selNodes;
33160 for(var i = 0, len = sn.length; i < len; i++){
33161 sn[i].ui.onSelectedChange(false);
33163 this.selNodes = [];
33165 if(suppressEvent !== true){
33166 this.fireEvent("selectionchange", this, this.selNodes);
33172 * Returns true if the node is selected
33173 * @param {TreeNode} node The node to check
33174 * @return {Boolean}
33176 isSelected : function(node){
33177 return this.selMap[node.id] ? true : false;
33181 * Returns an array of the selected nodes
33184 getSelectedNodes : function(){
33185 return this.selNodes;
33188 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
33190 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
33192 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
33195 * Ext JS Library 1.1.1
33196 * Copyright(c) 2006-2007, Ext JS, LLC.
33198 * Originally Released Under LGPL - original licence link has changed is not relivant.
33201 * <script type="text/javascript">
33205 * @class Roo.tree.TreeNode
33206 * @extends Roo.data.Node
33207 * @cfg {String} text The text for this node
33208 * @cfg {Boolean} expanded true to start the node expanded
33209 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33210 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33211 * @cfg {Boolean} disabled true to start the node disabled
33212 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33213 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33214 * @cfg {String} cls A css class to be added to the node
33215 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33216 * @cfg {String} href URL of the link used for the node (defaults to #)
33217 * @cfg {String} hrefTarget target frame for the link
33218 * @cfg {String} qtip An Ext QuickTip for the node
33219 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33220 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33221 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33222 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33223 * (defaults to undefined with no checkbox rendered)
33225 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33227 Roo.tree.TreeNode = function(attributes){
33228 attributes = attributes || {};
33229 if(typeof attributes == "string"){
33230 attributes = {text: attributes};
33232 this.childrenRendered = false;
33233 this.rendered = false;
33234 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33235 this.expanded = attributes.expanded === true;
33236 this.isTarget = attributes.isTarget !== false;
33237 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33238 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33241 * Read-only. The text for this node. To change it use setText().
33244 this.text = attributes.text;
33246 * True if this node is disabled.
33249 this.disabled = attributes.disabled === true;
33253 * @event textchange
33254 * Fires when the text for this node is changed
33255 * @param {Node} this This node
33256 * @param {String} text The new text
33257 * @param {String} oldText The old text
33259 "textchange" : true,
33261 * @event beforeexpand
33262 * Fires before this node is expanded, return false to cancel.
33263 * @param {Node} this This node
33264 * @param {Boolean} deep
33265 * @param {Boolean} anim
33267 "beforeexpand" : true,
33269 * @event beforecollapse
33270 * Fires before this node is collapsed, return false to cancel.
33271 * @param {Node} this This node
33272 * @param {Boolean} deep
33273 * @param {Boolean} anim
33275 "beforecollapse" : true,
33278 * Fires when this node is expanded
33279 * @param {Node} this This node
33283 * @event disabledchange
33284 * Fires when the disabled status of this node changes
33285 * @param {Node} this This node
33286 * @param {Boolean} disabled
33288 "disabledchange" : true,
33291 * Fires when this node is collapsed
33292 * @param {Node} this This node
33296 * @event beforeclick
33297 * Fires before click processing. Return false to cancel the default action.
33298 * @param {Node} this This node
33299 * @param {Roo.EventObject} e The event object
33301 "beforeclick":true,
33303 * @event checkchange
33304 * Fires when a node with a checkbox's checked property changes
33305 * @param {Node} this This node
33306 * @param {Boolean} checked
33308 "checkchange":true,
33311 * Fires when this node is clicked
33312 * @param {Node} this This node
33313 * @param {Roo.EventObject} e The event object
33318 * Fires when this node is double clicked
33319 * @param {Node} this This node
33320 * @param {Roo.EventObject} e The event object
33324 * @event contextmenu
33325 * Fires when this node is right clicked
33326 * @param {Node} this This node
33327 * @param {Roo.EventObject} e The event object
33329 "contextmenu":true,
33331 * @event beforechildrenrendered
33332 * Fires right before the child nodes for this node are rendered
33333 * @param {Node} this This node
33335 "beforechildrenrendered":true
33338 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33341 * Read-only. The UI for this node
33344 this.ui = new uiClass(this);
33346 // finally support items[]
33347 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33352 Roo.each(this.attributes.items, function(c) {
33353 this.appendChild(Roo.factory(c,Roo.Tree));
33355 delete this.attributes.items;
33360 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33361 preventHScroll: true,
33363 * Returns true if this node is expanded
33364 * @return {Boolean}
33366 isExpanded : function(){
33367 return this.expanded;
33371 * Returns the UI object for this node
33372 * @return {TreeNodeUI}
33374 getUI : function(){
33378 // private override
33379 setFirstChild : function(node){
33380 var of = this.firstChild;
33381 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33382 if(this.childrenRendered && of && node != of){
33383 of.renderIndent(true, true);
33386 this.renderIndent(true, true);
33390 // private override
33391 setLastChild : function(node){
33392 var ol = this.lastChild;
33393 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33394 if(this.childrenRendered && ol && node != ol){
33395 ol.renderIndent(true, true);
33398 this.renderIndent(true, true);
33402 // these methods are overridden to provide lazy rendering support
33403 // private override
33404 appendChild : function()
33406 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33407 if(node && this.childrenRendered){
33410 this.ui.updateExpandIcon();
33414 // private override
33415 removeChild : function(node){
33416 this.ownerTree.getSelectionModel().unselect(node);
33417 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33418 // if it's been rendered remove dom node
33419 if(this.childrenRendered){
33422 if(this.childNodes.length < 1){
33423 this.collapse(false, false);
33425 this.ui.updateExpandIcon();
33427 if(!this.firstChild) {
33428 this.childrenRendered = false;
33433 // private override
33434 insertBefore : function(node, refNode){
33435 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33436 if(newNode && refNode && this.childrenRendered){
33439 this.ui.updateExpandIcon();
33444 * Sets the text for this node
33445 * @param {String} text
33447 setText : function(text){
33448 var oldText = this.text;
33450 this.attributes.text = text;
33451 if(this.rendered){ // event without subscribing
33452 this.ui.onTextChange(this, text, oldText);
33454 this.fireEvent("textchange", this, text, oldText);
33458 * Triggers selection of this node
33460 select : function(){
33461 this.getOwnerTree().getSelectionModel().select(this);
33465 * Triggers deselection of this node
33467 unselect : function(){
33468 this.getOwnerTree().getSelectionModel().unselect(this);
33472 * Returns true if this node is selected
33473 * @return {Boolean}
33475 isSelected : function(){
33476 return this.getOwnerTree().getSelectionModel().isSelected(this);
33480 * Expand this node.
33481 * @param {Boolean} deep (optional) True to expand all children as well
33482 * @param {Boolean} anim (optional) false to cancel the default animation
33483 * @param {Function} callback (optional) A callback to be called when
33484 * expanding this node completes (does not wait for deep expand to complete).
33485 * Called with 1 parameter, this node.
33487 expand : function(deep, anim, callback){
33488 if(!this.expanded){
33489 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33492 if(!this.childrenRendered){
33493 this.renderChildren();
33495 this.expanded = true;
33496 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33497 this.ui.animExpand(function(){
33498 this.fireEvent("expand", this);
33499 if(typeof callback == "function"){
33503 this.expandChildNodes(true);
33505 }.createDelegate(this));
33509 this.fireEvent("expand", this);
33510 if(typeof callback == "function"){
33515 if(typeof callback == "function"){
33520 this.expandChildNodes(true);
33524 isHiddenRoot : function(){
33525 return this.isRoot && !this.getOwnerTree().rootVisible;
33529 * Collapse this node.
33530 * @param {Boolean} deep (optional) True to collapse all children as well
33531 * @param {Boolean} anim (optional) false to cancel the default animation
33533 collapse : function(deep, anim){
33534 if(this.expanded && !this.isHiddenRoot()){
33535 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33538 this.expanded = false;
33539 if((this.getOwnerTree().animate && anim !== false) || anim){
33540 this.ui.animCollapse(function(){
33541 this.fireEvent("collapse", this);
33543 this.collapseChildNodes(true);
33545 }.createDelegate(this));
33548 this.ui.collapse();
33549 this.fireEvent("collapse", this);
33553 var cs = this.childNodes;
33554 for(var i = 0, len = cs.length; i < len; i++) {
33555 cs[i].collapse(true, false);
33561 delayedExpand : function(delay){
33562 if(!this.expandProcId){
33563 this.expandProcId = this.expand.defer(delay, this);
33568 cancelExpand : function(){
33569 if(this.expandProcId){
33570 clearTimeout(this.expandProcId);
33572 this.expandProcId = false;
33576 * Toggles expanded/collapsed state of the node
33578 toggle : function(){
33587 * Ensures all parent nodes are expanded
33589 ensureVisible : function(callback){
33590 var tree = this.getOwnerTree();
33591 tree.expandPath(this.parentNode.getPath(), false, function(){
33592 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33593 Roo.callback(callback);
33594 }.createDelegate(this));
33598 * Expand all child nodes
33599 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33601 expandChildNodes : function(deep){
33602 var cs = this.childNodes;
33603 for(var i = 0, len = cs.length; i < len; i++) {
33604 cs[i].expand(deep);
33609 * Collapse all child nodes
33610 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33612 collapseChildNodes : function(deep){
33613 var cs = this.childNodes;
33614 for(var i = 0, len = cs.length; i < len; i++) {
33615 cs[i].collapse(deep);
33620 * Disables this node
33622 disable : function(){
33623 this.disabled = true;
33625 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33626 this.ui.onDisableChange(this, true);
33628 this.fireEvent("disabledchange", this, true);
33632 * Enables this node
33634 enable : function(){
33635 this.disabled = false;
33636 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33637 this.ui.onDisableChange(this, false);
33639 this.fireEvent("disabledchange", this, false);
33643 renderChildren : function(suppressEvent){
33644 if(suppressEvent !== false){
33645 this.fireEvent("beforechildrenrendered", this);
33647 var cs = this.childNodes;
33648 for(var i = 0, len = cs.length; i < len; i++){
33649 cs[i].render(true);
33651 this.childrenRendered = true;
33655 sort : function(fn, scope){
33656 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33657 if(this.childrenRendered){
33658 var cs = this.childNodes;
33659 for(var i = 0, len = cs.length; i < len; i++){
33660 cs[i].render(true);
33666 render : function(bulkRender){
33667 this.ui.render(bulkRender);
33668 if(!this.rendered){
33669 this.rendered = true;
33671 this.expanded = false;
33672 this.expand(false, false);
33678 renderIndent : function(deep, refresh){
33680 this.ui.childIndent = null;
33682 this.ui.renderIndent();
33683 if(deep === true && this.childrenRendered){
33684 var cs = this.childNodes;
33685 for(var i = 0, len = cs.length; i < len; i++){
33686 cs[i].renderIndent(true, refresh);
33692 * Ext JS Library 1.1.1
33693 * Copyright(c) 2006-2007, Ext JS, LLC.
33695 * Originally Released Under LGPL - original licence link has changed is not relivant.
33698 * <script type="text/javascript">
33702 * @class Roo.tree.AsyncTreeNode
33703 * @extends Roo.tree.TreeNode
33704 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33706 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33708 Roo.tree.AsyncTreeNode = function(config){
33709 this.loaded = false;
33710 this.loading = false;
33711 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33713 * @event beforeload
33714 * Fires before this node is loaded, return false to cancel
33715 * @param {Node} this This node
33717 this.addEvents({'beforeload':true, 'load': true});
33720 * Fires when this node is loaded
33721 * @param {Node} this This node
33724 * The loader used by this node (defaults to using the tree's defined loader)
33729 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33730 expand : function(deep, anim, callback){
33731 if(this.loading){ // if an async load is already running, waiting til it's done
33733 var f = function(){
33734 if(!this.loading){ // done loading
33735 clearInterval(timer);
33736 this.expand(deep, anim, callback);
33738 }.createDelegate(this);
33739 timer = setInterval(f, 200);
33743 if(this.fireEvent("beforeload", this) === false){
33746 this.loading = true;
33747 this.ui.beforeLoad(this);
33748 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33750 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33754 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33758 * Returns true if this node is currently loading
33759 * @return {Boolean}
33761 isLoading : function(){
33762 return this.loading;
33765 loadComplete : function(deep, anim, callback){
33766 this.loading = false;
33767 this.loaded = true;
33768 this.ui.afterLoad(this);
33769 this.fireEvent("load", this);
33770 this.expand(deep, anim, callback);
33774 * Returns true if this node has been loaded
33775 * @return {Boolean}
33777 isLoaded : function(){
33778 return this.loaded;
33781 hasChildNodes : function(){
33782 if(!this.isLeaf() && !this.loaded){
33785 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33790 * Trigger a reload for this node
33791 * @param {Function} callback
33793 reload : function(callback){
33794 this.collapse(false, false);
33795 while(this.firstChild){
33796 this.removeChild(this.firstChild);
33798 this.childrenRendered = false;
33799 this.loaded = false;
33800 if(this.isHiddenRoot()){
33801 this.expanded = false;
33803 this.expand(false, false, callback);
33807 * Ext JS Library 1.1.1
33808 * Copyright(c) 2006-2007, Ext JS, LLC.
33810 * Originally Released Under LGPL - original licence link has changed is not relivant.
33813 * <script type="text/javascript">
33817 * @class Roo.tree.TreeNodeUI
33819 * @param {Object} node The node to render
33820 * The TreeNode UI implementation is separate from the
33821 * tree implementation. Unless you are customizing the tree UI,
33822 * you should never have to use this directly.
33824 Roo.tree.TreeNodeUI = function(node){
33826 this.rendered = false;
33827 this.animating = false;
33828 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33831 Roo.tree.TreeNodeUI.prototype = {
33832 removeChild : function(node){
33834 this.ctNode.removeChild(node.ui.getEl());
33838 beforeLoad : function(){
33839 this.addClass("x-tree-node-loading");
33842 afterLoad : function(){
33843 this.removeClass("x-tree-node-loading");
33846 onTextChange : function(node, text, oldText){
33848 this.textNode.innerHTML = text;
33852 onDisableChange : function(node, state){
33853 this.disabled = state;
33855 this.addClass("x-tree-node-disabled");
33857 this.removeClass("x-tree-node-disabled");
33861 onSelectedChange : function(state){
33864 this.addClass("x-tree-selected");
33867 this.removeClass("x-tree-selected");
33871 onMove : function(tree, node, oldParent, newParent, index, refNode){
33872 this.childIndent = null;
33874 var targetNode = newParent.ui.getContainer();
33875 if(!targetNode){//target not rendered
33876 this.holder = document.createElement("div");
33877 this.holder.appendChild(this.wrap);
33880 var insertBefore = refNode ? refNode.ui.getEl() : null;
33882 targetNode.insertBefore(this.wrap, insertBefore);
33884 targetNode.appendChild(this.wrap);
33886 this.node.renderIndent(true);
33890 addClass : function(cls){
33892 Roo.fly(this.elNode).addClass(cls);
33896 removeClass : function(cls){
33898 Roo.fly(this.elNode).removeClass(cls);
33902 remove : function(){
33904 this.holder = document.createElement("div");
33905 this.holder.appendChild(this.wrap);
33909 fireEvent : function(){
33910 return this.node.fireEvent.apply(this.node, arguments);
33913 initEvents : function(){
33914 this.node.on("move", this.onMove, this);
33915 var E = Roo.EventManager;
33916 var a = this.anchor;
33918 var el = Roo.fly(a, '_treeui');
33920 if(Roo.isOpera){ // opera render bug ignores the CSS
33921 el.setStyle("text-decoration", "none");
33924 el.on("click", this.onClick, this);
33925 el.on("dblclick", this.onDblClick, this);
33928 Roo.EventManager.on(this.checkbox,
33929 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33932 el.on("contextmenu", this.onContextMenu, this);
33934 var icon = Roo.fly(this.iconNode);
33935 icon.on("click", this.onClick, this);
33936 icon.on("dblclick", this.onDblClick, this);
33937 icon.on("contextmenu", this.onContextMenu, this);
33938 E.on(this.ecNode, "click", this.ecClick, this, true);
33940 if(this.node.disabled){
33941 this.addClass("x-tree-node-disabled");
33943 if(this.node.hidden){
33944 this.addClass("x-tree-node-disabled");
33946 var ot = this.node.getOwnerTree();
33947 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33948 if(dd && (!this.node.isRoot || ot.rootVisible)){
33949 Roo.dd.Registry.register(this.elNode, {
33951 handles: this.getDDHandles(),
33957 getDDHandles : function(){
33958 return [this.iconNode, this.textNode];
33963 this.wrap.style.display = "none";
33969 this.wrap.style.display = "";
33973 onContextMenu : function(e){
33974 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33975 e.preventDefault();
33977 this.fireEvent("contextmenu", this.node, e);
33981 onClick : function(e){
33986 if(this.fireEvent("beforeclick", this.node, e) !== false){
33987 if(!this.disabled && this.node.attributes.href){
33988 this.fireEvent("click", this.node, e);
33991 e.preventDefault();
33996 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33997 this.node.toggle();
34000 this.fireEvent("click", this.node, e);
34006 onDblClick : function(e){
34007 e.preventDefault();
34012 this.toggleCheck();
34014 if(!this.animating && this.node.hasChildNodes()){
34015 this.node.toggle();
34017 this.fireEvent("dblclick", this.node, e);
34020 onCheckChange : function(){
34021 var checked = this.checkbox.checked;
34022 this.node.attributes.checked = checked;
34023 this.fireEvent('checkchange', this.node, checked);
34026 ecClick : function(e){
34027 if(!this.animating && this.node.hasChildNodes()){
34028 this.node.toggle();
34032 startDrop : function(){
34033 this.dropping = true;
34036 // delayed drop so the click event doesn't get fired on a drop
34037 endDrop : function(){
34038 setTimeout(function(){
34039 this.dropping = false;
34040 }.createDelegate(this), 50);
34043 expand : function(){
34044 this.updateExpandIcon();
34045 this.ctNode.style.display = "";
34048 focus : function(){
34049 if(!this.node.preventHScroll){
34050 try{this.anchor.focus();
34052 }else if(!Roo.isIE){
34054 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
34055 var l = noscroll.scrollLeft;
34056 this.anchor.focus();
34057 noscroll.scrollLeft = l;
34062 toggleCheck : function(value){
34063 var cb = this.checkbox;
34065 cb.checked = (value === undefined ? !cb.checked : value);
34071 this.anchor.blur();
34075 animExpand : function(callback){
34076 var ct = Roo.get(this.ctNode);
34078 if(!this.node.hasChildNodes()){
34079 this.updateExpandIcon();
34080 this.ctNode.style.display = "";
34081 Roo.callback(callback);
34084 this.animating = true;
34085 this.updateExpandIcon();
34088 callback : function(){
34089 this.animating = false;
34090 Roo.callback(callback);
34093 duration: this.node.ownerTree.duration || .25
34097 highlight : function(){
34098 var tree = this.node.getOwnerTree();
34099 Roo.fly(this.wrap).highlight(
34100 tree.hlColor || "C3DAF9",
34101 {endColor: tree.hlBaseColor}
34105 collapse : function(){
34106 this.updateExpandIcon();
34107 this.ctNode.style.display = "none";
34110 animCollapse : function(callback){
34111 var ct = Roo.get(this.ctNode);
34112 ct.enableDisplayMode('block');
34115 this.animating = true;
34116 this.updateExpandIcon();
34119 callback : function(){
34120 this.animating = false;
34121 Roo.callback(callback);
34124 duration: this.node.ownerTree.duration || .25
34128 getContainer : function(){
34129 return this.ctNode;
34132 getEl : function(){
34136 appendDDGhost : function(ghostNode){
34137 ghostNode.appendChild(this.elNode.cloneNode(true));
34140 getDDRepairXY : function(){
34141 return Roo.lib.Dom.getXY(this.iconNode);
34144 onRender : function(){
34148 render : function(bulkRender){
34149 var n = this.node, a = n.attributes;
34150 var targetNode = n.parentNode ?
34151 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
34153 if(!this.rendered){
34154 this.rendered = true;
34156 this.renderElements(n, a, targetNode, bulkRender);
34159 if(this.textNode.setAttributeNS){
34160 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
34162 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
34165 this.textNode.setAttribute("ext:qtip", a.qtip);
34167 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
34170 }else if(a.qtipCfg){
34171 a.qtipCfg.target = Roo.id(this.textNode);
34172 Roo.QuickTips.register(a.qtipCfg);
34175 if(!this.node.expanded){
34176 this.updateExpandIcon();
34179 if(bulkRender === true) {
34180 targetNode.appendChild(this.wrap);
34185 renderElements : function(n, a, targetNode, bulkRender)
34187 // add some indent caching, this helps performance when rendering a large tree
34188 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34189 var t = n.getOwnerTree();
34190 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
34191 if (typeof(n.attributes.html) != 'undefined') {
34192 txt = n.attributes.html;
34194 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
34195 var cb = typeof a.checked == 'boolean';
34196 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34197 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
34198 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
34199 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
34200 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
34201 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
34202 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
34203 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
34204 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
34205 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34208 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34209 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34210 n.nextSibling.ui.getEl(), buf.join(""));
34212 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34215 this.elNode = this.wrap.childNodes[0];
34216 this.ctNode = this.wrap.childNodes[1];
34217 var cs = this.elNode.childNodes;
34218 this.indentNode = cs[0];
34219 this.ecNode = cs[1];
34220 this.iconNode = cs[2];
34223 this.checkbox = cs[3];
34226 this.anchor = cs[index];
34227 this.textNode = cs[index].firstChild;
34230 getAnchor : function(){
34231 return this.anchor;
34234 getTextEl : function(){
34235 return this.textNode;
34238 getIconEl : function(){
34239 return this.iconNode;
34242 isChecked : function(){
34243 return this.checkbox ? this.checkbox.checked : false;
34246 updateExpandIcon : function(){
34248 var n = this.node, c1, c2;
34249 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34250 var hasChild = n.hasChildNodes();
34254 c1 = "x-tree-node-collapsed";
34255 c2 = "x-tree-node-expanded";
34258 c1 = "x-tree-node-expanded";
34259 c2 = "x-tree-node-collapsed";
34262 this.removeClass("x-tree-node-leaf");
34263 this.wasLeaf = false;
34265 if(this.c1 != c1 || this.c2 != c2){
34266 Roo.fly(this.elNode).replaceClass(c1, c2);
34267 this.c1 = c1; this.c2 = c2;
34270 // this changes non-leafs into leafs if they have no children.
34271 // it's not very rational behaviour..
34273 if(!this.wasLeaf && this.node.leaf){
34274 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34277 this.wasLeaf = true;
34280 var ecc = "x-tree-ec-icon "+cls;
34281 if(this.ecc != ecc){
34282 this.ecNode.className = ecc;
34288 getChildIndent : function(){
34289 if(!this.childIndent){
34293 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34295 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34297 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34302 this.childIndent = buf.join("");
34304 return this.childIndent;
34307 renderIndent : function(){
34310 var p = this.node.parentNode;
34312 indent = p.ui.getChildIndent();
34314 if(this.indentMarkup != indent){ // don't rerender if not required
34315 this.indentNode.innerHTML = indent;
34316 this.indentMarkup = indent;
34318 this.updateExpandIcon();
34323 Roo.tree.RootTreeNodeUI = function(){
34324 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34326 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34327 render : function(){
34328 if(!this.rendered){
34329 var targetNode = this.node.ownerTree.innerCt.dom;
34330 this.node.expanded = true;
34331 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34332 this.wrap = this.ctNode = targetNode.firstChild;
34335 collapse : function(){
34337 expand : function(){
34341 * Ext JS Library 1.1.1
34342 * Copyright(c) 2006-2007, Ext JS, LLC.
34344 * Originally Released Under LGPL - original licence link has changed is not relivant.
34347 * <script type="text/javascript">
34350 * @class Roo.tree.TreeLoader
34351 * @extends Roo.util.Observable
34352 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34353 * nodes from a specified URL. The response must be a javascript Array definition
34354 * who's elements are node definition objects. eg:
34359 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34360 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34367 * The old style respose with just an array is still supported, but not recommended.
34370 * A server request is sent, and child nodes are loaded only when a node is expanded.
34371 * The loading node's id is passed to the server under the parameter name "node" to
34372 * enable the server to produce the correct child nodes.
34374 * To pass extra parameters, an event handler may be attached to the "beforeload"
34375 * event, and the parameters specified in the TreeLoader's baseParams property:
34377 myTreeLoader.on("beforeload", function(treeLoader, node) {
34378 this.baseParams.category = node.attributes.category;
34381 * This would pass an HTTP parameter called "category" to the server containing
34382 * the value of the Node's "category" attribute.
34384 * Creates a new Treeloader.
34385 * @param {Object} config A config object containing config properties.
34387 Roo.tree.TreeLoader = function(config){
34388 this.baseParams = {};
34389 this.requestMethod = "POST";
34390 Roo.apply(this, config);
34395 * @event beforeload
34396 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34397 * @param {Object} This TreeLoader object.
34398 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34399 * @param {Object} callback The callback function specified in the {@link #load} call.
34404 * Fires when the node has been successfuly loaded.
34405 * @param {Object} This TreeLoader object.
34406 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34407 * @param {Object} response The response object containing the data from the server.
34411 * @event loadexception
34412 * Fires if the network request failed.
34413 * @param {Object} This TreeLoader object.
34414 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34415 * @param {Object} response The response object containing the data from the server.
34417 loadexception : true,
34420 * Fires before a node is created, enabling you to return custom Node types
34421 * @param {Object} This TreeLoader object.
34422 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34427 Roo.tree.TreeLoader.superclass.constructor.call(this);
34430 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34432 * @cfg {String} dataUrl The URL from which to request a Json string which
34433 * specifies an array of node definition object representing the child nodes
34437 * @cfg {String} requestMethod either GET or POST
34438 * defaults to POST (due to BC)
34442 * @cfg {Object} baseParams (optional) An object containing properties which
34443 * specify HTTP parameters to be passed to each request for child nodes.
34446 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34447 * created by this loader. If the attributes sent by the server have an attribute in this object,
34448 * they take priority.
34451 * @cfg {Object} uiProviders (optional) An object containing properties which
34453 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34454 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34455 * <i>uiProvider</i> attribute of a returned child node is a string rather
34456 * than a reference to a TreeNodeUI implementation, this that string value
34457 * is used as a property name in the uiProviders object. You can define the provider named
34458 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34463 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34464 * child nodes before loading.
34466 clearOnLoad : true,
34469 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34470 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34471 * Grid query { data : [ .....] }
34476 * @cfg {String} queryParam (optional)
34477 * Name of the query as it will be passed on the querystring (defaults to 'node')
34478 * eg. the request will be ?node=[id]
34485 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34486 * This is called automatically when a node is expanded, but may be used to reload
34487 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34488 * @param {Roo.tree.TreeNode} node
34489 * @param {Function} callback
34491 load : function(node, callback){
34492 if(this.clearOnLoad){
34493 while(node.firstChild){
34494 node.removeChild(node.firstChild);
34497 if(node.attributes.children){ // preloaded json children
34498 var cs = node.attributes.children;
34499 for(var i = 0, len = cs.length; i < len; i++){
34500 node.appendChild(this.createNode(cs[i]));
34502 if(typeof callback == "function"){
34505 }else if(this.dataUrl){
34506 this.requestData(node, callback);
34510 getParams: function(node){
34511 var buf = [], bp = this.baseParams;
34512 for(var key in bp){
34513 if(typeof bp[key] != "function"){
34514 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34517 var n = this.queryParam === false ? 'node' : this.queryParam;
34518 buf.push(n + "=", encodeURIComponent(node.id));
34519 return buf.join("");
34522 requestData : function(node, callback){
34523 if(this.fireEvent("beforeload", this, node, callback) !== false){
34524 this.transId = Roo.Ajax.request({
34525 method:this.requestMethod,
34526 url: this.dataUrl||this.url,
34527 success: this.handleResponse,
34528 failure: this.handleFailure,
34530 argument: {callback: callback, node: node},
34531 params: this.getParams(node)
34534 // if the load is cancelled, make sure we notify
34535 // the node that we are done
34536 if(typeof callback == "function"){
34542 isLoading : function(){
34543 return this.transId ? true : false;
34546 abort : function(){
34547 if(this.isLoading()){
34548 Roo.Ajax.abort(this.transId);
34553 createNode : function(attr)
34555 // apply baseAttrs, nice idea Corey!
34556 if(this.baseAttrs){
34557 Roo.applyIf(attr, this.baseAttrs);
34559 if(this.applyLoader !== false){
34560 attr.loader = this;
34562 // uiProvider = depreciated..
34564 if(typeof(attr.uiProvider) == 'string'){
34565 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34566 /** eval:var:attr */ eval(attr.uiProvider);
34568 if(typeof(this.uiProviders['default']) != 'undefined') {
34569 attr.uiProvider = this.uiProviders['default'];
34572 this.fireEvent('create', this, attr);
34574 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34576 new Roo.tree.TreeNode(attr) :
34577 new Roo.tree.AsyncTreeNode(attr));
34580 processResponse : function(response, node, callback)
34582 var json = response.responseText;
34585 var o = Roo.decode(json);
34587 if (this.root === false && typeof(o.success) != undefined) {
34588 this.root = 'data'; // the default behaviour for list like data..
34591 if (this.root !== false && !o.success) {
34592 // it's a failure condition.
34593 var a = response.argument;
34594 this.fireEvent("loadexception", this, a.node, response);
34595 Roo.log("Load failed - should have a handler really");
34601 if (this.root !== false) {
34605 for(var i = 0, len = o.length; i < len; i++){
34606 var n = this.createNode(o[i]);
34608 node.appendChild(n);
34611 if(typeof callback == "function"){
34612 callback(this, node);
34615 this.handleFailure(response);
34619 handleResponse : function(response){
34620 this.transId = false;
34621 var a = response.argument;
34622 this.processResponse(response, a.node, a.callback);
34623 this.fireEvent("load", this, a.node, response);
34626 handleFailure : function(response)
34628 // should handle failure better..
34629 this.transId = false;
34630 var a = response.argument;
34631 this.fireEvent("loadexception", this, a.node, response);
34632 if(typeof a.callback == "function"){
34633 a.callback(this, a.node);
34638 * Ext JS Library 1.1.1
34639 * Copyright(c) 2006-2007, Ext JS, LLC.
34641 * Originally Released Under LGPL - original licence link has changed is not relivant.
34644 * <script type="text/javascript">
34648 * @class Roo.tree.TreeFilter
34649 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34650 * @param {TreePanel} tree
34651 * @param {Object} config (optional)
34653 Roo.tree.TreeFilter = function(tree, config){
34655 this.filtered = {};
34656 Roo.apply(this, config);
34659 Roo.tree.TreeFilter.prototype = {
34666 * Filter the data by a specific attribute.
34667 * @param {String/RegExp} value Either string that the attribute value
34668 * should start with or a RegExp to test against the attribute
34669 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34670 * @param {TreeNode} startNode (optional) The node to start the filter at.
34672 filter : function(value, attr, startNode){
34673 attr = attr || "text";
34675 if(typeof value == "string"){
34676 var vlen = value.length;
34677 // auto clear empty filter
34678 if(vlen == 0 && this.clearBlank){
34682 value = value.toLowerCase();
34684 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34686 }else if(value.exec){ // regex?
34688 return value.test(n.attributes[attr]);
34691 throw 'Illegal filter type, must be string or regex';
34693 this.filterBy(f, null, startNode);
34697 * Filter by a function. The passed function will be called with each
34698 * node in the tree (or from the startNode). If the function returns true, the node is kept
34699 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34700 * @param {Function} fn The filter function
34701 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34703 filterBy : function(fn, scope, startNode){
34704 startNode = startNode || this.tree.root;
34705 if(this.autoClear){
34708 var af = this.filtered, rv = this.reverse;
34709 var f = function(n){
34710 if(n == startNode){
34716 var m = fn.call(scope || n, n);
34724 startNode.cascade(f);
34727 if(typeof id != "function"){
34729 if(n && n.parentNode){
34730 n.parentNode.removeChild(n);
34738 * Clears the current filter. Note: with the "remove" option
34739 * set a filter cannot be cleared.
34741 clear : function(){
34743 var af = this.filtered;
34745 if(typeof id != "function"){
34752 this.filtered = {};
34757 * Ext JS Library 1.1.1
34758 * Copyright(c) 2006-2007, Ext JS, LLC.
34760 * Originally Released Under LGPL - original licence link has changed is not relivant.
34763 * <script type="text/javascript">
34768 * @class Roo.tree.TreeSorter
34769 * Provides sorting of nodes in a TreePanel
34771 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34772 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34773 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34774 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34775 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34776 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34778 * @param {TreePanel} tree
34779 * @param {Object} config
34781 Roo.tree.TreeSorter = function(tree, config){
34782 Roo.apply(this, config);
34783 tree.on("beforechildrenrendered", this.doSort, this);
34784 tree.on("append", this.updateSort, this);
34785 tree.on("insert", this.updateSort, this);
34787 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34788 var p = this.property || "text";
34789 var sortType = this.sortType;
34790 var fs = this.folderSort;
34791 var cs = this.caseSensitive === true;
34792 var leafAttr = this.leafAttr || 'leaf';
34794 this.sortFn = function(n1, n2){
34796 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34799 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34803 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34804 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34806 return dsc ? +1 : -1;
34808 return dsc ? -1 : +1;
34815 Roo.tree.TreeSorter.prototype = {
34816 doSort : function(node){
34817 node.sort(this.sortFn);
34820 compareNodes : function(n1, n2){
34821 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34824 updateSort : function(tree, node){
34825 if(node.childrenRendered){
34826 this.doSort.defer(1, this, [node]);
34831 * Ext JS Library 1.1.1
34832 * Copyright(c) 2006-2007, Ext JS, LLC.
34834 * Originally Released Under LGPL - original licence link has changed is not relivant.
34837 * <script type="text/javascript">
34840 if(Roo.dd.DropZone){
34842 Roo.tree.TreeDropZone = function(tree, config){
34843 this.allowParentInsert = false;
34844 this.allowContainerDrop = false;
34845 this.appendOnly = false;
34846 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34848 this.lastInsertClass = "x-tree-no-status";
34849 this.dragOverData = {};
34852 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34853 ddGroup : "TreeDD",
34856 expandDelay : 1000,
34858 expandNode : function(node){
34859 if(node.hasChildNodes() && !node.isExpanded()){
34860 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34864 queueExpand : function(node){
34865 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34868 cancelExpand : function(){
34869 if(this.expandProcId){
34870 clearTimeout(this.expandProcId);
34871 this.expandProcId = false;
34875 isValidDropPoint : function(n, pt, dd, e, data){
34876 if(!n || !data){ return false; }
34877 var targetNode = n.node;
34878 var dropNode = data.node;
34879 // default drop rules
34880 if(!(targetNode && targetNode.isTarget && pt)){
34883 if(pt == "append" && targetNode.allowChildren === false){
34886 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34889 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34892 // reuse the object
34893 var overEvent = this.dragOverData;
34894 overEvent.tree = this.tree;
34895 overEvent.target = targetNode;
34896 overEvent.data = data;
34897 overEvent.point = pt;
34898 overEvent.source = dd;
34899 overEvent.rawEvent = e;
34900 overEvent.dropNode = dropNode;
34901 overEvent.cancel = false;
34902 var result = this.tree.fireEvent("nodedragover", overEvent);
34903 return overEvent.cancel === false && result !== false;
34906 getDropPoint : function(e, n, dd)
34910 return tn.allowChildren !== false ? "append" : false; // always append for root
34912 var dragEl = n.ddel;
34913 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34914 var y = Roo.lib.Event.getPageY(e);
34915 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34917 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34918 var noAppend = tn.allowChildren === false;
34919 if(this.appendOnly || tn.parentNode.allowChildren === false){
34920 return noAppend ? false : "append";
34922 var noBelow = false;
34923 if(!this.allowParentInsert){
34924 noBelow = tn.hasChildNodes() && tn.isExpanded();
34926 var q = (b - t) / (noAppend ? 2 : 3);
34927 if(y >= t && y < (t + q)){
34929 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34936 onNodeEnter : function(n, dd, e, data)
34938 this.cancelExpand();
34941 onNodeOver : function(n, dd, e, data)
34944 var pt = this.getDropPoint(e, n, dd);
34947 // auto node expand check
34948 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34949 this.queueExpand(node);
34950 }else if(pt != "append"){
34951 this.cancelExpand();
34954 // set the insert point style on the target node
34955 var returnCls = this.dropNotAllowed;
34956 if(this.isValidDropPoint(n, pt, dd, e, data)){
34961 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34962 cls = "x-tree-drag-insert-above";
34963 }else if(pt == "below"){
34964 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34965 cls = "x-tree-drag-insert-below";
34967 returnCls = "x-tree-drop-ok-append";
34968 cls = "x-tree-drag-append";
34970 if(this.lastInsertClass != cls){
34971 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34972 this.lastInsertClass = cls;
34979 onNodeOut : function(n, dd, e, data){
34981 this.cancelExpand();
34982 this.removeDropIndicators(n);
34985 onNodeDrop : function(n, dd, e, data){
34986 var point = this.getDropPoint(e, n, dd);
34987 var targetNode = n.node;
34988 targetNode.ui.startDrop();
34989 if(!this.isValidDropPoint(n, point, dd, e, data)){
34990 targetNode.ui.endDrop();
34993 // first try to find the drop node
34994 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34997 target: targetNode,
35002 dropNode: dropNode,
35005 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
35006 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
35007 targetNode.ui.endDrop();
35010 // allow target changing
35011 targetNode = dropEvent.target;
35012 if(point == "append" && !targetNode.isExpanded()){
35013 targetNode.expand(false, null, function(){
35014 this.completeDrop(dropEvent);
35015 }.createDelegate(this));
35017 this.completeDrop(dropEvent);
35022 completeDrop : function(de){
35023 var ns = de.dropNode, p = de.point, t = de.target;
35024 if(!(ns instanceof Array)){
35028 for(var i = 0, len = ns.length; i < len; i++){
35031 t.parentNode.insertBefore(n, t);
35032 }else if(p == "below"){
35033 t.parentNode.insertBefore(n, t.nextSibling);
35039 if(this.tree.hlDrop){
35043 this.tree.fireEvent("nodedrop", de);
35046 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
35047 if(this.tree.hlDrop){
35048 dropNode.ui.focus();
35049 dropNode.ui.highlight();
35051 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
35054 getTree : function(){
35058 removeDropIndicators : function(n){
35061 Roo.fly(el).removeClass([
35062 "x-tree-drag-insert-above",
35063 "x-tree-drag-insert-below",
35064 "x-tree-drag-append"]);
35065 this.lastInsertClass = "_noclass";
35069 beforeDragDrop : function(target, e, id){
35070 this.cancelExpand();
35074 afterRepair : function(data){
35075 if(data && Roo.enableFx){
35076 data.node.ui.highlight();
35086 * Ext JS Library 1.1.1
35087 * Copyright(c) 2006-2007, Ext JS, LLC.
35089 * Originally Released Under LGPL - original licence link has changed is not relivant.
35092 * <script type="text/javascript">
35096 if(Roo.dd.DragZone){
35097 Roo.tree.TreeDragZone = function(tree, config){
35098 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
35102 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
35103 ddGroup : "TreeDD",
35105 onBeforeDrag : function(data, e){
35107 return n && n.draggable && !n.disabled;
35111 onInitDrag : function(e){
35112 var data = this.dragData;
35113 this.tree.getSelectionModel().select(data.node);
35114 this.proxy.update("");
35115 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
35116 this.tree.fireEvent("startdrag", this.tree, data.node, e);
35119 getRepairXY : function(e, data){
35120 return data.node.ui.getDDRepairXY();
35123 onEndDrag : function(data, e){
35124 this.tree.fireEvent("enddrag", this.tree, data.node, e);
35129 onValidDrop : function(dd, e, id){
35130 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
35134 beforeInvalidDrop : function(e, id){
35135 // this scrolls the original position back into view
35136 var sm = this.tree.getSelectionModel();
35137 sm.clearSelections();
35138 sm.select(this.dragData.node);
35143 * Ext JS Library 1.1.1
35144 * Copyright(c) 2006-2007, Ext JS, LLC.
35146 * Originally Released Under LGPL - original licence link has changed is not relivant.
35149 * <script type="text/javascript">
35152 * @class Roo.tree.TreeEditor
35153 * @extends Roo.Editor
35154 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
35155 * as the editor field.
35157 * @param {Object} config (used to be the tree panel.)
35158 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
35160 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
35161 * @cfg {Roo.form.TextField|Object} field The field configuration
35165 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
35168 if (oldconfig) { // old style..
35169 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
35172 tree = config.tree;
35173 config.field = config.field || {};
35174 config.field.xtype = 'TextField';
35175 field = Roo.factory(config.field, Roo.form);
35177 config = config || {};
35182 * @event beforenodeedit
35183 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
35184 * false from the handler of this event.
35185 * @param {Editor} this
35186 * @param {Roo.tree.Node} node
35188 "beforenodeedit" : true
35192 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
35196 tree.on('beforeclick', this.beforeNodeClick, this);
35197 tree.getTreeEl().on('mousedown', this.hide, this);
35198 this.on('complete', this.updateNode, this);
35199 this.on('beforestartedit', this.fitToTree, this);
35200 this.on('startedit', this.bindScroll, this, {delay:10});
35201 this.on('specialkey', this.onSpecialKey, this);
35204 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
35206 * @cfg {String} alignment
35207 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35213 * @cfg {Boolean} hideEl
35214 * True to hide the bound element while the editor is displayed (defaults to false)
35218 * @cfg {String} cls
35219 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35221 cls: "x-small-editor x-tree-editor",
35223 * @cfg {Boolean} shim
35224 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35230 * @cfg {Number} maxWidth
35231 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35232 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35233 * scroll and client offsets into account prior to each edit.
35240 fitToTree : function(ed, el){
35241 var td = this.tree.getTreeEl().dom, nd = el.dom;
35242 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35243 td.scrollLeft = nd.offsetLeft;
35247 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35248 this.setSize(w, '');
35250 return this.fireEvent('beforenodeedit', this, this.editNode);
35255 triggerEdit : function(node){
35256 this.completeEdit();
35257 this.editNode = node;
35258 this.startEdit(node.ui.textNode, node.text);
35262 bindScroll : function(){
35263 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35267 beforeNodeClick : function(node, e){
35268 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35269 this.lastClick = new Date();
35270 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35272 this.triggerEdit(node);
35279 updateNode : function(ed, value){
35280 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35281 this.editNode.setText(value);
35285 onHide : function(){
35286 Roo.tree.TreeEditor.superclass.onHide.call(this);
35288 this.editNode.ui.focus();
35293 onSpecialKey : function(field, e){
35294 var k = e.getKey();
35298 }else if(k == e.ENTER && !e.hasModifier()){
35300 this.completeEdit();
35303 });//<Script type="text/javascript">
35306 * Ext JS Library 1.1.1
35307 * Copyright(c) 2006-2007, Ext JS, LLC.
35309 * Originally Released Under LGPL - original licence link has changed is not relivant.
35312 * <script type="text/javascript">
35316 * Not documented??? - probably should be...
35319 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35320 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35322 renderElements : function(n, a, targetNode, bulkRender){
35323 //consel.log("renderElements?");
35324 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35326 var t = n.getOwnerTree();
35327 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35329 var cols = t.columns;
35330 var bw = t.borderWidth;
35332 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35333 var cb = typeof a.checked == "boolean";
35334 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35335 var colcls = 'x-t-' + tid + '-c0';
35337 '<li class="x-tree-node">',
35340 '<div class="x-tree-node-el ', a.cls,'">',
35342 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35345 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35346 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35347 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35348 (a.icon ? ' x-tree-node-inline-icon' : ''),
35349 (a.iconCls ? ' '+a.iconCls : ''),
35350 '" unselectable="on" />',
35351 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35352 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35354 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35355 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35356 '<span unselectable="on" qtip="' + tx + '">',
35360 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35361 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35363 for(var i = 1, len = cols.length; i < len; i++){
35365 colcls = 'x-t-' + tid + '-c' +i;
35366 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35367 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35368 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35374 '<div class="x-clear"></div></div>',
35375 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35378 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35379 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35380 n.nextSibling.ui.getEl(), buf.join(""));
35382 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35384 var el = this.wrap.firstChild;
35386 this.elNode = el.firstChild;
35387 this.ranchor = el.childNodes[1];
35388 this.ctNode = this.wrap.childNodes[1];
35389 var cs = el.firstChild.childNodes;
35390 this.indentNode = cs[0];
35391 this.ecNode = cs[1];
35392 this.iconNode = cs[2];
35395 this.checkbox = cs[3];
35398 this.anchor = cs[index];
35400 this.textNode = cs[index].firstChild;
35402 //el.on("click", this.onClick, this);
35403 //el.on("dblclick", this.onDblClick, this);
35406 // console.log(this);
35408 initEvents : function(){
35409 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35412 var a = this.ranchor;
35414 var el = Roo.get(a);
35416 if(Roo.isOpera){ // opera render bug ignores the CSS
35417 el.setStyle("text-decoration", "none");
35420 el.on("click", this.onClick, this);
35421 el.on("dblclick", this.onDblClick, this);
35422 el.on("contextmenu", this.onContextMenu, this);
35426 /*onSelectedChange : function(state){
35429 this.addClass("x-tree-selected");
35432 this.removeClass("x-tree-selected");
35435 addClass : function(cls){
35437 Roo.fly(this.elRow).addClass(cls);
35443 removeClass : function(cls){
35445 Roo.fly(this.elRow).removeClass(cls);
35451 });//<Script type="text/javascript">
35455 * Ext JS Library 1.1.1
35456 * Copyright(c) 2006-2007, Ext JS, LLC.
35458 * Originally Released Under LGPL - original licence link has changed is not relivant.
35461 * <script type="text/javascript">
35466 * @class Roo.tree.ColumnTree
35467 * @extends Roo.data.TreePanel
35468 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35469 * @cfg {int} borderWidth compined right/left border allowance
35471 * @param {String/HTMLElement/Element} el The container element
35472 * @param {Object} config
35474 Roo.tree.ColumnTree = function(el, config)
35476 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35480 * Fire this event on a container when it resizes
35481 * @param {int} w Width
35482 * @param {int} h Height
35486 this.on('resize', this.onResize, this);
35489 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35493 borderWidth: Roo.isBorderBox ? 0 : 2,
35496 render : function(){
35497 // add the header.....
35499 Roo.tree.ColumnTree.superclass.render.apply(this);
35501 this.el.addClass('x-column-tree');
35503 this.headers = this.el.createChild(
35504 {cls:'x-tree-headers'},this.innerCt.dom);
35506 var cols = this.columns, c;
35507 var totalWidth = 0;
35509 var len = cols.length;
35510 for(var i = 0; i < len; i++){
35512 totalWidth += c.width;
35513 this.headEls.push(this.headers.createChild({
35514 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35516 cls:'x-tree-hd-text',
35519 style:'width:'+(c.width-this.borderWidth)+'px;'
35522 this.headers.createChild({cls:'x-clear'});
35523 // prevent floats from wrapping when clipped
35524 this.headers.setWidth(totalWidth);
35525 //this.innerCt.setWidth(totalWidth);
35526 this.innerCt.setStyle({ overflow: 'auto' });
35527 this.onResize(this.width, this.height);
35531 onResize : function(w,h)
35536 this.innerCt.setWidth(this.width);
35537 this.innerCt.setHeight(this.height-20);
35540 var cols = this.columns, c;
35541 var totalWidth = 0;
35543 var len = cols.length;
35544 for(var i = 0; i < len; i++){
35546 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35547 // it's the expander..
35548 expEl = this.headEls[i];
35551 totalWidth += c.width;
35555 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35557 this.headers.setWidth(w-20);
35566 * Ext JS Library 1.1.1
35567 * Copyright(c) 2006-2007, Ext JS, LLC.
35569 * Originally Released Under LGPL - original licence link has changed is not relivant.
35572 * <script type="text/javascript">
35576 * @class Roo.menu.Menu
35577 * @extends Roo.util.Observable
35578 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35579 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35581 * Creates a new Menu
35582 * @param {Object} config Configuration options
35584 Roo.menu.Menu = function(config){
35585 Roo.apply(this, config);
35586 this.id = this.id || Roo.id();
35589 * @event beforeshow
35590 * Fires before this menu is displayed
35591 * @param {Roo.menu.Menu} this
35595 * @event beforehide
35596 * Fires before this menu is hidden
35597 * @param {Roo.menu.Menu} this
35602 * Fires after this menu is displayed
35603 * @param {Roo.menu.Menu} this
35608 * Fires after this menu is hidden
35609 * @param {Roo.menu.Menu} this
35614 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35615 * @param {Roo.menu.Menu} this
35616 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35617 * @param {Roo.EventObject} e
35622 * Fires when the mouse is hovering over this menu
35623 * @param {Roo.menu.Menu} this
35624 * @param {Roo.EventObject} e
35625 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35630 * Fires when the mouse exits this menu
35631 * @param {Roo.menu.Menu} this
35632 * @param {Roo.EventObject} e
35633 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35638 * Fires when a menu item contained in this menu is clicked
35639 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35640 * @param {Roo.EventObject} e
35644 if (this.registerMenu) {
35645 Roo.menu.MenuMgr.register(this);
35648 var mis = this.items;
35649 this.items = new Roo.util.MixedCollection();
35651 this.add.apply(this, mis);
35655 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35657 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35661 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35662 * for bottom-right shadow (defaults to "sides")
35666 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35667 * this menu (defaults to "tl-tr?")
35669 subMenuAlign : "tl-tr?",
35671 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35672 * relative to its element of origin (defaults to "tl-bl?")
35674 defaultAlign : "tl-bl?",
35676 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35678 allowOtherMenus : false,
35680 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35682 registerMenu : true,
35687 render : function(){
35691 var el = this.el = new Roo.Layer({
35693 shadow:this.shadow,
35695 parentEl: this.parentEl || document.body,
35699 this.keyNav = new Roo.menu.MenuNav(this);
35702 el.addClass("x-menu-plain");
35705 el.addClass(this.cls);
35707 // generic focus element
35708 this.focusEl = el.createChild({
35709 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35711 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35712 //disabling touch- as it's causing issues ..
35713 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35714 ul.on('click' , this.onClick, this);
35717 ul.on("mouseover", this.onMouseOver, this);
35718 ul.on("mouseout", this.onMouseOut, this);
35719 this.items.each(function(item){
35724 var li = document.createElement("li");
35725 li.className = "x-menu-list-item";
35726 ul.dom.appendChild(li);
35727 item.render(li, this);
35734 autoWidth : function(){
35735 var el = this.el, ul = this.ul;
35739 var w = this.width;
35742 }else if(Roo.isIE){
35743 el.setWidth(this.minWidth);
35744 var t = el.dom.offsetWidth; // force recalc
35745 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35750 delayAutoWidth : function(){
35753 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35755 this.awTask.delay(20);
35760 findTargetItem : function(e){
35761 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35762 if(t && t.menuItemId){
35763 return this.items.get(t.menuItemId);
35768 onClick : function(e){
35769 Roo.log("menu.onClick");
35770 var t = this.findTargetItem(e);
35775 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35776 if(t == this.activeItem && t.shouldDeactivate(e)){
35777 this.activeItem.deactivate();
35778 delete this.activeItem;
35782 this.setActiveItem(t, true);
35790 this.fireEvent("click", this, t, e);
35794 setActiveItem : function(item, autoExpand){
35795 if(item != this.activeItem){
35796 if(this.activeItem){
35797 this.activeItem.deactivate();
35799 this.activeItem = item;
35800 item.activate(autoExpand);
35801 }else if(autoExpand){
35807 tryActivate : function(start, step){
35808 var items = this.items;
35809 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35810 var item = items.get(i);
35811 if(!item.disabled && item.canActivate){
35812 this.setActiveItem(item, false);
35820 onMouseOver : function(e){
35822 if(t = this.findTargetItem(e)){
35823 if(t.canActivate && !t.disabled){
35824 this.setActiveItem(t, true);
35827 this.fireEvent("mouseover", this, e, t);
35831 onMouseOut : function(e){
35833 if(t = this.findTargetItem(e)){
35834 if(t == this.activeItem && t.shouldDeactivate(e)){
35835 this.activeItem.deactivate();
35836 delete this.activeItem;
35839 this.fireEvent("mouseout", this, e, t);
35843 * Read-only. Returns true if the menu is currently displayed, else false.
35846 isVisible : function(){
35847 return this.el && !this.hidden;
35851 * Displays this menu relative to another element
35852 * @param {String/HTMLElement/Roo.Element} element The element to align to
35853 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35854 * the element (defaults to this.defaultAlign)
35855 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35857 show : function(el, pos, parentMenu){
35858 this.parentMenu = parentMenu;
35862 this.fireEvent("beforeshow", this);
35863 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35867 * Displays this menu at a specific xy position
35868 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35869 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35871 showAt : function(xy, parentMenu, /* private: */_e){
35872 this.parentMenu = parentMenu;
35877 this.fireEvent("beforeshow", this);
35878 xy = this.el.adjustForConstraints(xy);
35882 this.hidden = false;
35884 this.fireEvent("show", this);
35887 focus : function(){
35889 this.doFocus.defer(50, this);
35893 doFocus : function(){
35895 this.focusEl.focus();
35900 * Hides this menu and optionally all parent menus
35901 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35903 hide : function(deep){
35904 if(this.el && this.isVisible()){
35905 this.fireEvent("beforehide", this);
35906 if(this.activeItem){
35907 this.activeItem.deactivate();
35908 this.activeItem = null;
35911 this.hidden = true;
35912 this.fireEvent("hide", this);
35914 if(deep === true && this.parentMenu){
35915 this.parentMenu.hide(true);
35920 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35921 * Any of the following are valid:
35923 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35924 * <li>An HTMLElement object which will be converted to a menu item</li>
35925 * <li>A menu item config object that will be created as a new menu item</li>
35926 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35927 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35932 var menu = new Roo.menu.Menu();
35934 // Create a menu item to add by reference
35935 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35937 // Add a bunch of items at once using different methods.
35938 // Only the last item added will be returned.
35939 var item = menu.add(
35940 menuItem, // add existing item by ref
35941 'Dynamic Item', // new TextItem
35942 '-', // new separator
35943 { text: 'Config Item' } // new item by config
35946 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35947 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35950 var a = arguments, l = a.length, item;
35951 for(var i = 0; i < l; i++){
35953 if ((typeof(el) == "object") && el.xtype && el.xns) {
35954 el = Roo.factory(el, Roo.menu);
35957 if(el.render){ // some kind of Item
35958 item = this.addItem(el);
35959 }else if(typeof el == "string"){ // string
35960 if(el == "separator" || el == "-"){
35961 item = this.addSeparator();
35963 item = this.addText(el);
35965 }else if(el.tagName || el.el){ // element
35966 item = this.addElement(el);
35967 }else if(typeof el == "object"){ // must be menu item config?
35968 item = this.addMenuItem(el);
35975 * Returns this menu's underlying {@link Roo.Element} object
35976 * @return {Roo.Element} The element
35978 getEl : function(){
35986 * Adds a separator bar to the menu
35987 * @return {Roo.menu.Item} The menu item that was added
35989 addSeparator : function(){
35990 return this.addItem(new Roo.menu.Separator());
35994 * Adds an {@link Roo.Element} object to the menu
35995 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35996 * @return {Roo.menu.Item} The menu item that was added
35998 addElement : function(el){
35999 return this.addItem(new Roo.menu.BaseItem(el));
36003 * Adds an existing object based on {@link Roo.menu.Item} to the menu
36004 * @param {Roo.menu.Item} item The menu item to add
36005 * @return {Roo.menu.Item} The menu item that was added
36007 addItem : function(item){
36008 this.items.add(item);
36010 var li = document.createElement("li");
36011 li.className = "x-menu-list-item";
36012 this.ul.dom.appendChild(li);
36013 item.render(li, this);
36014 this.delayAutoWidth();
36020 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
36021 * @param {Object} config A MenuItem config object
36022 * @return {Roo.menu.Item} The menu item that was added
36024 addMenuItem : function(config){
36025 if(!(config instanceof Roo.menu.Item)){
36026 if(typeof config.checked == "boolean"){ // must be check menu item config?
36027 config = new Roo.menu.CheckItem(config);
36029 config = new Roo.menu.Item(config);
36032 return this.addItem(config);
36036 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
36037 * @param {String} text The text to display in the menu item
36038 * @return {Roo.menu.Item} The menu item that was added
36040 addText : function(text){
36041 return this.addItem(new Roo.menu.TextItem({ text : text }));
36045 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
36046 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
36047 * @param {Roo.menu.Item} item The menu item to add
36048 * @return {Roo.menu.Item} The menu item that was added
36050 insert : function(index, item){
36051 this.items.insert(index, item);
36053 var li = document.createElement("li");
36054 li.className = "x-menu-list-item";
36055 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
36056 item.render(li, this);
36057 this.delayAutoWidth();
36063 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
36064 * @param {Roo.menu.Item} item The menu item to remove
36066 remove : function(item){
36067 this.items.removeKey(item.id);
36072 * Removes and destroys all items in the menu
36074 removeAll : function(){
36076 while(f = this.items.first()){
36082 // MenuNav is a private utility class used internally by the Menu
36083 Roo.menu.MenuNav = function(menu){
36084 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
36085 this.scope = this.menu = menu;
36088 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
36089 doRelay : function(e, h){
36090 var k = e.getKey();
36091 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
36092 this.menu.tryActivate(0, 1);
36095 return h.call(this.scope || this, e, this.menu);
36098 up : function(e, m){
36099 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
36100 m.tryActivate(m.items.length-1, -1);
36104 down : function(e, m){
36105 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
36106 m.tryActivate(0, 1);
36110 right : function(e, m){
36112 m.activeItem.expandMenu(true);
36116 left : function(e, m){
36118 if(m.parentMenu && m.parentMenu.activeItem){
36119 m.parentMenu.activeItem.activate();
36123 enter : function(e, m){
36125 e.stopPropagation();
36126 m.activeItem.onClick(e);
36127 m.fireEvent("click", this, m.activeItem);
36133 * Ext JS Library 1.1.1
36134 * Copyright(c) 2006-2007, Ext JS, LLC.
36136 * Originally Released Under LGPL - original licence link has changed is not relivant.
36139 * <script type="text/javascript">
36143 * @class Roo.menu.MenuMgr
36144 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
36147 Roo.menu.MenuMgr = function(){
36148 var menus, active, groups = {}, attached = false, lastShow = new Date();
36150 // private - called when first menu is created
36153 active = new Roo.util.MixedCollection();
36154 Roo.get(document).addKeyListener(27, function(){
36155 if(active.length > 0){
36162 function hideAll(){
36163 if(active && active.length > 0){
36164 var c = active.clone();
36165 c.each(function(m){
36172 function onHide(m){
36174 if(active.length < 1){
36175 Roo.get(document).un("mousedown", onMouseDown);
36181 function onShow(m){
36182 var last = active.last();
36183 lastShow = new Date();
36186 Roo.get(document).on("mousedown", onMouseDown);
36190 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
36191 m.parentMenu.activeChild = m;
36192 }else if(last && last.isVisible()){
36193 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
36198 function onBeforeHide(m){
36200 m.activeChild.hide();
36202 if(m.autoHideTimer){
36203 clearTimeout(m.autoHideTimer);
36204 delete m.autoHideTimer;
36209 function onBeforeShow(m){
36210 var pm = m.parentMenu;
36211 if(!pm && !m.allowOtherMenus){
36213 }else if(pm && pm.activeChild && active != m){
36214 pm.activeChild.hide();
36219 function onMouseDown(e){
36220 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36226 function onBeforeCheck(mi, state){
36228 var g = groups[mi.group];
36229 for(var i = 0, l = g.length; i < l; i++){
36231 g[i].setChecked(false);
36240 * Hides all menus that are currently visible
36242 hideAll : function(){
36247 register : function(menu){
36251 menus[menu.id] = menu;
36252 menu.on("beforehide", onBeforeHide);
36253 menu.on("hide", onHide);
36254 menu.on("beforeshow", onBeforeShow);
36255 menu.on("show", onShow);
36256 var g = menu.group;
36257 if(g && menu.events["checkchange"]){
36261 groups[g].push(menu);
36262 menu.on("checkchange", onCheck);
36267 * Returns a {@link Roo.menu.Menu} object
36268 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36269 * be used to generate and return a new Menu instance.
36271 get : function(menu){
36272 if(typeof menu == "string"){ // menu id
36273 return menus[menu];
36274 }else if(menu.events){ // menu instance
36276 }else if(typeof menu.length == 'number'){ // array of menu items?
36277 return new Roo.menu.Menu({items:menu});
36278 }else{ // otherwise, must be a config
36279 return new Roo.menu.Menu(menu);
36284 unregister : function(menu){
36285 delete menus[menu.id];
36286 menu.un("beforehide", onBeforeHide);
36287 menu.un("hide", onHide);
36288 menu.un("beforeshow", onBeforeShow);
36289 menu.un("show", onShow);
36290 var g = menu.group;
36291 if(g && menu.events["checkchange"]){
36292 groups[g].remove(menu);
36293 menu.un("checkchange", onCheck);
36298 registerCheckable : function(menuItem){
36299 var g = menuItem.group;
36304 groups[g].push(menuItem);
36305 menuItem.on("beforecheckchange", onBeforeCheck);
36310 unregisterCheckable : function(menuItem){
36311 var g = menuItem.group;
36313 groups[g].remove(menuItem);
36314 menuItem.un("beforecheckchange", onBeforeCheck);
36320 * Ext JS Library 1.1.1
36321 * Copyright(c) 2006-2007, Ext JS, LLC.
36323 * Originally Released Under LGPL - original licence link has changed is not relivant.
36326 * <script type="text/javascript">
36331 * @class Roo.menu.BaseItem
36332 * @extends Roo.Component
36333 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36334 * management and base configuration options shared by all menu components.
36336 * Creates a new BaseItem
36337 * @param {Object} config Configuration options
36339 Roo.menu.BaseItem = function(config){
36340 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36345 * Fires when this item is clicked
36346 * @param {Roo.menu.BaseItem} this
36347 * @param {Roo.EventObject} e
36352 * Fires when this item is activated
36353 * @param {Roo.menu.BaseItem} this
36357 * @event deactivate
36358 * Fires when this item is deactivated
36359 * @param {Roo.menu.BaseItem} this
36365 this.on("click", this.handler, this.scope, true);
36369 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36371 * @cfg {Function} handler
36372 * A function that will handle the click event of this menu item (defaults to undefined)
36375 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36377 canActivate : false,
36380 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36385 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36387 activeClass : "x-menu-item-active",
36389 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36391 hideOnClick : true,
36393 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36398 ctype: "Roo.menu.BaseItem",
36401 actionMode : "container",
36404 render : function(container, parentMenu){
36405 this.parentMenu = parentMenu;
36406 Roo.menu.BaseItem.superclass.render.call(this, container);
36407 this.container.menuItemId = this.id;
36411 onRender : function(container, position){
36412 this.el = Roo.get(this.el);
36413 container.dom.appendChild(this.el.dom);
36417 onClick : function(e){
36418 if(!this.disabled && this.fireEvent("click", this, e) !== false
36419 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36420 this.handleClick(e);
36427 activate : function(){
36431 var li = this.container;
36432 li.addClass(this.activeClass);
36433 this.region = li.getRegion().adjust(2, 2, -2, -2);
36434 this.fireEvent("activate", this);
36439 deactivate : function(){
36440 this.container.removeClass(this.activeClass);
36441 this.fireEvent("deactivate", this);
36445 shouldDeactivate : function(e){
36446 return !this.region || !this.region.contains(e.getPoint());
36450 handleClick : function(e){
36451 if(this.hideOnClick){
36452 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36457 expandMenu : function(autoActivate){
36462 hideMenu : function(){
36467 * Ext JS Library 1.1.1
36468 * Copyright(c) 2006-2007, Ext JS, LLC.
36470 * Originally Released Under LGPL - original licence link has changed is not relivant.
36473 * <script type="text/javascript">
36477 * @class Roo.menu.Adapter
36478 * @extends Roo.menu.BaseItem
36479 * A base utility class that adapts a non-menu component so that it can be wrapped by a menu item and added to a menu.
36480 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36482 * Creates a new Adapter
36483 * @param {Object} config Configuration options
36485 Roo.menu.Adapter = function(component, config){
36486 Roo.menu.Adapter.superclass.constructor.call(this, config);
36487 this.component = component;
36489 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36491 canActivate : true,
36494 onRender : function(container, position){
36495 this.component.render(container);
36496 this.el = this.component.getEl();
36500 activate : function(){
36504 this.component.focus();
36505 this.fireEvent("activate", this);
36510 deactivate : function(){
36511 this.fireEvent("deactivate", this);
36515 disable : function(){
36516 this.component.disable();
36517 Roo.menu.Adapter.superclass.disable.call(this);
36521 enable : function(){
36522 this.component.enable();
36523 Roo.menu.Adapter.superclass.enable.call(this);
36527 * Ext JS Library 1.1.1
36528 * Copyright(c) 2006-2007, Ext JS, LLC.
36530 * Originally Released Under LGPL - original licence link has changed is not relivant.
36533 * <script type="text/javascript">
36537 * @class Roo.menu.TextItem
36538 * @extends Roo.menu.BaseItem
36539 * Adds a static text string to a menu, usually used as either a heading or group separator.
36540 * Note: old style constructor with text is still supported.
36543 * Creates a new TextItem
36544 * @param {Object} cfg Configuration
36546 Roo.menu.TextItem = function(cfg){
36547 if (typeof(cfg) == 'string') {
36550 Roo.apply(this,cfg);
36553 Roo.menu.TextItem.superclass.constructor.call(this);
36556 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36558 * @cfg {Boolean} text Text to show on item.
36563 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36565 hideOnClick : false,
36567 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36569 itemCls : "x-menu-text",
36572 onRender : function(){
36573 var s = document.createElement("span");
36574 s.className = this.itemCls;
36575 s.innerHTML = this.text;
36577 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36581 * Ext JS Library 1.1.1
36582 * Copyright(c) 2006-2007, Ext JS, LLC.
36584 * Originally Released Under LGPL - original licence link has changed is not relivant.
36587 * <script type="text/javascript">
36591 * @class Roo.menu.Separator
36592 * @extends Roo.menu.BaseItem
36593 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36594 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36596 * @param {Object} config Configuration options
36598 Roo.menu.Separator = function(config){
36599 Roo.menu.Separator.superclass.constructor.call(this, config);
36602 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36604 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36606 itemCls : "x-menu-sep",
36608 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36610 hideOnClick : false,
36613 onRender : function(li){
36614 var s = document.createElement("span");
36615 s.className = this.itemCls;
36616 s.innerHTML = " ";
36618 li.addClass("x-menu-sep-li");
36619 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36623 * Ext JS Library 1.1.1
36624 * Copyright(c) 2006-2007, Ext JS, LLC.
36626 * Originally Released Under LGPL - original licence link has changed is not relivant.
36629 * <script type="text/javascript">
36632 * @class Roo.menu.Item
36633 * @extends Roo.menu.BaseItem
36634 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36635 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36636 * activation and click handling.
36638 * Creates a new Item
36639 * @param {Object} config Configuration options
36641 Roo.menu.Item = function(config){
36642 Roo.menu.Item.superclass.constructor.call(this, config);
36644 this.menu = Roo.menu.MenuMgr.get(this.menu);
36647 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36650 * @cfg {String} text
36651 * The text to show on the menu item.
36655 * @cfg {String} HTML to render in menu
36656 * The text to show on the menu item (HTML version).
36660 * @cfg {String} icon
36661 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36665 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36667 itemCls : "x-menu-item",
36669 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36671 canActivate : true,
36673 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36676 // doc'd in BaseItem
36680 ctype: "Roo.menu.Item",
36683 onRender : function(container, position){
36684 var el = document.createElement("a");
36685 el.hideFocus = true;
36686 el.unselectable = "on";
36687 el.href = this.href || "#";
36688 if(this.hrefTarget){
36689 el.target = this.hrefTarget;
36691 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36693 var html = this.html.length ? this.html : String.format('{0}',this.text);
36695 el.innerHTML = String.format(
36696 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36697 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36699 Roo.menu.Item.superclass.onRender.call(this, container, position);
36703 * Sets the text to display in this menu item
36704 * @param {String} text The text to display
36705 * @param {Boolean} isHTML true to indicate text is pure html.
36707 setText : function(text, isHTML){
36715 var html = this.html.length ? this.html : String.format('{0}',this.text);
36717 this.el.update(String.format(
36718 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36719 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36720 this.parentMenu.autoWidth();
36725 handleClick : function(e){
36726 if(!this.href){ // if no link defined, stop the event automatically
36729 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36733 activate : function(autoExpand){
36734 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36744 shouldDeactivate : function(e){
36745 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36746 if(this.menu && this.menu.isVisible()){
36747 return !this.menu.getEl().getRegion().contains(e.getPoint());
36755 deactivate : function(){
36756 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36761 expandMenu : function(autoActivate){
36762 if(!this.disabled && this.menu){
36763 clearTimeout(this.hideTimer);
36764 delete this.hideTimer;
36765 if(!this.menu.isVisible() && !this.showTimer){
36766 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36767 }else if (this.menu.isVisible() && autoActivate){
36768 this.menu.tryActivate(0, 1);
36774 deferExpand : function(autoActivate){
36775 delete this.showTimer;
36776 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36778 this.menu.tryActivate(0, 1);
36783 hideMenu : function(){
36784 clearTimeout(this.showTimer);
36785 delete this.showTimer;
36786 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36787 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36792 deferHide : function(){
36793 delete this.hideTimer;
36798 * Ext JS Library 1.1.1
36799 * Copyright(c) 2006-2007, Ext JS, LLC.
36801 * Originally Released Under LGPL - original licence link has changed is not relivant.
36804 * <script type="text/javascript">
36808 * @class Roo.menu.CheckItem
36809 * @extends Roo.menu.Item
36810 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36812 * Creates a new CheckItem
36813 * @param {Object} config Configuration options
36815 Roo.menu.CheckItem = function(config){
36816 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36819 * @event beforecheckchange
36820 * Fires before the checked value is set, providing an opportunity to cancel if needed
36821 * @param {Roo.menu.CheckItem} this
36822 * @param {Boolean} checked The new checked value that will be set
36824 "beforecheckchange" : true,
36826 * @event checkchange
36827 * Fires after the checked value has been set
36828 * @param {Roo.menu.CheckItem} this
36829 * @param {Boolean} checked The checked value that was set
36831 "checkchange" : true
36833 if(this.checkHandler){
36834 this.on('checkchange', this.checkHandler, this.scope);
36837 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36839 * @cfg {String} group
36840 * All check items with the same group name will automatically be grouped into a single-select
36841 * radio button group (defaults to '')
36844 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36846 itemCls : "x-menu-item x-menu-check-item",
36848 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36850 groupClass : "x-menu-group-item",
36853 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36854 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36855 * initialized with checked = true will be rendered as checked.
36860 ctype: "Roo.menu.CheckItem",
36863 onRender : function(c){
36864 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36866 this.el.addClass(this.groupClass);
36868 Roo.menu.MenuMgr.registerCheckable(this);
36870 this.checked = false;
36871 this.setChecked(true, true);
36876 destroy : function(){
36878 Roo.menu.MenuMgr.unregisterCheckable(this);
36880 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36884 * Set the checked state of this item
36885 * @param {Boolean} checked The new checked value
36886 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36888 setChecked : function(state, suppressEvent){
36889 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36890 if(this.container){
36891 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36893 this.checked = state;
36894 if(suppressEvent !== true){
36895 this.fireEvent("checkchange", this, state);
36901 handleClick : function(e){
36902 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36903 this.setChecked(!this.checked);
36905 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36909 * Ext JS Library 1.1.1
36910 * Copyright(c) 2006-2007, Ext JS, LLC.
36912 * Originally Released Under LGPL - original licence link has changed is not relivant.
36915 * <script type="text/javascript">
36919 * @class Roo.menu.DateItem
36920 * @extends Roo.menu.Adapter
36921 * A menu item that wraps the {@link Roo.DatPicker} component.
36923 * Creates a new DateItem
36924 * @param {Object} config Configuration options
36926 Roo.menu.DateItem = function(config){
36927 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36928 /** The Roo.DatePicker object @type Roo.DatePicker */
36929 this.picker = this.component;
36930 this.addEvents({select: true});
36932 this.picker.on("render", function(picker){
36933 picker.getEl().swallowEvent("click");
36934 picker.container.addClass("x-menu-date-item");
36937 this.picker.on("select", this.onSelect, this);
36940 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36942 onSelect : function(picker, date){
36943 this.fireEvent("select", this, date, picker);
36944 Roo.menu.DateItem.superclass.handleClick.call(this);
36948 * Ext JS Library 1.1.1
36949 * Copyright(c) 2006-2007, Ext JS, LLC.
36951 * Originally Released Under LGPL - original licence link has changed is not relivant.
36954 * <script type="text/javascript">
36958 * @class Roo.menu.ColorItem
36959 * @extends Roo.menu.Adapter
36960 * A menu item that wraps the {@link Roo.ColorPalette} component.
36962 * Creates a new ColorItem
36963 * @param {Object} config Configuration options
36965 Roo.menu.ColorItem = function(config){
36966 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36967 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36968 this.palette = this.component;
36969 this.relayEvents(this.palette, ["select"]);
36970 if(this.selectHandler){
36971 this.on('select', this.selectHandler, this.scope);
36974 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36976 * Ext JS Library 1.1.1
36977 * Copyright(c) 2006-2007, Ext JS, LLC.
36979 * Originally Released Under LGPL - original licence link has changed is not relivant.
36982 * <script type="text/javascript">
36987 * @class Roo.menu.DateMenu
36988 * @extends Roo.menu.Menu
36989 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36991 * Creates a new DateMenu
36992 * @param {Object} config Configuration options
36994 Roo.menu.DateMenu = function(config){
36995 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36997 var di = new Roo.menu.DateItem(config);
37000 * The {@link Roo.DatePicker} instance for this DateMenu
37003 this.picker = di.picker;
37006 * @param {DatePicker} picker
37007 * @param {Date} date
37009 this.relayEvents(di, ["select"]);
37010 this.on('beforeshow', function(){
37012 this.picker.hideMonthPicker(false);
37016 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
37020 * Ext JS Library 1.1.1
37021 * Copyright(c) 2006-2007, Ext JS, LLC.
37023 * Originally Released Under LGPL - original licence link has changed is not relivant.
37026 * <script type="text/javascript">
37031 * @class Roo.menu.ColorMenu
37032 * @extends Roo.menu.Menu
37033 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
37035 * Creates a new ColorMenu
37036 * @param {Object} config Configuration options
37038 Roo.menu.ColorMenu = function(config){
37039 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
37041 var ci = new Roo.menu.ColorItem(config);
37044 * The {@link Roo.ColorPalette} instance for this ColorMenu
37045 * @type ColorPalette
37047 this.palette = ci.palette;
37050 * @param {ColorPalette} palette
37051 * @param {String} color
37053 this.relayEvents(ci, ["select"]);
37055 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
37057 * Ext JS Library 1.1.1
37058 * Copyright(c) 2006-2007, Ext JS, LLC.
37060 * Originally Released Under LGPL - original licence link has changed is not relivant.
37063 * <script type="text/javascript">
37067 * @class Roo.form.Field
37068 * @extends Roo.BoxComponent
37069 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
37071 * Creates a new Field
37072 * @param {Object} config Configuration options
37074 Roo.form.Field = function(config){
37075 Roo.form.Field.superclass.constructor.call(this, config);
37078 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
37080 * @cfg {String} fieldLabel Label to use when rendering a form.
37083 * @cfg {String} qtip Mouse over tip
37087 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
37089 invalidClass : "x-form-invalid",
37091 * @cfg {String} invalidText The error text to use when marking a field invalid and no message is provided (defaults to "The value in this field is invalid")
37093 invalidText : "The value in this field is invalid",
37095 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
37097 focusClass : "x-form-focus",
37099 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
37100 automatic validation (defaults to "keyup").
37102 validationEvent : "keyup",
37104 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
37106 validateOnBlur : true,
37108 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
37110 validationDelay : 250,
37112 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37113 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
37115 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
37117 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
37119 fieldClass : "x-form-field",
37121 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
37124 ----------- ----------------------------------------------------------------------
37125 qtip Display a quick tip when the user hovers over the field
37126 title Display a default browser title attribute popup
37127 under Add a block div beneath the field containing the error text
37128 side Add an error icon to the right of the field with a popup on hover
37129 [element id] Add the error text directly to the innerHTML of the specified element
37132 msgTarget : 'qtip',
37134 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
37139 * @cfg {Boolean} readOnly True to mark the field as readOnly in HTML (defaults to false) -- Note: this only sets the element's readOnly DOM attribute.
37144 * @cfg {Boolean} disabled True to disable the field (defaults to false).
37149 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
37151 inputType : undefined,
37154 * @cfg {Number} tabIndex The tabIndex for this field. Note this only applies to fields that are rendered, not those which are built via applyTo (defaults to undefined).
37156 tabIndex : undefined,
37159 isFormField : true,
37164 * @property {Roo.Element} fieldEl
37165 * Element Containing the rendered Field (with label etc.)
37168 * @cfg {Mixed} value A value to initialize this field with.
37173 * @cfg {String} name The field's HTML name attribute.
37176 * @cfg {String} cls A CSS class to apply to the field's underlying element.
37180 initComponent : function(){
37181 Roo.form.Field.superclass.initComponent.call(this);
37185 * Fires when this field receives input focus.
37186 * @param {Roo.form.Field} this
37191 * Fires when this field loses input focus.
37192 * @param {Roo.form.Field} this
37196 * @event specialkey
37197 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
37198 * {@link Roo.EventObject#getKey} to determine which key was pressed.
37199 * @param {Roo.form.Field} this
37200 * @param {Roo.EventObject} e The event object
37205 * Fires just before the field blurs if the field value has changed.
37206 * @param {Roo.form.Field} this
37207 * @param {Mixed} newValue The new value
37208 * @param {Mixed} oldValue The original value
37213 * Fires after the field has been marked as invalid.
37214 * @param {Roo.form.Field} this
37215 * @param {String} msg The validation message
37220 * Fires after the field has been validated with no errors.
37221 * @param {Roo.form.Field} this
37226 * Fires after the key up
37227 * @param {Roo.form.Field} this
37228 * @param {Roo.EventObject} e The event Object
37235 * Returns the name attribute of the field if available
37236 * @return {String} name The field name
37238 getName: function(){
37239 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37243 onRender : function(ct, position){
37244 Roo.form.Field.superclass.onRender.call(this, ct, position);
37246 var cfg = this.getAutoCreate();
37248 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37250 if (!cfg.name.length) {
37253 if(this.inputType){
37254 cfg.type = this.inputType;
37256 this.el = ct.createChild(cfg, position);
37258 var type = this.el.dom.type;
37260 if(type == 'password'){
37263 this.el.addClass('x-form-'+type);
37266 this.el.dom.readOnly = true;
37268 if(this.tabIndex !== undefined){
37269 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37272 this.el.addClass([this.fieldClass, this.cls]);
37277 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37278 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37279 * @return {Roo.form.Field} this
37281 applyTo : function(target){
37282 this.allowDomMove = false;
37283 this.el = Roo.get(target);
37284 this.render(this.el.dom.parentNode);
37289 initValue : function(){
37290 if(this.value !== undefined){
37291 this.setValue(this.value);
37292 }else if(this.el.dom.value.length > 0){
37293 this.setValue(this.el.dom.value);
37298 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37300 isDirty : function() {
37301 if(this.disabled) {
37304 return String(this.getValue()) !== String(this.originalValue);
37308 afterRender : function(){
37309 Roo.form.Field.superclass.afterRender.call(this);
37314 fireKey : function(e){
37315 //Roo.log('field ' + e.getKey());
37316 if(e.isNavKeyPress()){
37317 this.fireEvent("specialkey", this, e);
37322 * Resets the current field value to the originally loaded value and clears any validation messages
37324 reset : function(){
37325 this.setValue(this.resetValue);
37326 this.clearInvalid();
37330 initEvents : function(){
37331 // safari killled keypress - so keydown is now used..
37332 this.el.on("keydown" , this.fireKey, this);
37333 this.el.on("focus", this.onFocus, this);
37334 this.el.on("blur", this.onBlur, this);
37335 this.el.relayEvent('keyup', this);
37337 // reference to original value for reset
37338 this.originalValue = this.getValue();
37339 this.resetValue = this.getValue();
37343 onFocus : function(){
37344 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37345 this.el.addClass(this.focusClass);
37347 if(!this.hasFocus){
37348 this.hasFocus = true;
37349 this.startValue = this.getValue();
37350 this.fireEvent("focus", this);
37354 beforeBlur : Roo.emptyFn,
37357 onBlur : function(){
37359 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37360 this.el.removeClass(this.focusClass);
37362 this.hasFocus = false;
37363 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37366 var v = this.getValue();
37367 if(String(v) !== String(this.startValue)){
37368 this.fireEvent('change', this, v, this.startValue);
37370 this.fireEvent("blur", this);
37374 * Returns whether or not the field value is currently valid
37375 * @param {Boolean} preventMark True to disable marking the field invalid
37376 * @return {Boolean} True if the value is valid, else false
37378 isValid : function(preventMark){
37382 var restore = this.preventMark;
37383 this.preventMark = preventMark === true;
37384 var v = this.validateValue(this.processValue(this.getRawValue()));
37385 this.preventMark = restore;
37390 * Validates the field value
37391 * @return {Boolean} True if the value is valid, else false
37393 validate : function(){
37394 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37395 this.clearInvalid();
37401 processValue : function(value){
37406 // Subclasses should provide the validation implementation by overriding this
37407 validateValue : function(value){
37412 * Mark this field as invalid
37413 * @param {String} msg The validation message
37415 markInvalid : function(msg){
37416 if(!this.rendered || this.preventMark){ // not rendered
37420 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37422 obj.el.addClass(this.invalidClass);
37423 msg = msg || this.invalidText;
37424 switch(this.msgTarget){
37426 obj.el.dom.qtip = msg;
37427 obj.el.dom.qclass = 'x-form-invalid-tip';
37428 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37429 Roo.QuickTips.enable();
37433 this.el.dom.title = msg;
37437 var elp = this.el.findParent('.x-form-element', 5, true);
37438 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37439 this.errorEl.setWidth(elp.getWidth(true)-20);
37441 this.errorEl.update(msg);
37442 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37445 if(!this.errorIcon){
37446 var elp = this.el.findParent('.x-form-element', 5, true);
37447 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37449 this.alignErrorIcon();
37450 this.errorIcon.dom.qtip = msg;
37451 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37452 this.errorIcon.show();
37453 this.on('resize', this.alignErrorIcon, this);
37456 var t = Roo.getDom(this.msgTarget);
37458 t.style.display = this.msgDisplay;
37461 this.fireEvent('invalid', this, msg);
37465 alignErrorIcon : function(){
37466 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37470 * Clear any invalid styles/messages for this field
37472 clearInvalid : function(){
37473 if(!this.rendered || this.preventMark){ // not rendered
37476 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37478 obj.el.removeClass(this.invalidClass);
37479 switch(this.msgTarget){
37481 obj.el.dom.qtip = '';
37484 this.el.dom.title = '';
37488 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37492 if(this.errorIcon){
37493 this.errorIcon.dom.qtip = '';
37494 this.errorIcon.hide();
37495 this.un('resize', this.alignErrorIcon, this);
37499 var t = Roo.getDom(this.msgTarget);
37501 t.style.display = 'none';
37504 this.fireEvent('valid', this);
37508 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37509 * @return {Mixed} value The field value
37511 getRawValue : function(){
37512 var v = this.el.getValue();
37518 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37519 * @return {Mixed} value The field value
37521 getValue : function(){
37522 var v = this.el.getValue();
37528 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37529 * @param {Mixed} value The value to set
37531 setRawValue : function(v){
37532 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37536 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37537 * @param {Mixed} value The value to set
37539 setValue : function(v){
37542 this.el.dom.value = (v === null || v === undefined ? '' : v);
37547 adjustSize : function(w, h){
37548 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37549 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37553 adjustWidth : function(tag, w){
37554 tag = tag.toLowerCase();
37555 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37556 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37557 if(tag == 'input'){
37560 if(tag == 'textarea'){
37563 }else if(Roo.isOpera){
37564 if(tag == 'input'){
37567 if(tag == 'textarea'){
37577 // anything other than normal should be considered experimental
37578 Roo.form.Field.msgFx = {
37580 show: function(msgEl, f){
37581 msgEl.setDisplayed('block');
37584 hide : function(msgEl, f){
37585 msgEl.setDisplayed(false).update('');
37590 show: function(msgEl, f){
37591 msgEl.slideIn('t', {stopFx:true});
37594 hide : function(msgEl, f){
37595 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37600 show: function(msgEl, f){
37601 msgEl.fixDisplay();
37602 msgEl.alignTo(f.el, 'tl-tr');
37603 msgEl.slideIn('l', {stopFx:true});
37606 hide : function(msgEl, f){
37607 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37612 * Ext JS Library 1.1.1
37613 * Copyright(c) 2006-2007, Ext JS, LLC.
37615 * Originally Released Under LGPL - original licence link has changed is not relivant.
37618 * <script type="text/javascript">
37623 * @class Roo.form.TextField
37624 * @extends Roo.form.Field
37625 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37626 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37628 * Creates a new TextField
37629 * @param {Object} config Configuration options
37631 Roo.form.TextField = function(config){
37632 Roo.form.TextField.superclass.constructor.call(this, config);
37636 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37637 * according to the default logic, but this event provides a hook for the developer to apply additional
37638 * logic at runtime to resize the field if needed.
37639 * @param {Roo.form.Field} this This text field
37640 * @param {Number} width The new field width
37646 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37648 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37652 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37656 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37660 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37664 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37668 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37670 disableKeyFilter : false,
37672 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37676 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37680 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37682 maxLength : Number.MAX_VALUE,
37684 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37686 minLengthText : "The minimum length for this field is {0}",
37688 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37690 maxLengthText : "The maximum length for this field is {0}",
37692 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37694 selectOnFocus : false,
37696 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37698 blankText : "This field is required",
37700 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37701 * If available, this function will be called only after the basic validators all return true, and will be passed the
37702 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37706 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37707 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37708 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37712 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37716 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37722 initEvents : function()
37724 if (this.emptyText) {
37725 this.el.attr('placeholder', this.emptyText);
37728 Roo.form.TextField.superclass.initEvents.call(this);
37729 if(this.validationEvent == 'keyup'){
37730 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37731 this.el.on('keyup', this.filterValidation, this);
37733 else if(this.validationEvent !== false){
37734 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37737 if(this.selectOnFocus){
37738 this.on("focus", this.preFocus, this);
37741 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37742 this.el.on("keypress", this.filterKeys, this);
37745 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37746 this.el.on("click", this.autoSize, this);
37748 if(this.el.is('input[type=password]') && Roo.isSafari){
37749 this.el.on('keydown', this.SafariOnKeyDown, this);
37753 processValue : function(value){
37754 if(this.stripCharsRe){
37755 var newValue = value.replace(this.stripCharsRe, '');
37756 if(newValue !== value){
37757 this.setRawValue(newValue);
37764 filterValidation : function(e){
37765 if(!e.isNavKeyPress()){
37766 this.validationTask.delay(this.validationDelay);
37771 onKeyUp : function(e){
37772 if(!e.isNavKeyPress()){
37778 * Resets the current field value to the originally-loaded value and clears any validation messages.
37781 reset : function(){
37782 Roo.form.TextField.superclass.reset.call(this);
37788 preFocus : function(){
37790 if(this.selectOnFocus){
37791 this.el.dom.select();
37797 filterKeys : function(e){
37798 var k = e.getKey();
37799 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37802 var c = e.getCharCode(), cc = String.fromCharCode(c);
37803 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37806 if(!this.maskRe.test(cc)){
37811 setValue : function(v){
37813 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37819 * Validates a value according to the field's validation rules and marks the field as invalid
37820 * if the validation fails
37821 * @param {Mixed} value The value to validate
37822 * @return {Boolean} True if the value is valid, else false
37824 validateValue : function(value){
37825 if(value.length < 1) { // if it's blank
37826 if(this.allowBlank){
37827 this.clearInvalid();
37830 this.markInvalid(this.blankText);
37834 if(value.length < this.minLength){
37835 this.markInvalid(String.format(this.minLengthText, this.minLength));
37838 if(value.length > this.maxLength){
37839 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37843 var vt = Roo.form.VTypes;
37844 if(!vt[this.vtype](value, this)){
37845 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37849 if(typeof this.validator == "function"){
37850 var msg = this.validator(value);
37852 this.markInvalid(msg);
37856 if(this.regex && !this.regex.test(value)){
37857 this.markInvalid(this.regexText);
37864 * Selects text in this field
37865 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37866 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37868 selectText : function(start, end){
37869 var v = this.getRawValue();
37871 start = start === undefined ? 0 : start;
37872 end = end === undefined ? v.length : end;
37873 var d = this.el.dom;
37874 if(d.setSelectionRange){
37875 d.setSelectionRange(start, end);
37876 }else if(d.createTextRange){
37877 var range = d.createTextRange();
37878 range.moveStart("character", start);
37879 range.moveEnd("character", v.length-end);
37886 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37887 * This only takes effect if grow = true, and fires the autosize event.
37889 autoSize : function(){
37890 if(!this.grow || !this.rendered){
37894 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37897 var v = el.dom.value;
37898 var d = document.createElement('div');
37899 d.appendChild(document.createTextNode(v));
37903 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37904 this.el.setWidth(w);
37905 this.fireEvent("autosize", this, w);
37909 SafariOnKeyDown : function(event)
37911 // this is a workaround for a password hang bug on chrome/ webkit.
37913 var isSelectAll = false;
37915 if(this.el.dom.selectionEnd > 0){
37916 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37918 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37919 event.preventDefault();
37924 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
37926 event.preventDefault();
37927 // this is very hacky as keydown always get's upper case.
37929 var cc = String.fromCharCode(event.getCharCode());
37932 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37940 * Ext JS Library 1.1.1
37941 * Copyright(c) 2006-2007, Ext JS, LLC.
37943 * Originally Released Under LGPL - original licence link has changed is not relivant.
37946 * <script type="text/javascript">
37950 * @class Roo.form.Hidden
37951 * @extends Roo.form.TextField
37952 * Simple Hidden element used on forms
37954 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37957 * Creates a new Hidden form element.
37958 * @param {Object} config Configuration options
37963 // easy hidden field...
37964 Roo.form.Hidden = function(config){
37965 Roo.form.Hidden.superclass.constructor.call(this, config);
37968 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37970 inputType: 'hidden',
37973 labelSeparator: '',
37975 itemCls : 'x-form-item-display-none'
37983 * Ext JS Library 1.1.1
37984 * Copyright(c) 2006-2007, Ext JS, LLC.
37986 * Originally Released Under LGPL - original licence link has changed is not relivant.
37989 * <script type="text/javascript">
37993 * @class Roo.form.TriggerField
37994 * @extends Roo.form.TextField
37995 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37996 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37997 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37998 * for which you can provide a custom implementation. For example:
38000 var trigger = new Roo.form.TriggerField();
38001 trigger.onTriggerClick = myTriggerFn;
38002 trigger.applyTo('my-field');
38005 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
38006 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
38007 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
38008 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
38010 * Create a new TriggerField.
38011 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
38012 * to the base TextField)
38014 Roo.form.TriggerField = function(config){
38015 this.mimicing = false;
38016 Roo.form.TriggerField.superclass.constructor.call(this, config);
38019 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
38021 * @cfg {String} triggerClass A CSS class to apply to the trigger
38024 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38025 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
38027 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
38029 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
38033 /** @cfg {Boolean} grow @hide */
38034 /** @cfg {Number} growMin @hide */
38035 /** @cfg {Number} growMax @hide */
38041 autoSize: Roo.emptyFn,
38045 deferHeight : true,
38048 actionMode : 'wrap',
38050 onResize : function(w, h){
38051 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
38052 if(typeof w == 'number'){
38053 var x = w - this.trigger.getWidth();
38054 this.el.setWidth(this.adjustWidth('input', x));
38055 this.trigger.setStyle('left', x+'px');
38060 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38063 getResizeEl : function(){
38068 getPositionEl : function(){
38073 alignErrorIcon : function(){
38074 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
38078 onRender : function(ct, position){
38079 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
38080 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
38081 this.trigger = this.wrap.createChild(this.triggerConfig ||
38082 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
38083 if(this.hideTrigger){
38084 this.trigger.setDisplayed(false);
38086 this.initTrigger();
38088 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
38093 initTrigger : function(){
38094 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
38095 this.trigger.addClassOnOver('x-form-trigger-over');
38096 this.trigger.addClassOnClick('x-form-trigger-click');
38100 onDestroy : function(){
38102 this.trigger.removeAllListeners();
38103 this.trigger.remove();
38106 this.wrap.remove();
38108 Roo.form.TriggerField.superclass.onDestroy.call(this);
38112 onFocus : function(){
38113 Roo.form.TriggerField.superclass.onFocus.call(this);
38114 if(!this.mimicing){
38115 this.wrap.addClass('x-trigger-wrap-focus');
38116 this.mimicing = true;
38117 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
38118 if(this.monitorTab){
38119 this.el.on("keydown", this.checkTab, this);
38125 checkTab : function(e){
38126 if(e.getKey() == e.TAB){
38127 this.triggerBlur();
38132 onBlur : function(){
38137 mimicBlur : function(e, t){
38138 if(!this.wrap.contains(t) && this.validateBlur()){
38139 this.triggerBlur();
38144 triggerBlur : function(){
38145 this.mimicing = false;
38146 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
38147 if(this.monitorTab){
38148 this.el.un("keydown", this.checkTab, this);
38150 this.wrap.removeClass('x-trigger-wrap-focus');
38151 Roo.form.TriggerField.superclass.onBlur.call(this);
38155 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
38156 validateBlur : function(e, t){
38161 onDisable : function(){
38162 Roo.form.TriggerField.superclass.onDisable.call(this);
38164 this.wrap.addClass('x-item-disabled');
38169 onEnable : function(){
38170 Roo.form.TriggerField.superclass.onEnable.call(this);
38172 this.wrap.removeClass('x-item-disabled');
38177 onShow : function(){
38178 var ae = this.getActionEl();
38181 ae.dom.style.display = '';
38182 ae.dom.style.visibility = 'visible';
38188 onHide : function(){
38189 var ae = this.getActionEl();
38190 ae.dom.style.display = 'none';
38194 * The function that should handle the trigger's click event. This method does nothing by default until overridden
38195 * by an implementing function.
38197 * @param {EventObject} e
38199 onTriggerClick : Roo.emptyFn
38202 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
38203 // to be extended by an implementing class. For an example of implementing this class, see the custom
38204 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
38205 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
38206 initComponent : function(){
38207 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
38209 this.triggerConfig = {
38210 tag:'span', cls:'x-form-twin-triggers', cn:[
38211 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38212 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38216 getTrigger : function(index){
38217 return this.triggers[index];
38220 initTrigger : function(){
38221 var ts = this.trigger.select('.x-form-trigger', true);
38222 this.wrap.setStyle('overflow', 'hidden');
38223 var triggerField = this;
38224 ts.each(function(t, all, index){
38225 t.hide = function(){
38226 var w = triggerField.wrap.getWidth();
38227 this.dom.style.display = 'none';
38228 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38230 t.show = function(){
38231 var w = triggerField.wrap.getWidth();
38232 this.dom.style.display = '';
38233 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38235 var triggerIndex = 'Trigger'+(index+1);
38237 if(this['hide'+triggerIndex]){
38238 t.dom.style.display = 'none';
38240 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38241 t.addClassOnOver('x-form-trigger-over');
38242 t.addClassOnClick('x-form-trigger-click');
38244 this.triggers = ts.elements;
38247 onTrigger1Click : Roo.emptyFn,
38248 onTrigger2Click : Roo.emptyFn
38251 * Ext JS Library 1.1.1
38252 * Copyright(c) 2006-2007, Ext JS, LLC.
38254 * Originally Released Under LGPL - original licence link has changed is not relivant.
38257 * <script type="text/javascript">
38261 * @class Roo.form.TextArea
38262 * @extends Roo.form.TextField
38263 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38264 * support for auto-sizing.
38266 * Creates a new TextArea
38267 * @param {Object} config Configuration options
38269 Roo.form.TextArea = function(config){
38270 Roo.form.TextArea.superclass.constructor.call(this, config);
38271 // these are provided exchanges for backwards compat
38272 // minHeight/maxHeight were replaced by growMin/growMax to be
38273 // compatible with TextField growing config values
38274 if(this.minHeight !== undefined){
38275 this.growMin = this.minHeight;
38277 if(this.maxHeight !== undefined){
38278 this.growMax = this.maxHeight;
38282 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38284 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38288 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38292 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38293 * in the field (equivalent to setting overflow: hidden, defaults to false)
38295 preventScrollbars: false,
38297 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38298 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38302 onRender : function(ct, position){
38304 this.defaultAutoCreate = {
38306 style:"width:300px;height:60px;",
38307 autocomplete: "new-password"
38310 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38312 this.textSizeEl = Roo.DomHelper.append(document.body, {
38313 tag: "pre", cls: "x-form-grow-sizer"
38315 if(this.preventScrollbars){
38316 this.el.setStyle("overflow", "hidden");
38318 this.el.setHeight(this.growMin);
38322 onDestroy : function(){
38323 if(this.textSizeEl){
38324 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38326 Roo.form.TextArea.superclass.onDestroy.call(this);
38330 onKeyUp : function(e){
38331 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38337 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38338 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38340 autoSize : function(){
38341 if(!this.grow || !this.textSizeEl){
38345 var v = el.dom.value;
38346 var ts = this.textSizeEl;
38349 ts.appendChild(document.createTextNode(v));
38352 Roo.fly(ts).setWidth(this.el.getWidth());
38354 v = "  ";
38357 v = v.replace(/\n/g, '<p> </p>');
38359 v += " \n ";
38362 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38363 if(h != this.lastHeight){
38364 this.lastHeight = h;
38365 this.el.setHeight(h);
38366 this.fireEvent("autosize", this, h);
38371 * Ext JS Library 1.1.1
38372 * Copyright(c) 2006-2007, Ext JS, LLC.
38374 * Originally Released Under LGPL - original licence link has changed is not relivant.
38377 * <script type="text/javascript">
38382 * @class Roo.form.NumberField
38383 * @extends Roo.form.TextField
38384 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38386 * Creates a new NumberField
38387 * @param {Object} config Configuration options
38389 Roo.form.NumberField = function(config){
38390 Roo.form.NumberField.superclass.constructor.call(this, config);
38393 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38395 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38397 fieldClass: "x-form-field x-form-num-field",
38399 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38401 allowDecimals : true,
38403 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38405 decimalSeparator : ".",
38407 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38409 decimalPrecision : 2,
38411 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38413 allowNegative : true,
38415 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38417 minValue : Number.NEGATIVE_INFINITY,
38419 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38421 maxValue : Number.MAX_VALUE,
38423 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38425 minText : "The minimum value for this field is {0}",
38427 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38429 maxText : "The maximum value for this field is {0}",
38431 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38432 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38434 nanText : "{0} is not a valid number",
38437 initEvents : function(){
38438 Roo.form.NumberField.superclass.initEvents.call(this);
38439 var allowed = "0123456789";
38440 if(this.allowDecimals){
38441 allowed += this.decimalSeparator;
38443 if(this.allowNegative){
38446 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38447 var keyPress = function(e){
38448 var k = e.getKey();
38449 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38452 var c = e.getCharCode();
38453 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38457 this.el.on("keypress", keyPress, this);
38461 validateValue : function(value){
38462 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38465 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38468 var num = this.parseValue(value);
38470 this.markInvalid(String.format(this.nanText, value));
38473 if(num < this.minValue){
38474 this.markInvalid(String.format(this.minText, this.minValue));
38477 if(num > this.maxValue){
38478 this.markInvalid(String.format(this.maxText, this.maxValue));
38484 getValue : function(){
38485 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38489 parseValue : function(value){
38490 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38491 return isNaN(value) ? '' : value;
38495 fixPrecision : function(value){
38496 var nan = isNaN(value);
38497 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38498 return nan ? '' : value;
38500 return parseFloat(value).toFixed(this.decimalPrecision);
38503 setValue : function(v){
38504 v = this.fixPrecision(v);
38505 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38509 decimalPrecisionFcn : function(v){
38510 return Math.floor(v);
38513 beforeBlur : function(){
38514 var v = this.parseValue(this.getRawValue());
38521 * Ext JS Library 1.1.1
38522 * Copyright(c) 2006-2007, Ext JS, LLC.
38524 * Originally Released Under LGPL - original licence link has changed is not relivant.
38527 * <script type="text/javascript">
38531 * @class Roo.form.DateField
38532 * @extends Roo.form.TriggerField
38533 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38535 * Create a new DateField
38536 * @param {Object} config
38538 Roo.form.DateField = function(config){
38539 Roo.form.DateField.superclass.constructor.call(this, config);
38545 * Fires when a date is selected
38546 * @param {Roo.form.DateField} combo This combo box
38547 * @param {Date} date The date selected
38554 if(typeof this.minValue == "string") {
38555 this.minValue = this.parseDate(this.minValue);
38557 if(typeof this.maxValue == "string") {
38558 this.maxValue = this.parseDate(this.maxValue);
38560 this.ddMatch = null;
38561 if(this.disabledDates){
38562 var dd = this.disabledDates;
38564 for(var i = 0; i < dd.length; i++){
38566 if(i != dd.length-1) {
38570 this.ddMatch = new RegExp(re + ")");
38574 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38576 * @cfg {String} format
38577 * The default date format string which can be overriden for localization support. The format must be
38578 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38582 * @cfg {String} altFormats
38583 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38584 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38586 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38588 * @cfg {Array} disabledDays
38589 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38591 disabledDays : null,
38593 * @cfg {String} disabledDaysText
38594 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38596 disabledDaysText : "Disabled",
38598 * @cfg {Array} disabledDates
38599 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38600 * expression so they are very powerful. Some examples:
38602 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38603 * <li>["03/08", "09/16"] would disable those days for every year</li>
38604 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38605 * <li>["03/../2006"] would disable every day in March 2006</li>
38606 * <li>["^03"] would disable every day in every March</li>
38608 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38609 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38611 disabledDates : null,
38613 * @cfg {String} disabledDatesText
38614 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38616 disabledDatesText : "Disabled",
38618 * @cfg {Date/String} minValue
38619 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38620 * valid format (defaults to null).
38624 * @cfg {Date/String} maxValue
38625 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38626 * valid format (defaults to null).
38630 * @cfg {String} minText
38631 * The error text to display when the date in the cell is before minValue (defaults to
38632 * 'The date in this field must be after {minValue}').
38634 minText : "The date in this field must be equal to or after {0}",
38636 * @cfg {String} maxText
38637 * The error text to display when the date in the cell is after maxValue (defaults to
38638 * 'The date in this field must be before {maxValue}').
38640 maxText : "The date in this field must be equal to or before {0}",
38642 * @cfg {String} invalidText
38643 * The error text to display when the date in the field is invalid (defaults to
38644 * '{value} is not a valid date - it must be in the format {format}').
38646 invalidText : "{0} is not a valid date - it must be in the format {1}",
38648 * @cfg {String} triggerClass
38649 * An additional CSS class used to style the trigger button. The trigger will always get the
38650 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38651 * which displays a calendar icon).
38653 triggerClass : 'x-form-date-trigger',
38657 * @cfg {Boolean} useIso
38658 * if enabled, then the date field will use a hidden field to store the
38659 * real value as iso formated date. default (false)
38663 * @cfg {String/Object} autoCreate
38664 * A DomHelper element spec, or true for a default element spec (defaults to
38665 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38668 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38671 hiddenField: false,
38673 onRender : function(ct, position)
38675 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38677 //this.el.dom.removeAttribute('name');
38678 Roo.log("Changing name?");
38679 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38680 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38682 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38683 // prevent input submission
38684 this.hiddenName = this.name;
38691 validateValue : function(value)
38693 value = this.formatDate(value);
38694 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38695 Roo.log('super failed');
38698 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38701 var svalue = value;
38702 value = this.parseDate(value);
38704 Roo.log('parse date failed' + svalue);
38705 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38708 var time = value.getTime();
38709 if(this.minValue && time < this.minValue.getTime()){
38710 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38713 if(this.maxValue && time > this.maxValue.getTime()){
38714 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38717 if(this.disabledDays){
38718 var day = value.getDay();
38719 for(var i = 0; i < this.disabledDays.length; i++) {
38720 if(day === this.disabledDays[i]){
38721 this.markInvalid(this.disabledDaysText);
38726 var fvalue = this.formatDate(value);
38727 if(this.ddMatch && this.ddMatch.test(fvalue)){
38728 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38735 // Provides logic to override the default TriggerField.validateBlur which just returns true
38736 validateBlur : function(){
38737 return !this.menu || !this.menu.isVisible();
38740 getName: function()
38742 // returns hidden if it's set..
38743 if (!this.rendered) {return ''};
38744 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38749 * Returns the current date value of the date field.
38750 * @return {Date} The date value
38752 getValue : function(){
38754 return this.hiddenField ?
38755 this.hiddenField.value :
38756 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38760 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38761 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38762 * (the default format used is "m/d/y").
38765 //All of these calls set the same date value (May 4, 2006)
38767 //Pass a date object:
38768 var dt = new Date('5/4/06');
38769 dateField.setValue(dt);
38771 //Pass a date string (default format):
38772 dateField.setValue('5/4/06');
38774 //Pass a date string (custom format):
38775 dateField.format = 'Y-m-d';
38776 dateField.setValue('2006-5-4');
38778 * @param {String/Date} date The date or valid date string
38780 setValue : function(date){
38781 if (this.hiddenField) {
38782 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38784 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38785 // make sure the value field is always stored as a date..
38786 this.value = this.parseDate(date);
38792 parseDate : function(value){
38793 if(!value || value instanceof Date){
38796 var v = Date.parseDate(value, this.format);
38797 if (!v && this.useIso) {
38798 v = Date.parseDate(value, 'Y-m-d');
38800 if(!v && this.altFormats){
38801 if(!this.altFormatsArray){
38802 this.altFormatsArray = this.altFormats.split("|");
38804 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38805 v = Date.parseDate(value, this.altFormatsArray[i]);
38812 formatDate : function(date, fmt){
38813 return (!date || !(date instanceof Date)) ?
38814 date : date.dateFormat(fmt || this.format);
38819 select: function(m, d){
38822 this.fireEvent('select', this, d);
38824 show : function(){ // retain focus styling
38828 this.focus.defer(10, this);
38829 var ml = this.menuListeners;
38830 this.menu.un("select", ml.select, this);
38831 this.menu.un("show", ml.show, this);
38832 this.menu.un("hide", ml.hide, this);
38837 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38838 onTriggerClick : function(){
38842 if(this.menu == null){
38843 this.menu = new Roo.menu.DateMenu();
38845 Roo.apply(this.menu.picker, {
38846 showClear: this.allowBlank,
38847 minDate : this.minValue,
38848 maxDate : this.maxValue,
38849 disabledDatesRE : this.ddMatch,
38850 disabledDatesText : this.disabledDatesText,
38851 disabledDays : this.disabledDays,
38852 disabledDaysText : this.disabledDaysText,
38853 format : this.useIso ? 'Y-m-d' : this.format,
38854 minText : String.format(this.minText, this.formatDate(this.minValue)),
38855 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38857 this.menu.on(Roo.apply({}, this.menuListeners, {
38860 this.menu.picker.setValue(this.getValue() || new Date());
38861 this.menu.show(this.el, "tl-bl?");
38864 beforeBlur : function(){
38865 var v = this.parseDate(this.getRawValue());
38875 isDirty : function() {
38876 if(this.disabled) {
38880 if(typeof(this.startValue) === 'undefined'){
38884 return String(this.getValue()) !== String(this.startValue);
38889 * Ext JS Library 1.1.1
38890 * Copyright(c) 2006-2007, Ext JS, LLC.
38892 * Originally Released Under LGPL - original licence link has changed is not relivant.
38895 * <script type="text/javascript">
38899 * @class Roo.form.MonthField
38900 * @extends Roo.form.TriggerField
38901 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38903 * Create a new MonthField
38904 * @param {Object} config
38906 Roo.form.MonthField = function(config){
38908 Roo.form.MonthField.superclass.constructor.call(this, config);
38914 * Fires when a date is selected
38915 * @param {Roo.form.MonthFieeld} combo This combo box
38916 * @param {Date} date The date selected
38923 if(typeof this.minValue == "string") {
38924 this.minValue = this.parseDate(this.minValue);
38926 if(typeof this.maxValue == "string") {
38927 this.maxValue = this.parseDate(this.maxValue);
38929 this.ddMatch = null;
38930 if(this.disabledDates){
38931 var dd = this.disabledDates;
38933 for(var i = 0; i < dd.length; i++){
38935 if(i != dd.length-1) {
38939 this.ddMatch = new RegExp(re + ")");
38943 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38945 * @cfg {String} format
38946 * The default date format string which can be overriden for localization support. The format must be
38947 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38951 * @cfg {String} altFormats
38952 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38953 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38955 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38957 * @cfg {Array} disabledDays
38958 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38960 disabledDays : [0,1,2,3,4,5,6],
38962 * @cfg {String} disabledDaysText
38963 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38965 disabledDaysText : "Disabled",
38967 * @cfg {Array} disabledDates
38968 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38969 * expression so they are very powerful. Some examples:
38971 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38972 * <li>["03/08", "09/16"] would disable those days for every year</li>
38973 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38974 * <li>["03/../2006"] would disable every day in March 2006</li>
38975 * <li>["^03"] would disable every day in every March</li>
38977 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38978 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38980 disabledDates : null,
38982 * @cfg {String} disabledDatesText
38983 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38985 disabledDatesText : "Disabled",
38987 * @cfg {Date/String} minValue
38988 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38989 * valid format (defaults to null).
38993 * @cfg {Date/String} maxValue
38994 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38995 * valid format (defaults to null).
38999 * @cfg {String} minText
39000 * The error text to display when the date in the cell is before minValue (defaults to
39001 * 'The date in this field must be after {minValue}').
39003 minText : "The date in this field must be equal to or after {0}",
39005 * @cfg {String} maxTextf
39006 * The error text to display when the date in the cell is after maxValue (defaults to
39007 * 'The date in this field must be before {maxValue}').
39009 maxText : "The date in this field must be equal to or before {0}",
39011 * @cfg {String} invalidText
39012 * The error text to display when the date in the field is invalid (defaults to
39013 * '{value} is not a valid date - it must be in the format {format}').
39015 invalidText : "{0} is not a valid date - it must be in the format {1}",
39017 * @cfg {String} triggerClass
39018 * An additional CSS class used to style the trigger button. The trigger will always get the
39019 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
39020 * which displays a calendar icon).
39022 triggerClass : 'x-form-date-trigger',
39026 * @cfg {Boolean} useIso
39027 * if enabled, then the date field will use a hidden field to store the
39028 * real value as iso formated date. default (true)
39032 * @cfg {String/Object} autoCreate
39033 * A DomHelper element spec, or true for a default element spec (defaults to
39034 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
39037 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
39040 hiddenField: false,
39042 hideMonthPicker : false,
39044 onRender : function(ct, position)
39046 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
39048 this.el.dom.removeAttribute('name');
39049 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
39051 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
39052 // prevent input submission
39053 this.hiddenName = this.name;
39060 validateValue : function(value)
39062 value = this.formatDate(value);
39063 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
39066 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39069 var svalue = value;
39070 value = this.parseDate(value);
39072 this.markInvalid(String.format(this.invalidText, svalue, this.format));
39075 var time = value.getTime();
39076 if(this.minValue && time < this.minValue.getTime()){
39077 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
39080 if(this.maxValue && time > this.maxValue.getTime()){
39081 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
39084 /*if(this.disabledDays){
39085 var day = value.getDay();
39086 for(var i = 0; i < this.disabledDays.length; i++) {
39087 if(day === this.disabledDays[i]){
39088 this.markInvalid(this.disabledDaysText);
39094 var fvalue = this.formatDate(value);
39095 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
39096 this.markInvalid(String.format(this.disabledDatesText, fvalue));
39104 // Provides logic to override the default TriggerField.validateBlur which just returns true
39105 validateBlur : function(){
39106 return !this.menu || !this.menu.isVisible();
39110 * Returns the current date value of the date field.
39111 * @return {Date} The date value
39113 getValue : function(){
39117 return this.hiddenField ?
39118 this.hiddenField.value :
39119 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
39123 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
39124 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
39125 * (the default format used is "m/d/y").
39128 //All of these calls set the same date value (May 4, 2006)
39130 //Pass a date object:
39131 var dt = new Date('5/4/06');
39132 monthField.setValue(dt);
39134 //Pass a date string (default format):
39135 monthField.setValue('5/4/06');
39137 //Pass a date string (custom format):
39138 monthField.format = 'Y-m-d';
39139 monthField.setValue('2006-5-4');
39141 * @param {String/Date} date The date or valid date string
39143 setValue : function(date){
39144 Roo.log('month setValue' + date);
39145 // can only be first of month..
39147 var val = this.parseDate(date);
39149 if (this.hiddenField) {
39150 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
39152 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
39153 this.value = this.parseDate(date);
39157 parseDate : function(value){
39158 if(!value || value instanceof Date){
39159 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
39162 var v = Date.parseDate(value, this.format);
39163 if (!v && this.useIso) {
39164 v = Date.parseDate(value, 'Y-m-d');
39168 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
39172 if(!v && this.altFormats){
39173 if(!this.altFormatsArray){
39174 this.altFormatsArray = this.altFormats.split("|");
39176 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
39177 v = Date.parseDate(value, this.altFormatsArray[i]);
39184 formatDate : function(date, fmt){
39185 return (!date || !(date instanceof Date)) ?
39186 date : date.dateFormat(fmt || this.format);
39191 select: function(m, d){
39193 this.fireEvent('select', this, d);
39195 show : function(){ // retain focus styling
39199 this.focus.defer(10, this);
39200 var ml = this.menuListeners;
39201 this.menu.un("select", ml.select, this);
39202 this.menu.un("show", ml.show, this);
39203 this.menu.un("hide", ml.hide, this);
39207 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
39208 onTriggerClick : function(){
39212 if(this.menu == null){
39213 this.menu = new Roo.menu.DateMenu();
39217 Roo.apply(this.menu.picker, {
39219 showClear: this.allowBlank,
39220 minDate : this.minValue,
39221 maxDate : this.maxValue,
39222 disabledDatesRE : this.ddMatch,
39223 disabledDatesText : this.disabledDatesText,
39225 format : this.useIso ? 'Y-m-d' : this.format,
39226 minText : String.format(this.minText, this.formatDate(this.minValue)),
39227 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39230 this.menu.on(Roo.apply({}, this.menuListeners, {
39238 // hide month picker get's called when we called by 'before hide';
39240 var ignorehide = true;
39241 p.hideMonthPicker = function(disableAnim){
39245 if(this.monthPicker){
39246 Roo.log("hideMonthPicker called");
39247 if(disableAnim === true){
39248 this.monthPicker.hide();
39250 this.monthPicker.slideOut('t', {duration:.2});
39251 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39252 p.fireEvent("select", this, this.value);
39258 Roo.log('picker set value');
39259 Roo.log(this.getValue());
39260 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39261 m.show(this.el, 'tl-bl?');
39262 ignorehide = false;
39263 // this will trigger hideMonthPicker..
39266 // hidden the day picker
39267 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39273 p.showMonthPicker.defer(100, p);
39279 beforeBlur : function(){
39280 var v = this.parseDate(this.getRawValue());
39286 /** @cfg {Boolean} grow @hide */
39287 /** @cfg {Number} growMin @hide */
39288 /** @cfg {Number} growMax @hide */
39295 * Ext JS Library 1.1.1
39296 * Copyright(c) 2006-2007, Ext JS, LLC.
39298 * Originally Released Under LGPL - original licence link has changed is not relivant.
39301 * <script type="text/javascript">
39306 * @class Roo.form.ComboBox
39307 * @extends Roo.form.TriggerField
39308 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39310 * Create a new ComboBox.
39311 * @param {Object} config Configuration options
39313 Roo.form.ComboBox = function(config){
39314 Roo.form.ComboBox.superclass.constructor.call(this, config);
39318 * Fires when the dropdown list is expanded
39319 * @param {Roo.form.ComboBox} combo This combo box
39324 * Fires when the dropdown list is collapsed
39325 * @param {Roo.form.ComboBox} combo This combo box
39329 * @event beforeselect
39330 * Fires before a list item is selected. Return false to cancel the selection.
39331 * @param {Roo.form.ComboBox} combo This combo box
39332 * @param {Roo.data.Record} record The data record returned from the underlying store
39333 * @param {Number} index The index of the selected item in the dropdown list
39335 'beforeselect' : true,
39338 * Fires when a list item is selected
39339 * @param {Roo.form.ComboBox} combo This combo box
39340 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39341 * @param {Number} index The index of the selected item in the dropdown list
39345 * @event beforequery
39346 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39347 * The event object passed has these properties:
39348 * @param {Roo.form.ComboBox} combo This combo box
39349 * @param {String} query The query
39350 * @param {Boolean} forceAll true to force "all" query
39351 * @param {Boolean} cancel true to cancel the query
39352 * @param {Object} e The query event object
39354 'beforequery': true,
39357 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39358 * @param {Roo.form.ComboBox} combo This combo box
39363 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39364 * @param {Roo.form.ComboBox} combo This combo box
39365 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39371 if(this.transform){
39372 this.allowDomMove = false;
39373 var s = Roo.getDom(this.transform);
39374 if(!this.hiddenName){
39375 this.hiddenName = s.name;
39378 this.mode = 'local';
39379 var d = [], opts = s.options;
39380 for(var i = 0, len = opts.length;i < len; i++){
39382 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39384 this.value = value;
39386 d.push([value, o.text]);
39388 this.store = new Roo.data.SimpleStore({
39390 fields: ['value', 'text'],
39393 this.valueField = 'value';
39394 this.displayField = 'text';
39396 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39397 if(!this.lazyRender){
39398 this.target = true;
39399 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39400 s.parentNode.removeChild(s); // remove it
39401 this.render(this.el.parentNode);
39403 s.parentNode.removeChild(s); // remove it
39408 this.store = Roo.factory(this.store, Roo.data);
39411 this.selectedIndex = -1;
39412 if(this.mode == 'local'){
39413 if(config.queryDelay === undefined){
39414 this.queryDelay = 10;
39416 if(config.minChars === undefined){
39422 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39424 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39427 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39428 * rendering into an Roo.Editor, defaults to false)
39431 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39432 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39435 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39438 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39439 * the dropdown list (defaults to undefined, with no header element)
39443 * @cfg {String/Roo.Template} tpl The template to use to render the output
39447 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39449 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39451 listWidth: undefined,
39453 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39454 * mode = 'remote' or 'text' if mode = 'local')
39456 displayField: undefined,
39458 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39459 * mode = 'remote' or 'value' if mode = 'local').
39460 * Note: use of a valueField requires the user make a selection
39461 * in order for a value to be mapped.
39463 valueField: undefined,
39467 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39468 * field's data value (defaults to the underlying DOM element's name)
39470 hiddenName: undefined,
39472 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39476 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39478 selectedClass: 'x-combo-selected',
39480 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39481 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39482 * which displays a downward arrow icon).
39484 triggerClass : 'x-form-arrow-trigger',
39486 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39490 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39491 * anchor positions (defaults to 'tl-bl')
39493 listAlign: 'tl-bl?',
39495 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39499 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39500 * query specified by the allQuery config option (defaults to 'query')
39502 triggerAction: 'query',
39504 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39505 * (defaults to 4, does not apply if editable = false)
39509 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39510 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39514 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39515 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39519 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39520 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39524 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39525 * when editable = true (defaults to false)
39527 selectOnFocus:false,
39529 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39531 queryParam: 'query',
39533 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39534 * when mode = 'remote' (defaults to 'Loading...')
39536 loadingText: 'Loading...',
39538 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39542 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39546 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39547 * traditional select (defaults to true)
39551 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39555 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39559 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39560 * listWidth has a higher value)
39564 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39565 * allow the user to set arbitrary text into the field (defaults to false)
39567 forceSelection:false,
39569 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39570 * if typeAhead = true (defaults to 250)
39572 typeAheadDelay : 250,
39574 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39575 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39577 valueNotFoundText : undefined,
39579 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39581 blockFocus : false,
39584 * @cfg {Boolean} disableClear Disable showing of clear button.
39586 disableClear : false,
39588 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39590 alwaysQuery : false,
39596 // element that contains real text value.. (when hidden is used..)
39599 onRender : function(ct, position){
39600 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39601 if(this.hiddenName){
39602 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39604 this.hiddenField.value =
39605 this.hiddenValue !== undefined ? this.hiddenValue :
39606 this.value !== undefined ? this.value : '';
39608 // prevent input submission
39609 this.el.dom.removeAttribute('name');
39614 this.el.dom.setAttribute('autocomplete', 'off');
39617 var cls = 'x-combo-list';
39619 this.list = new Roo.Layer({
39620 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39623 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39624 this.list.setWidth(lw);
39625 this.list.swallowEvent('mousewheel');
39626 this.assetHeight = 0;
39629 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39630 this.assetHeight += this.header.getHeight();
39633 this.innerList = this.list.createChild({cls:cls+'-inner'});
39634 this.innerList.on('mouseover', this.onViewOver, this);
39635 this.innerList.on('mousemove', this.onViewMove, this);
39636 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39638 if(this.allowBlank && !this.pageSize && !this.disableClear){
39639 this.footer = this.list.createChild({cls:cls+'-ft'});
39640 this.pageTb = new Roo.Toolbar(this.footer);
39644 this.footer = this.list.createChild({cls:cls+'-ft'});
39645 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39646 {pageSize: this.pageSize});
39650 if (this.pageTb && this.allowBlank && !this.disableClear) {
39652 this.pageTb.add(new Roo.Toolbar.Fill(), {
39653 cls: 'x-btn-icon x-btn-clear',
39655 handler: function()
39658 _this.clearValue();
39659 _this.onSelect(false, -1);
39664 this.assetHeight += this.footer.getHeight();
39669 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39672 this.view = new Roo.View(this.innerList, this.tpl, {
39673 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39676 this.view.on('click', this.onViewClick, this);
39678 this.store.on('beforeload', this.onBeforeLoad, this);
39679 this.store.on('load', this.onLoad, this);
39680 this.store.on('loadexception', this.onLoadException, this);
39682 if(this.resizable){
39683 this.resizer = new Roo.Resizable(this.list, {
39684 pinned:true, handles:'se'
39686 this.resizer.on('resize', function(r, w, h){
39687 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39688 this.listWidth = w;
39689 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39690 this.restrictHeight();
39692 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39694 if(!this.editable){
39695 this.editable = true;
39696 this.setEditable(false);
39700 if (typeof(this.events.add.listeners) != 'undefined') {
39702 this.addicon = this.wrap.createChild(
39703 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39705 this.addicon.on('click', function(e) {
39706 this.fireEvent('add', this);
39709 if (typeof(this.events.edit.listeners) != 'undefined') {
39711 this.editicon = this.wrap.createChild(
39712 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39713 if (this.addicon) {
39714 this.editicon.setStyle('margin-left', '40px');
39716 this.editicon.on('click', function(e) {
39718 // we fire even if inothing is selected..
39719 this.fireEvent('edit', this, this.lastData );
39729 initEvents : function(){
39730 Roo.form.ComboBox.superclass.initEvents.call(this);
39732 this.keyNav = new Roo.KeyNav(this.el, {
39733 "up" : function(e){
39734 this.inKeyMode = true;
39738 "down" : function(e){
39739 if(!this.isExpanded()){
39740 this.onTriggerClick();
39742 this.inKeyMode = true;
39747 "enter" : function(e){
39748 this.onViewClick();
39752 "esc" : function(e){
39756 "tab" : function(e){
39757 this.onViewClick(false);
39758 this.fireEvent("specialkey", this, e);
39764 doRelay : function(foo, bar, hname){
39765 if(hname == 'down' || this.scope.isExpanded()){
39766 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39773 this.queryDelay = Math.max(this.queryDelay || 10,
39774 this.mode == 'local' ? 10 : 250);
39775 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39776 if(this.typeAhead){
39777 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39779 if(this.editable !== false){
39780 this.el.on("keyup", this.onKeyUp, this);
39782 if(this.forceSelection){
39783 this.on('blur', this.doForce, this);
39787 onDestroy : function(){
39789 this.view.setStore(null);
39790 this.view.el.removeAllListeners();
39791 this.view.el.remove();
39792 this.view.purgeListeners();
39795 this.list.destroy();
39798 this.store.un('beforeload', this.onBeforeLoad, this);
39799 this.store.un('load', this.onLoad, this);
39800 this.store.un('loadexception', this.onLoadException, this);
39802 Roo.form.ComboBox.superclass.onDestroy.call(this);
39806 fireKey : function(e){
39807 if(e.isNavKeyPress() && !this.list.isVisible()){
39808 this.fireEvent("specialkey", this, e);
39813 onResize: function(w, h){
39814 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39816 if(typeof w != 'number'){
39817 // we do not handle it!?!?
39820 var tw = this.trigger.getWidth();
39821 tw += this.addicon ? this.addicon.getWidth() : 0;
39822 tw += this.editicon ? this.editicon.getWidth() : 0;
39824 this.el.setWidth( this.adjustWidth('input', x));
39826 this.trigger.setStyle('left', x+'px');
39828 if(this.list && this.listWidth === undefined){
39829 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39830 this.list.setWidth(lw);
39831 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39839 * Allow or prevent the user from directly editing the field text. If false is passed,
39840 * the user will only be able to select from the items defined in the dropdown list. This method
39841 * is the runtime equivalent of setting the 'editable' config option at config time.
39842 * @param {Boolean} value True to allow the user to directly edit the field text
39844 setEditable : function(value){
39845 if(value == this.editable){
39848 this.editable = value;
39850 this.el.dom.setAttribute('readOnly', true);
39851 this.el.on('mousedown', this.onTriggerClick, this);
39852 this.el.addClass('x-combo-noedit');
39854 this.el.dom.setAttribute('readOnly', false);
39855 this.el.un('mousedown', this.onTriggerClick, this);
39856 this.el.removeClass('x-combo-noedit');
39861 onBeforeLoad : function(){
39862 if(!this.hasFocus){
39865 this.innerList.update(this.loadingText ?
39866 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39867 this.restrictHeight();
39868 this.selectedIndex = -1;
39872 onLoad : function(){
39873 if(!this.hasFocus){
39876 if(this.store.getCount() > 0){
39878 this.restrictHeight();
39879 if(this.lastQuery == this.allQuery){
39881 this.el.dom.select();
39883 if(!this.selectByValue(this.value, true)){
39884 this.select(0, true);
39888 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39889 this.taTask.delay(this.typeAheadDelay);
39893 this.onEmptyResults();
39898 onLoadException : function()
39901 Roo.log(this.store.reader.jsonData);
39902 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39903 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39909 onTypeAhead : function(){
39910 if(this.store.getCount() > 0){
39911 var r = this.store.getAt(0);
39912 var newValue = r.data[this.displayField];
39913 var len = newValue.length;
39914 var selStart = this.getRawValue().length;
39915 if(selStart != len){
39916 this.setRawValue(newValue);
39917 this.selectText(selStart, newValue.length);
39923 onSelect : function(record, index){
39924 if(this.fireEvent('beforeselect', this, record, index) !== false){
39925 this.setFromData(index > -1 ? record.data : false);
39927 this.fireEvent('select', this, record, index);
39932 * Returns the currently selected field value or empty string if no value is set.
39933 * @return {String} value The selected value
39935 getValue : function(){
39936 if(this.valueField){
39937 return typeof this.value != 'undefined' ? this.value : '';
39939 return Roo.form.ComboBox.superclass.getValue.call(this);
39943 * Clears any text/value currently set in the field
39945 clearValue : function(){
39946 if(this.hiddenField){
39947 this.hiddenField.value = '';
39950 this.setRawValue('');
39951 this.lastSelectionText = '';
39956 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39957 * will be displayed in the field. If the value does not match the data value of an existing item,
39958 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39959 * Otherwise the field will be blank (although the value will still be set).
39960 * @param {String} value The value to match
39962 setValue : function(v){
39964 if(this.valueField){
39965 var r = this.findRecord(this.valueField, v);
39967 text = r.data[this.displayField];
39968 }else if(this.valueNotFoundText !== undefined){
39969 text = this.valueNotFoundText;
39972 this.lastSelectionText = text;
39973 if(this.hiddenField){
39974 this.hiddenField.value = v;
39976 Roo.form.ComboBox.superclass.setValue.call(this, text);
39980 * @property {Object} the last set data for the element
39985 * Sets the value of the field based on a object which is related to the record format for the store.
39986 * @param {Object} value the value to set as. or false on reset?
39988 setFromData : function(o){
39989 var dv = ''; // display value
39990 var vv = ''; // value value..
39992 if (this.displayField) {
39993 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39995 // this is an error condition!!!
39996 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39999 if(this.valueField){
40000 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
40002 if(this.hiddenField){
40003 this.hiddenField.value = vv;
40005 this.lastSelectionText = dv;
40006 Roo.form.ComboBox.superclass.setValue.call(this, dv);
40010 // no hidden field.. - we store the value in 'value', but still display
40011 // display field!!!!
40012 this.lastSelectionText = dv;
40013 Roo.form.ComboBox.superclass.setValue.call(this, dv);
40019 reset : function(){
40020 // overridden so that last data is reset..
40021 this.setValue(this.resetValue);
40022 this.clearInvalid();
40023 this.lastData = false;
40025 this.view.clearSelections();
40029 findRecord : function(prop, value){
40031 if(this.store.getCount() > 0){
40032 this.store.each(function(r){
40033 if(r.data[prop] == value){
40043 getName: function()
40045 // returns hidden if it's set..
40046 if (!this.rendered) {return ''};
40047 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40051 onViewMove : function(e, t){
40052 this.inKeyMode = false;
40056 onViewOver : function(e, t){
40057 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
40060 var item = this.view.findItemFromChild(t);
40062 var index = this.view.indexOf(item);
40063 this.select(index, false);
40068 onViewClick : function(doFocus)
40070 var index = this.view.getSelectedIndexes()[0];
40071 var r = this.store.getAt(index);
40073 this.onSelect(r, index);
40075 if(doFocus !== false && !this.blockFocus){
40081 restrictHeight : function(){
40082 this.innerList.dom.style.height = '';
40083 var inner = this.innerList.dom;
40084 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
40085 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
40086 this.list.beginUpdate();
40087 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
40088 this.list.alignTo(this.el, this.listAlign);
40089 this.list.endUpdate();
40093 onEmptyResults : function(){
40098 * Returns true if the dropdown list is expanded, else false.
40100 isExpanded : function(){
40101 return this.list.isVisible();
40105 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
40106 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40107 * @param {String} value The data value of the item to select
40108 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40109 * selected item if it is not currently in view (defaults to true)
40110 * @return {Boolean} True if the value matched an item in the list, else false
40112 selectByValue : function(v, scrollIntoView){
40113 if(v !== undefined && v !== null){
40114 var r = this.findRecord(this.valueField || this.displayField, v);
40116 this.select(this.store.indexOf(r), scrollIntoView);
40124 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
40125 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40126 * @param {Number} index The zero-based index of the list item to select
40127 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40128 * selected item if it is not currently in view (defaults to true)
40130 select : function(index, scrollIntoView){
40131 this.selectedIndex = index;
40132 this.view.select(index);
40133 if(scrollIntoView !== false){
40134 var el = this.view.getNode(index);
40136 this.innerList.scrollChildIntoView(el, false);
40142 selectNext : function(){
40143 var ct = this.store.getCount();
40145 if(this.selectedIndex == -1){
40147 }else if(this.selectedIndex < ct-1){
40148 this.select(this.selectedIndex+1);
40154 selectPrev : function(){
40155 var ct = this.store.getCount();
40157 if(this.selectedIndex == -1){
40159 }else if(this.selectedIndex != 0){
40160 this.select(this.selectedIndex-1);
40166 onKeyUp : function(e){
40167 if(this.editable !== false && !e.isSpecialKey()){
40168 this.lastKey = e.getKey();
40169 this.dqTask.delay(this.queryDelay);
40174 validateBlur : function(){
40175 return !this.list || !this.list.isVisible();
40179 initQuery : function(){
40180 this.doQuery(this.getRawValue());
40184 doForce : function(){
40185 if(this.el.dom.value.length > 0){
40186 this.el.dom.value =
40187 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
40193 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
40194 * query allowing the query action to be canceled if needed.
40195 * @param {String} query The SQL query to execute
40196 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
40197 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
40198 * saved in the current store (defaults to false)
40200 doQuery : function(q, forceAll){
40201 if(q === undefined || q === null){
40206 forceAll: forceAll,
40210 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
40214 forceAll = qe.forceAll;
40215 if(forceAll === true || (q.length >= this.minChars)){
40216 if(this.lastQuery != q || this.alwaysQuery){
40217 this.lastQuery = q;
40218 if(this.mode == 'local'){
40219 this.selectedIndex = -1;
40221 this.store.clearFilter();
40223 this.store.filter(this.displayField, q);
40227 this.store.baseParams[this.queryParam] = q;
40229 params: this.getParams(q)
40234 this.selectedIndex = -1;
40241 getParams : function(q){
40243 //p[this.queryParam] = q;
40246 p.limit = this.pageSize;
40252 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40254 collapse : function(){
40255 if(!this.isExpanded()){
40259 Roo.get(document).un('mousedown', this.collapseIf, this);
40260 Roo.get(document).un('mousewheel', this.collapseIf, this);
40261 if (!this.editable) {
40262 Roo.get(document).un('keydown', this.listKeyPress, this);
40264 this.fireEvent('collapse', this);
40268 collapseIf : function(e){
40269 if(!e.within(this.wrap) && !e.within(this.list)){
40275 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40277 expand : function(){
40278 if(this.isExpanded() || !this.hasFocus){
40281 this.list.alignTo(this.el, this.listAlign);
40283 Roo.get(document).on('mousedown', this.collapseIf, this);
40284 Roo.get(document).on('mousewheel', this.collapseIf, this);
40285 if (!this.editable) {
40286 Roo.get(document).on('keydown', this.listKeyPress, this);
40289 this.fireEvent('expand', this);
40293 // Implements the default empty TriggerField.onTriggerClick function
40294 onTriggerClick : function(){
40298 if(this.isExpanded()){
40300 if (!this.blockFocus) {
40305 this.hasFocus = true;
40306 if(this.triggerAction == 'all') {
40307 this.doQuery(this.allQuery, true);
40309 this.doQuery(this.getRawValue());
40311 if (!this.blockFocus) {
40316 listKeyPress : function(e)
40318 //Roo.log('listkeypress');
40319 // scroll to first matching element based on key pres..
40320 if (e.isSpecialKey()) {
40323 var k = String.fromCharCode(e.getKey()).toUpperCase();
40326 var csel = this.view.getSelectedNodes();
40327 var cselitem = false;
40329 var ix = this.view.indexOf(csel[0]);
40330 cselitem = this.store.getAt(ix);
40331 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40337 this.store.each(function(v) {
40339 // start at existing selection.
40340 if (cselitem.id == v.id) {
40346 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40347 match = this.store.indexOf(v);
40352 if (match === false) {
40353 return true; // no more action?
40356 this.view.select(match);
40357 var sn = Roo.get(this.view.getSelectedNodes()[0]);
40358 sn.scrollIntoView(sn.dom.parentNode, false);
40362 * @cfg {Boolean} grow
40366 * @cfg {Number} growMin
40370 * @cfg {Number} growMax
40378 * Copyright(c) 2010-2012, Roo J Solutions Limited
40385 * @class Roo.form.ComboBoxArray
40386 * @extends Roo.form.TextField
40387 * A facebook style adder... for lists of email / people / countries etc...
40388 * pick multiple items from a combo box, and shows each one.
40390 * Fred [x] Brian [x] [Pick another |v]
40393 * For this to work: it needs various extra information
40394 * - normal combo problay has
40396 * + displayField, valueField
40398 * For our purpose...
40401 * If we change from 'extends' to wrapping...
40408 * Create a new ComboBoxArray.
40409 * @param {Object} config Configuration options
40413 Roo.form.ComboBoxArray = function(config)
40417 * @event beforeremove
40418 * Fires before remove the value from the list
40419 * @param {Roo.form.ComboBoxArray} _self This combo box array
40420 * @param {Roo.form.ComboBoxArray.Item} item removed item
40422 'beforeremove' : true,
40425 * Fires when remove the value from the list
40426 * @param {Roo.form.ComboBoxArray} _self This combo box array
40427 * @param {Roo.form.ComboBoxArray.Item} item removed item
40434 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40436 this.items = new Roo.util.MixedCollection(false);
40438 // construct the child combo...
40448 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40451 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40456 // behavies liek a hiddne field
40457 inputType: 'hidden',
40459 * @cfg {Number} width The width of the box that displays the selected element
40466 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40470 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40472 hiddenName : false,
40475 // private the array of items that are displayed..
40477 // private - the hidden field el.
40479 // private - the filed el..
40482 //validateValue : function() { return true; }, // all values are ok!
40483 //onAddClick: function() { },
40485 onRender : function(ct, position)
40488 // create the standard hidden element
40489 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40492 // give fake names to child combo;
40493 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40494 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40496 this.combo = Roo.factory(this.combo, Roo.form);
40497 this.combo.onRender(ct, position);
40498 if (typeof(this.combo.width) != 'undefined') {
40499 this.combo.onResize(this.combo.width,0);
40502 this.combo.initEvents();
40504 // assigned so form know we need to do this..
40505 this.store = this.combo.store;
40506 this.valueField = this.combo.valueField;
40507 this.displayField = this.combo.displayField ;
40510 this.combo.wrap.addClass('x-cbarray-grp');
40512 var cbwrap = this.combo.wrap.createChild(
40513 {tag: 'div', cls: 'x-cbarray-cb'},
40518 this.hiddenEl = this.combo.wrap.createChild({
40519 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40521 this.el = this.combo.wrap.createChild({
40522 tag: 'input', type:'hidden' , name: this.name, value : ''
40524 // this.el.dom.removeAttribute("name");
40527 this.outerWrap = this.combo.wrap;
40528 this.wrap = cbwrap;
40530 this.outerWrap.setWidth(this.width);
40531 this.outerWrap.dom.removeChild(this.el.dom);
40533 this.wrap.dom.appendChild(this.el.dom);
40534 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40535 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40537 this.combo.trigger.setStyle('position','relative');
40538 this.combo.trigger.setStyle('left', '0px');
40539 this.combo.trigger.setStyle('top', '2px');
40541 this.combo.el.setStyle('vertical-align', 'text-bottom');
40543 //this.trigger.setStyle('vertical-align', 'top');
40545 // this should use the code from combo really... on('add' ....)
40549 this.adder = this.outerWrap.createChild(
40550 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40552 this.adder.on('click', function(e) {
40553 _t.fireEvent('adderclick', this, e);
40557 //this.adder.on('click', this.onAddClick, _t);
40560 this.combo.on('select', function(cb, rec, ix) {
40561 this.addItem(rec.data);
40564 cb.el.dom.value = '';
40565 //cb.lastData = rec.data;
40574 getName: function()
40576 // returns hidden if it's set..
40577 if (!this.rendered) {return ''};
40578 return this.hiddenName ? this.hiddenName : this.name;
40583 onResize: function(w, h){
40586 // not sure if this is needed..
40587 //this.combo.onResize(w,h);
40589 if(typeof w != 'number'){
40590 // we do not handle it!?!?
40593 var tw = this.combo.trigger.getWidth();
40594 tw += this.addicon ? this.addicon.getWidth() : 0;
40595 tw += this.editicon ? this.editicon.getWidth() : 0;
40597 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40599 this.combo.trigger.setStyle('left', '0px');
40601 if(this.list && this.listWidth === undefined){
40602 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40603 this.list.setWidth(lw);
40604 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40611 addItem: function(rec)
40613 var valueField = this.combo.valueField;
40614 var displayField = this.combo.displayField;
40615 if (this.items.indexOfKey(rec[valueField]) > -1) {
40616 //console.log("GOT " + rec.data.id);
40620 var x = new Roo.form.ComboBoxArray.Item({
40621 //id : rec[this.idField],
40623 displayField : displayField ,
40624 tipField : displayField ,
40628 this.items.add(rec[valueField],x);
40629 // add it before the element..
40630 this.updateHiddenEl();
40631 x.render(this.outerWrap, this.wrap.dom);
40632 // add the image handler..
40635 updateHiddenEl : function()
40638 if (!this.hiddenEl) {
40642 var idField = this.combo.valueField;
40644 this.items.each(function(f) {
40645 ar.push(f.data[idField]);
40648 this.hiddenEl.dom.value = ar.join(',');
40654 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40655 this.items.each(function(f) {
40658 this.el.dom.value = '';
40659 if (this.hiddenEl) {
40660 this.hiddenEl.dom.value = '';
40664 getValue: function()
40666 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40668 setValue: function(v) // not a valid action - must use addItems..
40675 if (this.store.isLocal && (typeof(v) == 'string')) {
40676 // then we can use the store to find the values..
40677 // comma seperated at present.. this needs to allow JSON based encoding..
40678 this.hiddenEl.value = v;
40680 Roo.each(v.split(','), function(k) {
40681 Roo.log("CHECK " + this.valueField + ',' + k);
40682 var li = this.store.query(this.valueField, k);
40687 add[this.valueField] = k;
40688 add[this.displayField] = li.item(0).data[this.displayField];
40694 if (typeof(v) == 'object' ) {
40695 // then let's assume it's an array of objects..
40696 Roo.each(v, function(l) {
40704 setFromData: function(v)
40706 // this recieves an object, if setValues is called.
40708 this.el.dom.value = v[this.displayField];
40709 this.hiddenEl.dom.value = v[this.valueField];
40710 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40713 var kv = v[this.valueField];
40714 var dv = v[this.displayField];
40715 kv = typeof(kv) != 'string' ? '' : kv;
40716 dv = typeof(dv) != 'string' ? '' : dv;
40719 var keys = kv.split(',');
40720 var display = dv.split(',');
40721 for (var i = 0 ; i < keys.length; i++) {
40724 add[this.valueField] = keys[i];
40725 add[this.displayField] = display[i];
40733 * Validates the combox array value
40734 * @return {Boolean} True if the value is valid, else false
40736 validate : function(){
40737 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40738 this.clearInvalid();
40744 validateValue : function(value){
40745 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40753 isDirty : function() {
40754 if(this.disabled) {
40759 var d = Roo.decode(String(this.originalValue));
40761 return String(this.getValue()) !== String(this.originalValue);
40764 var originalValue = [];
40766 for (var i = 0; i < d.length; i++){
40767 originalValue.push(d[i][this.valueField]);
40770 return String(this.getValue()) !== String(originalValue.join(','));
40779 * @class Roo.form.ComboBoxArray.Item
40780 * @extends Roo.BoxComponent
40781 * A selected item in the list
40782 * Fred [x] Brian [x] [Pick another |v]
40785 * Create a new item.
40786 * @param {Object} config Configuration options
40789 Roo.form.ComboBoxArray.Item = function(config) {
40790 config.id = Roo.id();
40791 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40794 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40797 displayField : false,
40801 defaultAutoCreate : {
40803 cls: 'x-cbarray-item',
40810 src : Roo.BLANK_IMAGE_URL ,
40818 onRender : function(ct, position)
40820 Roo.form.Field.superclass.onRender.call(this, ct, position);
40823 var cfg = this.getAutoCreate();
40824 this.el = ct.createChild(cfg, position);
40827 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40829 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40830 this.cb.renderer(this.data) :
40831 String.format('{0}',this.data[this.displayField]);
40834 this.el.child('div').dom.setAttribute('qtip',
40835 String.format('{0}',this.data[this.tipField])
40838 this.el.child('img').on('click', this.remove, this);
40842 remove : function()
40844 if(this.cb.disabled){
40848 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
40849 this.cb.items.remove(this);
40850 this.el.child('img').un('click', this.remove, this);
40852 this.cb.updateHiddenEl();
40854 this.cb.fireEvent('remove', this.cb, this);
40860 * Ext JS Library 1.1.1
40861 * Copyright(c) 2006-2007, Ext JS, LLC.
40863 * Originally Released Under LGPL - original licence link has changed is not relivant.
40866 * <script type="text/javascript">
40869 * @class Roo.form.Checkbox
40870 * @extends Roo.form.Field
40871 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40873 * Creates a new Checkbox
40874 * @param {Object} config Configuration options
40876 Roo.form.Checkbox = function(config){
40877 Roo.form.Checkbox.superclass.constructor.call(this, config);
40881 * Fires when the checkbox is checked or unchecked.
40882 * @param {Roo.form.Checkbox} this This checkbox
40883 * @param {Boolean} checked The new checked value
40889 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40891 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40893 focusClass : undefined,
40895 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40897 fieldClass: "x-form-field",
40899 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40903 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40904 * {tag: "input", type: "checkbox", autocomplete: "off"})
40906 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40908 * @cfg {String} boxLabel The text that appears beside the checkbox
40912 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40916 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40918 valueOff: '0', // value when not checked..
40920 actionMode : 'viewEl',
40923 itemCls : 'x-menu-check-item x-form-item',
40924 groupClass : 'x-menu-group-item',
40925 inputType : 'hidden',
40928 inSetChecked: false, // check that we are not calling self...
40930 inputElement: false, // real input element?
40931 basedOn: false, // ????
40933 isFormField: true, // not sure where this is needed!!!!
40935 onResize : function(){
40936 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40937 if(!this.boxLabel){
40938 this.el.alignTo(this.wrap, 'c-c');
40942 initEvents : function(){
40943 Roo.form.Checkbox.superclass.initEvents.call(this);
40944 this.el.on("click", this.onClick, this);
40945 this.el.on("change", this.onClick, this);
40949 getResizeEl : function(){
40953 getPositionEl : function(){
40958 onRender : function(ct, position){
40959 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40961 if(this.inputValue !== undefined){
40962 this.el.dom.value = this.inputValue;
40965 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40966 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40967 var viewEl = this.wrap.createChild({
40968 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40969 this.viewEl = viewEl;
40970 this.wrap.on('click', this.onClick, this);
40972 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40973 this.el.on('propertychange', this.setFromHidden, this); //ie
40978 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40979 // viewEl.on('click', this.onClick, this);
40981 //if(this.checked){
40982 this.setChecked(this.checked);
40984 //this.checked = this.el.dom;
40990 initValue : Roo.emptyFn,
40993 * Returns the checked state of the checkbox.
40994 * @return {Boolean} True if checked, else false
40996 getValue : function(){
40998 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
41000 return this.valueOff;
41005 onClick : function(){
41006 if (this.disabled) {
41009 this.setChecked(!this.checked);
41011 //if(this.el.dom.checked != this.checked){
41012 // this.setValue(this.el.dom.checked);
41017 * Sets the checked state of the checkbox.
41018 * On is always based on a string comparison between inputValue and the param.
41019 * @param {Boolean/String} value - the value to set
41020 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
41022 setValue : function(v,suppressEvent){
41025 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
41026 //if(this.el && this.el.dom){
41027 // this.el.dom.checked = this.checked;
41028 // this.el.dom.defaultChecked = this.checked;
41030 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
41031 //this.fireEvent("check", this, this.checked);
41034 setChecked : function(state,suppressEvent)
41036 if (this.inSetChecked) {
41037 this.checked = state;
41043 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
41045 this.checked = state;
41046 if(suppressEvent !== true){
41047 this.fireEvent('check', this, state);
41049 this.inSetChecked = true;
41050 this.el.dom.value = state ? this.inputValue : this.valueOff;
41051 this.inSetChecked = false;
41054 // handle setting of hidden value by some other method!!?!?
41055 setFromHidden: function()
41060 //console.log("SET FROM HIDDEN");
41061 //alert('setFrom hidden');
41062 this.setValue(this.el.dom.value);
41065 onDestroy : function()
41068 Roo.get(this.viewEl).remove();
41071 Roo.form.Checkbox.superclass.onDestroy.call(this);
41076 * Ext JS Library 1.1.1
41077 * Copyright(c) 2006-2007, Ext JS, LLC.
41079 * Originally Released Under LGPL - original licence link has changed is not relivant.
41082 * <script type="text/javascript">
41086 * @class Roo.form.Radio
41087 * @extends Roo.form.Checkbox
41088 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
41089 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
41091 * Creates a new Radio
41092 * @param {Object} config Configuration options
41094 Roo.form.Radio = function(){
41095 Roo.form.Radio.superclass.constructor.apply(this, arguments);
41097 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
41098 inputType: 'radio',
41101 * If this radio is part of a group, it will return the selected value
41104 getGroupValue : function(){
41105 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
41109 onRender : function(ct, position){
41110 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
41112 if(this.inputValue !== undefined){
41113 this.el.dom.value = this.inputValue;
41116 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
41117 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
41118 //var viewEl = this.wrap.createChild({
41119 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
41120 //this.viewEl = viewEl;
41121 //this.wrap.on('click', this.onClick, this);
41123 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
41124 //this.el.on('propertychange', this.setFromHidden, this); //ie
41129 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
41130 // viewEl.on('click', this.onClick, this);
41133 this.el.dom.checked = 'checked' ;
41139 });//<script type="text/javascript">
41142 * Based Ext JS Library 1.1.1
41143 * Copyright(c) 2006-2007, Ext JS, LLC.
41149 * @class Roo.HtmlEditorCore
41150 * @extends Roo.Component
41151 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
41153 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
41156 Roo.HtmlEditorCore = function(config){
41159 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
41164 * @event initialize
41165 * Fires when the editor is fully initialized (including the iframe)
41166 * @param {Roo.HtmlEditorCore} this
41171 * Fires when the editor is first receives the focus. Any insertion must wait
41172 * until after this event.
41173 * @param {Roo.HtmlEditorCore} this
41177 * @event beforesync
41178 * Fires before the textarea is updated with content from the editor iframe. Return false
41179 * to cancel the sync.
41180 * @param {Roo.HtmlEditorCore} this
41181 * @param {String} html
41185 * @event beforepush
41186 * Fires before the iframe editor is updated with content from the textarea. Return false
41187 * to cancel the push.
41188 * @param {Roo.HtmlEditorCore} this
41189 * @param {String} html
41194 * Fires when the textarea is updated with content from the editor iframe.
41195 * @param {Roo.HtmlEditorCore} this
41196 * @param {String} html
41201 * Fires when the iframe editor is updated with content from the textarea.
41202 * @param {Roo.HtmlEditorCore} this
41203 * @param {String} html
41208 * @event editorevent
41209 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41210 * @param {Roo.HtmlEditorCore} this
41216 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
41218 // defaults : white / black...
41219 this.applyBlacklists();
41226 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41230 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41236 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41241 * @cfg {Number} height (in pixels)
41245 * @cfg {Number} width (in pixels)
41250 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41253 stylesheets: false,
41258 // private properties
41259 validationEvent : false,
41261 initialized : false,
41263 sourceEditMode : false,
41264 onFocus : Roo.emptyFn,
41266 hideMode:'offsets',
41270 // blacklist + whitelisted elements..
41277 * Protected method that will not generally be called directly. It
41278 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41279 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41281 getDocMarkup : function(){
41285 // inherit styels from page...??
41286 if (this.stylesheets === false) {
41288 Roo.get(document.head).select('style').each(function(node) {
41289 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41292 Roo.get(document.head).select('link').each(function(node) {
41293 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41296 } else if (!this.stylesheets.length) {
41298 st = '<style type="text/css">' +
41299 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41305 st += '<style type="text/css">' +
41306 'IMG { cursor: pointer } ' +
41310 return '<html><head>' + st +
41311 //<style type="text/css">' +
41312 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41314 ' </head><body class="roo-htmleditor-body"></body></html>';
41318 onRender : function(ct, position)
41321 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41322 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41325 this.el.dom.style.border = '0 none';
41326 this.el.dom.setAttribute('tabIndex', -1);
41327 this.el.addClass('x-hidden hide');
41331 if(Roo.isIE){ // fix IE 1px bogus margin
41332 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41336 this.frameId = Roo.id();
41340 var iframe = this.owner.wrap.createChild({
41342 cls: 'form-control', // bootstrap..
41344 name: this.frameId,
41345 frameBorder : 'no',
41346 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41351 this.iframe = iframe.dom;
41353 this.assignDocWin();
41355 this.doc.designMode = 'on';
41358 this.doc.write(this.getDocMarkup());
41362 var task = { // must defer to wait for browser to be ready
41364 //console.log("run task?" + this.doc.readyState);
41365 this.assignDocWin();
41366 if(this.doc.body || this.doc.readyState == 'complete'){
41368 this.doc.designMode="on";
41372 Roo.TaskMgr.stop(task);
41373 this.initEditor.defer(10, this);
41380 Roo.TaskMgr.start(task);
41385 onResize : function(w, h)
41387 Roo.log('resize: ' +w + ',' + h );
41388 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41392 if(typeof w == 'number'){
41394 this.iframe.style.width = w + 'px';
41396 if(typeof h == 'number'){
41398 this.iframe.style.height = h + 'px';
41400 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41407 * Toggles the editor between standard and source edit mode.
41408 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41410 toggleSourceEdit : function(sourceEditMode){
41412 this.sourceEditMode = sourceEditMode === true;
41414 if(this.sourceEditMode){
41416 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41419 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41420 //this.iframe.className = '';
41423 //this.setSize(this.owner.wrap.getSize());
41424 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41431 * Protected method that will not generally be called directly. If you need/want
41432 * custom HTML cleanup, this is the method you should override.
41433 * @param {String} html The HTML to be cleaned
41434 * return {String} The cleaned HTML
41436 cleanHtml : function(html){
41437 html = String(html);
41438 if(html.length > 5){
41439 if(Roo.isSafari){ // strip safari nonsense
41440 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41443 if(html == ' '){
41450 * HTML Editor -> Textarea
41451 * Protected method that will not generally be called directly. Syncs the contents
41452 * of the editor iframe with the textarea.
41454 syncValue : function(){
41455 if(this.initialized){
41456 var bd = (this.doc.body || this.doc.documentElement);
41457 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41458 var html = bd.innerHTML;
41460 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41461 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41463 html = '<div style="'+m[0]+'">' + html + '</div>';
41466 html = this.cleanHtml(html);
41467 // fix up the special chars.. normaly like back quotes in word...
41468 // however we do not want to do this with chinese..
41469 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41470 var cc = b.charCodeAt();
41472 (cc >= 0x4E00 && cc < 0xA000 ) ||
41473 (cc >= 0x3400 && cc < 0x4E00 ) ||
41474 (cc >= 0xf900 && cc < 0xfb00 )
41480 if(this.owner.fireEvent('beforesync', this, html) !== false){
41481 this.el.dom.value = html;
41482 this.owner.fireEvent('sync', this, html);
41488 * Protected method that will not generally be called directly. Pushes the value of the textarea
41489 * into the iframe editor.
41491 pushValue : function(){
41492 if(this.initialized){
41493 var v = this.el.dom.value.trim();
41495 // if(v.length < 1){
41499 if(this.owner.fireEvent('beforepush', this, v) !== false){
41500 var d = (this.doc.body || this.doc.documentElement);
41502 this.cleanUpPaste();
41503 this.el.dom.value = d.innerHTML;
41504 this.owner.fireEvent('push', this, v);
41510 deferFocus : function(){
41511 this.focus.defer(10, this);
41515 focus : function(){
41516 if(this.win && !this.sourceEditMode){
41523 assignDocWin: function()
41525 var iframe = this.iframe;
41528 this.doc = iframe.contentWindow.document;
41529 this.win = iframe.contentWindow;
41531 // if (!Roo.get(this.frameId)) {
41534 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41535 // this.win = Roo.get(this.frameId).dom.contentWindow;
41537 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
41541 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41542 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
41547 initEditor : function(){
41548 //console.log("INIT EDITOR");
41549 this.assignDocWin();
41553 this.doc.designMode="on";
41555 this.doc.write(this.getDocMarkup());
41558 var dbody = (this.doc.body || this.doc.documentElement);
41559 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41560 // this copies styles from the containing element into thsi one..
41561 // not sure why we need all of this..
41562 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41564 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41565 //ss['background-attachment'] = 'fixed'; // w3c
41566 dbody.bgProperties = 'fixed'; // ie
41567 //Roo.DomHelper.applyStyles(dbody, ss);
41568 Roo.EventManager.on(this.doc, {
41569 //'mousedown': this.onEditorEvent,
41570 'mouseup': this.onEditorEvent,
41571 'dblclick': this.onEditorEvent,
41572 'click': this.onEditorEvent,
41573 'keyup': this.onEditorEvent,
41578 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41580 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41581 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41583 this.initialized = true;
41585 this.owner.fireEvent('initialize', this);
41590 onDestroy : function(){
41596 //for (var i =0; i < this.toolbars.length;i++) {
41597 // // fixme - ask toolbars for heights?
41598 // this.toolbars[i].onDestroy();
41601 //this.wrap.dom.innerHTML = '';
41602 //this.wrap.remove();
41607 onFirstFocus : function(){
41609 this.assignDocWin();
41612 this.activated = true;
41615 if(Roo.isGecko){ // prevent silly gecko errors
41617 var s = this.win.getSelection();
41618 if(!s.focusNode || s.focusNode.nodeType != 3){
41619 var r = s.getRangeAt(0);
41620 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41625 this.execCmd('useCSS', true);
41626 this.execCmd('styleWithCSS', false);
41629 this.owner.fireEvent('activate', this);
41633 adjustFont: function(btn){
41634 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41635 //if(Roo.isSafari){ // safari
41638 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41639 if(Roo.isSafari){ // safari
41640 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41641 v = (v < 10) ? 10 : v;
41642 v = (v > 48) ? 48 : v;
41643 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41648 v = Math.max(1, v+adjust);
41650 this.execCmd('FontSize', v );
41653 onEditorEvent : function(e)
41655 this.owner.fireEvent('editorevent', this, e);
41656 // this.updateToolbar();
41657 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41660 insertTag : function(tg)
41662 // could be a bit smarter... -> wrap the current selected tRoo..
41663 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41665 range = this.createRange(this.getSelection());
41666 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41667 wrappingNode.appendChild(range.extractContents());
41668 range.insertNode(wrappingNode);
41675 this.execCmd("formatblock", tg);
41679 insertText : function(txt)
41683 var range = this.createRange();
41684 range.deleteContents();
41685 //alert(Sender.getAttribute('label'));
41687 range.insertNode(this.doc.createTextNode(txt));
41693 * Executes a Midas editor command on the editor document and performs necessary focus and
41694 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41695 * @param {String} cmd The Midas command
41696 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41698 relayCmd : function(cmd, value){
41700 this.execCmd(cmd, value);
41701 this.owner.fireEvent('editorevent', this);
41702 //this.updateToolbar();
41703 this.owner.deferFocus();
41707 * Executes a Midas editor command directly on the editor document.
41708 * For visual commands, you should use {@link #relayCmd} instead.
41709 * <b>This should only be called after the editor is initialized.</b>
41710 * @param {String} cmd The Midas command
41711 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41713 execCmd : function(cmd, value){
41714 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41721 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41723 * @param {String} text | dom node..
41725 insertAtCursor : function(text)
41730 if(!this.activated){
41736 var r = this.doc.selection.createRange();
41747 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41751 // from jquery ui (MIT licenced)
41753 var win = this.win;
41755 if (win.getSelection && win.getSelection().getRangeAt) {
41756 range = win.getSelection().getRangeAt(0);
41757 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41758 range.insertNode(node);
41759 } else if (win.document.selection && win.document.selection.createRange) {
41760 // no firefox support
41761 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41762 win.document.selection.createRange().pasteHTML(txt);
41764 // no firefox support
41765 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41766 this.execCmd('InsertHTML', txt);
41775 mozKeyPress : function(e){
41777 var c = e.getCharCode(), cmd;
41780 c = String.fromCharCode(c).toLowerCase();
41794 this.cleanUpPaste.defer(100, this);
41802 e.preventDefault();
41810 fixKeys : function(){ // load time branching for fastest keydown performance
41812 return function(e){
41813 var k = e.getKey(), r;
41816 r = this.doc.selection.createRange();
41819 r.pasteHTML('    ');
41826 r = this.doc.selection.createRange();
41828 var target = r.parentElement();
41829 if(!target || target.tagName.toLowerCase() != 'li'){
41831 r.pasteHTML('<br />');
41837 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41838 this.cleanUpPaste.defer(100, this);
41844 }else if(Roo.isOpera){
41845 return function(e){
41846 var k = e.getKey();
41850 this.execCmd('InsertHTML','    ');
41853 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41854 this.cleanUpPaste.defer(100, this);
41859 }else if(Roo.isSafari){
41860 return function(e){
41861 var k = e.getKey();
41865 this.execCmd('InsertText','\t');
41869 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41870 this.cleanUpPaste.defer(100, this);
41878 getAllAncestors: function()
41880 var p = this.getSelectedNode();
41883 a.push(p); // push blank onto stack..
41884 p = this.getParentElement();
41888 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41892 a.push(this.doc.body);
41896 lastSelNode : false,
41899 getSelection : function()
41901 this.assignDocWin();
41902 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41905 getSelectedNode: function()
41907 // this may only work on Gecko!!!
41909 // should we cache this!!!!
41914 var range = this.createRange(this.getSelection()).cloneRange();
41917 var parent = range.parentElement();
41919 var testRange = range.duplicate();
41920 testRange.moveToElementText(parent);
41921 if (testRange.inRange(range)) {
41924 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41927 parent = parent.parentElement;
41932 // is ancestor a text element.
41933 var ac = range.commonAncestorContainer;
41934 if (ac.nodeType == 3) {
41935 ac = ac.parentNode;
41938 var ar = ac.childNodes;
41941 var other_nodes = [];
41942 var has_other_nodes = false;
41943 for (var i=0;i<ar.length;i++) {
41944 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41947 // fullly contained node.
41949 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41954 // probably selected..
41955 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41956 other_nodes.push(ar[i]);
41960 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41965 has_other_nodes = true;
41967 if (!nodes.length && other_nodes.length) {
41968 nodes= other_nodes;
41970 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41976 createRange: function(sel)
41978 // this has strange effects when using with
41979 // top toolbar - not sure if it's a great idea.
41980 //this.editor.contentWindow.focus();
41981 if (typeof sel != "undefined") {
41983 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41985 return this.doc.createRange();
41988 return this.doc.createRange();
41991 getParentElement: function()
41994 this.assignDocWin();
41995 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41997 var range = this.createRange(sel);
42000 var p = range.commonAncestorContainer;
42001 while (p.nodeType == 3) { // text node
42012 * Range intersection.. the hard stuff...
42016 * [ -- selected range --- ]
42020 * if end is before start or hits it. fail.
42021 * if start is after end or hits it fail.
42023 * if either hits (but other is outside. - then it's not
42029 // @see http://www.thismuchiknow.co.uk/?p=64.
42030 rangeIntersectsNode : function(range, node)
42032 var nodeRange = node.ownerDocument.createRange();
42034 nodeRange.selectNode(node);
42036 nodeRange.selectNodeContents(node);
42039 var rangeStartRange = range.cloneRange();
42040 rangeStartRange.collapse(true);
42042 var rangeEndRange = range.cloneRange();
42043 rangeEndRange.collapse(false);
42045 var nodeStartRange = nodeRange.cloneRange();
42046 nodeStartRange.collapse(true);
42048 var nodeEndRange = nodeRange.cloneRange();
42049 nodeEndRange.collapse(false);
42051 return rangeStartRange.compareBoundaryPoints(
42052 Range.START_TO_START, nodeEndRange) == -1 &&
42053 rangeEndRange.compareBoundaryPoints(
42054 Range.START_TO_START, nodeStartRange) == 1;
42058 rangeCompareNode : function(range, node)
42060 var nodeRange = node.ownerDocument.createRange();
42062 nodeRange.selectNode(node);
42064 nodeRange.selectNodeContents(node);
42068 range.collapse(true);
42070 nodeRange.collapse(true);
42072 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
42073 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
42075 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
42077 var nodeIsBefore = ss == 1;
42078 var nodeIsAfter = ee == -1;
42080 if (nodeIsBefore && nodeIsAfter) {
42083 if (!nodeIsBefore && nodeIsAfter) {
42084 return 1; //right trailed.
42087 if (nodeIsBefore && !nodeIsAfter) {
42088 return 2; // left trailed.
42094 // private? - in a new class?
42095 cleanUpPaste : function()
42097 // cleans up the whole document..
42098 Roo.log('cleanuppaste');
42100 this.cleanUpChildren(this.doc.body);
42101 var clean = this.cleanWordChars(this.doc.body.innerHTML);
42102 if (clean != this.doc.body.innerHTML) {
42103 this.doc.body.innerHTML = clean;
42108 cleanWordChars : function(input) {// change the chars to hex code
42109 var he = Roo.HtmlEditorCore;
42111 var output = input;
42112 Roo.each(he.swapCodes, function(sw) {
42113 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
42115 output = output.replace(swapper, sw[1]);
42122 cleanUpChildren : function (n)
42124 if (!n.childNodes.length) {
42127 for (var i = n.childNodes.length-1; i > -1 ; i--) {
42128 this.cleanUpChild(n.childNodes[i]);
42135 cleanUpChild : function (node)
42138 //console.log(node);
42139 if (node.nodeName == "#text") {
42140 // clean up silly Windows -- stuff?
42143 if (node.nodeName == "#comment") {
42144 node.parentNode.removeChild(node);
42145 // clean up silly Windows -- stuff?
42148 var lcname = node.tagName.toLowerCase();
42149 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
42150 // whitelist of tags..
42152 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
42154 node.parentNode.removeChild(node);
42159 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
42161 // remove <a name=....> as rendering on yahoo mailer is borked with this.
42162 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
42164 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
42165 // remove_keep_children = true;
42168 if (remove_keep_children) {
42169 this.cleanUpChildren(node);
42170 // inserts everything just before this node...
42171 while (node.childNodes.length) {
42172 var cn = node.childNodes[0];
42173 node.removeChild(cn);
42174 node.parentNode.insertBefore(cn, node);
42176 node.parentNode.removeChild(node);
42180 if (!node.attributes || !node.attributes.length) {
42181 this.cleanUpChildren(node);
42185 function cleanAttr(n,v)
42188 if (v.match(/^\./) || v.match(/^\//)) {
42191 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
42194 if (v.match(/^#/)) {
42197 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
42198 node.removeAttribute(n);
42202 var cwhite = this.cwhite;
42203 var cblack = this.cblack;
42205 function cleanStyle(n,v)
42207 if (v.match(/expression/)) { //XSS?? should we even bother..
42208 node.removeAttribute(n);
42212 var parts = v.split(/;/);
42215 Roo.each(parts, function(p) {
42216 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42220 var l = p.split(':').shift().replace(/\s+/g,'');
42221 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42223 if ( cwhite.length && cblack.indexOf(l) > -1) {
42224 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42225 //node.removeAttribute(n);
42229 // only allow 'c whitelisted system attributes'
42230 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42231 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42232 //node.removeAttribute(n);
42242 if (clean.length) {
42243 node.setAttribute(n, clean.join(';'));
42245 node.removeAttribute(n);
42251 for (var i = node.attributes.length-1; i > -1 ; i--) {
42252 var a = node.attributes[i];
42255 if (a.name.toLowerCase().substr(0,2)=='on') {
42256 node.removeAttribute(a.name);
42259 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42260 node.removeAttribute(a.name);
42263 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42264 cleanAttr(a.name,a.value); // fixme..
42267 if (a.name == 'style') {
42268 cleanStyle(a.name,a.value);
42271 /// clean up MS crap..
42272 // tecnically this should be a list of valid class'es..
42275 if (a.name == 'class') {
42276 if (a.value.match(/^Mso/)) {
42277 node.className = '';
42280 if (a.value.match(/body/)) {
42281 node.className = '';
42292 this.cleanUpChildren(node);
42298 * Clean up MS wordisms...
42300 cleanWord : function(node)
42305 this.cleanWord(this.doc.body);
42308 if (node.nodeName == "#text") {
42309 // clean up silly Windows -- stuff?
42312 if (node.nodeName == "#comment") {
42313 node.parentNode.removeChild(node);
42314 // clean up silly Windows -- stuff?
42318 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42319 node.parentNode.removeChild(node);
42323 // remove - but keep children..
42324 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42325 while (node.childNodes.length) {
42326 var cn = node.childNodes[0];
42327 node.removeChild(cn);
42328 node.parentNode.insertBefore(cn, node);
42330 node.parentNode.removeChild(node);
42331 this.iterateChildren(node, this.cleanWord);
42335 if (node.className.length) {
42337 var cn = node.className.split(/\W+/);
42339 Roo.each(cn, function(cls) {
42340 if (cls.match(/Mso[a-zA-Z]+/)) {
42345 node.className = cna.length ? cna.join(' ') : '';
42347 node.removeAttribute("class");
42351 if (node.hasAttribute("lang")) {
42352 node.removeAttribute("lang");
42355 if (node.hasAttribute("style")) {
42357 var styles = node.getAttribute("style").split(";");
42359 Roo.each(styles, function(s) {
42360 if (!s.match(/:/)) {
42363 var kv = s.split(":");
42364 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42367 // what ever is left... we allow.
42370 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42371 if (!nstyle.length) {
42372 node.removeAttribute('style');
42375 this.iterateChildren(node, this.cleanWord);
42381 * iterateChildren of a Node, calling fn each time, using this as the scole..
42382 * @param {DomNode} node node to iterate children of.
42383 * @param {Function} fn method of this class to call on each item.
42385 iterateChildren : function(node, fn)
42387 if (!node.childNodes.length) {
42390 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42391 fn.call(this, node.childNodes[i])
42397 * cleanTableWidths.
42399 * Quite often pasting from word etc.. results in tables with column and widths.
42400 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
42403 cleanTableWidths : function(node)
42408 this.cleanTableWidths(this.doc.body);
42413 if (node.nodeName == "#text" || node.nodeName == "#comment") {
42416 Roo.log(node.tagName);
42417 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
42418 this.iterateChildren(node, this.cleanTableWidths);
42421 if (node.hasAttribute('width')) {
42422 node.removeAttribute('width');
42426 if (node.hasAttribute("style")) {
42429 var styles = node.getAttribute("style").split(";");
42431 Roo.each(styles, function(s) {
42432 if (!s.match(/:/)) {
42435 var kv = s.split(":");
42436 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
42439 // what ever is left... we allow.
42442 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42443 if (!nstyle.length) {
42444 node.removeAttribute('style');
42448 this.iterateChildren(node, this.cleanTableWidths);
42456 domToHTML : function(currentElement, depth, nopadtext) {
42458 depth = depth || 0;
42459 nopadtext = nopadtext || false;
42461 if (!currentElement) {
42462 return this.domToHTML(this.doc.body);
42465 //Roo.log(currentElement);
42467 var allText = false;
42468 var nodeName = currentElement.nodeName;
42469 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42471 if (nodeName == '#text') {
42473 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
42478 if (nodeName != 'BODY') {
42481 // Prints the node tagName, such as <A>, <IMG>, etc
42484 for(i = 0; i < currentElement.attributes.length;i++) {
42486 var aname = currentElement.attributes.item(i).name;
42487 if (!currentElement.attributes.item(i).value.length) {
42490 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42493 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42502 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42505 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42510 // Traverse the tree
42512 var currentElementChild = currentElement.childNodes.item(i);
42513 var allText = true;
42514 var innerHTML = '';
42516 while (currentElementChild) {
42517 // Formatting code (indent the tree so it looks nice on the screen)
42518 var nopad = nopadtext;
42519 if (lastnode == 'SPAN') {
42523 if (currentElementChild.nodeName == '#text') {
42524 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42525 toadd = nopadtext ? toadd : toadd.trim();
42526 if (!nopad && toadd.length > 80) {
42527 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42529 innerHTML += toadd;
42532 currentElementChild = currentElement.childNodes.item(i);
42538 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42540 // Recursively traverse the tree structure of the child node
42541 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42542 lastnode = currentElementChild.nodeName;
42544 currentElementChild=currentElement.childNodes.item(i);
42550 // The remaining code is mostly for formatting the tree
42551 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42556 ret+= "</"+tagName+">";
42562 applyBlacklists : function()
42564 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
42565 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
42569 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
42570 if (b.indexOf(tag) > -1) {
42573 this.white.push(tag);
42577 Roo.each(w, function(tag) {
42578 if (b.indexOf(tag) > -1) {
42581 if (this.white.indexOf(tag) > -1) {
42584 this.white.push(tag);
42589 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
42590 if (w.indexOf(tag) > -1) {
42593 this.black.push(tag);
42597 Roo.each(b, function(tag) {
42598 if (w.indexOf(tag) > -1) {
42601 if (this.black.indexOf(tag) > -1) {
42604 this.black.push(tag);
42609 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
42610 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
42614 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
42615 if (b.indexOf(tag) > -1) {
42618 this.cwhite.push(tag);
42622 Roo.each(w, function(tag) {
42623 if (b.indexOf(tag) > -1) {
42626 if (this.cwhite.indexOf(tag) > -1) {
42629 this.cwhite.push(tag);
42634 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
42635 if (w.indexOf(tag) > -1) {
42638 this.cblack.push(tag);
42642 Roo.each(b, function(tag) {
42643 if (w.indexOf(tag) > -1) {
42646 if (this.cblack.indexOf(tag) > -1) {
42649 this.cblack.push(tag);
42654 setStylesheets : function(stylesheets)
42656 if(typeof(stylesheets) == 'string'){
42657 Roo.get(this.iframe.contentDocument.head).createChild({
42659 rel : 'stylesheet',
42668 Roo.each(stylesheets, function(s) {
42673 Roo.get(_this.iframe.contentDocument.head).createChild({
42675 rel : 'stylesheet',
42684 removeStylesheets : function()
42688 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
42693 // hide stuff that is not compatible
42707 * @event specialkey
42711 * @cfg {String} fieldClass @hide
42714 * @cfg {String} focusClass @hide
42717 * @cfg {String} autoCreate @hide
42720 * @cfg {String} inputType @hide
42723 * @cfg {String} invalidClass @hide
42726 * @cfg {String} invalidText @hide
42729 * @cfg {String} msgFx @hide
42732 * @cfg {String} validateOnBlur @hide
42736 Roo.HtmlEditorCore.white = [
42737 'area', 'br', 'img', 'input', 'hr', 'wbr',
42739 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42740 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42741 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42742 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42743 'table', 'ul', 'xmp',
42745 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42748 'dir', 'menu', 'ol', 'ul', 'dl',
42754 Roo.HtmlEditorCore.black = [
42755 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42757 'base', 'basefont', 'bgsound', 'blink', 'body',
42758 'frame', 'frameset', 'head', 'html', 'ilayer',
42759 'iframe', 'layer', 'link', 'meta', 'object',
42760 'script', 'style' ,'title', 'xml' // clean later..
42762 Roo.HtmlEditorCore.clean = [
42763 'script', 'style', 'title', 'xml'
42765 Roo.HtmlEditorCore.remove = [
42770 Roo.HtmlEditorCore.ablack = [
42774 Roo.HtmlEditorCore.aclean = [
42775 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42779 Roo.HtmlEditorCore.pwhite= [
42780 'http', 'https', 'mailto'
42783 // white listed style attributes.
42784 Roo.HtmlEditorCore.cwhite= [
42785 // 'text-align', /// default is to allow most things..
42791 // black listed style attributes.
42792 Roo.HtmlEditorCore.cblack= [
42793 // 'font-size' -- this can be set by the project
42797 Roo.HtmlEditorCore.swapCodes =[
42808 //<script type="text/javascript">
42811 * Ext JS Library 1.1.1
42812 * Copyright(c) 2006-2007, Ext JS, LLC.
42818 Roo.form.HtmlEditor = function(config){
42822 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42824 if (!this.toolbars) {
42825 this.toolbars = [];
42827 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42833 * @class Roo.form.HtmlEditor
42834 * @extends Roo.form.Field
42835 * Provides a lightweight HTML Editor component.
42837 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42839 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42840 * supported by this editor.</b><br/><br/>
42841 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42842 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42844 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42846 * @cfg {Boolean} clearUp
42850 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42855 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42860 * @cfg {Number} height (in pixels)
42864 * @cfg {Number} width (in pixels)
42869 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42872 stylesheets: false,
42876 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
42881 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
42887 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
42892 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
42900 // private properties
42901 validationEvent : false,
42903 initialized : false,
42906 onFocus : Roo.emptyFn,
42908 hideMode:'offsets',
42910 actionMode : 'container', // defaults to hiding it...
42912 defaultAutoCreate : { // modified by initCompnoent..
42914 style:"width:500px;height:300px;",
42915 autocomplete: "new-password"
42919 initComponent : function(){
42922 * @event initialize
42923 * Fires when the editor is fully initialized (including the iframe)
42924 * @param {HtmlEditor} this
42929 * Fires when the editor is first receives the focus. Any insertion must wait
42930 * until after this event.
42931 * @param {HtmlEditor} this
42935 * @event beforesync
42936 * Fires before the textarea is updated with content from the editor iframe. Return false
42937 * to cancel the sync.
42938 * @param {HtmlEditor} this
42939 * @param {String} html
42943 * @event beforepush
42944 * Fires before the iframe editor is updated with content from the textarea. Return false
42945 * to cancel the push.
42946 * @param {HtmlEditor} this
42947 * @param {String} html
42952 * Fires when the textarea is updated with content from the editor iframe.
42953 * @param {HtmlEditor} this
42954 * @param {String} html
42959 * Fires when the iframe editor is updated with content from the textarea.
42960 * @param {HtmlEditor} this
42961 * @param {String} html
42965 * @event editmodechange
42966 * Fires when the editor switches edit modes
42967 * @param {HtmlEditor} this
42968 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42970 editmodechange: true,
42972 * @event editorevent
42973 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42974 * @param {HtmlEditor} this
42978 * @event firstfocus
42979 * Fires when on first focus - needed by toolbars..
42980 * @param {HtmlEditor} this
42985 * Auto save the htmlEditor value as a file into Events
42986 * @param {HtmlEditor} this
42990 * @event savedpreview
42991 * preview the saved version of htmlEditor
42992 * @param {HtmlEditor} this
42994 savedpreview: true,
42997 * @event stylesheetsclick
42998 * Fires when press the Sytlesheets button
42999 * @param {Roo.HtmlEditorCore} this
43001 stylesheetsclick: true
43003 this.defaultAutoCreate = {
43005 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
43006 autocomplete: "new-password"
43011 * Protected method that will not generally be called directly. It
43012 * is called when the editor creates its toolbar. Override this method if you need to
43013 * add custom toolbar buttons.
43014 * @param {HtmlEditor} editor
43016 createToolbar : function(editor){
43017 Roo.log("create toolbars");
43018 if (!editor.toolbars || !editor.toolbars.length) {
43019 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
43022 for (var i =0 ; i < editor.toolbars.length;i++) {
43023 editor.toolbars[i] = Roo.factory(
43024 typeof(editor.toolbars[i]) == 'string' ?
43025 { xtype: editor.toolbars[i]} : editor.toolbars[i],
43026 Roo.form.HtmlEditor);
43027 editor.toolbars[i].init(editor);
43035 onRender : function(ct, position)
43038 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
43040 this.wrap = this.el.wrap({
43041 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
43044 this.editorcore.onRender(ct, position);
43046 if (this.resizable) {
43047 this.resizeEl = new Roo.Resizable(this.wrap, {
43051 minHeight : this.height,
43052 height: this.height,
43053 handles : this.resizable,
43056 resize : function(r, w, h) {
43057 _t.onResize(w,h); // -something
43063 this.createToolbar(this);
43067 this.setSize(this.wrap.getSize());
43069 if (this.resizeEl) {
43070 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
43071 // should trigger onReize..
43074 this.keyNav = new Roo.KeyNav(this.el, {
43076 "tab" : function(e){
43077 e.preventDefault();
43079 var value = this.getValue();
43081 var start = this.el.dom.selectionStart;
43082 var end = this.el.dom.selectionEnd;
43086 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
43087 this.el.dom.setSelectionRange(end + 1, end + 1);
43091 var f = value.substring(0, start).split("\t");
43093 if(f.pop().length != 0){
43097 this.setValue(f.join("\t") + value.substring(end));
43098 this.el.dom.setSelectionRange(start - 1, start - 1);
43102 "home" : function(e){
43103 e.preventDefault();
43105 var curr = this.el.dom.selectionStart;
43106 var lines = this.getValue().split("\n");
43113 this.el.dom.setSelectionRange(0, 0);
43119 for (var i = 0; i < lines.length;i++) {
43120 pos += lines[i].length;
43130 pos -= lines[i].length;
43136 this.el.dom.setSelectionRange(pos, pos);
43140 this.el.dom.selectionStart = pos;
43141 this.el.dom.selectionEnd = curr;
43144 "end" : function(e){
43145 e.preventDefault();
43147 var curr = this.el.dom.selectionStart;
43148 var lines = this.getValue().split("\n");
43155 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
43161 for (var i = 0; i < lines.length;i++) {
43163 pos += lines[i].length;
43177 this.el.dom.setSelectionRange(pos, pos);
43181 this.el.dom.selectionStart = curr;
43182 this.el.dom.selectionEnd = pos;
43187 doRelay : function(foo, bar, hname){
43188 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
43194 // if(this.autosave && this.w){
43195 // this.autoSaveFn = setInterval(this.autosave, 1000);
43200 onResize : function(w, h)
43202 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
43207 if(typeof w == 'number'){
43208 var aw = w - this.wrap.getFrameWidth('lr');
43209 this.el.setWidth(this.adjustWidth('textarea', aw));
43212 if(typeof h == 'number'){
43214 for (var i =0; i < this.toolbars.length;i++) {
43215 // fixme - ask toolbars for heights?
43216 tbh += this.toolbars[i].tb.el.getHeight();
43217 if (this.toolbars[i].footer) {
43218 tbh += this.toolbars[i].footer.el.getHeight();
43225 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
43226 ah -= 5; // knock a few pixes off for look..
43228 this.el.setHeight(this.adjustWidth('textarea', ah));
43232 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
43233 this.editorcore.onResize(ew,eh);
43238 * Toggles the editor between standard and source edit mode.
43239 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43241 toggleSourceEdit : function(sourceEditMode)
43243 this.editorcore.toggleSourceEdit(sourceEditMode);
43245 if(this.editorcore.sourceEditMode){
43246 Roo.log('editor - showing textarea');
43249 // Roo.log(this.syncValue());
43250 this.editorcore.syncValue();
43251 this.el.removeClass('x-hidden');
43252 this.el.dom.removeAttribute('tabIndex');
43255 for (var i = 0; i < this.toolbars.length; i++) {
43256 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43257 this.toolbars[i].tb.hide();
43258 this.toolbars[i].footer.hide();
43263 Roo.log('editor - hiding textarea');
43265 // Roo.log(this.pushValue());
43266 this.editorcore.pushValue();
43268 this.el.addClass('x-hidden');
43269 this.el.dom.setAttribute('tabIndex', -1);
43271 for (var i = 0; i < this.toolbars.length; i++) {
43272 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43273 this.toolbars[i].tb.show();
43274 this.toolbars[i].footer.show();
43278 //this.deferFocus();
43281 this.setSize(this.wrap.getSize());
43282 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
43284 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
43287 // private (for BoxComponent)
43288 adjustSize : Roo.BoxComponent.prototype.adjustSize,
43290 // private (for BoxComponent)
43291 getResizeEl : function(){
43295 // private (for BoxComponent)
43296 getPositionEl : function(){
43301 initEvents : function(){
43302 this.originalValue = this.getValue();
43306 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43309 markInvalid : Roo.emptyFn,
43311 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43314 clearInvalid : Roo.emptyFn,
43316 setValue : function(v){
43317 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
43318 this.editorcore.pushValue();
43323 deferFocus : function(){
43324 this.focus.defer(10, this);
43328 focus : function(){
43329 this.editorcore.focus();
43335 onDestroy : function(){
43341 for (var i =0; i < this.toolbars.length;i++) {
43342 // fixme - ask toolbars for heights?
43343 this.toolbars[i].onDestroy();
43346 this.wrap.dom.innerHTML = '';
43347 this.wrap.remove();
43352 onFirstFocus : function(){
43353 //Roo.log("onFirstFocus");
43354 this.editorcore.onFirstFocus();
43355 for (var i =0; i < this.toolbars.length;i++) {
43356 this.toolbars[i].onFirstFocus();
43362 syncValue : function()
43364 this.editorcore.syncValue();
43367 pushValue : function()
43369 this.editorcore.pushValue();
43372 setStylesheets : function(stylesheets)
43374 this.editorcore.setStylesheets(stylesheets);
43377 removeStylesheets : function()
43379 this.editorcore.removeStylesheets();
43383 // hide stuff that is not compatible
43397 * @event specialkey
43401 * @cfg {String} fieldClass @hide
43404 * @cfg {String} focusClass @hide
43407 * @cfg {String} autoCreate @hide
43410 * @cfg {String} inputType @hide
43413 * @cfg {String} invalidClass @hide
43416 * @cfg {String} invalidText @hide
43419 * @cfg {String} msgFx @hide
43422 * @cfg {String} validateOnBlur @hide
43426 // <script type="text/javascript">
43429 * Ext JS Library 1.1.1
43430 * Copyright(c) 2006-2007, Ext JS, LLC.
43436 * @class Roo.form.HtmlEditorToolbar1
43441 new Roo.form.HtmlEditor({
43444 new Roo.form.HtmlEditorToolbar1({
43445 disable : { fonts: 1 , format: 1, ..., ... , ...],
43451 * @cfg {Object} disable List of elements to disable..
43452 * @cfg {Array} btns List of additional buttons.
43456 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
43459 Roo.form.HtmlEditor.ToolbarStandard = function(config)
43462 Roo.apply(this, config);
43464 // default disabled, based on 'good practice'..
43465 this.disable = this.disable || {};
43466 Roo.applyIf(this.disable, {
43469 specialElements : true
43473 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43474 // dont call parent... till later.
43477 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
43484 editorcore : false,
43486 * @cfg {Object} disable List of toolbar elements to disable
43493 * @cfg {String} createLinkText The default text for the create link prompt
43495 createLinkText : 'Please enter the URL for the link:',
43497 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
43499 defaultLinkValue : 'http:/'+'/',
43503 * @cfg {Array} fontFamilies An array of available font families
43521 // "á" , ?? a acute?
43526 "°" // , // degrees
43528 // "é" , // e ecute
43529 // "ú" , // u ecute?
43532 specialElements : [
43534 text: "Insert Table",
43537 ihtml : '<table><tr><td>Cell</td></tr></table>'
43541 text: "Insert Image",
43544 ihtml : '<img src="about:blank"/>'
43553 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
43554 "input:submit", "input:button", "select", "textarea", "label" ],
43557 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
43559 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
43567 * @cfg {String} defaultFont default font to use.
43569 defaultFont: 'tahoma',
43571 fontSelect : false,
43574 formatCombo : false,
43576 init : function(editor)
43578 this.editor = editor;
43579 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43580 var editorcore = this.editorcore;
43584 var fid = editorcore.frameId;
43586 function btn(id, toggle, handler){
43587 var xid = fid + '-'+ id ;
43591 cls : 'x-btn-icon x-edit-'+id,
43592 enableToggle:toggle !== false,
43593 scope: _t, // was editor...
43594 handler:handler||_t.relayBtnCmd,
43595 clickEvent:'mousedown',
43596 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43603 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43605 // stop form submits
43606 tb.el.on('click', function(e){
43607 e.preventDefault(); // what does this do?
43610 if(!this.disable.font) { // && !Roo.isSafari){
43611 /* why no safari for fonts
43612 editor.fontSelect = tb.el.createChild({
43615 cls:'x-font-select',
43616 html: this.createFontOptions()
43619 editor.fontSelect.on('change', function(){
43620 var font = editor.fontSelect.dom.value;
43621 editor.relayCmd('fontname', font);
43622 editor.deferFocus();
43626 editor.fontSelect.dom,
43632 if(!this.disable.formats){
43633 this.formatCombo = new Roo.form.ComboBox({
43634 store: new Roo.data.SimpleStore({
43637 data : this.formats // from states.js
43641 //autoCreate : {tag: "div", size: "20"},
43642 displayField:'tag',
43646 triggerAction: 'all',
43647 emptyText:'Add tag',
43648 selectOnFocus:true,
43651 'select': function(c, r, i) {
43652 editorcore.insertTag(r.get('tag'));
43658 tb.addField(this.formatCombo);
43662 if(!this.disable.format){
43667 btn('strikethrough')
43670 if(!this.disable.fontSize){
43675 btn('increasefontsize', false, editorcore.adjustFont),
43676 btn('decreasefontsize', false, editorcore.adjustFont)
43681 if(!this.disable.colors){
43684 id:editorcore.frameId +'-forecolor',
43685 cls:'x-btn-icon x-edit-forecolor',
43686 clickEvent:'mousedown',
43687 tooltip: this.buttonTips['forecolor'] || undefined,
43689 menu : new Roo.menu.ColorMenu({
43690 allowReselect: true,
43691 focus: Roo.emptyFn,
43694 selectHandler: function(cp, color){
43695 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43696 editor.deferFocus();
43699 clickEvent:'mousedown'
43702 id:editorcore.frameId +'backcolor',
43703 cls:'x-btn-icon x-edit-backcolor',
43704 clickEvent:'mousedown',
43705 tooltip: this.buttonTips['backcolor'] || undefined,
43707 menu : new Roo.menu.ColorMenu({
43708 focus: Roo.emptyFn,
43711 allowReselect: true,
43712 selectHandler: function(cp, color){
43714 editorcore.execCmd('useCSS', false);
43715 editorcore.execCmd('hilitecolor', color);
43716 editorcore.execCmd('useCSS', true);
43717 editor.deferFocus();
43719 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43720 Roo.isSafari || Roo.isIE ? '#'+color : color);
43721 editor.deferFocus();
43725 clickEvent:'mousedown'
43730 // now add all the items...
43733 if(!this.disable.alignments){
43736 btn('justifyleft'),
43737 btn('justifycenter'),
43738 btn('justifyright')
43742 //if(!Roo.isSafari){
43743 if(!this.disable.links){
43746 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43750 if(!this.disable.lists){
43753 btn('insertorderedlist'),
43754 btn('insertunorderedlist')
43757 if(!this.disable.sourceEdit){
43760 btn('sourceedit', true, function(btn){
43761 this.toggleSourceEdit(btn.pressed);
43768 // special menu.. - needs to be tidied up..
43769 if (!this.disable.special) {
43772 cls: 'x-edit-none',
43778 for (var i =0; i < this.specialChars.length; i++) {
43779 smenu.menu.items.push({
43781 html: this.specialChars[i],
43782 handler: function(a,b) {
43783 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43784 //editor.insertAtCursor(a.html);
43798 if (!this.disable.cleanStyles) {
43800 cls: 'x-btn-icon x-btn-clear',
43806 for (var i =0; i < this.cleanStyles.length; i++) {
43807 cmenu.menu.items.push({
43808 actiontype : this.cleanStyles[i],
43809 html: 'Remove ' + this.cleanStyles[i],
43810 handler: function(a,b) {
43813 var c = Roo.get(editorcore.doc.body);
43814 c.select('[style]').each(function(s) {
43815 s.dom.style.removeProperty(a.actiontype);
43817 editorcore.syncValue();
43822 cmenu.menu.items.push({
43823 actiontype : 'tablewidths',
43824 html: 'Remove Table Widths',
43825 handler: function(a,b) {
43826 editorcore.cleanTableWidths();
43827 editorcore.syncValue();
43831 cmenu.menu.items.push({
43832 actiontype : 'word',
43833 html: 'Remove MS Word Formating',
43834 handler: function(a,b) {
43835 editorcore.cleanWord();
43836 editorcore.syncValue();
43841 cmenu.menu.items.push({
43842 actiontype : 'all',
43843 html: 'Remove All Styles',
43844 handler: function(a,b) {
43846 var c = Roo.get(editorcore.doc.body);
43847 c.select('[style]').each(function(s) {
43848 s.dom.removeAttribute('style');
43850 editorcore.syncValue();
43855 cmenu.menu.items.push({
43856 actiontype : 'all',
43857 html: 'Remove All CSS Classes',
43858 handler: function(a,b) {
43860 var c = Roo.get(editorcore.doc.body);
43861 c.select('[class]').each(function(s) {
43862 s.dom.className = '';
43864 editorcore.syncValue();
43869 cmenu.menu.items.push({
43870 actiontype : 'tidy',
43871 html: 'Tidy HTML Source',
43872 handler: function(a,b) {
43873 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43874 editorcore.syncValue();
43883 if (!this.disable.specialElements) {
43886 cls: 'x-edit-none',
43891 for (var i =0; i < this.specialElements.length; i++) {
43892 semenu.menu.items.push(
43894 handler: function(a,b) {
43895 editor.insertAtCursor(this.ihtml);
43897 }, this.specialElements[i])
43909 for(var i =0; i< this.btns.length;i++) {
43910 var b = Roo.factory(this.btns[i],Roo.form);
43911 b.cls = 'x-edit-none';
43913 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
43914 b.cls += ' x-init-enable';
43917 b.scope = editorcore;
43925 // disable everything...
43927 this.tb.items.each(function(item){
43930 item.id != editorcore.frameId+ '-sourceedit' &&
43931 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
43937 this.rendered = true;
43939 // the all the btns;
43940 editor.on('editorevent', this.updateToolbar, this);
43941 // other toolbars need to implement this..
43942 //editor.on('editmodechange', this.updateToolbar, this);
43946 relayBtnCmd : function(btn) {
43947 this.editorcore.relayCmd(btn.cmd);
43949 // private used internally
43950 createLink : function(){
43951 Roo.log("create link?");
43952 var url = prompt(this.createLinkText, this.defaultLinkValue);
43953 if(url && url != 'http:/'+'/'){
43954 this.editorcore.relayCmd('createlink', url);
43960 * Protected method that will not generally be called directly. It triggers
43961 * a toolbar update by reading the markup state of the current selection in the editor.
43963 updateToolbar: function(){
43965 if(!this.editorcore.activated){
43966 this.editor.onFirstFocus();
43970 var btns = this.tb.items.map,
43971 doc = this.editorcore.doc,
43972 frameId = this.editorcore.frameId;
43974 if(!this.disable.font && !Roo.isSafari){
43976 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43977 if(name != this.fontSelect.dom.value){
43978 this.fontSelect.dom.value = name;
43982 if(!this.disable.format){
43983 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43984 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43985 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43986 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
43988 if(!this.disable.alignments){
43989 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43990 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43991 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43993 if(!Roo.isSafari && !this.disable.lists){
43994 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43995 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43998 var ans = this.editorcore.getAllAncestors();
43999 if (this.formatCombo) {
44002 var store = this.formatCombo.store;
44003 this.formatCombo.setValue("");
44004 for (var i =0; i < ans.length;i++) {
44005 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
44007 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
44015 // hides menus... - so this cant be on a menu...
44016 Roo.menu.MenuMgr.hideAll();
44018 //this.editorsyncValue();
44022 createFontOptions : function(){
44023 var buf = [], fs = this.fontFamilies, ff, lc;
44027 for(var i = 0, len = fs.length; i< len; i++){
44029 lc = ff.toLowerCase();
44031 '<option value="',lc,'" style="font-family:',ff,';"',
44032 (this.defaultFont == lc ? ' selected="true">' : '>'),
44037 return buf.join('');
44040 toggleSourceEdit : function(sourceEditMode){
44042 Roo.log("toolbar toogle");
44043 if(sourceEditMode === undefined){
44044 sourceEditMode = !this.sourceEditMode;
44046 this.sourceEditMode = sourceEditMode === true;
44047 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
44048 // just toggle the button?
44049 if(btn.pressed !== this.sourceEditMode){
44050 btn.toggle(this.sourceEditMode);
44054 if(sourceEditMode){
44055 Roo.log("disabling buttons");
44056 this.tb.items.each(function(item){
44057 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
44063 Roo.log("enabling buttons");
44064 if(this.editorcore.initialized){
44065 this.tb.items.each(function(item){
44071 Roo.log("calling toggole on editor");
44072 // tell the editor that it's been pressed..
44073 this.editor.toggleSourceEdit(sourceEditMode);
44077 * Object collection of toolbar tooltips for the buttons in the editor. The key
44078 * is the command id associated with that button and the value is a valid QuickTips object.
44083 title: 'Bold (Ctrl+B)',
44084 text: 'Make the selected text bold.',
44085 cls: 'x-html-editor-tip'
44088 title: 'Italic (Ctrl+I)',
44089 text: 'Make the selected text italic.',
44090 cls: 'x-html-editor-tip'
44098 title: 'Bold (Ctrl+B)',
44099 text: 'Make the selected text bold.',
44100 cls: 'x-html-editor-tip'
44103 title: 'Italic (Ctrl+I)',
44104 text: 'Make the selected text italic.',
44105 cls: 'x-html-editor-tip'
44108 title: 'Underline (Ctrl+U)',
44109 text: 'Underline the selected text.',
44110 cls: 'x-html-editor-tip'
44113 title: 'Strikethrough',
44114 text: 'Strikethrough the selected text.',
44115 cls: 'x-html-editor-tip'
44117 increasefontsize : {
44118 title: 'Grow Text',
44119 text: 'Increase the font size.',
44120 cls: 'x-html-editor-tip'
44122 decreasefontsize : {
44123 title: 'Shrink Text',
44124 text: 'Decrease the font size.',
44125 cls: 'x-html-editor-tip'
44128 title: 'Text Highlight Color',
44129 text: 'Change the background color of the selected text.',
44130 cls: 'x-html-editor-tip'
44133 title: 'Font Color',
44134 text: 'Change the color of the selected text.',
44135 cls: 'x-html-editor-tip'
44138 title: 'Align Text Left',
44139 text: 'Align text to the left.',
44140 cls: 'x-html-editor-tip'
44143 title: 'Center Text',
44144 text: 'Center text in the editor.',
44145 cls: 'x-html-editor-tip'
44148 title: 'Align Text Right',
44149 text: 'Align text to the right.',
44150 cls: 'x-html-editor-tip'
44152 insertunorderedlist : {
44153 title: 'Bullet List',
44154 text: 'Start a bulleted list.',
44155 cls: 'x-html-editor-tip'
44157 insertorderedlist : {
44158 title: 'Numbered List',
44159 text: 'Start a numbered list.',
44160 cls: 'x-html-editor-tip'
44163 title: 'Hyperlink',
44164 text: 'Make the selected text a hyperlink.',
44165 cls: 'x-html-editor-tip'
44168 title: 'Source Edit',
44169 text: 'Switch to source editing mode.',
44170 cls: 'x-html-editor-tip'
44174 onDestroy : function(){
44177 this.tb.items.each(function(item){
44179 item.menu.removeAll();
44181 item.menu.el.destroy();
44189 onFirstFocus: function() {
44190 this.tb.items.each(function(item){
44199 // <script type="text/javascript">
44202 * Ext JS Library 1.1.1
44203 * Copyright(c) 2006-2007, Ext JS, LLC.
44210 * @class Roo.form.HtmlEditor.ToolbarContext
44215 new Roo.form.HtmlEditor({
44218 { xtype: 'ToolbarStandard', styles : {} }
44219 { xtype: 'ToolbarContext', disable : {} }
44225 * @config : {Object} disable List of elements to disable.. (not done yet.)
44226 * @config : {Object} styles Map of styles available.
44230 Roo.form.HtmlEditor.ToolbarContext = function(config)
44233 Roo.apply(this, config);
44234 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44235 // dont call parent... till later.
44236 this.styles = this.styles || {};
44241 Roo.form.HtmlEditor.ToolbarContext.types = {
44253 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
44319 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
44324 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
44334 style : 'fontFamily',
44335 displayField: 'display',
44336 optname : 'font-family',
44385 // should we really allow this??
44386 // should this just be
44397 style : 'fontFamily',
44398 displayField: 'display',
44399 optname : 'font-family',
44406 style : 'fontFamily',
44407 displayField: 'display',
44408 optname : 'font-family',
44415 style : 'fontFamily',
44416 displayField: 'display',
44417 optname : 'font-family',
44428 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
44429 Roo.form.HtmlEditor.ToolbarContext.stores = false;
44431 Roo.form.HtmlEditor.ToolbarContext.options = {
44433 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
44434 [ 'Courier New', 'Courier New'],
44435 [ 'Tahoma', 'Tahoma'],
44436 [ 'Times New Roman,serif', 'Times'],
44437 [ 'Verdana','Verdana' ]
44441 // fixme - these need to be configurable..
44444 //Roo.form.HtmlEditor.ToolbarContext.types
44447 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
44454 editorcore : false,
44456 * @cfg {Object} disable List of toolbar elements to disable
44461 * @cfg {Object} styles List of styles
44462 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
44464 * These must be defined in the page, so they get rendered correctly..
44475 init : function(editor)
44477 this.editor = editor;
44478 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44479 var editorcore = this.editorcore;
44481 var fid = editorcore.frameId;
44483 function btn(id, toggle, handler){
44484 var xid = fid + '-'+ id ;
44488 cls : 'x-btn-icon x-edit-'+id,
44489 enableToggle:toggle !== false,
44490 scope: editorcore, // was editor...
44491 handler:handler||editorcore.relayBtnCmd,
44492 clickEvent:'mousedown',
44493 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44497 // create a new element.
44498 var wdiv = editor.wrap.createChild({
44500 }, editor.wrap.dom.firstChild.nextSibling, true);
44502 // can we do this more than once??
44504 // stop form submits
44507 // disable everything...
44508 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44509 this.toolbars = {};
44511 for (var i in ty) {
44513 this.toolbars[i] = this.buildToolbar(ty[i],i);
44515 this.tb = this.toolbars.BODY;
44517 this.buildFooter();
44518 this.footer.show();
44519 editor.on('hide', function( ) { this.footer.hide() }, this);
44520 editor.on('show', function( ) { this.footer.show() }, this);
44523 this.rendered = true;
44525 // the all the btns;
44526 editor.on('editorevent', this.updateToolbar, this);
44527 // other toolbars need to implement this..
44528 //editor.on('editmodechange', this.updateToolbar, this);
44534 * Protected method that will not generally be called directly. It triggers
44535 * a toolbar update by reading the markup state of the current selection in the editor.
44537 * Note you can force an update by calling on('editorevent', scope, false)
44539 updateToolbar: function(editor,ev,sel){
44542 // capture mouse up - this is handy for selecting images..
44543 // perhaps should go somewhere else...
44544 if(!this.editorcore.activated){
44545 this.editor.onFirstFocus();
44551 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
44552 // selectNode - might want to handle IE?
44554 (ev.type == 'mouseup' || ev.type == 'click' ) &&
44555 ev.target && ev.target.tagName == 'IMG') {
44556 // they have click on an image...
44557 // let's see if we can change the selection...
44560 var nodeRange = sel.ownerDocument.createRange();
44562 nodeRange.selectNode(sel);
44564 nodeRange.selectNodeContents(sel);
44566 //nodeRange.collapse(true);
44567 var s = this.editorcore.win.getSelection();
44568 s.removeAllRanges();
44569 s.addRange(nodeRange);
44573 var updateFooter = sel ? false : true;
44576 var ans = this.editorcore.getAllAncestors();
44579 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44582 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
44583 sel = sel ? sel : this.editorcore.doc.body;
44584 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
44587 // pick a menu that exists..
44588 var tn = sel.tagName.toUpperCase();
44589 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
44591 tn = sel.tagName.toUpperCase();
44593 var lastSel = this.tb.selectedNode;
44595 this.tb.selectedNode = sel;
44597 // if current menu does not match..
44599 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
44602 ///console.log("show: " + tn);
44603 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
44606 this.tb.items.first().el.innerHTML = tn + ': ';
44609 // update attributes
44610 if (this.tb.fields) {
44611 this.tb.fields.each(function(e) {
44613 e.setValue(sel.style[e.stylename]);
44616 e.setValue(sel.getAttribute(e.attrname));
44620 var hasStyles = false;
44621 for(var i in this.styles) {
44628 var st = this.tb.fields.item(0);
44630 st.store.removeAll();
44633 var cn = sel.className.split(/\s+/);
44636 if (this.styles['*']) {
44638 Roo.each(this.styles['*'], function(v) {
44639 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44642 if (this.styles[tn]) {
44643 Roo.each(this.styles[tn], function(v) {
44644 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44648 st.store.loadData(avs);
44652 // flag our selected Node.
44653 this.tb.selectedNode = sel;
44656 Roo.menu.MenuMgr.hideAll();
44660 if (!updateFooter) {
44661 //this.footDisp.dom.innerHTML = '';
44664 // update the footer
44668 this.footerEls = ans.reverse();
44669 Roo.each(this.footerEls, function(a,i) {
44670 if (!a) { return; }
44671 html += html.length ? ' > ' : '';
44673 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44678 var sz = this.footDisp.up('td').getSize();
44679 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44680 this.footDisp.dom.style.marginLeft = '5px';
44682 this.footDisp.dom.style.overflow = 'hidden';
44684 this.footDisp.dom.innerHTML = html;
44686 //this.editorsyncValue();
44693 onDestroy : function(){
44696 this.tb.items.each(function(item){
44698 item.menu.removeAll();
44700 item.menu.el.destroy();
44708 onFirstFocus: function() {
44709 // need to do this for all the toolbars..
44710 this.tb.items.each(function(item){
44714 buildToolbar: function(tlist, nm)
44716 var editor = this.editor;
44717 var editorcore = this.editorcore;
44718 // create a new element.
44719 var wdiv = editor.wrap.createChild({
44721 }, editor.wrap.dom.firstChild.nextSibling, true);
44724 var tb = new Roo.Toolbar(wdiv);
44727 tb.add(nm+ ": ");
44730 for(var i in this.styles) {
44735 if (styles && styles.length) {
44737 // this needs a multi-select checkbox...
44738 tb.addField( new Roo.form.ComboBox({
44739 store: new Roo.data.SimpleStore({
44741 fields: ['val', 'selected'],
44744 name : '-roo-edit-className',
44745 attrname : 'className',
44746 displayField: 'val',
44750 triggerAction: 'all',
44751 emptyText:'Select Style',
44752 selectOnFocus:true,
44755 'select': function(c, r, i) {
44756 // initial support only for on class per el..
44757 tb.selectedNode.className = r ? r.get('val') : '';
44758 editorcore.syncValue();
44765 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44766 var tbops = tbc.options;
44768 for (var i in tlist) {
44770 var item = tlist[i];
44771 tb.add(item.title + ": ");
44774 //optname == used so you can configure the options available..
44775 var opts = item.opts ? item.opts : false;
44776 if (item.optname) {
44777 opts = tbops[item.optname];
44782 // opts == pulldown..
44783 tb.addField( new Roo.form.ComboBox({
44784 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44786 fields: ['val', 'display'],
44789 name : '-roo-edit-' + i,
44791 stylename : item.style ? item.style : false,
44792 displayField: item.displayField ? item.displayField : 'val',
44793 valueField : 'val',
44795 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44797 triggerAction: 'all',
44798 emptyText:'Select',
44799 selectOnFocus:true,
44800 width: item.width ? item.width : 130,
44802 'select': function(c, r, i) {
44804 tb.selectedNode.style[c.stylename] = r.get('val');
44807 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44816 tb.addField( new Roo.form.TextField({
44819 //allowBlank:false,
44824 tb.addField( new Roo.form.TextField({
44825 name: '-roo-edit-' + i,
44832 'change' : function(f, nv, ov) {
44833 tb.selectedNode.setAttribute(f.attrname, nv);
44846 text: 'Stylesheets',
44849 click : function ()
44851 _this.editor.fireEvent('stylesheetsclick', _this.editor);
44859 text: 'Remove Tag',
44862 click : function ()
44865 // undo does not work.
44867 var sn = tb.selectedNode;
44869 var pn = sn.parentNode;
44871 var stn = sn.childNodes[0];
44872 var en = sn.childNodes[sn.childNodes.length - 1 ];
44873 while (sn.childNodes.length) {
44874 var node = sn.childNodes[0];
44875 sn.removeChild(node);
44877 pn.insertBefore(node, sn);
44880 pn.removeChild(sn);
44881 var range = editorcore.createRange();
44883 range.setStart(stn,0);
44884 range.setEnd(en,0); //????
44885 //range.selectNode(sel);
44888 var selection = editorcore.getSelection();
44889 selection.removeAllRanges();
44890 selection.addRange(range);
44894 //_this.updateToolbar(null, null, pn);
44895 _this.updateToolbar(null, null, null);
44896 _this.footDisp.dom.innerHTML = '';
44906 tb.el.on('click', function(e){
44907 e.preventDefault(); // what does this do?
44909 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44912 // dont need to disable them... as they will get hidden
44917 buildFooter : function()
44920 var fel = this.editor.wrap.createChild();
44921 this.footer = new Roo.Toolbar(fel);
44922 // toolbar has scrolly on left / right?
44923 var footDisp= new Roo.Toolbar.Fill();
44929 handler : function() {
44930 _t.footDisp.scrollTo('left',0,true)
44934 this.footer.add( footDisp );
44939 handler : function() {
44941 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44945 var fel = Roo.get(footDisp.el);
44946 fel.addClass('x-editor-context');
44947 this.footDispWrap = fel;
44948 this.footDispWrap.overflow = 'hidden';
44950 this.footDisp = fel.createChild();
44951 this.footDispWrap.on('click', this.onContextClick, this)
44955 onContextClick : function (ev,dom)
44957 ev.preventDefault();
44958 var cn = dom.className;
44960 if (!cn.match(/x-ed-loc-/)) {
44963 var n = cn.split('-').pop();
44964 var ans = this.footerEls;
44968 var range = this.editorcore.createRange();
44970 range.selectNodeContents(sel);
44971 //range.selectNode(sel);
44974 var selection = this.editorcore.getSelection();
44975 selection.removeAllRanges();
44976 selection.addRange(range);
44980 this.updateToolbar(null, null, sel);
44997 * Ext JS Library 1.1.1
44998 * Copyright(c) 2006-2007, Ext JS, LLC.
45000 * Originally Released Under LGPL - original licence link has changed is not relivant.
45003 * <script type="text/javascript">
45007 * @class Roo.form.BasicForm
45008 * @extends Roo.util.Observable
45009 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
45011 * @param {String/HTMLElement/Roo.Element} el The form element or its id
45012 * @param {Object} config Configuration options
45014 Roo.form.BasicForm = function(el, config){
45015 this.allItems = [];
45016 this.childForms = [];
45017 Roo.apply(this, config);
45019 * The Roo.form.Field items in this form.
45020 * @type MixedCollection
45024 this.items = new Roo.util.MixedCollection(false, function(o){
45025 return o.id || (o.id = Roo.id());
45029 * @event beforeaction
45030 * Fires before any action is performed. Return false to cancel the action.
45031 * @param {Form} this
45032 * @param {Action} action The action to be performed
45034 beforeaction: true,
45036 * @event actionfailed
45037 * Fires when an action fails.
45038 * @param {Form} this
45039 * @param {Action} action The action that failed
45041 actionfailed : true,
45043 * @event actioncomplete
45044 * Fires when an action is completed.
45045 * @param {Form} this
45046 * @param {Action} action The action that completed
45048 actioncomplete : true
45053 Roo.form.BasicForm.superclass.constructor.call(this);
45056 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
45058 * @cfg {String} method
45059 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
45062 * @cfg {DataReader} reader
45063 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
45064 * This is optional as there is built-in support for processing JSON.
45067 * @cfg {DataReader} errorReader
45068 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
45069 * This is completely optional as there is built-in support for processing JSON.
45072 * @cfg {String} url
45073 * The URL to use for form actions if one isn't supplied in the action options.
45076 * @cfg {Boolean} fileUpload
45077 * Set to true if this form is a file upload.
45081 * @cfg {Object} baseParams
45082 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
45087 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
45092 activeAction : null,
45095 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
45096 * or setValues() data instead of when the form was first created.
45098 trackResetOnLoad : false,
45102 * childForms - used for multi-tab forms
45105 childForms : false,
45108 * allItems - full list of fields.
45114 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
45115 * element by passing it or its id or mask the form itself by passing in true.
45118 waitMsgTarget : false,
45121 initEl : function(el){
45122 this.el = Roo.get(el);
45123 this.id = this.el.id || Roo.id();
45124 this.el.on('submit', this.onSubmit, this);
45125 this.el.addClass('x-form');
45129 onSubmit : function(e){
45134 * Returns true if client-side validation on the form is successful.
45137 isValid : function(){
45139 this.items.each(function(f){
45148 * Returns true if any fields in this form have changed since their original load.
45151 isDirty : function(){
45153 this.items.each(function(f){
45163 * Performs a predefined action (submit or load) or custom actions you define on this form.
45164 * @param {String} actionName The name of the action type
45165 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
45166 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
45167 * accept other config options):
45169 Property Type Description
45170 ---------------- --------------- ----------------------------------------------------------------------------------
45171 url String The url for the action (defaults to the form's url)
45172 method String The form method to use (defaults to the form's method, or POST if not defined)
45173 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
45174 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
45175 validate the form on the client (defaults to false)
45177 * @return {BasicForm} this
45179 doAction : function(action, options){
45180 if(typeof action == 'string'){
45181 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
45183 if(this.fireEvent('beforeaction', this, action) !== false){
45184 this.beforeAction(action);
45185 action.run.defer(100, action);
45191 * Shortcut to do a submit action.
45192 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45193 * @return {BasicForm} this
45195 submit : function(options){
45196 this.doAction('submit', options);
45201 * Shortcut to do a load action.
45202 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45203 * @return {BasicForm} this
45205 load : function(options){
45206 this.doAction('load', options);
45211 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
45212 * @param {Record} record The record to edit
45213 * @return {BasicForm} this
45215 updateRecord : function(record){
45216 record.beginEdit();
45217 var fs = record.fields;
45218 fs.each(function(f){
45219 var field = this.findField(f.name);
45221 record.set(f.name, field.getValue());
45229 * Loads an Roo.data.Record into this form.
45230 * @param {Record} record The record to load
45231 * @return {BasicForm} this
45233 loadRecord : function(record){
45234 this.setValues(record.data);
45239 beforeAction : function(action){
45240 var o = action.options;
45243 if(this.waitMsgTarget === true){
45244 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
45245 }else if(this.waitMsgTarget){
45246 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
45247 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
45249 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
45255 afterAction : function(action, success){
45256 this.activeAction = null;
45257 var o = action.options;
45259 if(this.waitMsgTarget === true){
45261 }else if(this.waitMsgTarget){
45262 this.waitMsgTarget.unmask();
45264 Roo.MessageBox.updateProgress(1);
45265 Roo.MessageBox.hide();
45272 Roo.callback(o.success, o.scope, [this, action]);
45273 this.fireEvent('actioncomplete', this, action);
45277 // failure condition..
45278 // we have a scenario where updates need confirming.
45279 // eg. if a locking scenario exists..
45280 // we look for { errors : { needs_confirm : true }} in the response.
45282 (typeof(action.result) != 'undefined') &&
45283 (typeof(action.result.errors) != 'undefined') &&
45284 (typeof(action.result.errors.needs_confirm) != 'undefined')
45287 Roo.MessageBox.confirm(
45288 "Change requires confirmation",
45289 action.result.errorMsg,
45294 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
45304 Roo.callback(o.failure, o.scope, [this, action]);
45305 // show an error message if no failed handler is set..
45306 if (!this.hasListener('actionfailed')) {
45307 Roo.MessageBox.alert("Error",
45308 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
45309 action.result.errorMsg :
45310 "Saving Failed, please check your entries or try again"
45314 this.fireEvent('actionfailed', this, action);
45320 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
45321 * @param {String} id The value to search for
45324 findField : function(id){
45325 var field = this.items.get(id);
45327 this.items.each(function(f){
45328 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
45334 return field || null;
45338 * Add a secondary form to this one,
45339 * Used to provide tabbed forms. One form is primary, with hidden values
45340 * which mirror the elements from the other forms.
45342 * @param {Roo.form.Form} form to add.
45345 addForm : function(form)
45348 if (this.childForms.indexOf(form) > -1) {
45352 this.childForms.push(form);
45354 Roo.each(form.allItems, function (fe) {
45356 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
45357 if (this.findField(n)) { // already added..
45360 var add = new Roo.form.Hidden({
45363 add.render(this.el);
45370 * Mark fields in this form invalid in bulk.
45371 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
45372 * @return {BasicForm} this
45374 markInvalid : function(errors){
45375 if(errors instanceof Array){
45376 for(var i = 0, len = errors.length; i < len; i++){
45377 var fieldError = errors[i];
45378 var f = this.findField(fieldError.id);
45380 f.markInvalid(fieldError.msg);
45386 if(typeof errors[id] != 'function' && (field = this.findField(id))){
45387 field.markInvalid(errors[id]);
45391 Roo.each(this.childForms || [], function (f) {
45392 f.markInvalid(errors);
45399 * Set values for fields in this form in bulk.
45400 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
45401 * @return {BasicForm} this
45403 setValues : function(values){
45404 if(values instanceof Array){ // array of objects
45405 for(var i = 0, len = values.length; i < len; i++){
45407 var f = this.findField(v.id);
45409 f.setValue(v.value);
45410 if(this.trackResetOnLoad){
45411 f.originalValue = f.getValue();
45415 }else{ // object hash
45418 if(typeof values[id] != 'function' && (field = this.findField(id))){
45420 if (field.setFromData &&
45421 field.valueField &&
45422 field.displayField &&
45423 // combos' with local stores can
45424 // be queried via setValue()
45425 // to set their value..
45426 (field.store && !field.store.isLocal)
45430 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
45431 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
45432 field.setFromData(sd);
45435 field.setValue(values[id]);
45439 if(this.trackResetOnLoad){
45440 field.originalValue = field.getValue();
45446 Roo.each(this.childForms || [], function (f) {
45447 f.setValues(values);
45454 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
45455 * they are returned as an array.
45456 * @param {Boolean} asString
45459 getValues : function(asString){
45460 if (this.childForms) {
45461 // copy values from the child forms
45462 Roo.each(this.childForms, function (f) {
45463 this.setValues(f.getValues());
45469 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
45470 if(asString === true){
45473 return Roo.urlDecode(fs);
45477 * Returns the fields in this form as an object with key/value pairs.
45478 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
45481 getFieldValues : function(with_hidden)
45483 if (this.childForms) {
45484 // copy values from the child forms
45485 // should this call getFieldValues - probably not as we do not currently copy
45486 // hidden fields when we generate..
45487 Roo.each(this.childForms, function (f) {
45488 this.setValues(f.getValues());
45493 this.items.each(function(f){
45494 if (!f.getName()) {
45497 var v = f.getValue();
45498 if (f.inputType =='radio') {
45499 if (typeof(ret[f.getName()]) == 'undefined') {
45500 ret[f.getName()] = ''; // empty..
45503 if (!f.el.dom.checked) {
45507 v = f.el.dom.value;
45511 // not sure if this supported any more..
45512 if ((typeof(v) == 'object') && f.getRawValue) {
45513 v = f.getRawValue() ; // dates..
45515 // combo boxes where name != hiddenName...
45516 if (f.name != f.getName()) {
45517 ret[f.name] = f.getRawValue();
45519 ret[f.getName()] = v;
45526 * Clears all invalid messages in this form.
45527 * @return {BasicForm} this
45529 clearInvalid : function(){
45530 this.items.each(function(f){
45534 Roo.each(this.childForms || [], function (f) {
45543 * Resets this form.
45544 * @return {BasicForm} this
45546 reset : function(){
45547 this.items.each(function(f){
45551 Roo.each(this.childForms || [], function (f) {
45560 * Add Roo.form components to this form.
45561 * @param {Field} field1
45562 * @param {Field} field2 (optional)
45563 * @param {Field} etc (optional)
45564 * @return {BasicForm} this
45567 this.items.addAll(Array.prototype.slice.call(arguments, 0));
45573 * Removes a field from the items collection (does NOT remove its markup).
45574 * @param {Field} field
45575 * @return {BasicForm} this
45577 remove : function(field){
45578 this.items.remove(field);
45583 * Looks at the fields in this form, checks them for an id attribute,
45584 * and calls applyTo on the existing dom element with that id.
45585 * @return {BasicForm} this
45587 render : function(){
45588 this.items.each(function(f){
45589 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
45597 * Calls {@link Ext#apply} for all fields in this form with the passed object.
45598 * @param {Object} values
45599 * @return {BasicForm} this
45601 applyToFields : function(o){
45602 this.items.each(function(f){
45609 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
45610 * @param {Object} values
45611 * @return {BasicForm} this
45613 applyIfToFields : function(o){
45614 this.items.each(function(f){
45622 Roo.BasicForm = Roo.form.BasicForm;/*
45624 * Ext JS Library 1.1.1
45625 * Copyright(c) 2006-2007, Ext JS, LLC.
45627 * Originally Released Under LGPL - original licence link has changed is not relivant.
45630 * <script type="text/javascript">
45634 * @class Roo.form.Form
45635 * @extends Roo.form.BasicForm
45636 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
45638 * @param {Object} config Configuration options
45640 Roo.form.Form = function(config){
45642 if (config.items) {
45643 xitems = config.items;
45644 delete config.items;
45648 Roo.form.Form.superclass.constructor.call(this, null, config);
45649 this.url = this.url || this.action;
45651 this.root = new Roo.form.Layout(Roo.applyIf({
45655 this.active = this.root;
45657 * Array of all the buttons that have been added to this form via {@link addButton}
45661 this.allItems = [];
45664 * @event clientvalidation
45665 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45666 * @param {Form} this
45667 * @param {Boolean} valid true if the form has passed client-side validation
45669 clientvalidation: true,
45672 * Fires when the form is rendered
45673 * @param {Roo.form.Form} form
45678 if (this.progressUrl) {
45679 // push a hidden field onto the list of fields..
45683 name : 'UPLOAD_IDENTIFIER'
45688 Roo.each(xitems, this.addxtype, this);
45694 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45696 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45699 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45702 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45704 buttonAlign:'center',
45707 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45712 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45713 * This property cascades to child containers if not set.
45718 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45719 * fires a looping event with that state. This is required to bind buttons to the valid
45720 * state using the config value formBind:true on the button.
45722 monitorValid : false,
45725 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45730 * @cfg {String} progressUrl - Url to return progress data
45733 progressUrl : false,
45736 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45737 * fields are added and the column is closed. If no fields are passed the column remains open
45738 * until end() is called.
45739 * @param {Object} config The config to pass to the column
45740 * @param {Field} field1 (optional)
45741 * @param {Field} field2 (optional)
45742 * @param {Field} etc (optional)
45743 * @return Column The column container object
45745 column : function(c){
45746 var col = new Roo.form.Column(c);
45748 if(arguments.length > 1){ // duplicate code required because of Opera
45749 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45756 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45757 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45758 * until end() is called.
45759 * @param {Object} config The config to pass to the fieldset
45760 * @param {Field} field1 (optional)
45761 * @param {Field} field2 (optional)
45762 * @param {Field} etc (optional)
45763 * @return FieldSet The fieldset container object
45765 fieldset : function(c){
45766 var fs = new Roo.form.FieldSet(c);
45768 if(arguments.length > 1){ // duplicate code required because of Opera
45769 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45776 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45777 * fields are added and the container is closed. If no fields are passed the container remains open
45778 * until end() is called.
45779 * @param {Object} config The config to pass to the Layout
45780 * @param {Field} field1 (optional)
45781 * @param {Field} field2 (optional)
45782 * @param {Field} etc (optional)
45783 * @return Layout The container object
45785 container : function(c){
45786 var l = new Roo.form.Layout(c);
45788 if(arguments.length > 1){ // duplicate code required because of Opera
45789 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45796 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45797 * @param {Object} container A Roo.form.Layout or subclass of Layout
45798 * @return {Form} this
45800 start : function(c){
45801 // cascade label info
45802 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45803 this.active.stack.push(c);
45804 c.ownerCt = this.active;
45810 * Closes the current open container
45811 * @return {Form} this
45814 if(this.active == this.root){
45817 this.active = this.active.ownerCt;
45822 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45823 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45824 * as the label of the field.
45825 * @param {Field} field1
45826 * @param {Field} field2 (optional)
45827 * @param {Field} etc. (optional)
45828 * @return {Form} this
45831 this.active.stack.push.apply(this.active.stack, arguments);
45832 this.allItems.push.apply(this.allItems,arguments);
45834 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45835 if(a[i].isFormField){
45840 Roo.form.Form.superclass.add.apply(this, r);
45850 * Find any element that has been added to a form, using it's ID or name
45851 * This can include framesets, columns etc. along with regular fields..
45852 * @param {String} id - id or name to find.
45854 * @return {Element} e - or false if nothing found.
45856 findbyId : function(id)
45862 Roo.each(this.allItems, function(f){
45863 if (f.id == id || f.name == id ){
45874 * Render this form into the passed container. This should only be called once!
45875 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45876 * @return {Form} this
45878 render : function(ct)
45884 var o = this.autoCreate || {
45886 method : this.method || 'POST',
45887 id : this.id || Roo.id()
45889 this.initEl(ct.createChild(o));
45891 this.root.render(this.el);
45895 this.items.each(function(f){
45896 f.render('x-form-el-'+f.id);
45899 if(this.buttons.length > 0){
45900 // tables are required to maintain order and for correct IE layout
45901 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45902 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45903 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45905 var tr = tb.getElementsByTagName('tr')[0];
45906 for(var i = 0, len = this.buttons.length; i < len; i++) {
45907 var b = this.buttons[i];
45908 var td = document.createElement('td');
45909 td.className = 'x-form-btn-td';
45910 b.render(tr.appendChild(td));
45913 if(this.monitorValid){ // initialize after render
45914 this.startMonitoring();
45916 this.fireEvent('rendered', this);
45921 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45922 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45923 * object or a valid Roo.DomHelper element config
45924 * @param {Function} handler The function called when the button is clicked
45925 * @param {Object} scope (optional) The scope of the handler function
45926 * @return {Roo.Button}
45928 addButton : function(config, handler, scope){
45932 minWidth: this.minButtonWidth,
45935 if(typeof config == "string"){
45938 Roo.apply(bc, config);
45940 var btn = new Roo.Button(null, bc);
45941 this.buttons.push(btn);
45946 * Adds a series of form elements (using the xtype property as the factory method.
45947 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45948 * @param {Object} config
45951 addxtype : function()
45953 var ar = Array.prototype.slice.call(arguments, 0);
45955 for(var i = 0; i < ar.length; i++) {
45957 continue; // skip -- if this happends something invalid got sent, we
45958 // should ignore it, as basically that interface element will not show up
45959 // and that should be pretty obvious!!
45962 if (Roo.form[ar[i].xtype]) {
45964 var fe = Roo.factory(ar[i], Roo.form);
45970 fe.store.form = this;
45975 this.allItems.push(fe);
45976 if (fe.items && fe.addxtype) {
45977 fe.addxtype.apply(fe, fe.items);
45987 // console.log('adding ' + ar[i].xtype);
45989 if (ar[i].xtype == 'Button') {
45990 //console.log('adding button');
45991 //console.log(ar[i]);
45992 this.addButton(ar[i]);
45993 this.allItems.push(fe);
45997 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45998 alert('end is not supported on xtype any more, use items');
46000 // //console.log('adding end');
46008 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
46009 * option "monitorValid"
46011 startMonitoring : function(){
46014 Roo.TaskMgr.start({
46015 run : this.bindHandler,
46016 interval : this.monitorPoll || 200,
46023 * Stops monitoring of the valid state of this form
46025 stopMonitoring : function(){
46026 this.bound = false;
46030 bindHandler : function(){
46032 return false; // stops binding
46035 this.items.each(function(f){
46036 if(!f.isValid(true)){
46041 for(var i = 0, len = this.buttons.length; i < len; i++){
46042 var btn = this.buttons[i];
46043 if(btn.formBind === true && btn.disabled === valid){
46044 btn.setDisabled(!valid);
46047 this.fireEvent('clientvalidation', this, valid);
46061 Roo.Form = Roo.form.Form;
46064 * Ext JS Library 1.1.1
46065 * Copyright(c) 2006-2007, Ext JS, LLC.
46067 * Originally Released Under LGPL - original licence link has changed is not relivant.
46070 * <script type="text/javascript">
46073 // as we use this in bootstrap.
46074 Roo.namespace('Roo.form');
46076 * @class Roo.form.Action
46077 * Internal Class used to handle form actions
46079 * @param {Roo.form.BasicForm} el The form element or its id
46080 * @param {Object} config Configuration options
46085 // define the action interface
46086 Roo.form.Action = function(form, options){
46088 this.options = options || {};
46091 * Client Validation Failed
46094 Roo.form.Action.CLIENT_INVALID = 'client';
46096 * Server Validation Failed
46099 Roo.form.Action.SERVER_INVALID = 'server';
46101 * Connect to Server Failed
46104 Roo.form.Action.CONNECT_FAILURE = 'connect';
46106 * Reading Data from Server Failed
46109 Roo.form.Action.LOAD_FAILURE = 'load';
46111 Roo.form.Action.prototype = {
46113 failureType : undefined,
46114 response : undefined,
46115 result : undefined,
46117 // interface method
46118 run : function(options){
46122 // interface method
46123 success : function(response){
46127 // interface method
46128 handleResponse : function(response){
46132 // default connection failure
46133 failure : function(response){
46135 this.response = response;
46136 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46137 this.form.afterAction(this, false);
46140 processResponse : function(response){
46141 this.response = response;
46142 if(!response.responseText){
46145 this.result = this.handleResponse(response);
46146 return this.result;
46149 // utility functions used internally
46150 getUrl : function(appendParams){
46151 var url = this.options.url || this.form.url || this.form.el.dom.action;
46153 var p = this.getParams();
46155 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
46161 getMethod : function(){
46162 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
46165 getParams : function(){
46166 var bp = this.form.baseParams;
46167 var p = this.options.params;
46169 if(typeof p == "object"){
46170 p = Roo.urlEncode(Roo.applyIf(p, bp));
46171 }else if(typeof p == 'string' && bp){
46172 p += '&' + Roo.urlEncode(bp);
46175 p = Roo.urlEncode(bp);
46180 createCallback : function(){
46182 success: this.success,
46183 failure: this.failure,
46185 timeout: (this.form.timeout*1000),
46186 upload: this.form.fileUpload ? this.success : undefined
46191 Roo.form.Action.Submit = function(form, options){
46192 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
46195 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
46198 haveProgress : false,
46199 uploadComplete : false,
46201 // uploadProgress indicator.
46202 uploadProgress : function()
46204 if (!this.form.progressUrl) {
46208 if (!this.haveProgress) {
46209 Roo.MessageBox.progress("Uploading", "Uploading");
46211 if (this.uploadComplete) {
46212 Roo.MessageBox.hide();
46216 this.haveProgress = true;
46218 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
46220 var c = new Roo.data.Connection();
46222 url : this.form.progressUrl,
46227 success : function(req){
46228 //console.log(data);
46232 rdata = Roo.decode(req.responseText)
46234 Roo.log("Invalid data from server..");
46238 if (!rdata || !rdata.success) {
46240 Roo.MessageBox.alert(Roo.encode(rdata));
46243 var data = rdata.data;
46245 if (this.uploadComplete) {
46246 Roo.MessageBox.hide();
46251 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
46252 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
46255 this.uploadProgress.defer(2000,this);
46258 failure: function(data) {
46259 Roo.log('progress url failed ');
46270 // run get Values on the form, so it syncs any secondary forms.
46271 this.form.getValues();
46273 var o = this.options;
46274 var method = this.getMethod();
46275 var isPost = method == 'POST';
46276 if(o.clientValidation === false || this.form.isValid()){
46278 if (this.form.progressUrl) {
46279 this.form.findField('UPLOAD_IDENTIFIER').setValue(
46280 (new Date() * 1) + '' + Math.random());
46285 Roo.Ajax.request(Roo.apply(this.createCallback(), {
46286 form:this.form.el.dom,
46287 url:this.getUrl(!isPost),
46289 params:isPost ? this.getParams() : null,
46290 isUpload: this.form.fileUpload
46293 this.uploadProgress();
46295 }else if (o.clientValidation !== false){ // client validation failed
46296 this.failureType = Roo.form.Action.CLIENT_INVALID;
46297 this.form.afterAction(this, false);
46301 success : function(response)
46303 this.uploadComplete= true;
46304 if (this.haveProgress) {
46305 Roo.MessageBox.hide();
46309 var result = this.processResponse(response);
46310 if(result === true || result.success){
46311 this.form.afterAction(this, true);
46315 this.form.markInvalid(result.errors);
46316 this.failureType = Roo.form.Action.SERVER_INVALID;
46318 this.form.afterAction(this, false);
46320 failure : function(response)
46322 this.uploadComplete= true;
46323 if (this.haveProgress) {
46324 Roo.MessageBox.hide();
46327 this.response = response;
46328 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46329 this.form.afterAction(this, false);
46332 handleResponse : function(response){
46333 if(this.form.errorReader){
46334 var rs = this.form.errorReader.read(response);
46337 for(var i = 0, len = rs.records.length; i < len; i++) {
46338 var r = rs.records[i];
46339 errors[i] = r.data;
46342 if(errors.length < 1){
46346 success : rs.success,
46352 ret = Roo.decode(response.responseText);
46356 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
46366 Roo.form.Action.Load = function(form, options){
46367 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
46368 this.reader = this.form.reader;
46371 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
46376 Roo.Ajax.request(Roo.apply(
46377 this.createCallback(), {
46378 method:this.getMethod(),
46379 url:this.getUrl(false),
46380 params:this.getParams()
46384 success : function(response){
46386 var result = this.processResponse(response);
46387 if(result === true || !result.success || !result.data){
46388 this.failureType = Roo.form.Action.LOAD_FAILURE;
46389 this.form.afterAction(this, false);
46392 this.form.clearInvalid();
46393 this.form.setValues(result.data);
46394 this.form.afterAction(this, true);
46397 handleResponse : function(response){
46398 if(this.form.reader){
46399 var rs = this.form.reader.read(response);
46400 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
46402 success : rs.success,
46406 return Roo.decode(response.responseText);
46410 Roo.form.Action.ACTION_TYPES = {
46411 'load' : Roo.form.Action.Load,
46412 'submit' : Roo.form.Action.Submit
46415 * Ext JS Library 1.1.1
46416 * Copyright(c) 2006-2007, Ext JS, LLC.
46418 * Originally Released Under LGPL - original licence link has changed is not relivant.
46421 * <script type="text/javascript">
46425 * @class Roo.form.Layout
46426 * @extends Roo.Component
46427 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
46429 * @param {Object} config Configuration options
46431 Roo.form.Layout = function(config){
46433 if (config.items) {
46434 xitems = config.items;
46435 delete config.items;
46437 Roo.form.Layout.superclass.constructor.call(this, config);
46439 Roo.each(xitems, this.addxtype, this);
46443 Roo.extend(Roo.form.Layout, Roo.Component, {
46445 * @cfg {String/Object} autoCreate
46446 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
46449 * @cfg {String/Object/Function} style
46450 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
46451 * a function which returns such a specification.
46454 * @cfg {String} labelAlign
46455 * Valid values are "left," "top" and "right" (defaults to "left")
46458 * @cfg {Number} labelWidth
46459 * Fixed width in pixels of all field labels (defaults to undefined)
46462 * @cfg {Boolean} clear
46463 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
46467 * @cfg {String} labelSeparator
46468 * The separator to use after field labels (defaults to ':')
46470 labelSeparator : ':',
46472 * @cfg {Boolean} hideLabels
46473 * True to suppress the display of field labels in this layout (defaults to false)
46475 hideLabels : false,
46478 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
46483 onRender : function(ct, position){
46484 if(this.el){ // from markup
46485 this.el = Roo.get(this.el);
46486 }else { // generate
46487 var cfg = this.getAutoCreate();
46488 this.el = ct.createChild(cfg, position);
46491 this.el.applyStyles(this.style);
46493 if(this.labelAlign){
46494 this.el.addClass('x-form-label-'+this.labelAlign);
46496 if(this.hideLabels){
46497 this.labelStyle = "display:none";
46498 this.elementStyle = "padding-left:0;";
46500 if(typeof this.labelWidth == 'number'){
46501 this.labelStyle = "width:"+this.labelWidth+"px;";
46502 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
46504 if(this.labelAlign == 'top'){
46505 this.labelStyle = "width:auto;";
46506 this.elementStyle = "padding-left:0;";
46509 var stack = this.stack;
46510 var slen = stack.length;
46512 if(!this.fieldTpl){
46513 var t = new Roo.Template(
46514 '<div class="x-form-item {5}">',
46515 '<label for="{0}" style="{2}">{1}{4}</label>',
46516 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46518 '</div><div class="x-form-clear-left"></div>'
46520 t.disableFormats = true;
46522 Roo.form.Layout.prototype.fieldTpl = t;
46524 for(var i = 0; i < slen; i++) {
46525 if(stack[i].isFormField){
46526 this.renderField(stack[i]);
46528 this.renderComponent(stack[i]);
46533 this.el.createChild({cls:'x-form-clear'});
46538 renderField : function(f){
46539 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
46542 f.labelStyle||this.labelStyle||'', //2
46543 this.elementStyle||'', //3
46544 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
46545 f.itemCls||this.itemCls||'' //5
46546 ], true).getPrevSibling());
46550 renderComponent : function(c){
46551 c.render(c.isLayout ? this.el : this.el.createChild());
46554 * Adds a object form elements (using the xtype property as the factory method.)
46555 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
46556 * @param {Object} config
46558 addxtype : function(o)
46560 // create the lement.
46561 o.form = this.form;
46562 var fe = Roo.factory(o, Roo.form);
46563 this.form.allItems.push(fe);
46564 this.stack.push(fe);
46566 if (fe.isFormField) {
46567 this.form.items.add(fe);
46575 * @class Roo.form.Column
46576 * @extends Roo.form.Layout
46577 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
46579 * @param {Object} config Configuration options
46581 Roo.form.Column = function(config){
46582 Roo.form.Column.superclass.constructor.call(this, config);
46585 Roo.extend(Roo.form.Column, Roo.form.Layout, {
46587 * @cfg {Number/String} width
46588 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46591 * @cfg {String/Object} autoCreate
46592 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
46596 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
46599 onRender : function(ct, position){
46600 Roo.form.Column.superclass.onRender.call(this, ct, position);
46602 this.el.setWidth(this.width);
46609 * @class Roo.form.Row
46610 * @extends Roo.form.Layout
46611 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
46613 * @param {Object} config Configuration options
46617 Roo.form.Row = function(config){
46618 Roo.form.Row.superclass.constructor.call(this, config);
46621 Roo.extend(Roo.form.Row, Roo.form.Layout, {
46623 * @cfg {Number/String} width
46624 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46627 * @cfg {Number/String} height
46628 * The fixed height of the column in pixels or CSS value (defaults to "auto")
46630 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
46634 onRender : function(ct, position){
46635 //console.log('row render');
46637 var t = new Roo.Template(
46638 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
46639 '<label for="{0}" style="{2}">{1}{4}</label>',
46640 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46644 t.disableFormats = true;
46646 Roo.form.Layout.prototype.rowTpl = t;
46648 this.fieldTpl = this.rowTpl;
46650 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46651 var labelWidth = 100;
46653 if ((this.labelAlign != 'top')) {
46654 if (typeof this.labelWidth == 'number') {
46655 labelWidth = this.labelWidth
46657 this.padWidth = 20 + labelWidth;
46661 Roo.form.Column.superclass.onRender.call(this, ct, position);
46663 this.el.setWidth(this.width);
46666 this.el.setHeight(this.height);
46671 renderField : function(f){
46672 f.fieldEl = this.fieldTpl.append(this.el, [
46673 f.id, f.fieldLabel,
46674 f.labelStyle||this.labelStyle||'',
46675 this.elementStyle||'',
46676 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46677 f.itemCls||this.itemCls||'',
46678 f.width ? f.width + this.padWidth : 160 + this.padWidth
46685 * @class Roo.form.FieldSet
46686 * @extends Roo.form.Layout
46687 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46689 * @param {Object} config Configuration options
46691 Roo.form.FieldSet = function(config){
46692 Roo.form.FieldSet.superclass.constructor.call(this, config);
46695 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46697 * @cfg {String} legend
46698 * The text to display as the legend for the FieldSet (defaults to '')
46701 * @cfg {String/Object} autoCreate
46702 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46706 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46709 onRender : function(ct, position){
46710 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46712 this.setLegend(this.legend);
46717 setLegend : function(text){
46719 this.el.child('legend').update(text);
46724 * Ext JS Library 1.1.1
46725 * Copyright(c) 2006-2007, Ext JS, LLC.
46727 * Originally Released Under LGPL - original licence link has changed is not relivant.
46730 * <script type="text/javascript">
46733 * @class Roo.form.VTypes
46734 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46737 Roo.form.VTypes = function(){
46738 // closure these in so they are only created once.
46739 var alpha = /^[a-zA-Z_]+$/;
46740 var alphanum = /^[a-zA-Z0-9_]+$/;
46741 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46742 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46744 // All these messages and functions are configurable
46747 * The function used to validate email addresses
46748 * @param {String} value The email address
46750 'email' : function(v){
46751 return email.test(v);
46754 * The error text to display when the email validation function returns false
46757 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46759 * The keystroke filter mask to be applied on email input
46762 'emailMask' : /[a-z0-9_\.\-@]/i,
46765 * The function used to validate URLs
46766 * @param {String} value The URL
46768 'url' : function(v){
46769 return url.test(v);
46772 * The error text to display when the url validation function returns false
46775 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46778 * The function used to validate alpha values
46779 * @param {String} value The value
46781 'alpha' : function(v){
46782 return alpha.test(v);
46785 * The error text to display when the alpha validation function returns false
46788 'alphaText' : 'This field should only contain letters and _',
46790 * The keystroke filter mask to be applied on alpha input
46793 'alphaMask' : /[a-z_]/i,
46796 * The function used to validate alphanumeric values
46797 * @param {String} value The value
46799 'alphanum' : function(v){
46800 return alphanum.test(v);
46803 * The error text to display when the alphanumeric validation function returns false
46806 'alphanumText' : 'This field should only contain letters, numbers and _',
46808 * The keystroke filter mask to be applied on alphanumeric input
46811 'alphanumMask' : /[a-z0-9_]/i
46813 }();//<script type="text/javascript">
46816 * @class Roo.form.FCKeditor
46817 * @extends Roo.form.TextArea
46818 * Wrapper around the FCKEditor http://www.fckeditor.net
46820 * Creates a new FCKeditor
46821 * @param {Object} config Configuration options
46823 Roo.form.FCKeditor = function(config){
46824 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46827 * @event editorinit
46828 * Fired when the editor is initialized - you can add extra handlers here..
46829 * @param {FCKeditor} this
46830 * @param {Object} the FCK object.
46837 Roo.form.FCKeditor.editors = { };
46838 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46840 //defaultAutoCreate : {
46841 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46845 * @cfg {Object} fck options - see fck manual for details.
46850 * @cfg {Object} fck toolbar set (Basic or Default)
46852 toolbarSet : 'Basic',
46854 * @cfg {Object} fck BasePath
46856 basePath : '/fckeditor/',
46864 onRender : function(ct, position)
46867 this.defaultAutoCreate = {
46869 style:"width:300px;height:60px;",
46870 autocomplete: "new-password"
46873 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46876 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46877 if(this.preventScrollbars){
46878 this.el.setStyle("overflow", "hidden");
46880 this.el.setHeight(this.growMin);
46883 //console.log('onrender' + this.getId() );
46884 Roo.form.FCKeditor.editors[this.getId()] = this;
46887 this.replaceTextarea() ;
46891 getEditor : function() {
46892 return this.fckEditor;
46895 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46896 * @param {Mixed} value The value to set
46900 setValue : function(value)
46902 //console.log('setValue: ' + value);
46904 if(typeof(value) == 'undefined') { // not sure why this is happending...
46907 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46909 //if(!this.el || !this.getEditor()) {
46910 // this.value = value;
46911 //this.setValue.defer(100,this,[value]);
46915 if(!this.getEditor()) {
46919 this.getEditor().SetData(value);
46926 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46927 * @return {Mixed} value The field value
46929 getValue : function()
46932 if (this.frame && this.frame.dom.style.display == 'none') {
46933 return Roo.form.FCKeditor.superclass.getValue.call(this);
46936 if(!this.el || !this.getEditor()) {
46938 // this.getValue.defer(100,this);
46943 var value=this.getEditor().GetData();
46944 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46945 return Roo.form.FCKeditor.superclass.getValue.call(this);
46951 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46952 * @return {Mixed} value The field value
46954 getRawValue : function()
46956 if (this.frame && this.frame.dom.style.display == 'none') {
46957 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46960 if(!this.el || !this.getEditor()) {
46961 //this.getRawValue.defer(100,this);
46968 var value=this.getEditor().GetData();
46969 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46970 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46974 setSize : function(w,h) {
46978 //if (this.frame && this.frame.dom.style.display == 'none') {
46979 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46982 //if(!this.el || !this.getEditor()) {
46983 // this.setSize.defer(100,this, [w,h]);
46989 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46991 this.frame.dom.setAttribute('width', w);
46992 this.frame.dom.setAttribute('height', h);
46993 this.frame.setSize(w,h);
46997 toggleSourceEdit : function(value) {
47001 this.el.dom.style.display = value ? '' : 'none';
47002 this.frame.dom.style.display = value ? 'none' : '';
47007 focus: function(tag)
47009 if (this.frame.dom.style.display == 'none') {
47010 return Roo.form.FCKeditor.superclass.focus.call(this);
47012 if(!this.el || !this.getEditor()) {
47013 this.focus.defer(100,this, [tag]);
47020 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
47021 this.getEditor().Focus();
47023 if (!this.getEditor().Selection.GetSelection()) {
47024 this.focus.defer(100,this, [tag]);
47029 var r = this.getEditor().EditorDocument.createRange();
47030 r.setStart(tgs[0],0);
47031 r.setEnd(tgs[0],0);
47032 this.getEditor().Selection.GetSelection().removeAllRanges();
47033 this.getEditor().Selection.GetSelection().addRange(r);
47034 this.getEditor().Focus();
47041 replaceTextarea : function()
47043 if ( document.getElementById( this.getId() + '___Frame' ) ) {
47046 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
47048 // We must check the elements firstly using the Id and then the name.
47049 var oTextarea = document.getElementById( this.getId() );
47051 var colElementsByName = document.getElementsByName( this.getId() ) ;
47053 oTextarea.style.display = 'none' ;
47055 if ( oTextarea.tabIndex ) {
47056 this.TabIndex = oTextarea.tabIndex ;
47059 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
47060 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
47061 this.frame = Roo.get(this.getId() + '___Frame')
47064 _getConfigHtml : function()
47068 for ( var o in this.fckconfig ) {
47069 sConfig += sConfig.length > 0 ? '&' : '';
47070 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
47073 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
47077 _getIFrameHtml : function()
47079 var sFile = 'fckeditor.html' ;
47080 /* no idea what this is about..
47083 if ( (/fcksource=true/i).test( window.top.location.search ) )
47084 sFile = 'fckeditor.original.html' ;
47089 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
47090 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
47093 var html = '<iframe id="' + this.getId() +
47094 '___Frame" src="' + sLink +
47095 '" width="' + this.width +
47096 '" height="' + this.height + '"' +
47097 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
47098 ' frameborder="0" scrolling="no"></iframe>' ;
47103 _insertHtmlBefore : function( html, element )
47105 if ( element.insertAdjacentHTML ) {
47107 element.insertAdjacentHTML( 'beforeBegin', html ) ;
47109 var oRange = document.createRange() ;
47110 oRange.setStartBefore( element ) ;
47111 var oFragment = oRange.createContextualFragment( html );
47112 element.parentNode.insertBefore( oFragment, element ) ;
47125 //Roo.reg('fckeditor', Roo.form.FCKeditor);
47127 function FCKeditor_OnComplete(editorInstance){
47128 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
47129 f.fckEditor = editorInstance;
47130 //console.log("loaded");
47131 f.fireEvent('editorinit', f, editorInstance);
47151 //<script type="text/javascript">
47153 * @class Roo.form.GridField
47154 * @extends Roo.form.Field
47155 * Embed a grid (or editable grid into a form)
47158 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
47160 * xgrid.store = Roo.data.Store
47161 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
47162 * xgrid.store.reader = Roo.data.JsonReader
47166 * Creates a new GridField
47167 * @param {Object} config Configuration options
47169 Roo.form.GridField = function(config){
47170 Roo.form.GridField.superclass.constructor.call(this, config);
47174 Roo.extend(Roo.form.GridField, Roo.form.Field, {
47176 * @cfg {Number} width - used to restrict width of grid..
47180 * @cfg {Number} height - used to restrict height of grid..
47184 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
47190 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47191 * {tag: "input", type: "checkbox", autocomplete: "off"})
47193 // defaultAutoCreate : { tag: 'div' },
47194 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
47196 * @cfg {String} addTitle Text to include for adding a title.
47200 onResize : function(){
47201 Roo.form.Field.superclass.onResize.apply(this, arguments);
47204 initEvents : function(){
47205 // Roo.form.Checkbox.superclass.initEvents.call(this);
47206 // has no events...
47211 getResizeEl : function(){
47215 getPositionEl : function(){
47220 onRender : function(ct, position){
47222 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
47223 var style = this.style;
47226 Roo.form.GridField.superclass.onRender.call(this, ct, position);
47227 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
47228 this.viewEl = this.wrap.createChild({ tag: 'div' });
47230 this.viewEl.applyStyles(style);
47233 this.viewEl.setWidth(this.width);
47236 this.viewEl.setHeight(this.height);
47238 //if(this.inputValue !== undefined){
47239 //this.setValue(this.value);
47242 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
47245 this.grid.render();
47246 this.grid.getDataSource().on('remove', this.refreshValue, this);
47247 this.grid.getDataSource().on('update', this.refreshValue, this);
47248 this.grid.on('afteredit', this.refreshValue, this);
47254 * Sets the value of the item.
47255 * @param {String} either an object or a string..
47257 setValue : function(v){
47259 v = v || []; // empty set..
47260 // this does not seem smart - it really only affects memoryproxy grids..
47261 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
47262 var ds = this.grid.getDataSource();
47263 // assumes a json reader..
47265 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
47266 ds.loadData( data);
47268 // clear selection so it does not get stale.
47269 if (this.grid.sm) {
47270 this.grid.sm.clearSelections();
47273 Roo.form.GridField.superclass.setValue.call(this, v);
47274 this.refreshValue();
47275 // should load data in the grid really....
47279 refreshValue: function() {
47281 this.grid.getDataSource().each(function(r) {
47284 this.el.dom.value = Roo.encode(val);
47292 * Ext JS Library 1.1.1
47293 * Copyright(c) 2006-2007, Ext JS, LLC.
47295 * Originally Released Under LGPL - original licence link has changed is not relivant.
47298 * <script type="text/javascript">
47301 * @class Roo.form.DisplayField
47302 * @extends Roo.form.Field
47303 * A generic Field to display non-editable data.
47304 * @cfg {Boolean} closable (true|false) default false
47306 * Creates a new Display Field item.
47307 * @param {Object} config Configuration options
47309 Roo.form.DisplayField = function(config){
47310 Roo.form.DisplayField.superclass.constructor.call(this, config);
47315 * Fires after the click the close btn
47316 * @param {Roo.form.DisplayField} this
47322 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
47323 inputType: 'hidden',
47329 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47331 focusClass : undefined,
47333 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47335 fieldClass: 'x-form-field',
47338 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
47340 valueRenderer: undefined,
47344 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47345 * {tag: "input", type: "checkbox", autocomplete: "off"})
47348 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
47352 onResize : function(){
47353 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
47357 initEvents : function(){
47358 // Roo.form.Checkbox.superclass.initEvents.call(this);
47359 // has no events...
47362 this.closeEl.on('click', this.onClose, this);
47368 getResizeEl : function(){
47372 getPositionEl : function(){
47377 onRender : function(ct, position){
47379 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
47380 //if(this.inputValue !== undefined){
47381 this.wrap = this.el.wrap();
47383 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
47386 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
47389 if (this.bodyStyle) {
47390 this.viewEl.applyStyles(this.bodyStyle);
47392 //this.viewEl.setStyle('padding', '2px');
47394 this.setValue(this.value);
47399 initValue : Roo.emptyFn,
47404 onClick : function(){
47409 * Sets the checked state of the checkbox.
47410 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
47412 setValue : function(v){
47414 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
47415 // this might be called before we have a dom element..
47416 if (!this.viewEl) {
47419 this.viewEl.dom.innerHTML = html;
47420 Roo.form.DisplayField.superclass.setValue.call(this, v);
47424 onClose : function(e)
47426 e.preventDefault();
47428 this.fireEvent('close', this);
47437 * @class Roo.form.DayPicker
47438 * @extends Roo.form.Field
47439 * A Day picker show [M] [T] [W] ....
47441 * Creates a new Day Picker
47442 * @param {Object} config Configuration options
47444 Roo.form.DayPicker= function(config){
47445 Roo.form.DayPicker.superclass.constructor.call(this, config);
47449 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
47451 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47453 focusClass : undefined,
47455 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47457 fieldClass: "x-form-field",
47460 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47461 * {tag: "input", type: "checkbox", autocomplete: "off"})
47463 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
47466 actionMode : 'viewEl',
47470 inputType : 'hidden',
47473 inputElement: false, // real input element?
47474 basedOn: false, // ????
47476 isFormField: true, // not sure where this is needed!!!!
47478 onResize : function(){
47479 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
47480 if(!this.boxLabel){
47481 this.el.alignTo(this.wrap, 'c-c');
47485 initEvents : function(){
47486 Roo.form.Checkbox.superclass.initEvents.call(this);
47487 this.el.on("click", this.onClick, this);
47488 this.el.on("change", this.onClick, this);
47492 getResizeEl : function(){
47496 getPositionEl : function(){
47502 onRender : function(ct, position){
47503 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
47505 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
47507 var r1 = '<table><tr>';
47508 var r2 = '<tr class="x-form-daypick-icons">';
47509 for (var i=0; i < 7; i++) {
47510 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
47511 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
47514 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
47515 viewEl.select('img').on('click', this.onClick, this);
47516 this.viewEl = viewEl;
47519 // this will not work on Chrome!!!
47520 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
47521 this.el.on('propertychange', this.setFromHidden, this); //ie
47529 initValue : Roo.emptyFn,
47532 * Returns the checked state of the checkbox.
47533 * @return {Boolean} True if checked, else false
47535 getValue : function(){
47536 return this.el.dom.value;
47541 onClick : function(e){
47542 //this.setChecked(!this.checked);
47543 Roo.get(e.target).toggleClass('x-menu-item-checked');
47544 this.refreshValue();
47545 //if(this.el.dom.checked != this.checked){
47546 // this.setValue(this.el.dom.checked);
47551 refreshValue : function()
47554 this.viewEl.select('img',true).each(function(e,i,n) {
47555 val += e.is(".x-menu-item-checked") ? String(n) : '';
47557 this.setValue(val, true);
47561 * Sets the checked state of the checkbox.
47562 * On is always based on a string comparison between inputValue and the param.
47563 * @param {Boolean/String} value - the value to set
47564 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
47566 setValue : function(v,suppressEvent){
47567 if (!this.el.dom) {
47570 var old = this.el.dom.value ;
47571 this.el.dom.value = v;
47572 if (suppressEvent) {
47576 // update display..
47577 this.viewEl.select('img',true).each(function(e,i,n) {
47579 var on = e.is(".x-menu-item-checked");
47580 var newv = v.indexOf(String(n)) > -1;
47582 e.toggleClass('x-menu-item-checked');
47588 this.fireEvent('change', this, v, old);
47593 // handle setting of hidden value by some other method!!?!?
47594 setFromHidden: function()
47599 //console.log("SET FROM HIDDEN");
47600 //alert('setFrom hidden');
47601 this.setValue(this.el.dom.value);
47604 onDestroy : function()
47607 Roo.get(this.viewEl).remove();
47610 Roo.form.DayPicker.superclass.onDestroy.call(this);
47614 * RooJS Library 1.1.1
47615 * Copyright(c) 2008-2011 Alan Knowles
47622 * @class Roo.form.ComboCheck
47623 * @extends Roo.form.ComboBox
47624 * A combobox for multiple select items.
47626 * FIXME - could do with a reset button..
47629 * Create a new ComboCheck
47630 * @param {Object} config Configuration options
47632 Roo.form.ComboCheck = function(config){
47633 Roo.form.ComboCheck.superclass.constructor.call(this, config);
47634 // should verify some data...
47636 // hiddenName = required..
47637 // displayField = required
47638 // valudField == required
47639 var req= [ 'hiddenName', 'displayField', 'valueField' ];
47641 Roo.each(req, function(e) {
47642 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
47643 throw "Roo.form.ComboCheck : missing value for: " + e;
47650 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
47655 selectedClass: 'x-menu-item-checked',
47658 onRender : function(ct, position){
47664 var cls = 'x-combo-list';
47667 this.tpl = new Roo.Template({
47668 html : '<div class="'+cls+'-item x-menu-check-item">' +
47669 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47670 '<span>{' + this.displayField + '}</span>' +
47677 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47678 this.view.singleSelect = false;
47679 this.view.multiSelect = true;
47680 this.view.toggleSelect = true;
47681 this.pageTb.add(new Roo.Toolbar.Fill(), {
47684 handler: function()
47691 onViewOver : function(e, t){
47697 onViewClick : function(doFocus,index){
47701 select: function () {
47702 //Roo.log("SELECT CALLED");
47705 selectByValue : function(xv, scrollIntoView){
47706 var ar = this.getValueArray();
47709 Roo.each(ar, function(v) {
47710 if(v === undefined || v === null){
47713 var r = this.findRecord(this.valueField, v);
47715 sels.push(this.store.indexOf(r))
47719 this.view.select(sels);
47725 onSelect : function(record, index){
47726 // Roo.log("onselect Called");
47727 // this is only called by the clear button now..
47728 this.view.clearSelections();
47729 this.setValue('[]');
47730 if (this.value != this.valueBefore) {
47731 this.fireEvent('change', this, this.value, this.valueBefore);
47732 this.valueBefore = this.value;
47735 getValueArray : function()
47740 //Roo.log(this.value);
47741 if (typeof(this.value) == 'undefined') {
47744 var ar = Roo.decode(this.value);
47745 return ar instanceof Array ? ar : []; //?? valid?
47748 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47753 expand : function ()
47756 Roo.form.ComboCheck.superclass.expand.call(this);
47757 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47758 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47763 collapse : function(){
47764 Roo.form.ComboCheck.superclass.collapse.call(this);
47765 var sl = this.view.getSelectedIndexes();
47766 var st = this.store;
47770 Roo.each(sl, function(i) {
47772 nv.push(r.get(this.valueField));
47774 this.setValue(Roo.encode(nv));
47775 if (this.value != this.valueBefore) {
47777 this.fireEvent('change', this, this.value, this.valueBefore);
47778 this.valueBefore = this.value;
47783 setValue : function(v){
47787 var vals = this.getValueArray();
47789 Roo.each(vals, function(k) {
47790 var r = this.findRecord(this.valueField, k);
47792 tv.push(r.data[this.displayField]);
47793 }else if(this.valueNotFoundText !== undefined){
47794 tv.push( this.valueNotFoundText );
47799 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47800 this.hiddenField.value = v;
47806 * Ext JS Library 1.1.1
47807 * Copyright(c) 2006-2007, Ext JS, LLC.
47809 * Originally Released Under LGPL - original licence link has changed is not relivant.
47812 * <script type="text/javascript">
47816 * @class Roo.form.Signature
47817 * @extends Roo.form.Field
47821 * @param {Object} config Configuration options
47824 Roo.form.Signature = function(config){
47825 Roo.form.Signature.superclass.constructor.call(this, config);
47827 this.addEvents({// not in used??
47830 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47831 * @param {Roo.form.Signature} combo This combo box
47836 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47837 * @param {Roo.form.ComboBox} combo This combo box
47838 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47844 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47846 * @cfg {Object} labels Label to use when rendering a form.
47850 * confirm : "Confirm"
47855 confirm : "Confirm"
47858 * @cfg {Number} width The signature panel width (defaults to 300)
47862 * @cfg {Number} height The signature panel height (defaults to 100)
47866 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47868 allowBlank : false,
47871 // {Object} signPanel The signature SVG panel element (defaults to {})
47873 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47874 isMouseDown : false,
47875 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47876 isConfirmed : false,
47877 // {String} signatureTmp SVG mapping string (defaults to empty string)
47881 defaultAutoCreate : { // modified by initCompnoent..
47887 onRender : function(ct, position){
47889 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47891 this.wrap = this.el.wrap({
47892 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47895 this.createToolbar(this);
47896 this.signPanel = this.wrap.createChild({
47898 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47902 this.svgID = Roo.id();
47903 this.svgEl = this.signPanel.createChild({
47904 xmlns : 'http://www.w3.org/2000/svg',
47906 id : this.svgID + "-svg",
47908 height: this.height,
47909 viewBox: '0 0 '+this.width+' '+this.height,
47913 id: this.svgID + "-svg-r",
47915 height: this.height,
47920 id: this.svgID + "-svg-l",
47922 y1: (this.height*0.8), // start set the line in 80% of height
47923 x2: this.width, // end
47924 y2: (this.height*0.8), // end set the line in 80% of height
47926 'stroke-width': "1",
47927 'stroke-dasharray': "3",
47928 'shape-rendering': "crispEdges",
47929 'pointer-events': "none"
47933 id: this.svgID + "-svg-p",
47935 'stroke-width': "3",
47937 'pointer-events': 'none'
47942 this.svgBox = this.svgEl.dom.getScreenCTM();
47944 createSVG : function(){
47945 var svg = this.signPanel;
47946 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47949 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47950 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47951 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47952 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47953 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47954 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47955 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47958 isTouchEvent : function(e){
47959 return e.type.match(/^touch/);
47961 getCoords : function (e) {
47962 var pt = this.svgEl.dom.createSVGPoint();
47965 if (this.isTouchEvent(e)) {
47966 pt.x = e.targetTouches[0].clientX;
47967 pt.y = e.targetTouches[0].clientY;
47969 var a = this.svgEl.dom.getScreenCTM();
47970 var b = a.inverse();
47971 var mx = pt.matrixTransform(b);
47972 return mx.x + ',' + mx.y;
47974 //mouse event headler
47975 down : function (e) {
47976 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47977 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47979 this.isMouseDown = true;
47981 e.preventDefault();
47983 move : function (e) {
47984 if (this.isMouseDown) {
47985 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47986 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47989 e.preventDefault();
47991 up : function (e) {
47992 this.isMouseDown = false;
47993 var sp = this.signatureTmp.split(' ');
47996 if(!sp[sp.length-2].match(/^L/)){
48000 this.signatureTmp = sp.join(" ");
48003 if(this.getValue() != this.signatureTmp){
48004 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48005 this.isConfirmed = false;
48007 e.preventDefault();
48011 * Protected method that will not generally be called directly. It
48012 * is called when the editor creates its toolbar. Override this method if you need to
48013 * add custom toolbar buttons.
48014 * @param {HtmlEditor} editor
48016 createToolbar : function(editor){
48017 function btn(id, toggle, handler){
48018 var xid = fid + '-'+ id ;
48022 cls : 'x-btn-icon x-edit-'+id,
48023 enableToggle:toggle !== false,
48024 scope: editor, // was editor...
48025 handler:handler||editor.relayBtnCmd,
48026 clickEvent:'mousedown',
48027 tooltip: etb.buttonTips[id] || undefined, ///tips ???
48033 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
48037 cls : ' x-signature-btn x-signature-'+id,
48038 scope: editor, // was editor...
48039 handler: this.reset,
48040 clickEvent:'mousedown',
48041 text: this.labels.clear
48048 cls : ' x-signature-btn x-signature-'+id,
48049 scope: editor, // was editor...
48050 handler: this.confirmHandler,
48051 clickEvent:'mousedown',
48052 text: this.labels.confirm
48059 * when user is clicked confirm then show this image.....
48061 * @return {String} Image Data URI
48063 getImageDataURI : function(){
48064 var svg = this.svgEl.dom.parentNode.innerHTML;
48065 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
48070 * @return {Boolean} this.isConfirmed
48072 getConfirmed : function(){
48073 return this.isConfirmed;
48077 * @return {Number} this.width
48079 getWidth : function(){
48084 * @return {Number} this.height
48086 getHeight : function(){
48087 return this.height;
48090 getSignature : function(){
48091 return this.signatureTmp;
48094 reset : function(){
48095 this.signatureTmp = '';
48096 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48097 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
48098 this.isConfirmed = false;
48099 Roo.form.Signature.superclass.reset.call(this);
48101 setSignature : function(s){
48102 this.signatureTmp = s;
48103 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48104 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
48106 this.isConfirmed = false;
48107 Roo.form.Signature.superclass.reset.call(this);
48110 // Roo.log(this.signPanel.dom.contentWindow.up())
48113 setConfirmed : function(){
48117 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
48120 confirmHandler : function(){
48121 if(!this.getSignature()){
48125 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
48126 this.setValue(this.getSignature());
48127 this.isConfirmed = true;
48129 this.fireEvent('confirm', this);
48132 // Subclasses should provide the validation implementation by overriding this
48133 validateValue : function(value){
48134 if(this.allowBlank){
48138 if(this.isConfirmed){
48145 * Ext JS Library 1.1.1
48146 * Copyright(c) 2006-2007, Ext JS, LLC.
48148 * Originally Released Under LGPL - original licence link has changed is not relivant.
48151 * <script type="text/javascript">
48156 * @class Roo.form.ComboBox
48157 * @extends Roo.form.TriggerField
48158 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
48160 * Create a new ComboBox.
48161 * @param {Object} config Configuration options
48163 Roo.form.Select = function(config){
48164 Roo.form.Select.superclass.constructor.call(this, config);
48168 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
48170 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
48173 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
48174 * rendering into an Roo.Editor, defaults to false)
48177 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
48178 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
48181 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
48184 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
48185 * the dropdown list (defaults to undefined, with no header element)
48189 * @cfg {String/Roo.Template} tpl The template to use to render the output
48193 defaultAutoCreate : {tag: "select" },
48195 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
48197 listWidth: undefined,
48199 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
48200 * mode = 'remote' or 'text' if mode = 'local')
48202 displayField: undefined,
48204 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
48205 * mode = 'remote' or 'value' if mode = 'local').
48206 * Note: use of a valueField requires the user make a selection
48207 * in order for a value to be mapped.
48209 valueField: undefined,
48213 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
48214 * field's data value (defaults to the underlying DOM element's name)
48216 hiddenName: undefined,
48218 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
48222 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
48224 selectedClass: 'x-combo-selected',
48226 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
48227 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
48228 * which displays a downward arrow icon).
48230 triggerClass : 'x-form-arrow-trigger',
48232 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
48236 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
48237 * anchor positions (defaults to 'tl-bl')
48239 listAlign: 'tl-bl?',
48241 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
48245 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
48246 * query specified by the allQuery config option (defaults to 'query')
48248 triggerAction: 'query',
48250 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
48251 * (defaults to 4, does not apply if editable = false)
48255 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
48256 * delay (typeAheadDelay) if it matches a known value (defaults to false)
48260 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
48261 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
48265 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
48266 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
48270 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
48271 * when editable = true (defaults to false)
48273 selectOnFocus:false,
48275 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
48277 queryParam: 'query',
48279 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
48280 * when mode = 'remote' (defaults to 'Loading...')
48282 loadingText: 'Loading...',
48284 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
48288 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
48292 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
48293 * traditional select (defaults to true)
48297 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
48301 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
48305 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
48306 * listWidth has a higher value)
48310 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
48311 * allow the user to set arbitrary text into the field (defaults to false)
48313 forceSelection:false,
48315 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
48316 * if typeAhead = true (defaults to 250)
48318 typeAheadDelay : 250,
48320 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
48321 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
48323 valueNotFoundText : undefined,
48326 * @cfg {String} defaultValue The value displayed after loading the store.
48331 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
48333 blockFocus : false,
48336 * @cfg {Boolean} disableClear Disable showing of clear button.
48338 disableClear : false,
48340 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
48342 alwaysQuery : false,
48348 // element that contains real text value.. (when hidden is used..)
48351 onRender : function(ct, position){
48352 Roo.form.Field.prototype.onRender.call(this, ct, position);
48355 this.store.on('beforeload', this.onBeforeLoad, this);
48356 this.store.on('load', this.onLoad, this);
48357 this.store.on('loadexception', this.onLoadException, this);
48358 this.store.load({});
48366 initEvents : function(){
48367 //Roo.form.ComboBox.superclass.initEvents.call(this);
48371 onDestroy : function(){
48374 this.store.un('beforeload', this.onBeforeLoad, this);
48375 this.store.un('load', this.onLoad, this);
48376 this.store.un('loadexception', this.onLoadException, this);
48378 //Roo.form.ComboBox.superclass.onDestroy.call(this);
48382 fireKey : function(e){
48383 if(e.isNavKeyPress() && !this.list.isVisible()){
48384 this.fireEvent("specialkey", this, e);
48389 onResize: function(w, h){
48397 * Allow or prevent the user from directly editing the field text. If false is passed,
48398 * the user will only be able to select from the items defined in the dropdown list. This method
48399 * is the runtime equivalent of setting the 'editable' config option at config time.
48400 * @param {Boolean} value True to allow the user to directly edit the field text
48402 setEditable : function(value){
48407 onBeforeLoad : function(){
48409 Roo.log("Select before load");
48412 this.innerList.update(this.loadingText ?
48413 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
48414 //this.restrictHeight();
48415 this.selectedIndex = -1;
48419 onLoad : function(){
48422 var dom = this.el.dom;
48423 dom.innerHTML = '';
48424 var od = dom.ownerDocument;
48426 if (this.emptyText) {
48427 var op = od.createElement('option');
48428 op.setAttribute('value', '');
48429 op.innerHTML = String.format('{0}', this.emptyText);
48430 dom.appendChild(op);
48432 if(this.store.getCount() > 0){
48434 var vf = this.valueField;
48435 var df = this.displayField;
48436 this.store.data.each(function(r) {
48437 // which colmsn to use... testing - cdoe / title..
48438 var op = od.createElement('option');
48439 op.setAttribute('value', r.data[vf]);
48440 op.innerHTML = String.format('{0}', r.data[df]);
48441 dom.appendChild(op);
48443 if (typeof(this.defaultValue != 'undefined')) {
48444 this.setValue(this.defaultValue);
48449 //this.onEmptyResults();
48454 onLoadException : function()
48456 dom.innerHTML = '';
48458 Roo.log("Select on load exception");
48462 Roo.log(this.store.reader.jsonData);
48463 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
48464 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
48470 onTypeAhead : function(){
48475 onSelect : function(record, index){
48476 Roo.log('on select?');
48478 if(this.fireEvent('beforeselect', this, record, index) !== false){
48479 this.setFromData(index > -1 ? record.data : false);
48481 this.fireEvent('select', this, record, index);
48486 * Returns the currently selected field value or empty string if no value is set.
48487 * @return {String} value The selected value
48489 getValue : function(){
48490 var dom = this.el.dom;
48491 this.value = dom.options[dom.selectedIndex].value;
48497 * Clears any text/value currently set in the field
48499 clearValue : function(){
48501 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
48506 * Sets the specified value into the field. If the value finds a match, the corresponding record text
48507 * will be displayed in the field. If the value does not match the data value of an existing item,
48508 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
48509 * Otherwise the field will be blank (although the value will still be set).
48510 * @param {String} value The value to match
48512 setValue : function(v){
48513 var d = this.el.dom;
48514 for (var i =0; i < d.options.length;i++) {
48515 if (v == d.options[i].value) {
48516 d.selectedIndex = i;
48524 * @property {Object} the last set data for the element
48529 * Sets the value of the field based on a object which is related to the record format for the store.
48530 * @param {Object} value the value to set as. or false on reset?
48532 setFromData : function(o){
48533 Roo.log('setfrom data?');
48539 reset : function(){
48543 findRecord : function(prop, value){
48548 if(this.store.getCount() > 0){
48549 this.store.each(function(r){
48550 if(r.data[prop] == value){
48560 getName: function()
48562 // returns hidden if it's set..
48563 if (!this.rendered) {return ''};
48564 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
48572 onEmptyResults : function(){
48573 Roo.log('empty results');
48578 * Returns true if the dropdown list is expanded, else false.
48580 isExpanded : function(){
48585 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
48586 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48587 * @param {String} value The data value of the item to select
48588 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48589 * selected item if it is not currently in view (defaults to true)
48590 * @return {Boolean} True if the value matched an item in the list, else false
48592 selectByValue : function(v, scrollIntoView){
48593 Roo.log('select By Value');
48596 if(v !== undefined && v !== null){
48597 var r = this.findRecord(this.valueField || this.displayField, v);
48599 this.select(this.store.indexOf(r), scrollIntoView);
48607 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
48608 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48609 * @param {Number} index The zero-based index of the list item to select
48610 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48611 * selected item if it is not currently in view (defaults to true)
48613 select : function(index, scrollIntoView){
48614 Roo.log('select ');
48617 this.selectedIndex = index;
48618 this.view.select(index);
48619 if(scrollIntoView !== false){
48620 var el = this.view.getNode(index);
48622 this.innerList.scrollChildIntoView(el, false);
48630 validateBlur : function(){
48637 initQuery : function(){
48638 this.doQuery(this.getRawValue());
48642 doForce : function(){
48643 if(this.el.dom.value.length > 0){
48644 this.el.dom.value =
48645 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
48651 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
48652 * query allowing the query action to be canceled if needed.
48653 * @param {String} query The SQL query to execute
48654 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
48655 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
48656 * saved in the current store (defaults to false)
48658 doQuery : function(q, forceAll){
48660 Roo.log('doQuery?');
48661 if(q === undefined || q === null){
48666 forceAll: forceAll,
48670 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48674 forceAll = qe.forceAll;
48675 if(forceAll === true || (q.length >= this.minChars)){
48676 if(this.lastQuery != q || this.alwaysQuery){
48677 this.lastQuery = q;
48678 if(this.mode == 'local'){
48679 this.selectedIndex = -1;
48681 this.store.clearFilter();
48683 this.store.filter(this.displayField, q);
48687 this.store.baseParams[this.queryParam] = q;
48689 params: this.getParams(q)
48694 this.selectedIndex = -1;
48701 getParams : function(q){
48703 //p[this.queryParam] = q;
48706 p.limit = this.pageSize;
48712 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48714 collapse : function(){
48719 collapseIf : function(e){
48724 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48726 expand : function(){
48734 * @cfg {Boolean} grow
48738 * @cfg {Number} growMin
48742 * @cfg {Number} growMax
48750 setWidth : function()
48754 getResizeEl : function(){
48757 });//<script type="text/javasscript">
48761 * @class Roo.DDView
48762 * A DnD enabled version of Roo.View.
48763 * @param {Element/String} container The Element in which to create the View.
48764 * @param {String} tpl The template string used to create the markup for each element of the View
48765 * @param {Object} config The configuration properties. These include all the config options of
48766 * {@link Roo.View} plus some specific to this class.<br>
48768 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48769 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48771 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48772 .x-view-drag-insert-above {
48773 border-top:1px dotted #3366cc;
48775 .x-view-drag-insert-below {
48776 border-bottom:1px dotted #3366cc;
48782 Roo.DDView = function(container, tpl, config) {
48783 Roo.DDView.superclass.constructor.apply(this, arguments);
48784 this.getEl().setStyle("outline", "0px none");
48785 this.getEl().unselectable();
48786 if (this.dragGroup) {
48787 this.setDraggable(this.dragGroup.split(","));
48789 if (this.dropGroup) {
48790 this.setDroppable(this.dropGroup.split(","));
48792 if (this.deletable) {
48793 this.setDeletable();
48795 this.isDirtyFlag = false;
48801 Roo.extend(Roo.DDView, Roo.View, {
48802 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48803 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48804 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48805 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48809 reset: Roo.emptyFn,
48811 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48813 validate: function() {
48817 destroy: function() {
48818 this.purgeListeners();
48819 this.getEl.removeAllListeners();
48820 this.getEl().remove();
48821 if (this.dragZone) {
48822 if (this.dragZone.destroy) {
48823 this.dragZone.destroy();
48826 if (this.dropZone) {
48827 if (this.dropZone.destroy) {
48828 this.dropZone.destroy();
48833 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48834 getName: function() {
48838 /** Loads the View from a JSON string representing the Records to put into the Store. */
48839 setValue: function(v) {
48841 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48844 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48845 this.store.proxy = new Roo.data.MemoryProxy(data);
48849 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48850 getValue: function() {
48852 this.store.each(function(rec) {
48853 result += rec.id + ',';
48855 return result.substr(0, result.length - 1) + ')';
48858 getIds: function() {
48859 var i = 0, result = new Array(this.store.getCount());
48860 this.store.each(function(rec) {
48861 result[i++] = rec.id;
48866 isDirty: function() {
48867 return this.isDirtyFlag;
48871 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48872 * whole Element becomes the target, and this causes the drop gesture to append.
48874 getTargetFromEvent : function(e) {
48875 var target = e.getTarget();
48876 while ((target !== null) && (target.parentNode != this.el.dom)) {
48877 target = target.parentNode;
48880 target = this.el.dom.lastChild || this.el.dom;
48886 * Create the drag data which consists of an object which has the property "ddel" as
48887 * the drag proxy element.
48889 getDragData : function(e) {
48890 var target = this.findItemFromChild(e.getTarget());
48892 this.handleSelection(e);
48893 var selNodes = this.getSelectedNodes();
48896 copy: this.copy || (this.allowCopy && e.ctrlKey),
48900 var selectedIndices = this.getSelectedIndexes();
48901 for (var i = 0; i < selectedIndices.length; i++) {
48902 dragData.records.push(this.store.getAt(selectedIndices[i]));
48904 if (selNodes.length == 1) {
48905 dragData.ddel = target.cloneNode(true); // the div element
48907 var div = document.createElement('div'); // create the multi element drag "ghost"
48908 div.className = 'multi-proxy';
48909 for (var i = 0, len = selNodes.length; i < len; i++) {
48910 div.appendChild(selNodes[i].cloneNode(true));
48912 dragData.ddel = div;
48914 //console.log(dragData)
48915 //console.log(dragData.ddel.innerHTML)
48918 //console.log('nodragData')
48922 /** Specify to which ddGroup items in this DDView may be dragged. */
48923 setDraggable: function(ddGroup) {
48924 if (ddGroup instanceof Array) {
48925 Roo.each(ddGroup, this.setDraggable, this);
48928 if (this.dragZone) {
48929 this.dragZone.addToGroup(ddGroup);
48931 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48932 containerScroll: true,
48936 // Draggability implies selection. DragZone's mousedown selects the element.
48937 if (!this.multiSelect) { this.singleSelect = true; }
48939 // Wire the DragZone's handlers up to methods in *this*
48940 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48944 /** Specify from which ddGroup this DDView accepts drops. */
48945 setDroppable: function(ddGroup) {
48946 if (ddGroup instanceof Array) {
48947 Roo.each(ddGroup, this.setDroppable, this);
48950 if (this.dropZone) {
48951 this.dropZone.addToGroup(ddGroup);
48953 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48954 containerScroll: true,
48958 // Wire the DropZone's handlers up to methods in *this*
48959 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48960 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48961 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48962 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48963 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48967 /** Decide whether to drop above or below a View node. */
48968 getDropPoint : function(e, n, dd){
48969 if (n == this.el.dom) { return "above"; }
48970 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48971 var c = t + (b - t) / 2;
48972 var y = Roo.lib.Event.getPageY(e);
48980 onNodeEnter : function(n, dd, e, data){
48984 onNodeOver : function(n, dd, e, data){
48985 var pt = this.getDropPoint(e, n, dd);
48986 // set the insert point style on the target node
48987 var dragElClass = this.dropNotAllowed;
48990 if (pt == "above"){
48991 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48992 targetElClass = "x-view-drag-insert-above";
48994 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48995 targetElClass = "x-view-drag-insert-below";
48997 if (this.lastInsertClass != targetElClass){
48998 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48999 this.lastInsertClass = targetElClass;
49002 return dragElClass;
49005 onNodeOut : function(n, dd, e, data){
49006 this.removeDropIndicators(n);
49009 onNodeDrop : function(n, dd, e, data){
49010 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
49013 var pt = this.getDropPoint(e, n, dd);
49014 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
49015 if (pt == "below") { insertAt++; }
49016 for (var i = 0; i < data.records.length; i++) {
49017 var r = data.records[i];
49018 var dup = this.store.getById(r.id);
49019 if (dup && (dd != this.dragZone)) {
49020 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
49023 this.store.insert(insertAt++, r.copy());
49025 data.source.isDirtyFlag = true;
49027 this.store.insert(insertAt++, r);
49029 this.isDirtyFlag = true;
49032 this.dragZone.cachedTarget = null;
49036 removeDropIndicators : function(n){
49038 Roo.fly(n).removeClass([
49039 "x-view-drag-insert-above",
49040 "x-view-drag-insert-below"]);
49041 this.lastInsertClass = "_noclass";
49046 * Utility method. Add a delete option to the DDView's context menu.
49047 * @param {String} imageUrl The URL of the "delete" icon image.
49049 setDeletable: function(imageUrl) {
49050 if (!this.singleSelect && !this.multiSelect) {
49051 this.singleSelect = true;
49053 var c = this.getContextMenu();
49054 this.contextMenu.on("itemclick", function(item) {
49057 this.remove(this.getSelectedIndexes());
49061 this.contextMenu.add({
49068 /** Return the context menu for this DDView. */
49069 getContextMenu: function() {
49070 if (!this.contextMenu) {
49071 // Create the View's context menu
49072 this.contextMenu = new Roo.menu.Menu({
49073 id: this.id + "-contextmenu"
49075 this.el.on("contextmenu", this.showContextMenu, this);
49077 return this.contextMenu;
49080 disableContextMenu: function() {
49081 if (this.contextMenu) {
49082 this.el.un("contextmenu", this.showContextMenu, this);
49086 showContextMenu: function(e, item) {
49087 item = this.findItemFromChild(e.getTarget());
49090 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
49091 this.contextMenu.showAt(e.getXY());
49096 * Remove {@link Roo.data.Record}s at the specified indices.
49097 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
49099 remove: function(selectedIndices) {
49100 selectedIndices = [].concat(selectedIndices);
49101 for (var i = 0; i < selectedIndices.length; i++) {
49102 var rec = this.store.getAt(selectedIndices[i]);
49103 this.store.remove(rec);
49108 * Double click fires the event, but also, if this is draggable, and there is only one other
49109 * related DropZone, it transfers the selected node.
49111 onDblClick : function(e){
49112 var item = this.findItemFromChild(e.getTarget());
49114 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
49117 if (this.dragGroup) {
49118 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
49119 while (targets.indexOf(this.dropZone) > -1) {
49120 targets.remove(this.dropZone);
49122 if (targets.length == 1) {
49123 this.dragZone.cachedTarget = null;
49124 var el = Roo.get(targets[0].getEl());
49125 var box = el.getBox(true);
49126 targets[0].onNodeDrop(el.dom, {
49128 xy: [box.x, box.y + box.height - 1]
49129 }, null, this.getDragData(e));
49135 handleSelection: function(e) {
49136 this.dragZone.cachedTarget = null;
49137 var item = this.findItemFromChild(e.getTarget());
49139 this.clearSelections(true);
49142 if (item && (this.multiSelect || this.singleSelect)){
49143 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
49144 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
49145 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
49146 this.unselect(item);
49148 this.select(item, this.multiSelect && e.ctrlKey);
49149 this.lastSelection = item;
49154 onItemClick : function(item, index, e){
49155 if(this.fireEvent("beforeclick", this, index, item, e) === false){
49161 unselect : function(nodeInfo, suppressEvent){
49162 var node = this.getNode(nodeInfo);
49163 if(node && this.isSelected(node)){
49164 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
49165 Roo.fly(node).removeClass(this.selectedClass);
49166 this.selections.remove(node);
49167 if(!suppressEvent){
49168 this.fireEvent("selectionchange", this, this.selections);
49176 * Ext JS Library 1.1.1
49177 * Copyright(c) 2006-2007, Ext JS, LLC.
49179 * Originally Released Under LGPL - original licence link has changed is not relivant.
49182 * <script type="text/javascript">
49186 * @class Roo.LayoutManager
49187 * @extends Roo.util.Observable
49188 * Base class for layout managers.
49190 Roo.LayoutManager = function(container, config){
49191 Roo.LayoutManager.superclass.constructor.call(this);
49192 this.el = Roo.get(container);
49193 // ie scrollbar fix
49194 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
49195 document.body.scroll = "no";
49196 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
49197 this.el.position('relative');
49199 this.id = this.el.id;
49200 this.el.addClass("x-layout-container");
49201 /** false to disable window resize monitoring @type Boolean */
49202 this.monitorWindowResize = true;
49207 * Fires when a layout is performed.
49208 * @param {Roo.LayoutManager} this
49212 * @event regionresized
49213 * Fires when the user resizes a region.
49214 * @param {Roo.LayoutRegion} region The resized region
49215 * @param {Number} newSize The new size (width for east/west, height for north/south)
49217 "regionresized" : true,
49219 * @event regioncollapsed
49220 * Fires when a region is collapsed.
49221 * @param {Roo.LayoutRegion} region The collapsed region
49223 "regioncollapsed" : true,
49225 * @event regionexpanded
49226 * Fires when a region is expanded.
49227 * @param {Roo.LayoutRegion} region The expanded region
49229 "regionexpanded" : true
49231 this.updating = false;
49232 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
49235 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
49237 * Returns true if this layout is currently being updated
49238 * @return {Boolean}
49240 isUpdating : function(){
49241 return this.updating;
49245 * Suspend the LayoutManager from doing auto-layouts while
49246 * making multiple add or remove calls
49248 beginUpdate : function(){
49249 this.updating = true;
49253 * Restore auto-layouts and optionally disable the manager from performing a layout
49254 * @param {Boolean} noLayout true to disable a layout update
49256 endUpdate : function(noLayout){
49257 this.updating = false;
49263 layout: function(){
49267 onRegionResized : function(region, newSize){
49268 this.fireEvent("regionresized", region, newSize);
49272 onRegionCollapsed : function(region){
49273 this.fireEvent("regioncollapsed", region);
49276 onRegionExpanded : function(region){
49277 this.fireEvent("regionexpanded", region);
49281 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
49282 * performs box-model adjustments.
49283 * @return {Object} The size as an object {width: (the width), height: (the height)}
49285 getViewSize : function(){
49287 if(this.el.dom != document.body){
49288 size = this.el.getSize();
49290 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
49292 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
49293 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
49298 * Returns the Element this layout is bound to.
49299 * @return {Roo.Element}
49301 getEl : function(){
49306 * Returns the specified region.
49307 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
49308 * @return {Roo.LayoutRegion}
49310 getRegion : function(target){
49311 return this.regions[target.toLowerCase()];
49314 onWindowResize : function(){
49315 if(this.monitorWindowResize){
49321 * Ext JS Library 1.1.1
49322 * Copyright(c) 2006-2007, Ext JS, LLC.
49324 * Originally Released Under LGPL - original licence link has changed is not relivant.
49327 * <script type="text/javascript">
49330 * @class Roo.BorderLayout
49331 * @extends Roo.LayoutManager
49332 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
49333 * please see: <br><br>
49334 * <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>
49335 * <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>
49338 var layout = new Roo.BorderLayout(document.body, {
49372 preferredTabWidth: 150
49377 var CP = Roo.ContentPanel;
49379 layout.beginUpdate();
49380 layout.add("north", new CP("north", "North"));
49381 layout.add("south", new CP("south", {title: "South", closable: true}));
49382 layout.add("west", new CP("west", {title: "West"}));
49383 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
49384 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
49385 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
49386 layout.getRegion("center").showPanel("center1");
49387 layout.endUpdate();
49390 <b>The container the layout is rendered into can be either the body element or any other element.
49391 If it is not the body element, the container needs to either be an absolute positioned element,
49392 or you will need to add "position:relative" to the css of the container. You will also need to specify
49393 the container size if it is not the body element.</b>
49396 * Create a new BorderLayout
49397 * @param {String/HTMLElement/Element} container The container this layout is bound to
49398 * @param {Object} config Configuration options
49400 Roo.BorderLayout = function(container, config){
49401 config = config || {};
49402 Roo.BorderLayout.superclass.constructor.call(this, container, config);
49403 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
49404 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
49405 var target = this.factory.validRegions[i];
49406 if(config[target]){
49407 this.addRegion(target, config[target]);
49412 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
49414 * Creates and adds a new region if it doesn't already exist.
49415 * @param {String} target The target region key (north, south, east, west or center).
49416 * @param {Object} config The regions config object
49417 * @return {BorderLayoutRegion} The new region
49419 addRegion : function(target, config){
49420 if(!this.regions[target]){
49421 var r = this.factory.create(target, this, config);
49422 this.bindRegion(target, r);
49424 return this.regions[target];
49428 bindRegion : function(name, r){
49429 this.regions[name] = r;
49430 r.on("visibilitychange", this.layout, this);
49431 r.on("paneladded", this.layout, this);
49432 r.on("panelremoved", this.layout, this);
49433 r.on("invalidated", this.layout, this);
49434 r.on("resized", this.onRegionResized, this);
49435 r.on("collapsed", this.onRegionCollapsed, this);
49436 r.on("expanded", this.onRegionExpanded, this);
49440 * Performs a layout update.
49442 layout : function(){
49443 if(this.updating) {
49446 var size = this.getViewSize();
49447 var w = size.width;
49448 var h = size.height;
49453 //var x = 0, y = 0;
49455 var rs = this.regions;
49456 var north = rs["north"];
49457 var south = rs["south"];
49458 var west = rs["west"];
49459 var east = rs["east"];
49460 var center = rs["center"];
49461 //if(this.hideOnLayout){ // not supported anymore
49462 //c.el.setStyle("display", "none");
49464 if(north && north.isVisible()){
49465 var b = north.getBox();
49466 var m = north.getMargins();
49467 b.width = w - (m.left+m.right);
49470 centerY = b.height + b.y + m.bottom;
49471 centerH -= centerY;
49472 north.updateBox(this.safeBox(b));
49474 if(south && south.isVisible()){
49475 var b = south.getBox();
49476 var m = south.getMargins();
49477 b.width = w - (m.left+m.right);
49479 var totalHeight = (b.height + m.top + m.bottom);
49480 b.y = h - totalHeight + m.top;
49481 centerH -= totalHeight;
49482 south.updateBox(this.safeBox(b));
49484 if(west && west.isVisible()){
49485 var b = west.getBox();
49486 var m = west.getMargins();
49487 b.height = centerH - (m.top+m.bottom);
49489 b.y = centerY + m.top;
49490 var totalWidth = (b.width + m.left + m.right);
49491 centerX += totalWidth;
49492 centerW -= totalWidth;
49493 west.updateBox(this.safeBox(b));
49495 if(east && east.isVisible()){
49496 var b = east.getBox();
49497 var m = east.getMargins();
49498 b.height = centerH - (m.top+m.bottom);
49499 var totalWidth = (b.width + m.left + m.right);
49500 b.x = w - totalWidth + m.left;
49501 b.y = centerY + m.top;
49502 centerW -= totalWidth;
49503 east.updateBox(this.safeBox(b));
49506 var m = center.getMargins();
49508 x: centerX + m.left,
49509 y: centerY + m.top,
49510 width: centerW - (m.left+m.right),
49511 height: centerH - (m.top+m.bottom)
49513 //if(this.hideOnLayout){
49514 //center.el.setStyle("display", "block");
49516 center.updateBox(this.safeBox(centerBox));
49519 this.fireEvent("layout", this);
49523 safeBox : function(box){
49524 box.width = Math.max(0, box.width);
49525 box.height = Math.max(0, box.height);
49530 * Adds a ContentPanel (or subclass) to this layout.
49531 * @param {String} target The target region key (north, south, east, west or center).
49532 * @param {Roo.ContentPanel} panel The panel to add
49533 * @return {Roo.ContentPanel} The added panel
49535 add : function(target, panel){
49537 target = target.toLowerCase();
49538 return this.regions[target].add(panel);
49542 * Remove a ContentPanel (or subclass) to this layout.
49543 * @param {String} target The target region key (north, south, east, west or center).
49544 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
49545 * @return {Roo.ContentPanel} The removed panel
49547 remove : function(target, panel){
49548 target = target.toLowerCase();
49549 return this.regions[target].remove(panel);
49553 * Searches all regions for a panel with the specified id
49554 * @param {String} panelId
49555 * @return {Roo.ContentPanel} The panel or null if it wasn't found
49557 findPanel : function(panelId){
49558 var rs = this.regions;
49559 for(var target in rs){
49560 if(typeof rs[target] != "function"){
49561 var p = rs[target].getPanel(panelId);
49571 * Searches all regions for a panel with the specified id and activates (shows) it.
49572 * @param {String/ContentPanel} panelId The panels id or the panel itself
49573 * @return {Roo.ContentPanel} The shown panel or null
49575 showPanel : function(panelId) {
49576 var rs = this.regions;
49577 for(var target in rs){
49578 var r = rs[target];
49579 if(typeof r != "function"){
49580 if(r.hasPanel(panelId)){
49581 return r.showPanel(panelId);
49589 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
49590 * @param {Roo.state.Provider} provider (optional) An alternate state provider
49592 restoreState : function(provider){
49594 provider = Roo.state.Manager;
49596 var sm = new Roo.LayoutStateManager();
49597 sm.init(this, provider);
49601 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
49602 * object should contain properties for each region to add ContentPanels to, and each property's value should be
49603 * a valid ContentPanel config object. Example:
49605 // Create the main layout
49606 var layout = new Roo.BorderLayout('main-ct', {
49617 // Create and add multiple ContentPanels at once via configs
49620 id: 'source-files',
49622 title:'Ext Source Files',
49635 * @param {Object} regions An object containing ContentPanel configs by region name
49637 batchAdd : function(regions){
49638 this.beginUpdate();
49639 for(var rname in regions){
49640 var lr = this.regions[rname];
49642 this.addTypedPanels(lr, regions[rname]);
49649 addTypedPanels : function(lr, ps){
49650 if(typeof ps == 'string'){
49651 lr.add(new Roo.ContentPanel(ps));
49653 else if(ps instanceof Array){
49654 for(var i =0, len = ps.length; i < len; i++){
49655 this.addTypedPanels(lr, ps[i]);
49658 else if(!ps.events){ // raw config?
49660 delete ps.el; // prevent conflict
49661 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
49663 else { // panel object assumed!
49668 * Adds a xtype elements to the layout.
49672 xtype : 'ContentPanel',
49679 xtype : 'NestedLayoutPanel',
49685 items : [ ... list of content panels or nested layout panels.. ]
49689 * @param {Object} cfg Xtype definition of item to add.
49691 addxtype : function(cfg)
49693 // basically accepts a pannel...
49694 // can accept a layout region..!?!?
49695 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49697 if (!cfg.xtype.match(/Panel$/)) {
49702 if (typeof(cfg.region) == 'undefined') {
49703 Roo.log("Failed to add Panel, region was not set");
49707 var region = cfg.region;
49713 xitems = cfg.items;
49720 case 'ContentPanel': // ContentPanel (el, cfg)
49721 case 'ScrollPanel': // ContentPanel (el, cfg)
49723 if(cfg.autoCreate) {
49724 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49726 var el = this.el.createChild();
49727 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49730 this.add(region, ret);
49734 case 'TreePanel': // our new panel!
49735 cfg.el = this.el.createChild();
49736 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49737 this.add(region, ret);
49740 case 'NestedLayoutPanel':
49741 // create a new Layout (which is a Border Layout...
49742 var el = this.el.createChild();
49743 var clayout = cfg.layout;
49745 clayout.items = clayout.items || [];
49746 // replace this exitems with the clayout ones..
49747 xitems = clayout.items;
49750 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49751 cfg.background = false;
49753 var layout = new Roo.BorderLayout(el, clayout);
49755 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49756 //console.log('adding nested layout panel ' + cfg.toSource());
49757 this.add(region, ret);
49758 nb = {}; /// find first...
49763 // needs grid and region
49765 //var el = this.getRegion(region).el.createChild();
49766 var el = this.el.createChild();
49767 // create the grid first...
49769 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49771 if (region == 'center' && this.active ) {
49772 cfg.background = false;
49774 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49776 this.add(region, ret);
49777 if (cfg.background) {
49778 ret.on('activate', function(gp) {
49779 if (!gp.grid.rendered) {
49794 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49796 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49797 this.add(region, ret);
49800 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49804 // GridPanel (grid, cfg)
49807 this.beginUpdate();
49811 Roo.each(xitems, function(i) {
49812 region = nb && i.region ? i.region : false;
49814 var add = ret.addxtype(i);
49817 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49818 if (!i.background) {
49819 abn[region] = nb[region] ;
49826 // make the last non-background panel active..
49827 //if (nb) { Roo.log(abn); }
49830 for(var r in abn) {
49831 region = this.getRegion(r);
49833 // tried using nb[r], but it does not work..
49835 region.showPanel(abn[r]);
49846 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49847 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49848 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49849 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49852 var CP = Roo.ContentPanel;
49854 var layout = Roo.BorderLayout.create({
49858 panels: [new CP("north", "North")]
49867 panels: [new CP("west", {title: "West"})]
49876 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49885 panels: [new CP("south", {title: "South", closable: true})]
49892 preferredTabWidth: 150,
49894 new CP("center1", {title: "Close Me", closable: true}),
49895 new CP("center2", {title: "Center Panel", closable: false})
49900 layout.getRegion("center").showPanel("center1");
49905 Roo.BorderLayout.create = function(config, targetEl){
49906 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49907 layout.beginUpdate();
49908 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49909 for(var j = 0, jlen = regions.length; j < jlen; j++){
49910 var lr = regions[j];
49911 if(layout.regions[lr] && config[lr].panels){
49912 var r = layout.regions[lr];
49913 var ps = config[lr].panels;
49914 layout.addTypedPanels(r, ps);
49917 layout.endUpdate();
49922 Roo.BorderLayout.RegionFactory = {
49924 validRegions : ["north","south","east","west","center"],
49927 create : function(target, mgr, config){
49928 target = target.toLowerCase();
49929 if(config.lightweight || config.basic){
49930 return new Roo.BasicLayoutRegion(mgr, config, target);
49934 return new Roo.NorthLayoutRegion(mgr, config);
49936 return new Roo.SouthLayoutRegion(mgr, config);
49938 return new Roo.EastLayoutRegion(mgr, config);
49940 return new Roo.WestLayoutRegion(mgr, config);
49942 return new Roo.CenterLayoutRegion(mgr, config);
49944 throw 'Layout region "'+target+'" not supported.';
49948 * Ext JS Library 1.1.1
49949 * Copyright(c) 2006-2007, Ext JS, LLC.
49951 * Originally Released Under LGPL - original licence link has changed is not relivant.
49954 * <script type="text/javascript">
49958 * @class Roo.BasicLayoutRegion
49959 * @extends Roo.util.Observable
49960 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49961 * and does not have a titlebar, tabs or any other features. All it does is size and position
49962 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49964 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49966 this.position = pos;
49969 * @scope Roo.BasicLayoutRegion
49973 * @event beforeremove
49974 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49975 * @param {Roo.LayoutRegion} this
49976 * @param {Roo.ContentPanel} panel The panel
49977 * @param {Object} e The cancel event object
49979 "beforeremove" : true,
49981 * @event invalidated
49982 * Fires when the layout for this region is changed.
49983 * @param {Roo.LayoutRegion} this
49985 "invalidated" : true,
49987 * @event visibilitychange
49988 * Fires when this region is shown or hidden
49989 * @param {Roo.LayoutRegion} this
49990 * @param {Boolean} visibility true or false
49992 "visibilitychange" : true,
49994 * @event paneladded
49995 * Fires when a panel is added.
49996 * @param {Roo.LayoutRegion} this
49997 * @param {Roo.ContentPanel} panel The panel
49999 "paneladded" : true,
50001 * @event panelremoved
50002 * Fires when a panel is removed.
50003 * @param {Roo.LayoutRegion} this
50004 * @param {Roo.ContentPanel} panel The panel
50006 "panelremoved" : true,
50009 * Fires when this region is collapsed.
50010 * @param {Roo.LayoutRegion} this
50012 "collapsed" : true,
50015 * Fires when this region is expanded.
50016 * @param {Roo.LayoutRegion} this
50021 * Fires when this region is slid into view.
50022 * @param {Roo.LayoutRegion} this
50024 "slideshow" : true,
50027 * Fires when this region slides out of view.
50028 * @param {Roo.LayoutRegion} this
50030 "slidehide" : true,
50032 * @event panelactivated
50033 * Fires when a panel is activated.
50034 * @param {Roo.LayoutRegion} this
50035 * @param {Roo.ContentPanel} panel The activated panel
50037 "panelactivated" : true,
50040 * Fires when the user resizes this region.
50041 * @param {Roo.LayoutRegion} this
50042 * @param {Number} newSize The new size (width for east/west, height for north/south)
50046 /** A collection of panels in this region. @type Roo.util.MixedCollection */
50047 this.panels = new Roo.util.MixedCollection();
50048 this.panels.getKey = this.getPanelId.createDelegate(this);
50050 this.activePanel = null;
50051 // ensure listeners are added...
50053 if (config.listeners || config.events) {
50054 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
50055 listeners : config.listeners || {},
50056 events : config.events || {}
50060 if(skipConfig !== true){
50061 this.applyConfig(config);
50065 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
50066 getPanelId : function(p){
50070 applyConfig : function(config){
50071 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50072 this.config = config;
50077 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
50078 * the width, for horizontal (north, south) the height.
50079 * @param {Number} newSize The new width or height
50081 resizeTo : function(newSize){
50082 var el = this.el ? this.el :
50083 (this.activePanel ? this.activePanel.getEl() : null);
50085 switch(this.position){
50088 el.setWidth(newSize);
50089 this.fireEvent("resized", this, newSize);
50093 el.setHeight(newSize);
50094 this.fireEvent("resized", this, newSize);
50100 getBox : function(){
50101 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
50104 getMargins : function(){
50105 return this.margins;
50108 updateBox : function(box){
50110 var el = this.activePanel.getEl();
50111 el.dom.style.left = box.x + "px";
50112 el.dom.style.top = box.y + "px";
50113 this.activePanel.setSize(box.width, box.height);
50117 * Returns the container element for this region.
50118 * @return {Roo.Element}
50120 getEl : function(){
50121 return this.activePanel;
50125 * Returns true if this region is currently visible.
50126 * @return {Boolean}
50128 isVisible : function(){
50129 return this.activePanel ? true : false;
50132 setActivePanel : function(panel){
50133 panel = this.getPanel(panel);
50134 if(this.activePanel && this.activePanel != panel){
50135 this.activePanel.setActiveState(false);
50136 this.activePanel.getEl().setLeftTop(-10000,-10000);
50138 this.activePanel = panel;
50139 panel.setActiveState(true);
50141 panel.setSize(this.box.width, this.box.height);
50143 this.fireEvent("panelactivated", this, panel);
50144 this.fireEvent("invalidated");
50148 * Show the specified panel.
50149 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
50150 * @return {Roo.ContentPanel} The shown panel or null
50152 showPanel : function(panel){
50153 if(panel = this.getPanel(panel)){
50154 this.setActivePanel(panel);
50160 * Get the active panel for this region.
50161 * @return {Roo.ContentPanel} The active panel or null
50163 getActivePanel : function(){
50164 return this.activePanel;
50168 * Add the passed ContentPanel(s)
50169 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50170 * @return {Roo.ContentPanel} The panel added (if only one was added)
50172 add : function(panel){
50173 if(arguments.length > 1){
50174 for(var i = 0, len = arguments.length; i < len; i++) {
50175 this.add(arguments[i]);
50179 if(this.hasPanel(panel)){
50180 this.showPanel(panel);
50183 var el = panel.getEl();
50184 if(el.dom.parentNode != this.mgr.el.dom){
50185 this.mgr.el.dom.appendChild(el.dom);
50187 if(panel.setRegion){
50188 panel.setRegion(this);
50190 this.panels.add(panel);
50191 el.setStyle("position", "absolute");
50192 if(!panel.background){
50193 this.setActivePanel(panel);
50194 if(this.config.initialSize && this.panels.getCount()==1){
50195 this.resizeTo(this.config.initialSize);
50198 this.fireEvent("paneladded", this, panel);
50203 * Returns true if the panel is in this region.
50204 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50205 * @return {Boolean}
50207 hasPanel : function(panel){
50208 if(typeof panel == "object"){ // must be panel obj
50209 panel = panel.getId();
50211 return this.getPanel(panel) ? true : false;
50215 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50216 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50217 * @param {Boolean} preservePanel Overrides the config preservePanel option
50218 * @return {Roo.ContentPanel} The panel that was removed
50220 remove : function(panel, preservePanel){
50221 panel = this.getPanel(panel);
50226 this.fireEvent("beforeremove", this, panel, e);
50227 if(e.cancel === true){
50230 var panelId = panel.getId();
50231 this.panels.removeKey(panelId);
50236 * Returns the panel specified or null if it's not in this region.
50237 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50238 * @return {Roo.ContentPanel}
50240 getPanel : function(id){
50241 if(typeof id == "object"){ // must be panel obj
50244 return this.panels.get(id);
50248 * Returns this regions position (north/south/east/west/center).
50251 getPosition: function(){
50252 return this.position;
50256 * Ext JS Library 1.1.1
50257 * Copyright(c) 2006-2007, Ext JS, LLC.
50259 * Originally Released Under LGPL - original licence link has changed is not relivant.
50262 * <script type="text/javascript">
50266 * @class Roo.LayoutRegion
50267 * @extends Roo.BasicLayoutRegion
50268 * This class represents a region in a layout manager.
50269 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
50270 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
50271 * @cfg {Boolean} floatable False to disable floating (defaults to true)
50272 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
50273 * @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})
50274 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
50275 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
50276 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
50277 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
50278 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
50279 * @cfg {String} title The title for the region (overrides panel titles)
50280 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
50281 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
50282 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
50283 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
50284 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
50285 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
50286 * the space available, similar to FireFox 1.5 tabs (defaults to false)
50287 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
50288 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
50289 * @cfg {Boolean} showPin True to show a pin button
50290 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
50291 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
50292 * @cfg {Boolean} disableTabTips True to disable tab tooltips
50293 * @cfg {Number} width For East/West panels
50294 * @cfg {Number} height For North/South panels
50295 * @cfg {Boolean} split To show the splitter
50296 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
50298 Roo.LayoutRegion = function(mgr, config, pos){
50299 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
50300 var dh = Roo.DomHelper;
50301 /** This region's container element
50302 * @type Roo.Element */
50303 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
50304 /** This region's title element
50305 * @type Roo.Element */
50307 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
50308 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
50309 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
50311 this.titleEl.enableDisplayMode();
50312 /** This region's title text element
50313 * @type HTMLElement */
50314 this.titleTextEl = this.titleEl.dom.firstChild;
50315 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
50316 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
50317 this.closeBtn.enableDisplayMode();
50318 this.closeBtn.on("click", this.closeClicked, this);
50319 this.closeBtn.hide();
50321 this.createBody(config);
50322 this.visible = true;
50323 this.collapsed = false;
50325 if(config.hideWhenEmpty){
50327 this.on("paneladded", this.validateVisibility, this);
50328 this.on("panelremoved", this.validateVisibility, this);
50330 this.applyConfig(config);
50333 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
50335 createBody : function(){
50336 /** This region's body element
50337 * @type Roo.Element */
50338 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
50341 applyConfig : function(c){
50342 if(c.collapsible && this.position != "center" && !this.collapsedEl){
50343 var dh = Roo.DomHelper;
50344 if(c.titlebar !== false){
50345 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
50346 this.collapseBtn.on("click", this.collapse, this);
50347 this.collapseBtn.enableDisplayMode();
50349 if(c.showPin === true || this.showPin){
50350 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
50351 this.stickBtn.enableDisplayMode();
50352 this.stickBtn.on("click", this.expand, this);
50353 this.stickBtn.hide();
50356 /** This region's collapsed element
50357 * @type Roo.Element */
50358 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
50359 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
50361 if(c.floatable !== false){
50362 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
50363 this.collapsedEl.on("click", this.collapseClick, this);
50366 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
50367 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
50368 id: "message", unselectable: "on", style:{"float":"left"}});
50369 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
50371 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
50372 this.expandBtn.on("click", this.expand, this);
50374 if(this.collapseBtn){
50375 this.collapseBtn.setVisible(c.collapsible == true);
50377 this.cmargins = c.cmargins || this.cmargins ||
50378 (this.position == "west" || this.position == "east" ?
50379 {top: 0, left: 2, right:2, bottom: 0} :
50380 {top: 2, left: 0, right:0, bottom: 2});
50381 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50382 this.bottomTabs = c.tabPosition != "top";
50383 this.autoScroll = c.autoScroll || false;
50384 if(this.autoScroll){
50385 this.bodyEl.setStyle("overflow", "auto");
50387 this.bodyEl.setStyle("overflow", "hidden");
50389 //if(c.titlebar !== false){
50390 if((!c.titlebar && !c.title) || c.titlebar === false){
50391 this.titleEl.hide();
50393 this.titleEl.show();
50395 this.titleTextEl.innerHTML = c.title;
50399 this.duration = c.duration || .30;
50400 this.slideDuration = c.slideDuration || .45;
50403 this.collapse(true);
50410 * Returns true if this region is currently visible.
50411 * @return {Boolean}
50413 isVisible : function(){
50414 return this.visible;
50418 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
50419 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
50421 setCollapsedTitle : function(title){
50422 title = title || " ";
50423 if(this.collapsedTitleTextEl){
50424 this.collapsedTitleTextEl.innerHTML = title;
50428 getBox : function(){
50430 if(!this.collapsed){
50431 b = this.el.getBox(false, true);
50433 b = this.collapsedEl.getBox(false, true);
50438 getMargins : function(){
50439 return this.collapsed ? this.cmargins : this.margins;
50442 highlight : function(){
50443 this.el.addClass("x-layout-panel-dragover");
50446 unhighlight : function(){
50447 this.el.removeClass("x-layout-panel-dragover");
50450 updateBox : function(box){
50452 if(!this.collapsed){
50453 this.el.dom.style.left = box.x + "px";
50454 this.el.dom.style.top = box.y + "px";
50455 this.updateBody(box.width, box.height);
50457 this.collapsedEl.dom.style.left = box.x + "px";
50458 this.collapsedEl.dom.style.top = box.y + "px";
50459 this.collapsedEl.setSize(box.width, box.height);
50462 this.tabs.autoSizeTabs();
50466 updateBody : function(w, h){
50468 this.el.setWidth(w);
50469 w -= this.el.getBorderWidth("rl");
50470 if(this.config.adjustments){
50471 w += this.config.adjustments[0];
50475 this.el.setHeight(h);
50476 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
50477 h -= this.el.getBorderWidth("tb");
50478 if(this.config.adjustments){
50479 h += this.config.adjustments[1];
50481 this.bodyEl.setHeight(h);
50483 h = this.tabs.syncHeight(h);
50486 if(this.panelSize){
50487 w = w !== null ? w : this.panelSize.width;
50488 h = h !== null ? h : this.panelSize.height;
50490 if(this.activePanel){
50491 var el = this.activePanel.getEl();
50492 w = w !== null ? w : el.getWidth();
50493 h = h !== null ? h : el.getHeight();
50494 this.panelSize = {width: w, height: h};
50495 this.activePanel.setSize(w, h);
50497 if(Roo.isIE && this.tabs){
50498 this.tabs.el.repaint();
50503 * Returns the container element for this region.
50504 * @return {Roo.Element}
50506 getEl : function(){
50511 * Hides this region.
50514 if(!this.collapsed){
50515 this.el.dom.style.left = "-2000px";
50518 this.collapsedEl.dom.style.left = "-2000px";
50519 this.collapsedEl.hide();
50521 this.visible = false;
50522 this.fireEvent("visibilitychange", this, false);
50526 * Shows this region if it was previously hidden.
50529 if(!this.collapsed){
50532 this.collapsedEl.show();
50534 this.visible = true;
50535 this.fireEvent("visibilitychange", this, true);
50538 closeClicked : function(){
50539 if(this.activePanel){
50540 this.remove(this.activePanel);
50544 collapseClick : function(e){
50546 e.stopPropagation();
50549 e.stopPropagation();
50555 * Collapses this region.
50556 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
50558 collapse : function(skipAnim){
50559 if(this.collapsed) {
50562 this.collapsed = true;
50564 this.split.el.hide();
50566 if(this.config.animate && skipAnim !== true){
50567 this.fireEvent("invalidated", this);
50568 this.animateCollapse();
50570 this.el.setLocation(-20000,-20000);
50572 this.collapsedEl.show();
50573 this.fireEvent("collapsed", this);
50574 this.fireEvent("invalidated", this);
50578 animateCollapse : function(){
50583 * Expands this region if it was previously collapsed.
50584 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
50585 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
50587 expand : function(e, skipAnim){
50589 e.stopPropagation();
50591 if(!this.collapsed || this.el.hasActiveFx()) {
50595 this.afterSlideIn();
50598 this.collapsed = false;
50599 if(this.config.animate && skipAnim !== true){
50600 this.animateExpand();
50604 this.split.el.show();
50606 this.collapsedEl.setLocation(-2000,-2000);
50607 this.collapsedEl.hide();
50608 this.fireEvent("invalidated", this);
50609 this.fireEvent("expanded", this);
50613 animateExpand : function(){
50617 initTabs : function()
50619 this.bodyEl.setStyle("overflow", "hidden");
50620 var ts = new Roo.TabPanel(
50623 tabPosition: this.bottomTabs ? 'bottom' : 'top',
50624 disableTooltips: this.config.disableTabTips,
50625 toolbar : this.config.toolbar
50628 if(this.config.hideTabs){
50629 ts.stripWrap.setDisplayed(false);
50632 ts.resizeTabs = this.config.resizeTabs === true;
50633 ts.minTabWidth = this.config.minTabWidth || 40;
50634 ts.maxTabWidth = this.config.maxTabWidth || 250;
50635 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
50636 ts.monitorResize = false;
50637 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50638 ts.bodyEl.addClass('x-layout-tabs-body');
50639 this.panels.each(this.initPanelAsTab, this);
50642 initPanelAsTab : function(panel){
50643 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
50644 this.config.closeOnTab && panel.isClosable());
50645 if(panel.tabTip !== undefined){
50646 ti.setTooltip(panel.tabTip);
50648 ti.on("activate", function(){
50649 this.setActivePanel(panel);
50651 if(this.config.closeOnTab){
50652 ti.on("beforeclose", function(t, e){
50654 this.remove(panel);
50660 updatePanelTitle : function(panel, title){
50661 if(this.activePanel == panel){
50662 this.updateTitle(title);
50665 var ti = this.tabs.getTab(panel.getEl().id);
50667 if(panel.tabTip !== undefined){
50668 ti.setTooltip(panel.tabTip);
50673 updateTitle : function(title){
50674 if(this.titleTextEl && !this.config.title){
50675 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50679 setActivePanel : function(panel){
50680 panel = this.getPanel(panel);
50681 if(this.activePanel && this.activePanel != panel){
50682 this.activePanel.setActiveState(false);
50684 this.activePanel = panel;
50685 panel.setActiveState(true);
50686 if(this.panelSize){
50687 panel.setSize(this.panelSize.width, this.panelSize.height);
50690 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50692 this.updateTitle(panel.getTitle());
50694 this.fireEvent("invalidated", this);
50696 this.fireEvent("panelactivated", this, panel);
50700 * Shows the specified panel.
50701 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50702 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50704 showPanel : function(panel)
50706 panel = this.getPanel(panel);
50709 var tab = this.tabs.getTab(panel.getEl().id);
50710 if(tab.isHidden()){
50711 this.tabs.unhideTab(tab.id);
50715 this.setActivePanel(panel);
50722 * Get the active panel for this region.
50723 * @return {Roo.ContentPanel} The active panel or null
50725 getActivePanel : function(){
50726 return this.activePanel;
50729 validateVisibility : function(){
50730 if(this.panels.getCount() < 1){
50731 this.updateTitle(" ");
50732 this.closeBtn.hide();
50735 if(!this.isVisible()){
50742 * Adds the passed ContentPanel(s) to this region.
50743 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50744 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50746 add : function(panel){
50747 if(arguments.length > 1){
50748 for(var i = 0, len = arguments.length; i < len; i++) {
50749 this.add(arguments[i]);
50753 if(this.hasPanel(panel)){
50754 this.showPanel(panel);
50757 panel.setRegion(this);
50758 this.panels.add(panel);
50759 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50760 this.bodyEl.dom.appendChild(panel.getEl().dom);
50761 if(panel.background !== true){
50762 this.setActivePanel(panel);
50764 this.fireEvent("paneladded", this, panel);
50770 this.initPanelAsTab(panel);
50772 if(panel.background !== true){
50773 this.tabs.activate(panel.getEl().id);
50775 this.fireEvent("paneladded", this, panel);
50780 * Hides the tab for the specified panel.
50781 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50783 hidePanel : function(panel){
50784 if(this.tabs && (panel = this.getPanel(panel))){
50785 this.tabs.hideTab(panel.getEl().id);
50790 * Unhides the tab for a previously hidden panel.
50791 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50793 unhidePanel : function(panel){
50794 if(this.tabs && (panel = this.getPanel(panel))){
50795 this.tabs.unhideTab(panel.getEl().id);
50799 clearPanels : function(){
50800 while(this.panels.getCount() > 0){
50801 this.remove(this.panels.first());
50806 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50807 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50808 * @param {Boolean} preservePanel Overrides the config preservePanel option
50809 * @return {Roo.ContentPanel} The panel that was removed
50811 remove : function(panel, preservePanel){
50812 panel = this.getPanel(panel);
50817 this.fireEvent("beforeremove", this, panel, e);
50818 if(e.cancel === true){
50821 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50822 var panelId = panel.getId();
50823 this.panels.removeKey(panelId);
50825 document.body.appendChild(panel.getEl().dom);
50828 this.tabs.removeTab(panel.getEl().id);
50829 }else if (!preservePanel){
50830 this.bodyEl.dom.removeChild(panel.getEl().dom);
50832 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50833 var p = this.panels.first();
50834 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50835 tempEl.appendChild(p.getEl().dom);
50836 this.bodyEl.update("");
50837 this.bodyEl.dom.appendChild(p.getEl().dom);
50839 this.updateTitle(p.getTitle());
50841 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50842 this.setActivePanel(p);
50844 panel.setRegion(null);
50845 if(this.activePanel == panel){
50846 this.activePanel = null;
50848 if(this.config.autoDestroy !== false && preservePanel !== true){
50849 try{panel.destroy();}catch(e){}
50851 this.fireEvent("panelremoved", this, panel);
50856 * Returns the TabPanel component used by this region
50857 * @return {Roo.TabPanel}
50859 getTabs : function(){
50863 createTool : function(parentEl, className){
50864 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50865 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50866 btn.addClassOnOver("x-layout-tools-button-over");
50871 * Ext JS Library 1.1.1
50872 * Copyright(c) 2006-2007, Ext JS, LLC.
50874 * Originally Released Under LGPL - original licence link has changed is not relivant.
50877 * <script type="text/javascript">
50883 * @class Roo.SplitLayoutRegion
50884 * @extends Roo.LayoutRegion
50885 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50887 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50888 this.cursor = cursor;
50889 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50892 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50893 splitTip : "Drag to resize.",
50894 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50895 useSplitTips : false,
50897 applyConfig : function(config){
50898 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50901 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50902 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50903 /** The SplitBar for this region
50904 * @type Roo.SplitBar */
50905 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50906 this.split.on("moved", this.onSplitMove, this);
50907 this.split.useShim = config.useShim === true;
50908 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50909 if(this.useSplitTips){
50910 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50912 if(config.collapsible){
50913 this.split.el.on("dblclick", this.collapse, this);
50916 if(typeof config.minSize != "undefined"){
50917 this.split.minSize = config.minSize;
50919 if(typeof config.maxSize != "undefined"){
50920 this.split.maxSize = config.maxSize;
50922 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50923 this.hideSplitter();
50928 getHMaxSize : function(){
50929 var cmax = this.config.maxSize || 10000;
50930 var center = this.mgr.getRegion("center");
50931 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50934 getVMaxSize : function(){
50935 var cmax = this.config.maxSize || 10000;
50936 var center = this.mgr.getRegion("center");
50937 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50940 onSplitMove : function(split, newSize){
50941 this.fireEvent("resized", this, newSize);
50945 * Returns the {@link Roo.SplitBar} for this region.
50946 * @return {Roo.SplitBar}
50948 getSplitBar : function(){
50953 this.hideSplitter();
50954 Roo.SplitLayoutRegion.superclass.hide.call(this);
50957 hideSplitter : function(){
50959 this.split.el.setLocation(-2000,-2000);
50960 this.split.el.hide();
50966 this.split.el.show();
50968 Roo.SplitLayoutRegion.superclass.show.call(this);
50971 beforeSlide: function(){
50972 if(Roo.isGecko){// firefox overflow auto bug workaround
50973 this.bodyEl.clip();
50975 this.tabs.bodyEl.clip();
50977 if(this.activePanel){
50978 this.activePanel.getEl().clip();
50980 if(this.activePanel.beforeSlide){
50981 this.activePanel.beforeSlide();
50987 afterSlide : function(){
50988 if(Roo.isGecko){// firefox overflow auto bug workaround
50989 this.bodyEl.unclip();
50991 this.tabs.bodyEl.unclip();
50993 if(this.activePanel){
50994 this.activePanel.getEl().unclip();
50995 if(this.activePanel.afterSlide){
50996 this.activePanel.afterSlide();
51002 initAutoHide : function(){
51003 if(this.autoHide !== false){
51004 if(!this.autoHideHd){
51005 var st = new Roo.util.DelayedTask(this.slideIn, this);
51006 this.autoHideHd = {
51007 "mouseout": function(e){
51008 if(!e.within(this.el, true)){
51012 "mouseover" : function(e){
51018 this.el.on(this.autoHideHd);
51022 clearAutoHide : function(){
51023 if(this.autoHide !== false){
51024 this.el.un("mouseout", this.autoHideHd.mouseout);
51025 this.el.un("mouseover", this.autoHideHd.mouseover);
51029 clearMonitor : function(){
51030 Roo.get(document).un("click", this.slideInIf, this);
51033 // these names are backwards but not changed for compat
51034 slideOut : function(){
51035 if(this.isSlid || this.el.hasActiveFx()){
51038 this.isSlid = true;
51039 if(this.collapseBtn){
51040 this.collapseBtn.hide();
51042 this.closeBtnState = this.closeBtn.getStyle('display');
51043 this.closeBtn.hide();
51045 this.stickBtn.show();
51048 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
51049 this.beforeSlide();
51050 this.el.setStyle("z-index", 10001);
51051 this.el.slideIn(this.getSlideAnchor(), {
51052 callback: function(){
51054 this.initAutoHide();
51055 Roo.get(document).on("click", this.slideInIf, this);
51056 this.fireEvent("slideshow", this);
51063 afterSlideIn : function(){
51064 this.clearAutoHide();
51065 this.isSlid = false;
51066 this.clearMonitor();
51067 this.el.setStyle("z-index", "");
51068 if(this.collapseBtn){
51069 this.collapseBtn.show();
51071 this.closeBtn.setStyle('display', this.closeBtnState);
51073 this.stickBtn.hide();
51075 this.fireEvent("slidehide", this);
51078 slideIn : function(cb){
51079 if(!this.isSlid || this.el.hasActiveFx()){
51083 this.isSlid = false;
51084 this.beforeSlide();
51085 this.el.slideOut(this.getSlideAnchor(), {
51086 callback: function(){
51087 this.el.setLeftTop(-10000, -10000);
51089 this.afterSlideIn();
51097 slideInIf : function(e){
51098 if(!e.within(this.el)){
51103 animateCollapse : function(){
51104 this.beforeSlide();
51105 this.el.setStyle("z-index", 20000);
51106 var anchor = this.getSlideAnchor();
51107 this.el.slideOut(anchor, {
51108 callback : function(){
51109 this.el.setStyle("z-index", "");
51110 this.collapsedEl.slideIn(anchor, {duration:.3});
51112 this.el.setLocation(-10000,-10000);
51114 this.fireEvent("collapsed", this);
51121 animateExpand : function(){
51122 this.beforeSlide();
51123 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
51124 this.el.setStyle("z-index", 20000);
51125 this.collapsedEl.hide({
51128 this.el.slideIn(this.getSlideAnchor(), {
51129 callback : function(){
51130 this.el.setStyle("z-index", "");
51133 this.split.el.show();
51135 this.fireEvent("invalidated", this);
51136 this.fireEvent("expanded", this);
51164 getAnchor : function(){
51165 return this.anchors[this.position];
51168 getCollapseAnchor : function(){
51169 return this.canchors[this.position];
51172 getSlideAnchor : function(){
51173 return this.sanchors[this.position];
51176 getAlignAdj : function(){
51177 var cm = this.cmargins;
51178 switch(this.position){
51194 getExpandAdj : function(){
51195 var c = this.collapsedEl, cm = this.cmargins;
51196 switch(this.position){
51198 return [-(cm.right+c.getWidth()+cm.left), 0];
51201 return [cm.right+c.getWidth()+cm.left, 0];
51204 return [0, -(cm.top+cm.bottom+c.getHeight())];
51207 return [0, cm.top+cm.bottom+c.getHeight()];
51213 * Ext JS Library 1.1.1
51214 * Copyright(c) 2006-2007, Ext JS, LLC.
51216 * Originally Released Under LGPL - original licence link has changed is not relivant.
51219 * <script type="text/javascript">
51222 * These classes are private internal classes
51224 Roo.CenterLayoutRegion = function(mgr, config){
51225 Roo.LayoutRegion.call(this, mgr, config, "center");
51226 this.visible = true;
51227 this.minWidth = config.minWidth || 20;
51228 this.minHeight = config.minHeight || 20;
51231 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
51233 // center panel can't be hidden
51237 // center panel can't be hidden
51240 getMinWidth: function(){
51241 return this.minWidth;
51244 getMinHeight: function(){
51245 return this.minHeight;
51250 Roo.NorthLayoutRegion = function(mgr, config){
51251 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
51253 this.split.placement = Roo.SplitBar.TOP;
51254 this.split.orientation = Roo.SplitBar.VERTICAL;
51255 this.split.el.addClass("x-layout-split-v");
51257 var size = config.initialSize || config.height;
51258 if(typeof size != "undefined"){
51259 this.el.setHeight(size);
51262 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
51263 orientation: Roo.SplitBar.VERTICAL,
51264 getBox : function(){
51265 if(this.collapsed){
51266 return this.collapsedEl.getBox();
51268 var box = this.el.getBox();
51270 box.height += this.split.el.getHeight();
51275 updateBox : function(box){
51276 if(this.split && !this.collapsed){
51277 box.height -= this.split.el.getHeight();
51278 this.split.el.setLeft(box.x);
51279 this.split.el.setTop(box.y+box.height);
51280 this.split.el.setWidth(box.width);
51282 if(this.collapsed){
51283 this.updateBody(box.width, null);
51285 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51289 Roo.SouthLayoutRegion = function(mgr, config){
51290 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
51292 this.split.placement = Roo.SplitBar.BOTTOM;
51293 this.split.orientation = Roo.SplitBar.VERTICAL;
51294 this.split.el.addClass("x-layout-split-v");
51296 var size = config.initialSize || config.height;
51297 if(typeof size != "undefined"){
51298 this.el.setHeight(size);
51301 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
51302 orientation: Roo.SplitBar.VERTICAL,
51303 getBox : function(){
51304 if(this.collapsed){
51305 return this.collapsedEl.getBox();
51307 var box = this.el.getBox();
51309 var sh = this.split.el.getHeight();
51316 updateBox : function(box){
51317 if(this.split && !this.collapsed){
51318 var sh = this.split.el.getHeight();
51321 this.split.el.setLeft(box.x);
51322 this.split.el.setTop(box.y-sh);
51323 this.split.el.setWidth(box.width);
51325 if(this.collapsed){
51326 this.updateBody(box.width, null);
51328 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51332 Roo.EastLayoutRegion = function(mgr, config){
51333 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
51335 this.split.placement = Roo.SplitBar.RIGHT;
51336 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51337 this.split.el.addClass("x-layout-split-h");
51339 var size = config.initialSize || config.width;
51340 if(typeof size != "undefined"){
51341 this.el.setWidth(size);
51344 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
51345 orientation: Roo.SplitBar.HORIZONTAL,
51346 getBox : function(){
51347 if(this.collapsed){
51348 return this.collapsedEl.getBox();
51350 var box = this.el.getBox();
51352 var sw = this.split.el.getWidth();
51359 updateBox : function(box){
51360 if(this.split && !this.collapsed){
51361 var sw = this.split.el.getWidth();
51363 this.split.el.setLeft(box.x);
51364 this.split.el.setTop(box.y);
51365 this.split.el.setHeight(box.height);
51368 if(this.collapsed){
51369 this.updateBody(null, box.height);
51371 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51375 Roo.WestLayoutRegion = function(mgr, config){
51376 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
51378 this.split.placement = Roo.SplitBar.LEFT;
51379 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51380 this.split.el.addClass("x-layout-split-h");
51382 var size = config.initialSize || config.width;
51383 if(typeof size != "undefined"){
51384 this.el.setWidth(size);
51387 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
51388 orientation: Roo.SplitBar.HORIZONTAL,
51389 getBox : function(){
51390 if(this.collapsed){
51391 return this.collapsedEl.getBox();
51393 var box = this.el.getBox();
51395 box.width += this.split.el.getWidth();
51400 updateBox : function(box){
51401 if(this.split && !this.collapsed){
51402 var sw = this.split.el.getWidth();
51404 this.split.el.setLeft(box.x+box.width);
51405 this.split.el.setTop(box.y);
51406 this.split.el.setHeight(box.height);
51408 if(this.collapsed){
51409 this.updateBody(null, box.height);
51411 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51416 * Ext JS Library 1.1.1
51417 * Copyright(c) 2006-2007, Ext JS, LLC.
51419 * Originally Released Under LGPL - original licence link has changed is not relivant.
51422 * <script type="text/javascript">
51427 * Private internal class for reading and applying state
51429 Roo.LayoutStateManager = function(layout){
51430 // default empty state
51439 Roo.LayoutStateManager.prototype = {
51440 init : function(layout, provider){
51441 this.provider = provider;
51442 var state = provider.get(layout.id+"-layout-state");
51444 var wasUpdating = layout.isUpdating();
51446 layout.beginUpdate();
51448 for(var key in state){
51449 if(typeof state[key] != "function"){
51450 var rstate = state[key];
51451 var r = layout.getRegion(key);
51454 r.resizeTo(rstate.size);
51456 if(rstate.collapsed == true){
51459 r.expand(null, true);
51465 layout.endUpdate();
51467 this.state = state;
51469 this.layout = layout;
51470 layout.on("regionresized", this.onRegionResized, this);
51471 layout.on("regioncollapsed", this.onRegionCollapsed, this);
51472 layout.on("regionexpanded", this.onRegionExpanded, this);
51475 storeState : function(){
51476 this.provider.set(this.layout.id+"-layout-state", this.state);
51479 onRegionResized : function(region, newSize){
51480 this.state[region.getPosition()].size = newSize;
51484 onRegionCollapsed : function(region){
51485 this.state[region.getPosition()].collapsed = true;
51489 onRegionExpanded : function(region){
51490 this.state[region.getPosition()].collapsed = false;
51495 * Ext JS Library 1.1.1
51496 * Copyright(c) 2006-2007, Ext JS, LLC.
51498 * Originally Released Under LGPL - original licence link has changed is not relivant.
51501 * <script type="text/javascript">
51504 * @class Roo.ContentPanel
51505 * @extends Roo.util.Observable
51506 * A basic ContentPanel element.
51507 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
51508 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
51509 * @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
51510 * @cfg {Boolean} closable True if the panel can be closed/removed
51511 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
51512 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
51513 * @cfg {Toolbar} toolbar A toolbar for this panel
51514 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
51515 * @cfg {String} title The title for this panel
51516 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
51517 * @cfg {String} url Calls {@link #setUrl} with this value
51518 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
51519 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
51520 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
51521 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
51524 * Create a new ContentPanel.
51525 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
51526 * @param {String/Object} config A string to set only the title or a config object
51527 * @param {String} content (optional) Set the HTML content for this panel
51528 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
51530 Roo.ContentPanel = function(el, config, content){
51534 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
51538 if (config && config.parentLayout) {
51539 el = config.parentLayout.el.createChild();
51542 if(el.autoCreate){ // xtype is available if this is called from factory
51546 this.el = Roo.get(el);
51547 if(!this.el && config && config.autoCreate){
51548 if(typeof config.autoCreate == "object"){
51549 if(!config.autoCreate.id){
51550 config.autoCreate.id = config.id||el;
51552 this.el = Roo.DomHelper.append(document.body,
51553 config.autoCreate, true);
51555 this.el = Roo.DomHelper.append(document.body,
51556 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
51559 this.closable = false;
51560 this.loaded = false;
51561 this.active = false;
51562 if(typeof config == "string"){
51563 this.title = config;
51565 Roo.apply(this, config);
51568 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
51569 this.wrapEl = this.el.wrap();
51570 this.toolbar.container = this.el.insertSibling(false, 'before');
51571 this.toolbar = new Roo.Toolbar(this.toolbar);
51574 // xtype created footer. - not sure if will work as we normally have to render first..
51575 if (this.footer && !this.footer.el && this.footer.xtype) {
51576 if (!this.wrapEl) {
51577 this.wrapEl = this.el.wrap();
51580 this.footer.container = this.wrapEl.createChild();
51582 this.footer = Roo.factory(this.footer, Roo);
51587 this.resizeEl = Roo.get(this.resizeEl, true);
51589 this.resizeEl = this.el;
51591 // handle view.xtype
51599 * Fires when this panel is activated.
51600 * @param {Roo.ContentPanel} this
51604 * @event deactivate
51605 * Fires when this panel is activated.
51606 * @param {Roo.ContentPanel} this
51608 "deactivate" : true,
51612 * Fires when this panel is resized if fitToFrame is true.
51613 * @param {Roo.ContentPanel} this
51614 * @param {Number} width The width after any component adjustments
51615 * @param {Number} height The height after any component adjustments
51621 * Fires when this tab is created
51622 * @param {Roo.ContentPanel} this
51633 if(this.autoScroll){
51634 this.resizeEl.setStyle("overflow", "auto");
51636 // fix randome scrolling
51637 this.el.on('scroll', function() {
51638 Roo.log('fix random scolling');
51639 this.scrollTo('top',0);
51642 content = content || this.content;
51644 this.setContent(content);
51646 if(config && config.url){
51647 this.setUrl(this.url, this.params, this.loadOnce);
51652 Roo.ContentPanel.superclass.constructor.call(this);
51654 if (this.view && typeof(this.view.xtype) != 'undefined') {
51655 this.view.el = this.el.appendChild(document.createElement("div"));
51656 this.view = Roo.factory(this.view);
51657 this.view.render && this.view.render(false, '');
51661 this.fireEvent('render', this);
51664 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
51666 setRegion : function(region){
51667 this.region = region;
51669 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
51671 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
51676 * Returns the toolbar for this Panel if one was configured.
51677 * @return {Roo.Toolbar}
51679 getToolbar : function(){
51680 return this.toolbar;
51683 setActiveState : function(active){
51684 this.active = active;
51686 this.fireEvent("deactivate", this);
51688 this.fireEvent("activate", this);
51692 * Updates this panel's element
51693 * @param {String} content The new content
51694 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51696 setContent : function(content, loadScripts){
51697 this.el.update(content, loadScripts);
51700 ignoreResize : function(w, h){
51701 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51704 this.lastSize = {width: w, height: h};
51709 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51710 * @return {Roo.UpdateManager} The UpdateManager
51712 getUpdateManager : function(){
51713 return this.el.getUpdateManager();
51716 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51717 * @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:
51720 url: "your-url.php",
51721 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51722 callback: yourFunction,
51723 scope: yourObject, //(optional scope)
51726 text: "Loading...",
51731 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51732 * 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.
51733 * @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}
51734 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51735 * @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.
51736 * @return {Roo.ContentPanel} this
51739 var um = this.el.getUpdateManager();
51740 um.update.apply(um, arguments);
51746 * 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.
51747 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51748 * @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)
51749 * @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)
51750 * @return {Roo.UpdateManager} The UpdateManager
51752 setUrl : function(url, params, loadOnce){
51753 if(this.refreshDelegate){
51754 this.removeListener("activate", this.refreshDelegate);
51756 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51757 this.on("activate", this.refreshDelegate);
51758 return this.el.getUpdateManager();
51761 _handleRefresh : function(url, params, loadOnce){
51762 if(!loadOnce || !this.loaded){
51763 var updater = this.el.getUpdateManager();
51764 updater.update(url, params, this._setLoaded.createDelegate(this));
51768 _setLoaded : function(){
51769 this.loaded = true;
51773 * Returns this panel's id
51776 getId : function(){
51781 * Returns this panel's element - used by regiosn to add.
51782 * @return {Roo.Element}
51784 getEl : function(){
51785 return this.wrapEl || this.el;
51788 adjustForComponents : function(width, height)
51790 //Roo.log('adjustForComponents ');
51791 if(this.resizeEl != this.el){
51792 width -= this.el.getFrameWidth('lr');
51793 height -= this.el.getFrameWidth('tb');
51796 var te = this.toolbar.getEl();
51797 height -= te.getHeight();
51798 te.setWidth(width);
51801 var te = this.footer.getEl();
51802 Roo.log("footer:" + te.getHeight());
51804 height -= te.getHeight();
51805 te.setWidth(width);
51809 if(this.adjustments){
51810 width += this.adjustments[0];
51811 height += this.adjustments[1];
51813 return {"width": width, "height": height};
51816 setSize : function(width, height){
51817 if(this.fitToFrame && !this.ignoreResize(width, height)){
51818 if(this.fitContainer && this.resizeEl != this.el){
51819 this.el.setSize(width, height);
51821 var size = this.adjustForComponents(width, height);
51822 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51823 this.fireEvent('resize', this, size.width, size.height);
51828 * Returns this panel's title
51831 getTitle : function(){
51836 * Set this panel's title
51837 * @param {String} title
51839 setTitle : function(title){
51840 this.title = title;
51842 this.region.updatePanelTitle(this, title);
51847 * Returns true is this panel was configured to be closable
51848 * @return {Boolean}
51850 isClosable : function(){
51851 return this.closable;
51854 beforeSlide : function(){
51856 this.resizeEl.clip();
51859 afterSlide : function(){
51861 this.resizeEl.unclip();
51865 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51866 * Will fail silently if the {@link #setUrl} method has not been called.
51867 * This does not activate the panel, just updates its content.
51869 refresh : function(){
51870 if(this.refreshDelegate){
51871 this.loaded = false;
51872 this.refreshDelegate();
51877 * Destroys this panel
51879 destroy : function(){
51880 this.el.removeAllListeners();
51881 var tempEl = document.createElement("span");
51882 tempEl.appendChild(this.el.dom);
51883 tempEl.innerHTML = "";
51889 * form - if the content panel contains a form - this is a reference to it.
51890 * @type {Roo.form.Form}
51894 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51895 * This contains a reference to it.
51901 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51911 * @param {Object} cfg Xtype definition of item to add.
51914 addxtype : function(cfg) {
51916 if (cfg.xtype.match(/^Form$/)) {
51919 //if (this.footer) {
51920 // el = this.footer.container.insertSibling(false, 'before');
51922 el = this.el.createChild();
51925 this.form = new Roo.form.Form(cfg);
51928 if ( this.form.allItems.length) {
51929 this.form.render(el.dom);
51933 // should only have one of theses..
51934 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51935 // views.. should not be just added - used named prop 'view''
51937 cfg.el = this.el.appendChild(document.createElement("div"));
51940 var ret = new Roo.factory(cfg);
51942 ret.render && ret.render(false, ''); // render blank..
51951 * @class Roo.GridPanel
51952 * @extends Roo.ContentPanel
51954 * Create a new GridPanel.
51955 * @param {Roo.grid.Grid} grid The grid for this panel
51956 * @param {String/Object} config A string to set only the panel's title, or a config object
51958 Roo.GridPanel = function(grid, config){
51961 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51962 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51964 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51966 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51969 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51971 // xtype created footer. - not sure if will work as we normally have to render first..
51972 if (this.footer && !this.footer.el && this.footer.xtype) {
51974 this.footer.container = this.grid.getView().getFooterPanel(true);
51975 this.footer.dataSource = this.grid.dataSource;
51976 this.footer = Roo.factory(this.footer, Roo);
51980 grid.monitorWindowResize = false; // turn off autosizing
51981 grid.autoHeight = false;
51982 grid.autoWidth = false;
51984 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51987 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51988 getId : function(){
51989 return this.grid.id;
51993 * Returns the grid for this panel
51994 * @return {Roo.grid.Grid}
51996 getGrid : function(){
52000 setSize : function(width, height){
52001 if(!this.ignoreResize(width, height)){
52002 var grid = this.grid;
52003 var size = this.adjustForComponents(width, height);
52004 grid.getGridEl().setSize(size.width, size.height);
52009 beforeSlide : function(){
52010 this.grid.getView().scroller.clip();
52013 afterSlide : function(){
52014 this.grid.getView().scroller.unclip();
52017 destroy : function(){
52018 this.grid.destroy();
52020 Roo.GridPanel.superclass.destroy.call(this);
52026 * @class Roo.NestedLayoutPanel
52027 * @extends Roo.ContentPanel
52029 * Create a new NestedLayoutPanel.
52032 * @param {Roo.BorderLayout} layout The layout for this panel
52033 * @param {String/Object} config A string to set only the title or a config object
52035 Roo.NestedLayoutPanel = function(layout, config)
52037 // construct with only one argument..
52038 /* FIXME - implement nicer consturctors
52039 if (layout.layout) {
52041 layout = config.layout;
52042 delete config.layout;
52044 if (layout.xtype && !layout.getEl) {
52045 // then layout needs constructing..
52046 layout = Roo.factory(layout, Roo);
52051 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
52053 layout.monitorWindowResize = false; // turn off autosizing
52054 this.layout = layout;
52055 this.layout.getEl().addClass("x-layout-nested-layout");
52062 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
52064 setSize : function(width, height){
52065 if(!this.ignoreResize(width, height)){
52066 var size = this.adjustForComponents(width, height);
52067 var el = this.layout.getEl();
52068 el.setSize(size.width, size.height);
52069 var touch = el.dom.offsetWidth;
52070 this.layout.layout();
52071 // ie requires a double layout on the first pass
52072 if(Roo.isIE && !this.initialized){
52073 this.initialized = true;
52074 this.layout.layout();
52079 // activate all subpanels if not currently active..
52081 setActiveState : function(active){
52082 this.active = active;
52084 this.fireEvent("deactivate", this);
52088 this.fireEvent("activate", this);
52089 // not sure if this should happen before or after..
52090 if (!this.layout) {
52091 return; // should not happen..
52094 for (var r in this.layout.regions) {
52095 reg = this.layout.getRegion(r);
52096 if (reg.getActivePanel()) {
52097 //reg.showPanel(reg.getActivePanel()); // force it to activate..
52098 reg.setActivePanel(reg.getActivePanel());
52101 if (!reg.panels.length) {
52104 reg.showPanel(reg.getPanel(0));
52113 * Returns the nested BorderLayout for this panel
52114 * @return {Roo.BorderLayout}
52116 getLayout : function(){
52117 return this.layout;
52121 * Adds a xtype elements to the layout of the nested panel
52125 xtype : 'ContentPanel',
52132 xtype : 'NestedLayoutPanel',
52138 items : [ ... list of content panels or nested layout panels.. ]
52142 * @param {Object} cfg Xtype definition of item to add.
52144 addxtype : function(cfg) {
52145 return this.layout.addxtype(cfg);
52150 Roo.ScrollPanel = function(el, config, content){
52151 config = config || {};
52152 config.fitToFrame = true;
52153 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
52155 this.el.dom.style.overflow = "hidden";
52156 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
52157 this.el.removeClass("x-layout-inactive-content");
52158 this.el.on("mousewheel", this.onWheel, this);
52160 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
52161 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
52162 up.unselectable(); down.unselectable();
52163 up.on("click", this.scrollUp, this);
52164 down.on("click", this.scrollDown, this);
52165 up.addClassOnOver("x-scroller-btn-over");
52166 down.addClassOnOver("x-scroller-btn-over");
52167 up.addClassOnClick("x-scroller-btn-click");
52168 down.addClassOnClick("x-scroller-btn-click");
52169 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
52171 this.resizeEl = this.el;
52172 this.el = wrap; this.up = up; this.down = down;
52175 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
52177 wheelIncrement : 5,
52178 scrollUp : function(){
52179 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
52182 scrollDown : function(){
52183 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
52186 afterScroll : function(){
52187 var el = this.resizeEl;
52188 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
52189 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52190 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52193 setSize : function(){
52194 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
52195 this.afterScroll();
52198 onWheel : function(e){
52199 var d = e.getWheelDelta();
52200 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
52201 this.afterScroll();
52205 setContent : function(content, loadScripts){
52206 this.resizeEl.update(content, loadScripts);
52220 * @class Roo.TreePanel
52221 * @extends Roo.ContentPanel
52223 * Create a new TreePanel. - defaults to fit/scoll contents.
52224 * @param {String/Object} config A string to set only the panel's title, or a config object
52225 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
52227 Roo.TreePanel = function(config){
52228 var el = config.el;
52229 var tree = config.tree;
52230 delete config.tree;
52231 delete config.el; // hopefull!
52233 // wrapper for IE7 strict & safari scroll issue
52235 var treeEl = el.createChild();
52236 config.resizeEl = treeEl;
52240 Roo.TreePanel.superclass.constructor.call(this, el, config);
52243 this.tree = new Roo.tree.TreePanel(treeEl , tree);
52244 //console.log(tree);
52245 this.on('activate', function()
52247 if (this.tree.rendered) {
52250 //console.log('render tree');
52251 this.tree.render();
52253 // this should not be needed.. - it's actually the 'el' that resizes?
52254 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
52256 //this.on('resize', function (cp, w, h) {
52257 // this.tree.innerCt.setWidth(w);
52258 // this.tree.innerCt.setHeight(h);
52259 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
52266 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
52283 * Ext JS Library 1.1.1
52284 * Copyright(c) 2006-2007, Ext JS, LLC.
52286 * Originally Released Under LGPL - original licence link has changed is not relivant.
52289 * <script type="text/javascript">
52294 * @class Roo.ReaderLayout
52295 * @extends Roo.BorderLayout
52296 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
52297 * center region containing two nested regions (a top one for a list view and one for item preview below),
52298 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
52299 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
52300 * expedites the setup of the overall layout and regions for this common application style.
52303 var reader = new Roo.ReaderLayout();
52304 var CP = Roo.ContentPanel; // shortcut for adding
52306 reader.beginUpdate();
52307 reader.add("north", new CP("north", "North"));
52308 reader.add("west", new CP("west", {title: "West"}));
52309 reader.add("east", new CP("east", {title: "East"}));
52311 reader.regions.listView.add(new CP("listView", "List"));
52312 reader.regions.preview.add(new CP("preview", "Preview"));
52313 reader.endUpdate();
52316 * Create a new ReaderLayout
52317 * @param {Object} config Configuration options
52318 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
52319 * document.body if omitted)
52321 Roo.ReaderLayout = function(config, renderTo){
52322 var c = config || {size:{}};
52323 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
52324 north: c.north !== false ? Roo.apply({
52328 }, c.north) : false,
52329 west: c.west !== false ? Roo.apply({
52337 margins:{left:5,right:0,bottom:5,top:5},
52338 cmargins:{left:5,right:5,bottom:5,top:5}
52339 }, c.west) : false,
52340 east: c.east !== false ? Roo.apply({
52348 margins:{left:0,right:5,bottom:5,top:5},
52349 cmargins:{left:5,right:5,bottom:5,top:5}
52350 }, c.east) : false,
52351 center: Roo.apply({
52352 tabPosition: 'top',
52356 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
52360 this.el.addClass('x-reader');
52362 this.beginUpdate();
52364 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
52365 south: c.preview !== false ? Roo.apply({
52372 cmargins:{top:5,left:0, right:0, bottom:0}
52373 }, c.preview) : false,
52374 center: Roo.apply({
52380 this.add('center', new Roo.NestedLayoutPanel(inner,
52381 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
52385 this.regions.preview = inner.getRegion('south');
52386 this.regions.listView = inner.getRegion('center');
52389 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
52391 * Ext JS Library 1.1.1
52392 * Copyright(c) 2006-2007, Ext JS, LLC.
52394 * Originally Released Under LGPL - original licence link has changed is not relivant.
52397 * <script type="text/javascript">
52401 * @class Roo.grid.Grid
52402 * @extends Roo.util.Observable
52403 * This class represents the primary interface of a component based grid control.
52404 * <br><br>Usage:<pre><code>
52405 var grid = new Roo.grid.Grid("my-container-id", {
52408 selModel: mySelectionModel,
52409 autoSizeColumns: true,
52410 monitorWindowResize: false,
52411 trackMouseOver: true
52416 * <b>Common Problems:</b><br/>
52417 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
52418 * element will correct this<br/>
52419 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
52420 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
52421 * are unpredictable.<br/>
52422 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
52423 * grid to calculate dimensions/offsets.<br/>
52425 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
52426 * The container MUST have some type of size defined for the grid to fill. The container will be
52427 * automatically set to position relative if it isn't already.
52428 * @param {Object} config A config object that sets properties on this grid.
52430 Roo.grid.Grid = function(container, config){
52431 // initialize the container
52432 this.container = Roo.get(container);
52433 this.container.update("");
52434 this.container.setStyle("overflow", "hidden");
52435 this.container.addClass('x-grid-container');
52437 this.id = this.container.id;
52439 Roo.apply(this, config);
52440 // check and correct shorthanded configs
52442 this.dataSource = this.ds;
52446 this.colModel = this.cm;
52450 this.selModel = this.sm;
52454 if (this.selModel) {
52455 this.selModel = Roo.factory(this.selModel, Roo.grid);
52456 this.sm = this.selModel;
52457 this.sm.xmodule = this.xmodule || false;
52459 if (typeof(this.colModel.config) == 'undefined') {
52460 this.colModel = new Roo.grid.ColumnModel(this.colModel);
52461 this.cm = this.colModel;
52462 this.cm.xmodule = this.xmodule || false;
52464 if (this.dataSource) {
52465 this.dataSource= Roo.factory(this.dataSource, Roo.data);
52466 this.ds = this.dataSource;
52467 this.ds.xmodule = this.xmodule || false;
52474 this.container.setWidth(this.width);
52478 this.container.setHeight(this.height);
52485 * The raw click event for the entire grid.
52486 * @param {Roo.EventObject} e
52491 * The raw dblclick event for the entire grid.
52492 * @param {Roo.EventObject} e
52496 * @event contextmenu
52497 * The raw contextmenu event for the entire grid.
52498 * @param {Roo.EventObject} e
52500 "contextmenu" : true,
52503 * The raw mousedown event for the entire grid.
52504 * @param {Roo.EventObject} e
52506 "mousedown" : true,
52509 * The raw mouseup event for the entire grid.
52510 * @param {Roo.EventObject} e
52515 * The raw mouseover event for the entire grid.
52516 * @param {Roo.EventObject} e
52518 "mouseover" : true,
52521 * The raw mouseout event for the entire grid.
52522 * @param {Roo.EventObject} e
52527 * The raw keypress event for the entire grid.
52528 * @param {Roo.EventObject} e
52533 * The raw keydown event for the entire grid.
52534 * @param {Roo.EventObject} e
52542 * Fires when a cell is clicked
52543 * @param {Grid} this
52544 * @param {Number} rowIndex
52545 * @param {Number} columnIndex
52546 * @param {Roo.EventObject} e
52548 "cellclick" : true,
52550 * @event celldblclick
52551 * Fires when a cell is double clicked
52552 * @param {Grid} this
52553 * @param {Number} rowIndex
52554 * @param {Number} columnIndex
52555 * @param {Roo.EventObject} e
52557 "celldblclick" : true,
52560 * Fires when a row is clicked
52561 * @param {Grid} this
52562 * @param {Number} rowIndex
52563 * @param {Roo.EventObject} e
52567 * @event rowdblclick
52568 * Fires when a row is double clicked
52569 * @param {Grid} this
52570 * @param {Number} rowIndex
52571 * @param {Roo.EventObject} e
52573 "rowdblclick" : true,
52575 * @event headerclick
52576 * Fires when a header is clicked
52577 * @param {Grid} this
52578 * @param {Number} columnIndex
52579 * @param {Roo.EventObject} e
52581 "headerclick" : true,
52583 * @event headerdblclick
52584 * Fires when a header cell is double clicked
52585 * @param {Grid} this
52586 * @param {Number} columnIndex
52587 * @param {Roo.EventObject} e
52589 "headerdblclick" : true,
52591 * @event rowcontextmenu
52592 * Fires when a row is right clicked
52593 * @param {Grid} this
52594 * @param {Number} rowIndex
52595 * @param {Roo.EventObject} e
52597 "rowcontextmenu" : true,
52599 * @event cellcontextmenu
52600 * Fires when a cell is right clicked
52601 * @param {Grid} this
52602 * @param {Number} rowIndex
52603 * @param {Number} cellIndex
52604 * @param {Roo.EventObject} e
52606 "cellcontextmenu" : true,
52608 * @event headercontextmenu
52609 * Fires when a header is right clicked
52610 * @param {Grid} this
52611 * @param {Number} columnIndex
52612 * @param {Roo.EventObject} e
52614 "headercontextmenu" : true,
52616 * @event bodyscroll
52617 * Fires when the body element is scrolled
52618 * @param {Number} scrollLeft
52619 * @param {Number} scrollTop
52621 "bodyscroll" : true,
52623 * @event columnresize
52624 * Fires when the user resizes a column
52625 * @param {Number} columnIndex
52626 * @param {Number} newSize
52628 "columnresize" : true,
52630 * @event columnmove
52631 * Fires when the user moves a column
52632 * @param {Number} oldIndex
52633 * @param {Number} newIndex
52635 "columnmove" : true,
52638 * Fires when row(s) start being dragged
52639 * @param {Grid} this
52640 * @param {Roo.GridDD} dd The drag drop object
52641 * @param {event} e The raw browser event
52643 "startdrag" : true,
52646 * Fires when a drag operation is complete
52647 * @param {Grid} this
52648 * @param {Roo.GridDD} dd The drag drop object
52649 * @param {event} e The raw browser event
52654 * Fires when dragged row(s) are dropped on a valid DD target
52655 * @param {Grid} this
52656 * @param {Roo.GridDD} dd The drag drop object
52657 * @param {String} targetId The target drag drop object
52658 * @param {event} e The raw browser event
52663 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
52664 * @param {Grid} this
52665 * @param {Roo.GridDD} dd The drag drop object
52666 * @param {String} targetId The target drag drop object
52667 * @param {event} e The raw browser event
52672 * Fires when the dragged row(s) first cross another DD target while being dragged
52673 * @param {Grid} this
52674 * @param {Roo.GridDD} dd The drag drop object
52675 * @param {String} targetId The target drag drop object
52676 * @param {event} e The raw browser event
52678 "dragenter" : true,
52681 * Fires when the dragged row(s) leave another DD target while being dragged
52682 * @param {Grid} this
52683 * @param {Roo.GridDD} dd The drag drop object
52684 * @param {String} targetId The target drag drop object
52685 * @param {event} e The raw browser event
52690 * Fires when a row is rendered, so you can change add a style to it.
52691 * @param {GridView} gridview The grid view
52692 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52698 * Fires when the grid is rendered
52699 * @param {Grid} grid
52704 Roo.grid.Grid.superclass.constructor.call(this);
52706 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52709 * @cfg {String} ddGroup - drag drop group.
52713 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52715 minColumnWidth : 25,
52718 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52719 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52720 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52722 autoSizeColumns : false,
52725 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52727 autoSizeHeaders : true,
52730 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52732 monitorWindowResize : true,
52735 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52736 * rows measured to get a columns size. Default is 0 (all rows).
52738 maxRowsToMeasure : 0,
52741 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52743 trackMouseOver : true,
52746 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52750 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52752 enableDragDrop : false,
52755 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52757 enableColumnMove : true,
52760 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52762 enableColumnHide : true,
52765 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52767 enableRowHeightSync : false,
52770 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52775 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52777 autoHeight : false,
52780 * @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.
52782 autoExpandColumn : false,
52785 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52788 autoExpandMin : 50,
52791 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52793 autoExpandMax : 1000,
52796 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52801 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52805 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52815 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52816 * of a fixed width. Default is false.
52819 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52822 * Called once after all setup has been completed and the grid is ready to be rendered.
52823 * @return {Roo.grid.Grid} this
52825 render : function()
52827 var c = this.container;
52828 // try to detect autoHeight/width mode
52829 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52830 this.autoHeight = true;
52832 var view = this.getView();
52835 c.on("click", this.onClick, this);
52836 c.on("dblclick", this.onDblClick, this);
52837 c.on("contextmenu", this.onContextMenu, this);
52838 c.on("keydown", this.onKeyDown, this);
52840 c.on("touchstart", this.onTouchStart, this);
52843 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52845 this.getSelectionModel().init(this);
52850 this.loadMask = new Roo.LoadMask(this.container,
52851 Roo.apply({store:this.dataSource}, this.loadMask));
52855 if (this.toolbar && this.toolbar.xtype) {
52856 this.toolbar.container = this.getView().getHeaderPanel(true);
52857 this.toolbar = new Roo.Toolbar(this.toolbar);
52859 if (this.footer && this.footer.xtype) {
52860 this.footer.dataSource = this.getDataSource();
52861 this.footer.container = this.getView().getFooterPanel(true);
52862 this.footer = Roo.factory(this.footer, Roo);
52864 if (this.dropTarget && this.dropTarget.xtype) {
52865 delete this.dropTarget.xtype;
52866 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52870 this.rendered = true;
52871 this.fireEvent('render', this);
52876 * Reconfigures the grid to use a different Store and Column Model.
52877 * The View will be bound to the new objects and refreshed.
52878 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52879 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52881 reconfigure : function(dataSource, colModel){
52883 this.loadMask.destroy();
52884 this.loadMask = new Roo.LoadMask(this.container,
52885 Roo.apply({store:dataSource}, this.loadMask));
52887 this.view.bind(dataSource, colModel);
52888 this.dataSource = dataSource;
52889 this.colModel = colModel;
52890 this.view.refresh(true);
52894 onKeyDown : function(e){
52895 this.fireEvent("keydown", e);
52899 * Destroy this grid.
52900 * @param {Boolean} removeEl True to remove the element
52902 destroy : function(removeEl, keepListeners){
52904 this.loadMask.destroy();
52906 var c = this.container;
52907 c.removeAllListeners();
52908 this.view.destroy();
52909 this.colModel.purgeListeners();
52910 if(!keepListeners){
52911 this.purgeListeners();
52914 if(removeEl === true){
52920 processEvent : function(name, e){
52921 // does this fire select???
52922 //Roo.log('grid:processEvent ' + name);
52924 if (name != 'touchstart' ) {
52925 this.fireEvent(name, e);
52928 var t = e.getTarget();
52930 var header = v.findHeaderIndex(t);
52931 if(header !== false){
52932 var ename = name == 'touchstart' ? 'click' : name;
52934 this.fireEvent("header" + ename, this, header, e);
52936 var row = v.findRowIndex(t);
52937 var cell = v.findCellIndex(t);
52938 if (name == 'touchstart') {
52939 // first touch is always a click.
52940 // hopefull this happens after selection is updated.?
52943 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52944 var cs = this.selModel.getSelectedCell();
52945 if (row == cs[0] && cell == cs[1]){
52949 if (typeof(this.selModel.getSelections) != 'undefined') {
52950 var cs = this.selModel.getSelections();
52951 var ds = this.dataSource;
52952 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52963 this.fireEvent("row" + name, this, row, e);
52964 if(cell !== false){
52965 this.fireEvent("cell" + name, this, row, cell, e);
52972 onClick : function(e){
52973 this.processEvent("click", e);
52976 onTouchStart : function(e){
52977 this.processEvent("touchstart", e);
52981 onContextMenu : function(e, t){
52982 this.processEvent("contextmenu", e);
52986 onDblClick : function(e){
52987 this.processEvent("dblclick", e);
52991 walkCells : function(row, col, step, fn, scope){
52992 var cm = this.colModel, clen = cm.getColumnCount();
52993 var ds = this.dataSource, rlen = ds.getCount(), first = true;
53005 if(fn.call(scope || this, row, col, cm) === true){
53023 if(fn.call(scope || this, row, col, cm) === true){
53035 getSelections : function(){
53036 return this.selModel.getSelections();
53040 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
53041 * but if manual update is required this method will initiate it.
53043 autoSize : function(){
53045 this.view.layout();
53046 if(this.view.adjustForScroll){
53047 this.view.adjustForScroll();
53053 * Returns the grid's underlying element.
53054 * @return {Element} The element
53056 getGridEl : function(){
53057 return this.container;
53060 // private for compatibility, overridden by editor grid
53061 stopEditing : function(){},
53064 * Returns the grid's SelectionModel.
53065 * @return {SelectionModel}
53067 getSelectionModel : function(){
53068 if(!this.selModel){
53069 this.selModel = new Roo.grid.RowSelectionModel();
53071 return this.selModel;
53075 * Returns the grid's DataSource.
53076 * @return {DataSource}
53078 getDataSource : function(){
53079 return this.dataSource;
53083 * Returns the grid's ColumnModel.
53084 * @return {ColumnModel}
53086 getColumnModel : function(){
53087 return this.colModel;
53091 * Returns the grid's GridView object.
53092 * @return {GridView}
53094 getView : function(){
53096 this.view = new Roo.grid.GridView(this.viewConfig);
53101 * Called to get grid's drag proxy text, by default returns this.ddText.
53104 getDragDropText : function(){
53105 var count = this.selModel.getCount();
53106 return String.format(this.ddText, count, count == 1 ? '' : 's');
53110 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
53111 * %0 is replaced with the number of selected rows.
53114 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
53116 * Ext JS Library 1.1.1
53117 * Copyright(c) 2006-2007, Ext JS, LLC.
53119 * Originally Released Under LGPL - original licence link has changed is not relivant.
53122 * <script type="text/javascript">
53125 Roo.grid.AbstractGridView = function(){
53129 "beforerowremoved" : true,
53130 "beforerowsinserted" : true,
53131 "beforerefresh" : true,
53132 "rowremoved" : true,
53133 "rowsinserted" : true,
53134 "rowupdated" : true,
53137 Roo.grid.AbstractGridView.superclass.constructor.call(this);
53140 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
53141 rowClass : "x-grid-row",
53142 cellClass : "x-grid-cell",
53143 tdClass : "x-grid-td",
53144 hdClass : "x-grid-hd",
53145 splitClass : "x-grid-hd-split",
53147 init: function(grid){
53149 var cid = this.grid.getGridEl().id;
53150 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
53151 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
53152 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
53153 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
53156 getColumnRenderers : function(){
53157 var renderers = [];
53158 var cm = this.grid.colModel;
53159 var colCount = cm.getColumnCount();
53160 for(var i = 0; i < colCount; i++){
53161 renderers[i] = cm.getRenderer(i);
53166 getColumnIds : function(){
53168 var cm = this.grid.colModel;
53169 var colCount = cm.getColumnCount();
53170 for(var i = 0; i < colCount; i++){
53171 ids[i] = cm.getColumnId(i);
53176 getDataIndexes : function(){
53177 if(!this.indexMap){
53178 this.indexMap = this.buildIndexMap();
53180 return this.indexMap.colToData;
53183 getColumnIndexByDataIndex : function(dataIndex){
53184 if(!this.indexMap){
53185 this.indexMap = this.buildIndexMap();
53187 return this.indexMap.dataToCol[dataIndex];
53191 * Set a css style for a column dynamically.
53192 * @param {Number} colIndex The index of the column
53193 * @param {String} name The css property name
53194 * @param {String} value The css value
53196 setCSSStyle : function(colIndex, name, value){
53197 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
53198 Roo.util.CSS.updateRule(selector, name, value);
53201 generateRules : function(cm){
53202 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
53203 Roo.util.CSS.removeStyleSheet(rulesId);
53204 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53205 var cid = cm.getColumnId(i);
53206 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
53207 this.tdSelector, cid, " {\n}\n",
53208 this.hdSelector, cid, " {\n}\n",
53209 this.splitSelector, cid, " {\n}\n");
53211 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53215 * Ext JS Library 1.1.1
53216 * Copyright(c) 2006-2007, Ext JS, LLC.
53218 * Originally Released Under LGPL - original licence link has changed is not relivant.
53221 * <script type="text/javascript">
53225 // This is a support class used internally by the Grid components
53226 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
53228 this.view = grid.getView();
53229 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53230 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
53232 this.setHandleElId(Roo.id(hd));
53233 this.setOuterHandleElId(Roo.id(hd2));
53235 this.scroll = false;
53237 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
53239 getDragData : function(e){
53240 var t = Roo.lib.Event.getTarget(e);
53241 var h = this.view.findHeaderCell(t);
53243 return {ddel: h.firstChild, header:h};
53248 onInitDrag : function(e){
53249 this.view.headersDisabled = true;
53250 var clone = this.dragData.ddel.cloneNode(true);
53251 clone.id = Roo.id();
53252 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
53253 this.proxy.update(clone);
53257 afterValidDrop : function(){
53259 setTimeout(function(){
53260 v.headersDisabled = false;
53264 afterInvalidDrop : function(){
53266 setTimeout(function(){
53267 v.headersDisabled = false;
53273 * Ext JS Library 1.1.1
53274 * Copyright(c) 2006-2007, Ext JS, LLC.
53276 * Originally Released Under LGPL - original licence link has changed is not relivant.
53279 * <script type="text/javascript">
53282 // This is a support class used internally by the Grid components
53283 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
53285 this.view = grid.getView();
53286 // split the proxies so they don't interfere with mouse events
53287 this.proxyTop = Roo.DomHelper.append(document.body, {
53288 cls:"col-move-top", html:" "
53290 this.proxyBottom = Roo.DomHelper.append(document.body, {
53291 cls:"col-move-bottom", html:" "
53293 this.proxyTop.hide = this.proxyBottom.hide = function(){
53294 this.setLeftTop(-100,-100);
53295 this.setStyle("visibility", "hidden");
53297 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53298 // temporarily disabled
53299 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
53300 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
53302 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
53303 proxyOffsets : [-4, -9],
53304 fly: Roo.Element.fly,
53306 getTargetFromEvent : function(e){
53307 var t = Roo.lib.Event.getTarget(e);
53308 var cindex = this.view.findCellIndex(t);
53309 if(cindex !== false){
53310 return this.view.getHeaderCell(cindex);
53315 nextVisible : function(h){
53316 var v = this.view, cm = this.grid.colModel;
53319 if(!cm.isHidden(v.getCellIndex(h))){
53327 prevVisible : function(h){
53328 var v = this.view, cm = this.grid.colModel;
53331 if(!cm.isHidden(v.getCellIndex(h))){
53339 positionIndicator : function(h, n, e){
53340 var x = Roo.lib.Event.getPageX(e);
53341 var r = Roo.lib.Dom.getRegion(n.firstChild);
53342 var px, pt, py = r.top + this.proxyOffsets[1];
53343 if((r.right - x) <= (r.right-r.left)/2){
53344 px = r.right+this.view.borderWidth;
53350 var oldIndex = this.view.getCellIndex(h);
53351 var newIndex = this.view.getCellIndex(n);
53353 if(this.grid.colModel.isFixed(newIndex)){
53357 var locked = this.grid.colModel.isLocked(newIndex);
53362 if(oldIndex < newIndex){
53365 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
53368 px += this.proxyOffsets[0];
53369 this.proxyTop.setLeftTop(px, py);
53370 this.proxyTop.show();
53371 if(!this.bottomOffset){
53372 this.bottomOffset = this.view.mainHd.getHeight();
53374 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
53375 this.proxyBottom.show();
53379 onNodeEnter : function(n, dd, e, data){
53380 if(data.header != n){
53381 this.positionIndicator(data.header, n, e);
53385 onNodeOver : function(n, dd, e, data){
53386 var result = false;
53387 if(data.header != n){
53388 result = this.positionIndicator(data.header, n, e);
53391 this.proxyTop.hide();
53392 this.proxyBottom.hide();
53394 return result ? this.dropAllowed : this.dropNotAllowed;
53397 onNodeOut : function(n, dd, e, data){
53398 this.proxyTop.hide();
53399 this.proxyBottom.hide();
53402 onNodeDrop : function(n, dd, e, data){
53403 var h = data.header;
53405 var cm = this.grid.colModel;
53406 var x = Roo.lib.Event.getPageX(e);
53407 var r = Roo.lib.Dom.getRegion(n.firstChild);
53408 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
53409 var oldIndex = this.view.getCellIndex(h);
53410 var newIndex = this.view.getCellIndex(n);
53411 var locked = cm.isLocked(newIndex);
53415 if(oldIndex < newIndex){
53418 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
53421 cm.setLocked(oldIndex, locked, true);
53422 cm.moveColumn(oldIndex, newIndex);
53423 this.grid.fireEvent("columnmove", oldIndex, newIndex);
53431 * Ext JS Library 1.1.1
53432 * Copyright(c) 2006-2007, Ext JS, LLC.
53434 * Originally Released Under LGPL - original licence link has changed is not relivant.
53437 * <script type="text/javascript">
53441 * @class Roo.grid.GridView
53442 * @extends Roo.util.Observable
53445 * @param {Object} config
53447 Roo.grid.GridView = function(config){
53448 Roo.grid.GridView.superclass.constructor.call(this);
53451 Roo.apply(this, config);
53454 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
53456 unselectable : 'unselectable="on"',
53457 unselectableCls : 'x-unselectable',
53460 rowClass : "x-grid-row",
53462 cellClass : "x-grid-col",
53464 tdClass : "x-grid-td",
53466 hdClass : "x-grid-hd",
53468 splitClass : "x-grid-split",
53470 sortClasses : ["sort-asc", "sort-desc"],
53472 enableMoveAnim : false,
53476 dh : Roo.DomHelper,
53478 fly : Roo.Element.fly,
53480 css : Roo.util.CSS,
53486 scrollIncrement : 22,
53488 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
53490 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
53492 bind : function(ds, cm){
53494 this.ds.un("load", this.onLoad, this);
53495 this.ds.un("datachanged", this.onDataChange, this);
53496 this.ds.un("add", this.onAdd, this);
53497 this.ds.un("remove", this.onRemove, this);
53498 this.ds.un("update", this.onUpdate, this);
53499 this.ds.un("clear", this.onClear, this);
53502 ds.on("load", this.onLoad, this);
53503 ds.on("datachanged", this.onDataChange, this);
53504 ds.on("add", this.onAdd, this);
53505 ds.on("remove", this.onRemove, this);
53506 ds.on("update", this.onUpdate, this);
53507 ds.on("clear", this.onClear, this);
53512 this.cm.un("widthchange", this.onColWidthChange, this);
53513 this.cm.un("headerchange", this.onHeaderChange, this);
53514 this.cm.un("hiddenchange", this.onHiddenChange, this);
53515 this.cm.un("columnmoved", this.onColumnMove, this);
53516 this.cm.un("columnlockchange", this.onColumnLock, this);
53519 this.generateRules(cm);
53520 cm.on("widthchange", this.onColWidthChange, this);
53521 cm.on("headerchange", this.onHeaderChange, this);
53522 cm.on("hiddenchange", this.onHiddenChange, this);
53523 cm.on("columnmoved", this.onColumnMove, this);
53524 cm.on("columnlockchange", this.onColumnLock, this);
53529 init: function(grid){
53530 Roo.grid.GridView.superclass.init.call(this, grid);
53532 this.bind(grid.dataSource, grid.colModel);
53534 grid.on("headerclick", this.handleHeaderClick, this);
53536 if(grid.trackMouseOver){
53537 grid.on("mouseover", this.onRowOver, this);
53538 grid.on("mouseout", this.onRowOut, this);
53540 grid.cancelTextSelection = function(){};
53541 this.gridId = grid.id;
53543 var tpls = this.templates || {};
53546 tpls.master = new Roo.Template(
53547 '<div class="x-grid" hidefocus="true">',
53548 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
53549 '<div class="x-grid-topbar"></div>',
53550 '<div class="x-grid-scroller"><div></div></div>',
53551 '<div class="x-grid-locked">',
53552 '<div class="x-grid-header">{lockedHeader}</div>',
53553 '<div class="x-grid-body">{lockedBody}</div>',
53555 '<div class="x-grid-viewport">',
53556 '<div class="x-grid-header">{header}</div>',
53557 '<div class="x-grid-body">{body}</div>',
53559 '<div class="x-grid-bottombar"></div>',
53561 '<div class="x-grid-resize-proxy"> </div>',
53564 tpls.master.disableformats = true;
53568 tpls.header = new Roo.Template(
53569 '<table border="0" cellspacing="0" cellpadding="0">',
53570 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
53573 tpls.header.disableformats = true;
53575 tpls.header.compile();
53578 tpls.hcell = new Roo.Template(
53579 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
53580 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
53583 tpls.hcell.disableFormats = true;
53585 tpls.hcell.compile();
53588 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
53589 this.unselectableCls + '" ' + this.unselectable +'> </div>');
53590 tpls.hsplit.disableFormats = true;
53592 tpls.hsplit.compile();
53595 tpls.body = new Roo.Template(
53596 '<table border="0" cellspacing="0" cellpadding="0">',
53597 "<tbody>{rows}</tbody>",
53600 tpls.body.disableFormats = true;
53602 tpls.body.compile();
53605 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
53606 tpls.row.disableFormats = true;
53608 tpls.row.compile();
53611 tpls.cell = new Roo.Template(
53612 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
53613 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
53614 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
53617 tpls.cell.disableFormats = true;
53619 tpls.cell.compile();
53621 this.templates = tpls;
53624 // remap these for backwards compat
53625 onColWidthChange : function(){
53626 this.updateColumns.apply(this, arguments);
53628 onHeaderChange : function(){
53629 this.updateHeaders.apply(this, arguments);
53631 onHiddenChange : function(){
53632 this.handleHiddenChange.apply(this, arguments);
53634 onColumnMove : function(){
53635 this.handleColumnMove.apply(this, arguments);
53637 onColumnLock : function(){
53638 this.handleLockChange.apply(this, arguments);
53641 onDataChange : function(){
53643 this.updateHeaderSortState();
53646 onClear : function(){
53650 onUpdate : function(ds, record){
53651 this.refreshRow(record);
53654 refreshRow : function(record){
53655 var ds = this.ds, index;
53656 if(typeof record == 'number'){
53658 record = ds.getAt(index);
53660 index = ds.indexOf(record);
53662 this.insertRows(ds, index, index, true);
53663 this.onRemove(ds, record, index+1, true);
53664 this.syncRowHeights(index, index);
53666 this.fireEvent("rowupdated", this, index, record);
53669 onAdd : function(ds, records, index){
53670 this.insertRows(ds, index, index + (records.length-1));
53673 onRemove : function(ds, record, index, isUpdate){
53674 if(isUpdate !== true){
53675 this.fireEvent("beforerowremoved", this, index, record);
53677 var bt = this.getBodyTable(), lt = this.getLockedTable();
53678 if(bt.rows[index]){
53679 bt.firstChild.removeChild(bt.rows[index]);
53681 if(lt.rows[index]){
53682 lt.firstChild.removeChild(lt.rows[index]);
53684 if(isUpdate !== true){
53685 this.stripeRows(index);
53686 this.syncRowHeights(index, index);
53688 this.fireEvent("rowremoved", this, index, record);
53692 onLoad : function(){
53693 this.scrollToTop();
53697 * Scrolls the grid to the top
53699 scrollToTop : function(){
53701 this.scroller.dom.scrollTop = 0;
53707 * Gets a panel in the header of the grid that can be used for toolbars etc.
53708 * After modifying the contents of this panel a call to grid.autoSize() may be
53709 * required to register any changes in size.
53710 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
53711 * @return Roo.Element
53713 getHeaderPanel : function(doShow){
53715 this.headerPanel.show();
53717 return this.headerPanel;
53721 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53722 * After modifying the contents of this panel a call to grid.autoSize() may be
53723 * required to register any changes in size.
53724 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53725 * @return Roo.Element
53727 getFooterPanel : function(doShow){
53729 this.footerPanel.show();
53731 return this.footerPanel;
53734 initElements : function(){
53735 var E = Roo.Element;
53736 var el = this.grid.getGridEl().dom.firstChild;
53737 var cs = el.childNodes;
53739 this.el = new E(el);
53741 this.focusEl = new E(el.firstChild);
53742 this.focusEl.swallowEvent("click", true);
53744 this.headerPanel = new E(cs[1]);
53745 this.headerPanel.enableDisplayMode("block");
53747 this.scroller = new E(cs[2]);
53748 this.scrollSizer = new E(this.scroller.dom.firstChild);
53750 this.lockedWrap = new E(cs[3]);
53751 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53752 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53754 this.mainWrap = new E(cs[4]);
53755 this.mainHd = new E(this.mainWrap.dom.firstChild);
53756 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53758 this.footerPanel = new E(cs[5]);
53759 this.footerPanel.enableDisplayMode("block");
53761 this.resizeProxy = new E(cs[6]);
53763 this.headerSelector = String.format(
53764 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53765 this.lockedHd.id, this.mainHd.id
53768 this.splitterSelector = String.format(
53769 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53770 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53773 idToCssName : function(s)
53775 return s.replace(/[^a-z0-9]+/ig, '-');
53778 getHeaderCell : function(index){
53779 return Roo.DomQuery.select(this.headerSelector)[index];
53782 getHeaderCellMeasure : function(index){
53783 return this.getHeaderCell(index).firstChild;
53786 getHeaderCellText : function(index){
53787 return this.getHeaderCell(index).firstChild.firstChild;
53790 getLockedTable : function(){
53791 return this.lockedBody.dom.firstChild;
53794 getBodyTable : function(){
53795 return this.mainBody.dom.firstChild;
53798 getLockedRow : function(index){
53799 return this.getLockedTable().rows[index];
53802 getRow : function(index){
53803 return this.getBodyTable().rows[index];
53806 getRowComposite : function(index){
53808 this.rowEl = new Roo.CompositeElementLite();
53810 var els = [], lrow, mrow;
53811 if(lrow = this.getLockedRow(index)){
53814 if(mrow = this.getRow(index)){
53817 this.rowEl.elements = els;
53821 * Gets the 'td' of the cell
53823 * @param {Integer} rowIndex row to select
53824 * @param {Integer} colIndex column to select
53828 getCell : function(rowIndex, colIndex){
53829 var locked = this.cm.getLockedCount();
53831 if(colIndex < locked){
53832 source = this.lockedBody.dom.firstChild;
53834 source = this.mainBody.dom.firstChild;
53835 colIndex -= locked;
53837 return source.rows[rowIndex].childNodes[colIndex];
53840 getCellText : function(rowIndex, colIndex){
53841 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53844 getCellBox : function(cell){
53845 var b = this.fly(cell).getBox();
53846 if(Roo.isOpera){ // opera fails to report the Y
53847 b.y = cell.offsetTop + this.mainBody.getY();
53852 getCellIndex : function(cell){
53853 var id = String(cell.className).match(this.cellRE);
53855 return parseInt(id[1], 10);
53860 findHeaderIndex : function(n){
53861 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53862 return r ? this.getCellIndex(r) : false;
53865 findHeaderCell : function(n){
53866 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53867 return r ? r : false;
53870 findRowIndex : function(n){
53874 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53875 return r ? r.rowIndex : false;
53878 findCellIndex : function(node){
53879 var stop = this.el.dom;
53880 while(node && node != stop){
53881 if(this.findRE.test(node.className)){
53882 return this.getCellIndex(node);
53884 node = node.parentNode;
53889 getColumnId : function(index){
53890 return this.cm.getColumnId(index);
53893 getSplitters : function()
53895 if(this.splitterSelector){
53896 return Roo.DomQuery.select(this.splitterSelector);
53902 getSplitter : function(index){
53903 return this.getSplitters()[index];
53906 onRowOver : function(e, t){
53908 if((row = this.findRowIndex(t)) !== false){
53909 this.getRowComposite(row).addClass("x-grid-row-over");
53913 onRowOut : function(e, t){
53915 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53916 this.getRowComposite(row).removeClass("x-grid-row-over");
53920 renderHeaders : function(){
53922 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53923 var cb = [], lb = [], sb = [], lsb = [], p = {};
53924 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53925 p.cellId = "x-grid-hd-0-" + i;
53926 p.splitId = "x-grid-csplit-0-" + i;
53927 p.id = cm.getColumnId(i);
53928 p.title = cm.getColumnTooltip(i) || "";
53929 p.value = cm.getColumnHeader(i) || "";
53930 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53931 if(!cm.isLocked(i)){
53932 cb[cb.length] = ct.apply(p);
53933 sb[sb.length] = st.apply(p);
53935 lb[lb.length] = ct.apply(p);
53936 lsb[lsb.length] = st.apply(p);
53939 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53940 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53943 updateHeaders : function(){
53944 var html = this.renderHeaders();
53945 this.lockedHd.update(html[0]);
53946 this.mainHd.update(html[1]);
53950 * Focuses the specified row.
53951 * @param {Number} row The row index
53953 focusRow : function(row)
53955 //Roo.log('GridView.focusRow');
53956 var x = this.scroller.dom.scrollLeft;
53957 this.focusCell(row, 0, false);
53958 this.scroller.dom.scrollLeft = x;
53962 * Focuses the specified cell.
53963 * @param {Number} row The row index
53964 * @param {Number} col The column index
53965 * @param {Boolean} hscroll false to disable horizontal scrolling
53967 focusCell : function(row, col, hscroll)
53969 //Roo.log('GridView.focusCell');
53970 var el = this.ensureVisible(row, col, hscroll);
53971 this.focusEl.alignTo(el, "tl-tl");
53973 this.focusEl.focus();
53975 this.focusEl.focus.defer(1, this.focusEl);
53980 * Scrolls the specified cell into view
53981 * @param {Number} row The row index
53982 * @param {Number} col The column index
53983 * @param {Boolean} hscroll false to disable horizontal scrolling
53985 ensureVisible : function(row, col, hscroll)
53987 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53988 //return null; //disable for testing.
53989 if(typeof row != "number"){
53990 row = row.rowIndex;
53992 if(row < 0 && row >= this.ds.getCount()){
53995 col = (col !== undefined ? col : 0);
53996 var cm = this.grid.colModel;
53997 while(cm.isHidden(col)){
54001 var el = this.getCell(row, col);
54005 var c = this.scroller.dom;
54007 var ctop = parseInt(el.offsetTop, 10);
54008 var cleft = parseInt(el.offsetLeft, 10);
54009 var cbot = ctop + el.offsetHeight;
54010 var cright = cleft + el.offsetWidth;
54012 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
54013 var stop = parseInt(c.scrollTop, 10);
54014 var sleft = parseInt(c.scrollLeft, 10);
54015 var sbot = stop + ch;
54016 var sright = sleft + c.clientWidth;
54018 Roo.log('GridView.ensureVisible:' +
54020 ' c.clientHeight:' + c.clientHeight +
54021 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
54029 c.scrollTop = ctop;
54030 //Roo.log("set scrolltop to ctop DISABLE?");
54031 }else if(cbot > sbot){
54032 //Roo.log("set scrolltop to cbot-ch");
54033 c.scrollTop = cbot-ch;
54036 if(hscroll !== false){
54038 c.scrollLeft = cleft;
54039 }else if(cright > sright){
54040 c.scrollLeft = cright-c.clientWidth;
54047 updateColumns : function(){
54048 this.grid.stopEditing();
54049 var cm = this.grid.colModel, colIds = this.getColumnIds();
54050 //var totalWidth = cm.getTotalWidth();
54052 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54053 //if(cm.isHidden(i)) continue;
54054 var w = cm.getColumnWidth(i);
54055 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
54056 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
54058 this.updateSplitters();
54061 generateRules : function(cm){
54062 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
54063 Roo.util.CSS.removeStyleSheet(rulesId);
54064 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54065 var cid = cm.getColumnId(i);
54067 if(cm.config[i].align){
54068 align = 'text-align:'+cm.config[i].align+';';
54071 if(cm.isHidden(i)){
54072 hidden = 'display:none;';
54074 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
54076 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
54077 this.hdSelector, cid, " {\n", align, width, "}\n",
54078 this.tdSelector, cid, " {\n",hidden,"\n}\n",
54079 this.splitSelector, cid, " {\n", hidden , "\n}\n");
54081 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54084 updateSplitters : function(){
54085 var cm = this.cm, s = this.getSplitters();
54086 if(s){ // splitters not created yet
54087 var pos = 0, locked = true;
54088 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54089 if(cm.isHidden(i)) {
54092 var w = cm.getColumnWidth(i); // make sure it's a number
54093 if(!cm.isLocked(i) && locked){
54098 s[i].style.left = (pos-this.splitOffset) + "px";
54103 handleHiddenChange : function(colModel, colIndex, hidden){
54105 this.hideColumn(colIndex);
54107 this.unhideColumn(colIndex);
54111 hideColumn : function(colIndex){
54112 var cid = this.getColumnId(colIndex);
54113 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
54114 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
54116 this.updateHeaders();
54118 this.updateSplitters();
54122 unhideColumn : function(colIndex){
54123 var cid = this.getColumnId(colIndex);
54124 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
54125 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
54128 this.updateHeaders();
54130 this.updateSplitters();
54134 insertRows : function(dm, firstRow, lastRow, isUpdate){
54135 if(firstRow == 0 && lastRow == dm.getCount()-1){
54139 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
54141 var s = this.getScrollState();
54142 var markup = this.renderRows(firstRow, lastRow);
54143 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
54144 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
54145 this.restoreScroll(s);
54147 this.fireEvent("rowsinserted", this, firstRow, lastRow);
54148 this.syncRowHeights(firstRow, lastRow);
54149 this.stripeRows(firstRow);
54155 bufferRows : function(markup, target, index){
54156 var before = null, trows = target.rows, tbody = target.tBodies[0];
54157 if(index < trows.length){
54158 before = trows[index];
54160 var b = document.createElement("div");
54161 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
54162 var rows = b.firstChild.rows;
54163 for(var i = 0, len = rows.length; i < len; i++){
54165 tbody.insertBefore(rows[0], before);
54167 tbody.appendChild(rows[0]);
54174 deleteRows : function(dm, firstRow, lastRow){
54175 if(dm.getRowCount()<1){
54176 this.fireEvent("beforerefresh", this);
54177 this.mainBody.update("");
54178 this.lockedBody.update("");
54179 this.fireEvent("refresh", this);
54181 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
54182 var bt = this.getBodyTable();
54183 var tbody = bt.firstChild;
54184 var rows = bt.rows;
54185 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
54186 tbody.removeChild(rows[firstRow]);
54188 this.stripeRows(firstRow);
54189 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
54193 updateRows : function(dataSource, firstRow, lastRow){
54194 var s = this.getScrollState();
54196 this.restoreScroll(s);
54199 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
54203 this.updateHeaderSortState();
54206 getScrollState : function(){
54208 var sb = this.scroller.dom;
54209 return {left: sb.scrollLeft, top: sb.scrollTop};
54212 stripeRows : function(startRow){
54213 if(!this.grid.stripeRows || this.ds.getCount() < 1){
54216 startRow = startRow || 0;
54217 var rows = this.getBodyTable().rows;
54218 var lrows = this.getLockedTable().rows;
54219 var cls = ' x-grid-row-alt ';
54220 for(var i = startRow, len = rows.length; i < len; i++){
54221 var row = rows[i], lrow = lrows[i];
54222 var isAlt = ((i+1) % 2 == 0);
54223 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
54224 if(isAlt == hasAlt){
54228 row.className += " x-grid-row-alt";
54230 row.className = row.className.replace("x-grid-row-alt", "");
54233 lrow.className = row.className;
54238 restoreScroll : function(state){
54239 //Roo.log('GridView.restoreScroll');
54240 var sb = this.scroller.dom;
54241 sb.scrollLeft = state.left;
54242 sb.scrollTop = state.top;
54246 syncScroll : function(){
54247 //Roo.log('GridView.syncScroll');
54248 var sb = this.scroller.dom;
54249 var sh = this.mainHd.dom;
54250 var bs = this.mainBody.dom;
54251 var lv = this.lockedBody.dom;
54252 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
54253 lv.scrollTop = bs.scrollTop = sb.scrollTop;
54256 handleScroll : function(e){
54258 var sb = this.scroller.dom;
54259 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
54263 handleWheel : function(e){
54264 var d = e.getWheelDelta();
54265 this.scroller.dom.scrollTop -= d*22;
54266 // set this here to prevent jumpy scrolling on large tables
54267 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
54271 renderRows : function(startRow, endRow){
54272 // pull in all the crap needed to render rows
54273 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
54274 var colCount = cm.getColumnCount();
54276 if(ds.getCount() < 1){
54280 // build a map for all the columns
54282 for(var i = 0; i < colCount; i++){
54283 var name = cm.getDataIndex(i);
54285 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
54286 renderer : cm.getRenderer(i),
54287 id : cm.getColumnId(i),
54288 locked : cm.isLocked(i)
54292 startRow = startRow || 0;
54293 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
54295 // records to render
54296 var rs = ds.getRange(startRow, endRow);
54298 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
54301 // As much as I hate to duplicate code, this was branched because FireFox really hates
54302 // [].join("") on strings. The performance difference was substantial enough to
54303 // branch this function
54304 doRender : Roo.isGecko ?
54305 function(cs, rs, ds, startRow, colCount, stripe){
54306 var ts = this.templates, ct = ts.cell, rt = ts.row;
54308 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54310 var hasListener = this.grid.hasListener('rowclass');
54312 for(var j = 0, len = rs.length; j < len; j++){
54313 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
54314 for(var i = 0; i < colCount; i++){
54316 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54318 p.css = p.attr = "";
54319 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54320 if(p.value == undefined || p.value === "") {
54321 p.value = " ";
54323 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54324 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54326 var markup = ct.apply(p);
54334 if(stripe && ((rowIndex+1) % 2 == 0)){
54335 alt.push("x-grid-row-alt")
54338 alt.push( " x-grid-dirty-row");
54341 if(this.getRowClass){
54342 alt.push(this.getRowClass(r, rowIndex));
54348 rowIndex : rowIndex,
54351 this.grid.fireEvent('rowclass', this, rowcfg);
54352 alt.push(rowcfg.rowClass);
54354 rp.alt = alt.join(" ");
54355 lbuf+= rt.apply(rp);
54357 buf+= rt.apply(rp);
54359 return [lbuf, buf];
54361 function(cs, rs, ds, startRow, colCount, stripe){
54362 var ts = this.templates, ct = ts.cell, rt = ts.row;
54364 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54365 var hasListener = this.grid.hasListener('rowclass');
54368 for(var j = 0, len = rs.length; j < len; j++){
54369 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
54370 for(var i = 0; i < colCount; i++){
54372 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54374 p.css = p.attr = "";
54375 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54376 if(p.value == undefined || p.value === "") {
54377 p.value = " ";
54379 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54380 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54383 var markup = ct.apply(p);
54385 cb[cb.length] = markup;
54387 lcb[lcb.length] = markup;
54391 if(stripe && ((rowIndex+1) % 2 == 0)){
54392 alt.push( "x-grid-row-alt");
54395 alt.push(" x-grid-dirty-row");
54398 if(this.getRowClass){
54399 alt.push( this.getRowClass(r, rowIndex));
54405 rowIndex : rowIndex,
54408 this.grid.fireEvent('rowclass', this, rowcfg);
54409 alt.push(rowcfg.rowClass);
54411 rp.alt = alt.join(" ");
54412 rp.cells = lcb.join("");
54413 lbuf[lbuf.length] = rt.apply(rp);
54414 rp.cells = cb.join("");
54415 buf[buf.length] = rt.apply(rp);
54417 return [lbuf.join(""), buf.join("")];
54420 renderBody : function(){
54421 var markup = this.renderRows();
54422 var bt = this.templates.body;
54423 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
54427 * Refreshes the grid
54428 * @param {Boolean} headersToo
54430 refresh : function(headersToo){
54431 this.fireEvent("beforerefresh", this);
54432 this.grid.stopEditing();
54433 var result = this.renderBody();
54434 this.lockedBody.update(result[0]);
54435 this.mainBody.update(result[1]);
54436 if(headersToo === true){
54437 this.updateHeaders();
54438 this.updateColumns();
54439 this.updateSplitters();
54440 this.updateHeaderSortState();
54442 this.syncRowHeights();
54444 this.fireEvent("refresh", this);
54447 handleColumnMove : function(cm, oldIndex, newIndex){
54448 this.indexMap = null;
54449 var s = this.getScrollState();
54450 this.refresh(true);
54451 this.restoreScroll(s);
54452 this.afterMove(newIndex);
54455 afterMove : function(colIndex){
54456 if(this.enableMoveAnim && Roo.enableFx){
54457 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
54459 // if multisort - fix sortOrder, and reload..
54460 if (this.grid.dataSource.multiSort) {
54461 // the we can call sort again..
54462 var dm = this.grid.dataSource;
54463 var cm = this.grid.colModel;
54465 for(var i = 0; i < cm.config.length; i++ ) {
54467 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
54468 continue; // dont' bother, it's not in sort list or being set.
54471 so.push(cm.config[i].dataIndex);
54474 dm.load(dm.lastOptions);
54481 updateCell : function(dm, rowIndex, dataIndex){
54482 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
54483 if(typeof colIndex == "undefined"){ // not present in grid
54486 var cm = this.grid.colModel;
54487 var cell = this.getCell(rowIndex, colIndex);
54488 var cellText = this.getCellText(rowIndex, colIndex);
54491 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
54492 id : cm.getColumnId(colIndex),
54493 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
54495 var renderer = cm.getRenderer(colIndex);
54496 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
54497 if(typeof val == "undefined" || val === "") {
54500 cellText.innerHTML = val;
54501 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
54502 this.syncRowHeights(rowIndex, rowIndex);
54505 calcColumnWidth : function(colIndex, maxRowsToMeasure){
54507 if(this.grid.autoSizeHeaders){
54508 var h = this.getHeaderCellMeasure(colIndex);
54509 maxWidth = Math.max(maxWidth, h.scrollWidth);
54512 if(this.cm.isLocked(colIndex)){
54513 tb = this.getLockedTable();
54516 tb = this.getBodyTable();
54517 index = colIndex - this.cm.getLockedCount();
54520 var rows = tb.rows;
54521 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
54522 for(var i = 0; i < stopIndex; i++){
54523 var cell = rows[i].childNodes[index].firstChild;
54524 maxWidth = Math.max(maxWidth, cell.scrollWidth);
54527 return maxWidth + /*margin for error in IE*/ 5;
54530 * Autofit a column to its content.
54531 * @param {Number} colIndex
54532 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
54534 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
54535 if(this.cm.isHidden(colIndex)){
54536 return; // can't calc a hidden column
54539 var cid = this.cm.getColumnId(colIndex);
54540 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
54541 if(this.grid.autoSizeHeaders){
54542 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
54545 var newWidth = this.calcColumnWidth(colIndex);
54546 this.cm.setColumnWidth(colIndex,
54547 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
54548 if(!suppressEvent){
54549 this.grid.fireEvent("columnresize", colIndex, newWidth);
54554 * Autofits all columns to their content and then expands to fit any extra space in the grid
54556 autoSizeColumns : function(){
54557 var cm = this.grid.colModel;
54558 var colCount = cm.getColumnCount();
54559 for(var i = 0; i < colCount; i++){
54560 this.autoSizeColumn(i, true, true);
54562 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
54565 this.updateColumns();
54571 * Autofits all columns to the grid's width proportionate with their current size
54572 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
54574 fitColumns : function(reserveScrollSpace){
54575 var cm = this.grid.colModel;
54576 var colCount = cm.getColumnCount();
54580 for (i = 0; i < colCount; i++){
54581 if(!cm.isHidden(i) && !cm.isFixed(i)){
54582 w = cm.getColumnWidth(i);
54588 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
54589 if(reserveScrollSpace){
54592 var frac = (avail - cm.getTotalWidth())/width;
54593 while (cols.length){
54596 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
54598 this.updateColumns();
54602 onRowSelect : function(rowIndex){
54603 var row = this.getRowComposite(rowIndex);
54604 row.addClass("x-grid-row-selected");
54607 onRowDeselect : function(rowIndex){
54608 var row = this.getRowComposite(rowIndex);
54609 row.removeClass("x-grid-row-selected");
54612 onCellSelect : function(row, col){
54613 var cell = this.getCell(row, col);
54615 Roo.fly(cell).addClass("x-grid-cell-selected");
54619 onCellDeselect : function(row, col){
54620 var cell = this.getCell(row, col);
54622 Roo.fly(cell).removeClass("x-grid-cell-selected");
54626 updateHeaderSortState : function(){
54628 // sort state can be single { field: xxx, direction : yyy}
54629 // or { xxx=>ASC , yyy : DESC ..... }
54632 if (!this.ds.multiSort) {
54633 var state = this.ds.getSortState();
54637 mstate[state.field] = state.direction;
54638 // FIXME... - this is not used here.. but might be elsewhere..
54639 this.sortState = state;
54642 mstate = this.ds.sortToggle;
54644 //remove existing sort classes..
54646 var sc = this.sortClasses;
54647 var hds = this.el.select(this.headerSelector).removeClass(sc);
54649 for(var f in mstate) {
54651 var sortColumn = this.cm.findColumnIndex(f);
54653 if(sortColumn != -1){
54654 var sortDir = mstate[f];
54655 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
54664 handleHeaderClick : function(g, index,e){
54666 Roo.log("header click");
54669 // touch events on header are handled by context
54670 this.handleHdCtx(g,index,e);
54675 if(this.headersDisabled){
54678 var dm = g.dataSource, cm = g.colModel;
54679 if(!cm.isSortable(index)){
54684 if (dm.multiSort) {
54685 // update the sortOrder
54687 for(var i = 0; i < cm.config.length; i++ ) {
54689 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
54690 continue; // dont' bother, it's not in sort list or being set.
54693 so.push(cm.config[i].dataIndex);
54699 dm.sort(cm.getDataIndex(index));
54703 destroy : function(){
54705 this.colMenu.removeAll();
54706 Roo.menu.MenuMgr.unregister(this.colMenu);
54707 this.colMenu.getEl().remove();
54708 delete this.colMenu;
54711 this.hmenu.removeAll();
54712 Roo.menu.MenuMgr.unregister(this.hmenu);
54713 this.hmenu.getEl().remove();
54716 if(this.grid.enableColumnMove){
54717 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54719 for(var dd in dds){
54720 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54721 var elid = dds[dd].dragElId;
54723 Roo.get(elid).remove();
54724 } else if(dds[dd].config.isTarget){
54725 dds[dd].proxyTop.remove();
54726 dds[dd].proxyBottom.remove();
54729 if(Roo.dd.DDM.locationCache[dd]){
54730 delete Roo.dd.DDM.locationCache[dd];
54733 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54736 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54737 this.bind(null, null);
54738 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54741 handleLockChange : function(){
54742 this.refresh(true);
54745 onDenyColumnLock : function(){
54749 onDenyColumnHide : function(){
54753 handleHdMenuClick : function(item){
54754 var index = this.hdCtxIndex;
54755 var cm = this.cm, ds = this.ds;
54758 ds.sort(cm.getDataIndex(index), "ASC");
54761 ds.sort(cm.getDataIndex(index), "DESC");
54764 var lc = cm.getLockedCount();
54765 if(cm.getColumnCount(true) <= lc+1){
54766 this.onDenyColumnLock();
54770 cm.setLocked(index, true, true);
54771 cm.moveColumn(index, lc);
54772 this.grid.fireEvent("columnmove", index, lc);
54774 cm.setLocked(index, true);
54778 var lc = cm.getLockedCount();
54779 if((lc-1) != index){
54780 cm.setLocked(index, false, true);
54781 cm.moveColumn(index, lc-1);
54782 this.grid.fireEvent("columnmove", index, lc-1);
54784 cm.setLocked(index, false);
54787 case 'wider': // used to expand cols on touch..
54789 var cw = cm.getColumnWidth(index);
54790 cw += (item.id == 'wider' ? 1 : -1) * 50;
54791 cw = Math.max(0, cw);
54792 cw = Math.min(cw,4000);
54793 cm.setColumnWidth(index, cw);
54797 index = cm.getIndexById(item.id.substr(4));
54799 if(item.checked && cm.getColumnCount(true) <= 1){
54800 this.onDenyColumnHide();
54803 cm.setHidden(index, item.checked);
54809 beforeColMenuShow : function(){
54810 var cm = this.cm, colCount = cm.getColumnCount();
54811 this.colMenu.removeAll();
54812 for(var i = 0; i < colCount; i++){
54813 this.colMenu.add(new Roo.menu.CheckItem({
54814 id: "col-"+cm.getColumnId(i),
54815 text: cm.getColumnHeader(i),
54816 checked: !cm.isHidden(i),
54822 handleHdCtx : function(g, index, e){
54824 var hd = this.getHeaderCell(index);
54825 this.hdCtxIndex = index;
54826 var ms = this.hmenu.items, cm = this.cm;
54827 ms.get("asc").setDisabled(!cm.isSortable(index));
54828 ms.get("desc").setDisabled(!cm.isSortable(index));
54829 if(this.grid.enableColLock !== false){
54830 ms.get("lock").setDisabled(cm.isLocked(index));
54831 ms.get("unlock").setDisabled(!cm.isLocked(index));
54833 this.hmenu.show(hd, "tl-bl");
54836 handleHdOver : function(e){
54837 var hd = this.findHeaderCell(e.getTarget());
54838 if(hd && !this.headersDisabled){
54839 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54840 this.fly(hd).addClass("x-grid-hd-over");
54845 handleHdOut : function(e){
54846 var hd = this.findHeaderCell(e.getTarget());
54848 this.fly(hd).removeClass("x-grid-hd-over");
54852 handleSplitDblClick : function(e, t){
54853 var i = this.getCellIndex(t);
54854 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54855 this.autoSizeColumn(i, true);
54860 render : function(){
54863 var colCount = cm.getColumnCount();
54865 if(this.grid.monitorWindowResize === true){
54866 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54868 var header = this.renderHeaders();
54869 var body = this.templates.body.apply({rows:""});
54870 var html = this.templates.master.apply({
54873 lockedHeader: header[0],
54877 //this.updateColumns();
54879 this.grid.getGridEl().dom.innerHTML = html;
54881 this.initElements();
54883 // a kludge to fix the random scolling effect in webkit
54884 this.el.on("scroll", function() {
54885 this.el.dom.scrollTop=0; // hopefully not recursive..
54888 this.scroller.on("scroll", this.handleScroll, this);
54889 this.lockedBody.on("mousewheel", this.handleWheel, this);
54890 this.mainBody.on("mousewheel", this.handleWheel, this);
54892 this.mainHd.on("mouseover", this.handleHdOver, this);
54893 this.mainHd.on("mouseout", this.handleHdOut, this);
54894 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54895 {delegate: "."+this.splitClass});
54897 this.lockedHd.on("mouseover", this.handleHdOver, this);
54898 this.lockedHd.on("mouseout", this.handleHdOut, this);
54899 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54900 {delegate: "."+this.splitClass});
54902 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54903 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54906 this.updateSplitters();
54908 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54909 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54910 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54913 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54914 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54916 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54917 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54919 if(this.grid.enableColLock !== false){
54920 this.hmenu.add('-',
54921 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54922 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54926 this.hmenu.add('-',
54927 {id:"wider", text: this.columnsWiderText},
54928 {id:"narrow", text: this.columnsNarrowText }
54934 if(this.grid.enableColumnHide !== false){
54936 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54937 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54938 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54940 this.hmenu.add('-',
54941 {id:"columns", text: this.columnsText, menu: this.colMenu}
54944 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54946 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54949 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54950 this.dd = new Roo.grid.GridDragZone(this.grid, {
54951 ddGroup : this.grid.ddGroup || 'GridDD'
54957 for(var i = 0; i < colCount; i++){
54958 if(cm.isHidden(i)){
54959 this.hideColumn(i);
54961 if(cm.config[i].align){
54962 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54963 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54967 this.updateHeaderSortState();
54969 this.beforeInitialResize();
54972 // two part rendering gives faster view to the user
54973 this.renderPhase2.defer(1, this);
54976 renderPhase2 : function(){
54977 // render the rows now
54979 if(this.grid.autoSizeColumns){
54980 this.autoSizeColumns();
54984 beforeInitialResize : function(){
54988 onColumnSplitterMoved : function(i, w){
54989 this.userResized = true;
54990 var cm = this.grid.colModel;
54991 cm.setColumnWidth(i, w, true);
54992 var cid = cm.getColumnId(i);
54993 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54994 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54995 this.updateSplitters();
54997 this.grid.fireEvent("columnresize", i, w);
55000 syncRowHeights : function(startIndex, endIndex){
55001 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
55002 startIndex = startIndex || 0;
55003 var mrows = this.getBodyTable().rows;
55004 var lrows = this.getLockedTable().rows;
55005 var len = mrows.length-1;
55006 endIndex = Math.min(endIndex || len, len);
55007 for(var i = startIndex; i <= endIndex; i++){
55008 var m = mrows[i], l = lrows[i];
55009 var h = Math.max(m.offsetHeight, l.offsetHeight);
55010 m.style.height = l.style.height = h + "px";
55015 layout : function(initialRender, is2ndPass){
55017 var auto = g.autoHeight;
55018 var scrollOffset = 16;
55019 var c = g.getGridEl(), cm = this.cm,
55020 expandCol = g.autoExpandColumn,
55022 //c.beginMeasure();
55024 if(!c.dom.offsetWidth){ // display:none?
55026 this.lockedWrap.show();
55027 this.mainWrap.show();
55032 var hasLock = this.cm.isLocked(0);
55034 var tbh = this.headerPanel.getHeight();
55035 var bbh = this.footerPanel.getHeight();
55038 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
55039 var newHeight = ch + c.getBorderWidth("tb");
55041 newHeight = Math.min(g.maxHeight, newHeight);
55043 c.setHeight(newHeight);
55047 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
55050 var s = this.scroller;
55052 var csize = c.getSize(true);
55054 this.el.setSize(csize.width, csize.height);
55056 this.headerPanel.setWidth(csize.width);
55057 this.footerPanel.setWidth(csize.width);
55059 var hdHeight = this.mainHd.getHeight();
55060 var vw = csize.width;
55061 var vh = csize.height - (tbh + bbh);
55065 var bt = this.getBodyTable();
55066 var ltWidth = hasLock ?
55067 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
55069 var scrollHeight = bt.offsetHeight;
55070 var scrollWidth = ltWidth + bt.offsetWidth;
55071 var vscroll = false, hscroll = false;
55073 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
55075 var lw = this.lockedWrap, mw = this.mainWrap;
55076 var lb = this.lockedBody, mb = this.mainBody;
55078 setTimeout(function(){
55079 var t = s.dom.offsetTop;
55080 var w = s.dom.clientWidth,
55081 h = s.dom.clientHeight;
55084 lw.setSize(ltWidth, h);
55086 mw.setLeftTop(ltWidth, t);
55087 mw.setSize(w-ltWidth, h);
55089 lb.setHeight(h-hdHeight);
55090 mb.setHeight(h-hdHeight);
55092 if(is2ndPass !== true && !gv.userResized && expandCol){
55093 // high speed resize without full column calculation
55095 var ci = cm.getIndexById(expandCol);
55097 ci = cm.findColumnIndex(expandCol);
55099 ci = Math.max(0, ci); // make sure it's got at least the first col.
55100 var expandId = cm.getColumnId(ci);
55101 var tw = cm.getTotalWidth(false);
55102 var currentWidth = cm.getColumnWidth(ci);
55103 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
55104 if(currentWidth != cw){
55105 cm.setColumnWidth(ci, cw, true);
55106 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
55107 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
55108 gv.updateSplitters();
55109 gv.layout(false, true);
55121 onWindowResize : function(){
55122 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
55128 appendFooter : function(parentEl){
55132 sortAscText : "Sort Ascending",
55133 sortDescText : "Sort Descending",
55134 lockText : "Lock Column",
55135 unlockText : "Unlock Column",
55136 columnsText : "Columns",
55138 columnsWiderText : "Wider",
55139 columnsNarrowText : "Thinner"
55143 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
55144 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
55145 this.proxy.el.addClass('x-grid3-col-dd');
55148 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
55149 handleMouseDown : function(e){
55153 callHandleMouseDown : function(e){
55154 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
55159 * Ext JS Library 1.1.1
55160 * Copyright(c) 2006-2007, Ext JS, LLC.
55162 * Originally Released Under LGPL - original licence link has changed is not relivant.
55165 * <script type="text/javascript">
55169 // This is a support class used internally by the Grid components
55170 Roo.grid.SplitDragZone = function(grid, hd, hd2){
55172 this.view = grid.getView();
55173 this.proxy = this.view.resizeProxy;
55174 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
55175 "gridSplitters" + this.grid.getGridEl().id, {
55176 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
55178 this.setHandleElId(Roo.id(hd));
55179 this.setOuterHandleElId(Roo.id(hd2));
55180 this.scroll = false;
55182 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
55183 fly: Roo.Element.fly,
55185 b4StartDrag : function(x, y){
55186 this.view.headersDisabled = true;
55187 this.proxy.setHeight(this.view.mainWrap.getHeight());
55188 var w = this.cm.getColumnWidth(this.cellIndex);
55189 var minw = Math.max(w-this.grid.minColumnWidth, 0);
55190 this.resetConstraints();
55191 this.setXConstraint(minw, 1000);
55192 this.setYConstraint(0, 0);
55193 this.minX = x - minw;
55194 this.maxX = x + 1000;
55196 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
55200 handleMouseDown : function(e){
55201 ev = Roo.EventObject.setEvent(e);
55202 var t = this.fly(ev.getTarget());
55203 if(t.hasClass("x-grid-split")){
55204 this.cellIndex = this.view.getCellIndex(t.dom);
55205 this.split = t.dom;
55206 this.cm = this.grid.colModel;
55207 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
55208 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
55213 endDrag : function(e){
55214 this.view.headersDisabled = false;
55215 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
55216 var diff = endX - this.startPos;
55217 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
55220 autoOffset : function(){
55221 this.setDelta(0,0);
55225 * Ext JS Library 1.1.1
55226 * Copyright(c) 2006-2007, Ext JS, LLC.
55228 * Originally Released Under LGPL - original licence link has changed is not relivant.
55231 * <script type="text/javascript">
55235 // This is a support class used internally by the Grid components
55236 Roo.grid.GridDragZone = function(grid, config){
55237 this.view = grid.getView();
55238 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
55239 if(this.view.lockedBody){
55240 this.setHandleElId(Roo.id(this.view.mainBody.dom));
55241 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
55243 this.scroll = false;
55245 this.ddel = document.createElement('div');
55246 this.ddel.className = 'x-grid-dd-wrap';
55249 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
55250 ddGroup : "GridDD",
55252 getDragData : function(e){
55253 var t = Roo.lib.Event.getTarget(e);
55254 var rowIndex = this.view.findRowIndex(t);
55255 var sm = this.grid.selModel;
55257 //Roo.log(rowIndex);
55259 if (sm.getSelectedCell) {
55260 // cell selection..
55261 if (!sm.getSelectedCell()) {
55264 if (rowIndex != sm.getSelectedCell()[0]) {
55270 if(rowIndex !== false){
55275 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
55277 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
55280 if (e.hasModifier()){
55281 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
55284 Roo.log("getDragData");
55289 rowIndex: rowIndex,
55290 selections:sm.getSelections ? sm.getSelections() : (
55291 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
55298 onInitDrag : function(e){
55299 var data = this.dragData;
55300 this.ddel.innerHTML = this.grid.getDragDropText();
55301 this.proxy.update(this.ddel);
55302 // fire start drag?
55305 afterRepair : function(){
55306 this.dragging = false;
55309 getRepairXY : function(e, data){
55313 onEndDrag : function(data, e){
55317 onValidDrop : function(dd, e, id){
55322 beforeInvalidDrop : function(e, id){
55327 * Ext JS Library 1.1.1
55328 * Copyright(c) 2006-2007, Ext JS, LLC.
55330 * Originally Released Under LGPL - original licence link has changed is not relivant.
55333 * <script type="text/javascript">
55338 * @class Roo.grid.ColumnModel
55339 * @extends Roo.util.Observable
55340 * This is the default implementation of a ColumnModel used by the Grid. It defines
55341 * the columns in the grid.
55344 var colModel = new Roo.grid.ColumnModel([
55345 {header: "Ticker", width: 60, sortable: true, locked: true},
55346 {header: "Company Name", width: 150, sortable: true},
55347 {header: "Market Cap.", width: 100, sortable: true},
55348 {header: "$ Sales", width: 100, sortable: true, renderer: money},
55349 {header: "Employees", width: 100, sortable: true, resizable: false}
55354 * The config options listed for this class are options which may appear in each
55355 * individual column definition.
55356 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
55358 * @param {Object} config An Array of column config objects. See this class's
55359 * config objects for details.
55361 Roo.grid.ColumnModel = function(config){
55363 * The config passed into the constructor
55365 this.config = config;
55368 // if no id, create one
55369 // if the column does not have a dataIndex mapping,
55370 // map it to the order it is in the config
55371 for(var i = 0, len = config.length; i < len; i++){
55373 if(typeof c.dataIndex == "undefined"){
55376 if(typeof c.renderer == "string"){
55377 c.renderer = Roo.util.Format[c.renderer];
55379 if(typeof c.id == "undefined"){
55382 if(c.editor && c.editor.xtype){
55383 c.editor = Roo.factory(c.editor, Roo.grid);
55385 if(c.editor && c.editor.isFormField){
55386 c.editor = new Roo.grid.GridEditor(c.editor);
55388 this.lookup[c.id] = c;
55392 * The width of columns which have no width specified (defaults to 100)
55395 this.defaultWidth = 100;
55398 * Default sortable of columns which have no sortable specified (defaults to false)
55401 this.defaultSortable = false;
55405 * @event widthchange
55406 * Fires when the width of a column changes.
55407 * @param {ColumnModel} this
55408 * @param {Number} columnIndex The column index
55409 * @param {Number} newWidth The new width
55411 "widthchange": true,
55413 * @event headerchange
55414 * Fires when the text of a header changes.
55415 * @param {ColumnModel} this
55416 * @param {Number} columnIndex The column index
55417 * @param {Number} newText The new header text
55419 "headerchange": true,
55421 * @event hiddenchange
55422 * Fires when a column is hidden or "unhidden".
55423 * @param {ColumnModel} this
55424 * @param {Number} columnIndex The column index
55425 * @param {Boolean} hidden true if hidden, false otherwise
55427 "hiddenchange": true,
55429 * @event columnmoved
55430 * Fires when a column is moved.
55431 * @param {ColumnModel} this
55432 * @param {Number} oldIndex
55433 * @param {Number} newIndex
55435 "columnmoved" : true,
55437 * @event columlockchange
55438 * Fires when a column's locked state is changed
55439 * @param {ColumnModel} this
55440 * @param {Number} colIndex
55441 * @param {Boolean} locked true if locked
55443 "columnlockchange" : true
55445 Roo.grid.ColumnModel.superclass.constructor.call(this);
55447 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
55449 * @cfg {String} header The header text to display in the Grid view.
55452 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
55453 * {@link Roo.data.Record} definition from which to draw the column's value. If not
55454 * specified, the column's index is used as an index into the Record's data Array.
55457 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
55458 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
55461 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
55462 * Defaults to the value of the {@link #defaultSortable} property.
55463 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
55466 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
55469 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
55472 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
55475 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
55478 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
55479 * given the cell's data value. See {@link #setRenderer}. If not specified, the
55480 * default renderer uses the raw data value. If an object is returned (bootstrap only)
55481 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
55484 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
55487 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
55490 * @cfg {String} cursor (Optional)
55493 * @cfg {String} tooltip (Optional)
55496 * @cfg {Number} xs (Optional)
55499 * @cfg {Number} sm (Optional)
55502 * @cfg {Number} md (Optional)
55505 * @cfg {Number} lg (Optional)
55508 * Returns the id of the column at the specified index.
55509 * @param {Number} index The column index
55510 * @return {String} the id
55512 getColumnId : function(index){
55513 return this.config[index].id;
55517 * Returns the column for a specified id.
55518 * @param {String} id The column id
55519 * @return {Object} the column
55521 getColumnById : function(id){
55522 return this.lookup[id];
55527 * Returns the column for a specified dataIndex.
55528 * @param {String} dataIndex The column dataIndex
55529 * @return {Object|Boolean} the column or false if not found
55531 getColumnByDataIndex: function(dataIndex){
55532 var index = this.findColumnIndex(dataIndex);
55533 return index > -1 ? this.config[index] : false;
55537 * Returns the index for a specified column id.
55538 * @param {String} id The column id
55539 * @return {Number} the index, or -1 if not found
55541 getIndexById : function(id){
55542 for(var i = 0, len = this.config.length; i < len; i++){
55543 if(this.config[i].id == id){
55551 * Returns the index for a specified column dataIndex.
55552 * @param {String} dataIndex The column dataIndex
55553 * @return {Number} the index, or -1 if not found
55556 findColumnIndex : function(dataIndex){
55557 for(var i = 0, len = this.config.length; i < len; i++){
55558 if(this.config[i].dataIndex == dataIndex){
55566 moveColumn : function(oldIndex, newIndex){
55567 var c = this.config[oldIndex];
55568 this.config.splice(oldIndex, 1);
55569 this.config.splice(newIndex, 0, c);
55570 this.dataMap = null;
55571 this.fireEvent("columnmoved", this, oldIndex, newIndex);
55574 isLocked : function(colIndex){
55575 return this.config[colIndex].locked === true;
55578 setLocked : function(colIndex, value, suppressEvent){
55579 if(this.isLocked(colIndex) == value){
55582 this.config[colIndex].locked = value;
55583 if(!suppressEvent){
55584 this.fireEvent("columnlockchange", this, colIndex, value);
55588 getTotalLockedWidth : function(){
55589 var totalWidth = 0;
55590 for(var i = 0; i < this.config.length; i++){
55591 if(this.isLocked(i) && !this.isHidden(i)){
55592 this.totalWidth += this.getColumnWidth(i);
55598 getLockedCount : function(){
55599 for(var i = 0, len = this.config.length; i < len; i++){
55600 if(!this.isLocked(i)){
55607 * Returns the number of columns.
55610 getColumnCount : function(visibleOnly){
55611 if(visibleOnly === true){
55613 for(var i = 0, len = this.config.length; i < len; i++){
55614 if(!this.isHidden(i)){
55620 return this.config.length;
55624 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
55625 * @param {Function} fn
55626 * @param {Object} scope (optional)
55627 * @return {Array} result
55629 getColumnsBy : function(fn, scope){
55631 for(var i = 0, len = this.config.length; i < len; i++){
55632 var c = this.config[i];
55633 if(fn.call(scope||this, c, i) === true){
55641 * Returns true if the specified column is sortable.
55642 * @param {Number} col The column index
55643 * @return {Boolean}
55645 isSortable : function(col){
55646 if(typeof this.config[col].sortable == "undefined"){
55647 return this.defaultSortable;
55649 return this.config[col].sortable;
55653 * Returns the rendering (formatting) function defined for the column.
55654 * @param {Number} col The column index.
55655 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
55657 getRenderer : function(col){
55658 if(!this.config[col].renderer){
55659 return Roo.grid.ColumnModel.defaultRenderer;
55661 return this.config[col].renderer;
55665 * Sets the rendering (formatting) function for a column.
55666 * @param {Number} col The column index
55667 * @param {Function} fn The function to use to process the cell's raw data
55668 * to return HTML markup for the grid view. The render function is called with
55669 * the following parameters:<ul>
55670 * <li>Data value.</li>
55671 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
55672 * <li>css A CSS style string to apply to the table cell.</li>
55673 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
55674 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
55675 * <li>Row index</li>
55676 * <li>Column index</li>
55677 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
55679 setRenderer : function(col, fn){
55680 this.config[col].renderer = fn;
55684 * Returns the width for the specified column.
55685 * @param {Number} col The column index
55688 getColumnWidth : function(col){
55689 return this.config[col].width * 1 || this.defaultWidth;
55693 * Sets the width for a column.
55694 * @param {Number} col The column index
55695 * @param {Number} width The new width
55697 setColumnWidth : function(col, width, suppressEvent){
55698 this.config[col].width = width;
55699 this.totalWidth = null;
55700 if(!suppressEvent){
55701 this.fireEvent("widthchange", this, col, width);
55706 * Returns the total width of all columns.
55707 * @param {Boolean} includeHidden True to include hidden column widths
55710 getTotalWidth : function(includeHidden){
55711 if(!this.totalWidth){
55712 this.totalWidth = 0;
55713 for(var i = 0, len = this.config.length; i < len; i++){
55714 if(includeHidden || !this.isHidden(i)){
55715 this.totalWidth += this.getColumnWidth(i);
55719 return this.totalWidth;
55723 * Returns the header for the specified column.
55724 * @param {Number} col The column index
55727 getColumnHeader : function(col){
55728 return this.config[col].header;
55732 * Sets the header for a column.
55733 * @param {Number} col The column index
55734 * @param {String} header The new header
55736 setColumnHeader : function(col, header){
55737 this.config[col].header = header;
55738 this.fireEvent("headerchange", this, col, header);
55742 * Returns the tooltip for the specified column.
55743 * @param {Number} col The column index
55746 getColumnTooltip : function(col){
55747 return this.config[col].tooltip;
55750 * Sets the tooltip for a column.
55751 * @param {Number} col The column index
55752 * @param {String} tooltip The new tooltip
55754 setColumnTooltip : function(col, tooltip){
55755 this.config[col].tooltip = tooltip;
55759 * Returns the dataIndex for the specified column.
55760 * @param {Number} col The column index
55763 getDataIndex : function(col){
55764 return this.config[col].dataIndex;
55768 * Sets the dataIndex for a column.
55769 * @param {Number} col The column index
55770 * @param {Number} dataIndex The new dataIndex
55772 setDataIndex : function(col, dataIndex){
55773 this.config[col].dataIndex = dataIndex;
55779 * Returns true if the cell is editable.
55780 * @param {Number} colIndex The column index
55781 * @param {Number} rowIndex The row index
55782 * @return {Boolean}
55784 isCellEditable : function(colIndex, rowIndex){
55785 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55789 * Returns the editor defined for the cell/column.
55790 * return false or null to disable editing.
55791 * @param {Number} colIndex The column index
55792 * @param {Number} rowIndex The row index
55795 getCellEditor : function(colIndex, rowIndex){
55796 return this.config[colIndex].editor;
55800 * Sets if a column is editable.
55801 * @param {Number} col The column index
55802 * @param {Boolean} editable True if the column is editable
55804 setEditable : function(col, editable){
55805 this.config[col].editable = editable;
55810 * Returns true if the column is hidden.
55811 * @param {Number} colIndex The column index
55812 * @return {Boolean}
55814 isHidden : function(colIndex){
55815 return this.config[colIndex].hidden;
55820 * Returns true if the column width cannot be changed
55822 isFixed : function(colIndex){
55823 return this.config[colIndex].fixed;
55827 * Returns true if the column can be resized
55828 * @return {Boolean}
55830 isResizable : function(colIndex){
55831 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55834 * Sets if a column is hidden.
55835 * @param {Number} colIndex The column index
55836 * @param {Boolean} hidden True if the column is hidden
55838 setHidden : function(colIndex, hidden){
55839 this.config[colIndex].hidden = hidden;
55840 this.totalWidth = null;
55841 this.fireEvent("hiddenchange", this, colIndex, hidden);
55845 * Sets the editor for a column.
55846 * @param {Number} col The column index
55847 * @param {Object} editor The editor object
55849 setEditor : function(col, editor){
55850 this.config[col].editor = editor;
55854 Roo.grid.ColumnModel.defaultRenderer = function(value){
55855 if(typeof value == "string" && value.length < 1){
55861 // Alias for backwards compatibility
55862 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55865 * Ext JS Library 1.1.1
55866 * Copyright(c) 2006-2007, Ext JS, LLC.
55868 * Originally Released Under LGPL - original licence link has changed is not relivant.
55871 * <script type="text/javascript">
55875 * @class Roo.grid.AbstractSelectionModel
55876 * @extends Roo.util.Observable
55877 * Abstract base class for grid SelectionModels. It provides the interface that should be
55878 * implemented by descendant classes. This class should not be directly instantiated.
55881 Roo.grid.AbstractSelectionModel = function(){
55882 this.locked = false;
55883 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55886 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55887 /** @ignore Called by the grid automatically. Do not call directly. */
55888 init : function(grid){
55894 * Locks the selections.
55897 this.locked = true;
55901 * Unlocks the selections.
55903 unlock : function(){
55904 this.locked = false;
55908 * Returns true if the selections are locked.
55909 * @return {Boolean}
55911 isLocked : function(){
55912 return this.locked;
55916 * Ext JS Library 1.1.1
55917 * Copyright(c) 2006-2007, Ext JS, LLC.
55919 * Originally Released Under LGPL - original licence link has changed is not relivant.
55922 * <script type="text/javascript">
55925 * @extends Roo.grid.AbstractSelectionModel
55926 * @class Roo.grid.RowSelectionModel
55927 * The default SelectionModel used by {@link Roo.grid.Grid}.
55928 * It supports multiple selections and keyboard selection/navigation.
55930 * @param {Object} config
55932 Roo.grid.RowSelectionModel = function(config){
55933 Roo.apply(this, config);
55934 this.selections = new Roo.util.MixedCollection(false, function(o){
55939 this.lastActive = false;
55943 * @event selectionchange
55944 * Fires when the selection changes
55945 * @param {SelectionModel} this
55947 "selectionchange" : true,
55949 * @event afterselectionchange
55950 * Fires after the selection changes (eg. by key press or clicking)
55951 * @param {SelectionModel} this
55953 "afterselectionchange" : true,
55955 * @event beforerowselect
55956 * Fires when a row is selected being selected, return false to cancel.
55957 * @param {SelectionModel} this
55958 * @param {Number} rowIndex The selected index
55959 * @param {Boolean} keepExisting False if other selections will be cleared
55961 "beforerowselect" : true,
55964 * Fires when a row is selected.
55965 * @param {SelectionModel} this
55966 * @param {Number} rowIndex The selected index
55967 * @param {Roo.data.Record} r The record
55969 "rowselect" : true,
55971 * @event rowdeselect
55972 * Fires when a row is deselected.
55973 * @param {SelectionModel} this
55974 * @param {Number} rowIndex The selected index
55976 "rowdeselect" : true
55978 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55979 this.locked = false;
55982 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55984 * @cfg {Boolean} singleSelect
55985 * True to allow selection of only one row at a time (defaults to false)
55987 singleSelect : false,
55990 initEvents : function(){
55992 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55993 this.grid.on("mousedown", this.handleMouseDown, this);
55994 }else{ // allow click to work like normal
55995 this.grid.on("rowclick", this.handleDragableRowClick, this);
55998 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55999 "up" : function(e){
56001 this.selectPrevious(e.shiftKey);
56002 }else if(this.last !== false && this.lastActive !== false){
56003 var last = this.last;
56004 this.selectRange(this.last, this.lastActive-1);
56005 this.grid.getView().focusRow(this.lastActive);
56006 if(last !== false){
56010 this.selectFirstRow();
56012 this.fireEvent("afterselectionchange", this);
56014 "down" : function(e){
56016 this.selectNext(e.shiftKey);
56017 }else if(this.last !== false && this.lastActive !== false){
56018 var last = this.last;
56019 this.selectRange(this.last, this.lastActive+1);
56020 this.grid.getView().focusRow(this.lastActive);
56021 if(last !== false){
56025 this.selectFirstRow();
56027 this.fireEvent("afterselectionchange", this);
56032 var view = this.grid.view;
56033 view.on("refresh", this.onRefresh, this);
56034 view.on("rowupdated", this.onRowUpdated, this);
56035 view.on("rowremoved", this.onRemove, this);
56039 onRefresh : function(){
56040 var ds = this.grid.dataSource, i, v = this.grid.view;
56041 var s = this.selections;
56042 s.each(function(r){
56043 if((i = ds.indexOfId(r.id)) != -1){
56045 s.add(ds.getAt(i)); // updating the selection relate data
56053 onRemove : function(v, index, r){
56054 this.selections.remove(r);
56058 onRowUpdated : function(v, index, r){
56059 if(this.isSelected(r)){
56060 v.onRowSelect(index);
56066 * @param {Array} records The records to select
56067 * @param {Boolean} keepExisting (optional) True to keep existing selections
56069 selectRecords : function(records, keepExisting){
56071 this.clearSelections();
56073 var ds = this.grid.dataSource;
56074 for(var i = 0, len = records.length; i < len; i++){
56075 this.selectRow(ds.indexOf(records[i]), true);
56080 * Gets the number of selected rows.
56083 getCount : function(){
56084 return this.selections.length;
56088 * Selects the first row in the grid.
56090 selectFirstRow : function(){
56095 * Select the last row.
56096 * @param {Boolean} keepExisting (optional) True to keep existing selections
56098 selectLastRow : function(keepExisting){
56099 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
56103 * Selects the row immediately following the last selected row.
56104 * @param {Boolean} keepExisting (optional) True to keep existing selections
56106 selectNext : function(keepExisting){
56107 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
56108 this.selectRow(this.last+1, keepExisting);
56109 this.grid.getView().focusRow(this.last);
56114 * Selects the row that precedes the last selected row.
56115 * @param {Boolean} keepExisting (optional) True to keep existing selections
56117 selectPrevious : function(keepExisting){
56119 this.selectRow(this.last-1, keepExisting);
56120 this.grid.getView().focusRow(this.last);
56125 * Returns the selected records
56126 * @return {Array} Array of selected records
56128 getSelections : function(){
56129 return [].concat(this.selections.items);
56133 * Returns the first selected record.
56136 getSelected : function(){
56137 return this.selections.itemAt(0);
56142 * Clears all selections.
56144 clearSelections : function(fast){
56149 var ds = this.grid.dataSource;
56150 var s = this.selections;
56151 s.each(function(r){
56152 this.deselectRow(ds.indexOfId(r.id));
56156 this.selections.clear();
56163 * Selects all rows.
56165 selectAll : function(){
56169 this.selections.clear();
56170 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
56171 this.selectRow(i, true);
56176 * Returns True if there is a selection.
56177 * @return {Boolean}
56179 hasSelection : function(){
56180 return this.selections.length > 0;
56184 * Returns True if the specified row is selected.
56185 * @param {Number/Record} record The record or index of the record to check
56186 * @return {Boolean}
56188 isSelected : function(index){
56189 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
56190 return (r && this.selections.key(r.id) ? true : false);
56194 * Returns True if the specified record id is selected.
56195 * @param {String} id The id of record to check
56196 * @return {Boolean}
56198 isIdSelected : function(id){
56199 return (this.selections.key(id) ? true : false);
56203 handleMouseDown : function(e, t){
56204 var view = this.grid.getView(), rowIndex;
56205 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
56208 if(e.shiftKey && this.last !== false){
56209 var last = this.last;
56210 this.selectRange(last, rowIndex, e.ctrlKey);
56211 this.last = last; // reset the last
56212 view.focusRow(rowIndex);
56214 var isSelected = this.isSelected(rowIndex);
56215 if(e.button !== 0 && isSelected){
56216 view.focusRow(rowIndex);
56217 }else if(e.ctrlKey && isSelected){
56218 this.deselectRow(rowIndex);
56219 }else if(!isSelected){
56220 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
56221 view.focusRow(rowIndex);
56224 this.fireEvent("afterselectionchange", this);
56227 handleDragableRowClick : function(grid, rowIndex, e)
56229 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
56230 this.selectRow(rowIndex, false);
56231 grid.view.focusRow(rowIndex);
56232 this.fireEvent("afterselectionchange", this);
56237 * Selects multiple rows.
56238 * @param {Array} rows Array of the indexes of the row to select
56239 * @param {Boolean} keepExisting (optional) True to keep existing selections
56241 selectRows : function(rows, keepExisting){
56243 this.clearSelections();
56245 for(var i = 0, len = rows.length; i < len; i++){
56246 this.selectRow(rows[i], true);
56251 * Selects a range of rows. All rows in between startRow and endRow are also selected.
56252 * @param {Number} startRow The index of the first row in the range
56253 * @param {Number} endRow The index of the last row in the range
56254 * @param {Boolean} keepExisting (optional) True to retain existing selections
56256 selectRange : function(startRow, endRow, keepExisting){
56261 this.clearSelections();
56263 if(startRow <= endRow){
56264 for(var i = startRow; i <= endRow; i++){
56265 this.selectRow(i, true);
56268 for(var i = startRow; i >= endRow; i--){
56269 this.selectRow(i, true);
56275 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
56276 * @param {Number} startRow The index of the first row in the range
56277 * @param {Number} endRow The index of the last row in the range
56279 deselectRange : function(startRow, endRow, preventViewNotify){
56283 for(var i = startRow; i <= endRow; i++){
56284 this.deselectRow(i, preventViewNotify);
56290 * @param {Number} row The index of the row to select
56291 * @param {Boolean} keepExisting (optional) True to keep existing selections
56293 selectRow : function(index, keepExisting, preventViewNotify){
56294 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
56297 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
56298 if(!keepExisting || this.singleSelect){
56299 this.clearSelections();
56301 var r = this.grid.dataSource.getAt(index);
56302 this.selections.add(r);
56303 this.last = this.lastActive = index;
56304 if(!preventViewNotify){
56305 this.grid.getView().onRowSelect(index);
56307 this.fireEvent("rowselect", this, index, r);
56308 this.fireEvent("selectionchange", this);
56314 * @param {Number} row The index of the row to deselect
56316 deselectRow : function(index, preventViewNotify){
56320 if(this.last == index){
56323 if(this.lastActive == index){
56324 this.lastActive = false;
56326 var r = this.grid.dataSource.getAt(index);
56327 this.selections.remove(r);
56328 if(!preventViewNotify){
56329 this.grid.getView().onRowDeselect(index);
56331 this.fireEvent("rowdeselect", this, index);
56332 this.fireEvent("selectionchange", this);
56336 restoreLast : function(){
56338 this.last = this._last;
56343 acceptsNav : function(row, col, cm){
56344 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56348 onEditorKey : function(field, e){
56349 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
56354 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56356 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56358 }else if(k == e.ENTER && !e.ctrlKey){
56362 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
56364 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
56366 }else if(k == e.ESC){
56370 g.startEditing(newCell[0], newCell[1]);
56375 * Ext JS Library 1.1.1
56376 * Copyright(c) 2006-2007, Ext JS, LLC.
56378 * Originally Released Under LGPL - original licence link has changed is not relivant.
56381 * <script type="text/javascript">
56384 * @class Roo.grid.CellSelectionModel
56385 * @extends Roo.grid.AbstractSelectionModel
56386 * This class provides the basic implementation for cell selection in a grid.
56388 * @param {Object} config The object containing the configuration of this model.
56389 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
56391 Roo.grid.CellSelectionModel = function(config){
56392 Roo.apply(this, config);
56394 this.selection = null;
56398 * @event beforerowselect
56399 * Fires before a cell is selected.
56400 * @param {SelectionModel} this
56401 * @param {Number} rowIndex The selected row index
56402 * @param {Number} colIndex The selected cell index
56404 "beforecellselect" : true,
56406 * @event cellselect
56407 * Fires when a cell is selected.
56408 * @param {SelectionModel} this
56409 * @param {Number} rowIndex The selected row index
56410 * @param {Number} colIndex The selected cell index
56412 "cellselect" : true,
56414 * @event selectionchange
56415 * Fires when the active selection changes.
56416 * @param {SelectionModel} this
56417 * @param {Object} selection null for no selection or an object (o) with two properties
56419 <li>o.record: the record object for the row the selection is in</li>
56420 <li>o.cell: An array of [rowIndex, columnIndex]</li>
56423 "selectionchange" : true,
56426 * Fires when the tab (or enter) was pressed on the last editable cell
56427 * You can use this to trigger add new row.
56428 * @param {SelectionModel} this
56432 * @event beforeeditnext
56433 * Fires before the next editable sell is made active
56434 * You can use this to skip to another cell or fire the tabend
56435 * if you set cell to false
56436 * @param {Object} eventdata object : { cell : [ row, col ] }
56438 "beforeeditnext" : true
56440 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
56443 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
56445 enter_is_tab: false,
56448 initEvents : function(){
56449 this.grid.on("mousedown", this.handleMouseDown, this);
56450 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
56451 var view = this.grid.view;
56452 view.on("refresh", this.onViewChange, this);
56453 view.on("rowupdated", this.onRowUpdated, this);
56454 view.on("beforerowremoved", this.clearSelections, this);
56455 view.on("beforerowsinserted", this.clearSelections, this);
56456 if(this.grid.isEditor){
56457 this.grid.on("beforeedit", this.beforeEdit, this);
56462 beforeEdit : function(e){
56463 this.select(e.row, e.column, false, true, e.record);
56467 onRowUpdated : function(v, index, r){
56468 if(this.selection && this.selection.record == r){
56469 v.onCellSelect(index, this.selection.cell[1]);
56474 onViewChange : function(){
56475 this.clearSelections(true);
56479 * Returns the currently selected cell,.
56480 * @return {Array} The selected cell (row, column) or null if none selected.
56482 getSelectedCell : function(){
56483 return this.selection ? this.selection.cell : null;
56487 * Clears all selections.
56488 * @param {Boolean} true to prevent the gridview from being notified about the change.
56490 clearSelections : function(preventNotify){
56491 var s = this.selection;
56493 if(preventNotify !== true){
56494 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
56496 this.selection = null;
56497 this.fireEvent("selectionchange", this, null);
56502 * Returns true if there is a selection.
56503 * @return {Boolean}
56505 hasSelection : function(){
56506 return this.selection ? true : false;
56510 handleMouseDown : function(e, t){
56511 var v = this.grid.getView();
56512 if(this.isLocked()){
56515 var row = v.findRowIndex(t);
56516 var cell = v.findCellIndex(t);
56517 if(row !== false && cell !== false){
56518 this.select(row, cell);
56524 * @param {Number} rowIndex
56525 * @param {Number} collIndex
56527 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
56528 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
56529 this.clearSelections();
56530 r = r || this.grid.dataSource.getAt(rowIndex);
56533 cell : [rowIndex, colIndex]
56535 if(!preventViewNotify){
56536 var v = this.grid.getView();
56537 v.onCellSelect(rowIndex, colIndex);
56538 if(preventFocus !== true){
56539 v.focusCell(rowIndex, colIndex);
56542 this.fireEvent("cellselect", this, rowIndex, colIndex);
56543 this.fireEvent("selectionchange", this, this.selection);
56548 isSelectable : function(rowIndex, colIndex, cm){
56549 return !cm.isHidden(colIndex);
56553 handleKeyDown : function(e){
56554 //Roo.log('Cell Sel Model handleKeyDown');
56555 if(!e.isNavKeyPress()){
56558 var g = this.grid, s = this.selection;
56561 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
56563 this.select(cell[0], cell[1]);
56568 var walk = function(row, col, step){
56569 return g.walkCells(row, col, step, sm.isSelectable, sm);
56571 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
56578 // handled by onEditorKey
56579 if (g.isEditor && g.editing) {
56583 newCell = walk(r, c-1, -1);
56585 newCell = walk(r, c+1, 1);
56590 newCell = walk(r+1, c, 1);
56594 newCell = walk(r-1, c, -1);
56598 newCell = walk(r, c+1, 1);
56602 newCell = walk(r, c-1, -1);
56607 if(g.isEditor && !g.editing){
56608 g.startEditing(r, c);
56617 this.select(newCell[0], newCell[1]);
56623 acceptsNav : function(row, col, cm){
56624 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56628 * @param {Number} field (not used) - as it's normally used as a listener
56629 * @param {Number} e - event - fake it by using
56631 * var e = Roo.EventObjectImpl.prototype;
56632 * e.keyCode = e.TAB
56636 onEditorKey : function(field, e){
56638 var k = e.getKey(),
56641 ed = g.activeEditor,
56643 ///Roo.log('onEditorKey' + k);
56646 if (this.enter_is_tab && k == e.ENTER) {
56652 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56654 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56660 } else if(k == e.ENTER && !e.ctrlKey){
56663 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56665 } else if(k == e.ESC){
56670 var ecall = { cell : newCell, forward : forward };
56671 this.fireEvent('beforeeditnext', ecall );
56672 newCell = ecall.cell;
56673 forward = ecall.forward;
56677 //Roo.log('next cell after edit');
56678 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
56679 } else if (forward) {
56680 // tabbed past last
56681 this.fireEvent.defer(100, this, ['tabend',this]);
56686 * Ext JS Library 1.1.1
56687 * Copyright(c) 2006-2007, Ext JS, LLC.
56689 * Originally Released Under LGPL - original licence link has changed is not relivant.
56692 * <script type="text/javascript">
56696 * @class Roo.grid.EditorGrid
56697 * @extends Roo.grid.Grid
56698 * Class for creating and editable grid.
56699 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56700 * The container MUST have some type of size defined for the grid to fill. The container will be
56701 * automatically set to position relative if it isn't already.
56702 * @param {Object} dataSource The data model to bind to
56703 * @param {Object} colModel The column model with info about this grid's columns
56705 Roo.grid.EditorGrid = function(container, config){
56706 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
56707 this.getGridEl().addClass("xedit-grid");
56709 if(!this.selModel){
56710 this.selModel = new Roo.grid.CellSelectionModel();
56713 this.activeEditor = null;
56717 * @event beforeedit
56718 * Fires before cell editing is triggered. The edit event object has the following properties <br />
56719 * <ul style="padding:5px;padding-left:16px;">
56720 * <li>grid - This grid</li>
56721 * <li>record - The record being edited</li>
56722 * <li>field - The field name being edited</li>
56723 * <li>value - The value for the field being edited.</li>
56724 * <li>row - The grid row index</li>
56725 * <li>column - The grid column index</li>
56726 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56728 * @param {Object} e An edit event (see above for description)
56730 "beforeedit" : true,
56733 * Fires after a cell is edited. <br />
56734 * <ul style="padding:5px;padding-left:16px;">
56735 * <li>grid - This grid</li>
56736 * <li>record - The record being edited</li>
56737 * <li>field - The field name being edited</li>
56738 * <li>value - The value being set</li>
56739 * <li>originalValue - The original value for the field, before the edit.</li>
56740 * <li>row - The grid row index</li>
56741 * <li>column - The grid column index</li>
56743 * @param {Object} e An edit event (see above for description)
56745 "afteredit" : true,
56747 * @event validateedit
56748 * Fires after a cell is edited, but before the value is set in the record.
56749 * You can use this to modify the value being set in the field, Return false
56750 * to cancel the change. The edit event object has the following properties <br />
56751 * <ul style="padding:5px;padding-left:16px;">
56752 * <li>editor - This editor</li>
56753 * <li>grid - This grid</li>
56754 * <li>record - The record being edited</li>
56755 * <li>field - The field name being edited</li>
56756 * <li>value - The value being set</li>
56757 * <li>originalValue - The original value for the field, before the edit.</li>
56758 * <li>row - The grid row index</li>
56759 * <li>column - The grid column index</li>
56760 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56762 * @param {Object} e An edit event (see above for description)
56764 "validateedit" : true
56766 this.on("bodyscroll", this.stopEditing, this);
56767 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56770 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56772 * @cfg {Number} clicksToEdit
56773 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56780 trackMouseOver: false, // causes very odd FF errors
56782 onCellDblClick : function(g, row, col){
56783 this.startEditing(row, col);
56786 onEditComplete : function(ed, value, startValue){
56787 this.editing = false;
56788 this.activeEditor = null;
56789 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56791 var field = this.colModel.getDataIndex(ed.col);
56796 originalValue: startValue,
56803 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
56806 if(String(value) !== String(startValue)){
56808 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56809 r.set(field, e.value);
56810 // if we are dealing with a combo box..
56811 // then we also set the 'name' colum to be the displayField
56812 if (ed.field.displayField && ed.field.name) {
56813 r.set(ed.field.name, ed.field.el.dom.value);
56816 delete e.cancel; //?? why!!!
56817 this.fireEvent("afteredit", e);
56820 this.fireEvent("afteredit", e); // always fire it!
56822 this.view.focusCell(ed.row, ed.col);
56826 * Starts editing the specified for the specified row/column
56827 * @param {Number} rowIndex
56828 * @param {Number} colIndex
56830 startEditing : function(row, col){
56831 this.stopEditing();
56832 if(this.colModel.isCellEditable(col, row)){
56833 this.view.ensureVisible(row, col, true);
56835 var r = this.dataSource.getAt(row);
56836 var field = this.colModel.getDataIndex(col);
56837 var cell = Roo.get(this.view.getCell(row,col));
56842 value: r.data[field],
56847 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56848 this.editing = true;
56849 var ed = this.colModel.getCellEditor(col, row);
56855 ed.render(ed.parentEl || document.body);
56861 (function(){ // complex but required for focus issues in safari, ie and opera
56865 ed.on("complete", this.onEditComplete, this, {single: true});
56866 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56867 this.activeEditor = ed;
56868 var v = r.data[field];
56869 ed.startEdit(this.view.getCell(row, col), v);
56870 // combo's with 'displayField and name set
56871 if (ed.field.displayField && ed.field.name) {
56872 ed.field.el.dom.value = r.data[ed.field.name];
56876 }).defer(50, this);
56882 * Stops any active editing
56884 stopEditing : function(){
56885 if(this.activeEditor){
56886 this.activeEditor.completeEdit();
56888 this.activeEditor = null;
56892 * Called to get grid's drag proxy text, by default returns this.ddText.
56895 getDragDropText : function(){
56896 var count = this.selModel.getSelectedCell() ? 1 : 0;
56897 return String.format(this.ddText, count, count == 1 ? '' : 's');
56902 * Ext JS Library 1.1.1
56903 * Copyright(c) 2006-2007, Ext JS, LLC.
56905 * Originally Released Under LGPL - original licence link has changed is not relivant.
56908 * <script type="text/javascript">
56911 // private - not really -- you end up using it !
56912 // This is a support class used internally by the Grid components
56915 * @class Roo.grid.GridEditor
56916 * @extends Roo.Editor
56917 * Class for creating and editable grid elements.
56918 * @param {Object} config any settings (must include field)
56920 Roo.grid.GridEditor = function(field, config){
56921 if (!config && field.field) {
56923 field = Roo.factory(config.field, Roo.form);
56925 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56926 field.monitorTab = false;
56929 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56932 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56935 alignment: "tl-tl",
56938 cls: "x-small-editor x-grid-editor",
56943 * Ext JS Library 1.1.1
56944 * Copyright(c) 2006-2007, Ext JS, LLC.
56946 * Originally Released Under LGPL - original licence link has changed is not relivant.
56949 * <script type="text/javascript">
56954 Roo.grid.PropertyRecord = Roo.data.Record.create([
56955 {name:'name',type:'string'}, 'value'
56959 Roo.grid.PropertyStore = function(grid, source){
56961 this.store = new Roo.data.Store({
56962 recordType : Roo.grid.PropertyRecord
56964 this.store.on('update', this.onUpdate, this);
56966 this.setSource(source);
56968 Roo.grid.PropertyStore.superclass.constructor.call(this);
56973 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56974 setSource : function(o){
56976 this.store.removeAll();
56979 if(this.isEditableValue(o[k])){
56980 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56983 this.store.loadRecords({records: data}, {}, true);
56986 onUpdate : function(ds, record, type){
56987 if(type == Roo.data.Record.EDIT){
56988 var v = record.data['value'];
56989 var oldValue = record.modified['value'];
56990 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56991 this.source[record.id] = v;
56993 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
57000 getProperty : function(row){
57001 return this.store.getAt(row);
57004 isEditableValue: function(val){
57005 if(val && val instanceof Date){
57007 }else if(typeof val == 'object' || typeof val == 'function'){
57013 setValue : function(prop, value){
57014 this.source[prop] = value;
57015 this.store.getById(prop).set('value', value);
57018 getSource : function(){
57019 return this.source;
57023 Roo.grid.PropertyColumnModel = function(grid, store){
57026 g.PropertyColumnModel.superclass.constructor.call(this, [
57027 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
57028 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
57030 this.store = store;
57031 this.bselect = Roo.DomHelper.append(document.body, {
57032 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
57033 {tag: 'option', value: 'true', html: 'true'},
57034 {tag: 'option', value: 'false', html: 'false'}
57037 Roo.id(this.bselect);
57040 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
57041 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
57042 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
57043 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
57044 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
57046 this.renderCellDelegate = this.renderCell.createDelegate(this);
57047 this.renderPropDelegate = this.renderProp.createDelegate(this);
57050 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
57054 valueText : 'Value',
57056 dateFormat : 'm/j/Y',
57059 renderDate : function(dateVal){
57060 return dateVal.dateFormat(this.dateFormat);
57063 renderBool : function(bVal){
57064 return bVal ? 'true' : 'false';
57067 isCellEditable : function(colIndex, rowIndex){
57068 return colIndex == 1;
57071 getRenderer : function(col){
57073 this.renderCellDelegate : this.renderPropDelegate;
57076 renderProp : function(v){
57077 return this.getPropertyName(v);
57080 renderCell : function(val){
57082 if(val instanceof Date){
57083 rv = this.renderDate(val);
57084 }else if(typeof val == 'boolean'){
57085 rv = this.renderBool(val);
57087 return Roo.util.Format.htmlEncode(rv);
57090 getPropertyName : function(name){
57091 var pn = this.grid.propertyNames;
57092 return pn && pn[name] ? pn[name] : name;
57095 getCellEditor : function(colIndex, rowIndex){
57096 var p = this.store.getProperty(rowIndex);
57097 var n = p.data['name'], val = p.data['value'];
57099 if(typeof(this.grid.customEditors[n]) == 'string'){
57100 return this.editors[this.grid.customEditors[n]];
57102 if(typeof(this.grid.customEditors[n]) != 'undefined'){
57103 return this.grid.customEditors[n];
57105 if(val instanceof Date){
57106 return this.editors['date'];
57107 }else if(typeof val == 'number'){
57108 return this.editors['number'];
57109 }else if(typeof val == 'boolean'){
57110 return this.editors['boolean'];
57112 return this.editors['string'];
57118 * @class Roo.grid.PropertyGrid
57119 * @extends Roo.grid.EditorGrid
57120 * This class represents the interface of a component based property grid control.
57121 * <br><br>Usage:<pre><code>
57122 var grid = new Roo.grid.PropertyGrid("my-container-id", {
57130 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57131 * The container MUST have some type of size defined for the grid to fill. The container will be
57132 * automatically set to position relative if it isn't already.
57133 * @param {Object} config A config object that sets properties on this grid.
57135 Roo.grid.PropertyGrid = function(container, config){
57136 config = config || {};
57137 var store = new Roo.grid.PropertyStore(this);
57138 this.store = store;
57139 var cm = new Roo.grid.PropertyColumnModel(this, store);
57140 store.store.sort('name', 'ASC');
57141 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
57144 enableColLock:false,
57145 enableColumnMove:false,
57147 trackMouseOver: false,
57150 this.getGridEl().addClass('x-props-grid');
57151 this.lastEditRow = null;
57152 this.on('columnresize', this.onColumnResize, this);
57155 * @event beforepropertychange
57156 * Fires before a property changes (return false to stop?)
57157 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57158 * @param {String} id Record Id
57159 * @param {String} newval New Value
57160 * @param {String} oldval Old Value
57162 "beforepropertychange": true,
57164 * @event propertychange
57165 * Fires after a property changes
57166 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57167 * @param {String} id Record Id
57168 * @param {String} newval New Value
57169 * @param {String} oldval Old Value
57171 "propertychange": true
57173 this.customEditors = this.customEditors || {};
57175 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
57178 * @cfg {Object} customEditors map of colnames=> custom editors.
57179 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
57180 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
57181 * false disables editing of the field.
57185 * @cfg {Object} propertyNames map of property Names to their displayed value
57188 render : function(){
57189 Roo.grid.PropertyGrid.superclass.render.call(this);
57190 this.autoSize.defer(100, this);
57193 autoSize : function(){
57194 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
57196 this.view.fitColumns();
57200 onColumnResize : function(){
57201 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
57205 * Sets the data for the Grid
57206 * accepts a Key => Value object of all the elements avaiable.
57207 * @param {Object} data to appear in grid.
57209 setSource : function(source){
57210 this.store.setSource(source);
57214 * Gets all the data from the grid.
57215 * @return {Object} data data stored in grid
57217 getSource : function(){
57218 return this.store.getSource();
57227 * @class Roo.grid.Calendar
57228 * @extends Roo.util.Grid
57229 * This class extends the Grid to provide a calendar widget
57230 * <br><br>Usage:<pre><code>
57231 var grid = new Roo.grid.Calendar("my-container-id", {
57234 selModel: mySelectionModel,
57235 autoSizeColumns: true,
57236 monitorWindowResize: false,
57237 trackMouseOver: true
57238 eventstore : real data store..
57244 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57245 * The container MUST have some type of size defined for the grid to fill. The container will be
57246 * automatically set to position relative if it isn't already.
57247 * @param {Object} config A config object that sets properties on this grid.
57249 Roo.grid.Calendar = function(container, config){
57250 // initialize the container
57251 this.container = Roo.get(container);
57252 this.container.update("");
57253 this.container.setStyle("overflow", "hidden");
57254 this.container.addClass('x-grid-container');
57256 this.id = this.container.id;
57258 Roo.apply(this, config);
57259 // check and correct shorthanded configs
57263 for (var r = 0;r < 6;r++) {
57266 for (var c =0;c < 7;c++) {
57270 if (this.eventStore) {
57271 this.eventStore= Roo.factory(this.eventStore, Roo.data);
57272 this.eventStore.on('load',this.onLoad, this);
57273 this.eventStore.on('beforeload',this.clearEvents, this);
57277 this.dataSource = new Roo.data.Store({
57278 proxy: new Roo.data.MemoryProxy(rows),
57279 reader: new Roo.data.ArrayReader({}, [
57280 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
57283 this.dataSource.load();
57284 this.ds = this.dataSource;
57285 this.ds.xmodule = this.xmodule || false;
57288 var cellRender = function(v,x,r)
57290 return String.format(
57291 '<div class="fc-day fc-widget-content"><div>' +
57292 '<div class="fc-event-container"></div>' +
57293 '<div class="fc-day-number">{0}</div>'+
57295 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
57296 '</div></div>', v);
57301 this.colModel = new Roo.grid.ColumnModel( [
57303 xtype: 'ColumnModel',
57305 dataIndex : 'weekday0',
57307 renderer : cellRender
57310 xtype: 'ColumnModel',
57312 dataIndex : 'weekday1',
57314 renderer : cellRender
57317 xtype: 'ColumnModel',
57319 dataIndex : 'weekday2',
57320 header : 'Tuesday',
57321 renderer : cellRender
57324 xtype: 'ColumnModel',
57326 dataIndex : 'weekday3',
57327 header : 'Wednesday',
57328 renderer : cellRender
57331 xtype: 'ColumnModel',
57333 dataIndex : 'weekday4',
57334 header : 'Thursday',
57335 renderer : cellRender
57338 xtype: 'ColumnModel',
57340 dataIndex : 'weekday5',
57342 renderer : cellRender
57345 xtype: 'ColumnModel',
57347 dataIndex : 'weekday6',
57348 header : 'Saturday',
57349 renderer : cellRender
57352 this.cm = this.colModel;
57353 this.cm.xmodule = this.xmodule || false;
57357 //this.selModel = new Roo.grid.CellSelectionModel();
57358 //this.sm = this.selModel;
57359 //this.selModel.init(this);
57363 this.container.setWidth(this.width);
57367 this.container.setHeight(this.height);
57374 * The raw click event for the entire grid.
57375 * @param {Roo.EventObject} e
57380 * The raw dblclick event for the entire grid.
57381 * @param {Roo.EventObject} e
57385 * @event contextmenu
57386 * The raw contextmenu event for the entire grid.
57387 * @param {Roo.EventObject} e
57389 "contextmenu" : true,
57392 * The raw mousedown event for the entire grid.
57393 * @param {Roo.EventObject} e
57395 "mousedown" : true,
57398 * The raw mouseup event for the entire grid.
57399 * @param {Roo.EventObject} e
57404 * The raw mouseover event for the entire grid.
57405 * @param {Roo.EventObject} e
57407 "mouseover" : true,
57410 * The raw mouseout event for the entire grid.
57411 * @param {Roo.EventObject} e
57416 * The raw keypress event for the entire grid.
57417 * @param {Roo.EventObject} e
57422 * The raw keydown event for the entire grid.
57423 * @param {Roo.EventObject} e
57431 * Fires when a cell is clicked
57432 * @param {Grid} this
57433 * @param {Number} rowIndex
57434 * @param {Number} columnIndex
57435 * @param {Roo.EventObject} e
57437 "cellclick" : true,
57439 * @event celldblclick
57440 * Fires when a cell is double clicked
57441 * @param {Grid} this
57442 * @param {Number} rowIndex
57443 * @param {Number} columnIndex
57444 * @param {Roo.EventObject} e
57446 "celldblclick" : true,
57449 * Fires when a row is clicked
57450 * @param {Grid} this
57451 * @param {Number} rowIndex
57452 * @param {Roo.EventObject} e
57456 * @event rowdblclick
57457 * Fires when a row is double clicked
57458 * @param {Grid} this
57459 * @param {Number} rowIndex
57460 * @param {Roo.EventObject} e
57462 "rowdblclick" : true,
57464 * @event headerclick
57465 * Fires when a header is clicked
57466 * @param {Grid} this
57467 * @param {Number} columnIndex
57468 * @param {Roo.EventObject} e
57470 "headerclick" : true,
57472 * @event headerdblclick
57473 * Fires when a header cell is double clicked
57474 * @param {Grid} this
57475 * @param {Number} columnIndex
57476 * @param {Roo.EventObject} e
57478 "headerdblclick" : true,
57480 * @event rowcontextmenu
57481 * Fires when a row is right clicked
57482 * @param {Grid} this
57483 * @param {Number} rowIndex
57484 * @param {Roo.EventObject} e
57486 "rowcontextmenu" : true,
57488 * @event cellcontextmenu
57489 * Fires when a cell is right clicked
57490 * @param {Grid} this
57491 * @param {Number} rowIndex
57492 * @param {Number} cellIndex
57493 * @param {Roo.EventObject} e
57495 "cellcontextmenu" : true,
57497 * @event headercontextmenu
57498 * Fires when a header is right clicked
57499 * @param {Grid} this
57500 * @param {Number} columnIndex
57501 * @param {Roo.EventObject} e
57503 "headercontextmenu" : true,
57505 * @event bodyscroll
57506 * Fires when the body element is scrolled
57507 * @param {Number} scrollLeft
57508 * @param {Number} scrollTop
57510 "bodyscroll" : true,
57512 * @event columnresize
57513 * Fires when the user resizes a column
57514 * @param {Number} columnIndex
57515 * @param {Number} newSize
57517 "columnresize" : true,
57519 * @event columnmove
57520 * Fires when the user moves a column
57521 * @param {Number} oldIndex
57522 * @param {Number} newIndex
57524 "columnmove" : true,
57527 * Fires when row(s) start being dragged
57528 * @param {Grid} this
57529 * @param {Roo.GridDD} dd The drag drop object
57530 * @param {event} e The raw browser event
57532 "startdrag" : true,
57535 * Fires when a drag operation is complete
57536 * @param {Grid} this
57537 * @param {Roo.GridDD} dd The drag drop object
57538 * @param {event} e The raw browser event
57543 * Fires when dragged row(s) are dropped on a valid DD target
57544 * @param {Grid} this
57545 * @param {Roo.GridDD} dd The drag drop object
57546 * @param {String} targetId The target drag drop object
57547 * @param {event} e The raw browser event
57552 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
57553 * @param {Grid} this
57554 * @param {Roo.GridDD} dd The drag drop object
57555 * @param {String} targetId The target drag drop object
57556 * @param {event} e The raw browser event
57561 * Fires when the dragged row(s) first cross another DD target while being dragged
57562 * @param {Grid} this
57563 * @param {Roo.GridDD} dd The drag drop object
57564 * @param {String} targetId The target drag drop object
57565 * @param {event} e The raw browser event
57567 "dragenter" : true,
57570 * Fires when the dragged row(s) leave another DD target while being dragged
57571 * @param {Grid} this
57572 * @param {Roo.GridDD} dd The drag drop object
57573 * @param {String} targetId The target drag drop object
57574 * @param {event} e The raw browser event
57579 * Fires when a row is rendered, so you can change add a style to it.
57580 * @param {GridView} gridview The grid view
57581 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
57587 * Fires when the grid is rendered
57588 * @param {Grid} grid
57593 * Fires when a date is selected
57594 * @param {DatePicker} this
57595 * @param {Date} date The selected date
57599 * @event monthchange
57600 * Fires when the displayed month changes
57601 * @param {DatePicker} this
57602 * @param {Date} date The selected month
57604 'monthchange': true,
57606 * @event evententer
57607 * Fires when mouse over an event
57608 * @param {Calendar} this
57609 * @param {event} Event
57611 'evententer': true,
57613 * @event eventleave
57614 * Fires when the mouse leaves an
57615 * @param {Calendar} this
57618 'eventleave': true,
57620 * @event eventclick
57621 * Fires when the mouse click an
57622 * @param {Calendar} this
57625 'eventclick': true,
57627 * @event eventrender
57628 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
57629 * @param {Calendar} this
57630 * @param {data} data to be modified
57632 'eventrender': true
57636 Roo.grid.Grid.superclass.constructor.call(this);
57637 this.on('render', function() {
57638 this.view.el.addClass('x-grid-cal');
57640 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
57644 if (!Roo.grid.Calendar.style) {
57645 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
57648 '.x-grid-cal .x-grid-col' : {
57649 height: 'auto !important',
57650 'vertical-align': 'top'
57652 '.x-grid-cal .fc-event-hori' : {
57663 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
57665 * @cfg {Store} eventStore The store that loads events.
57670 activeDate : false,
57673 monitorWindowResize : false,
57676 resizeColumns : function() {
57677 var col = (this.view.el.getWidth() / 7) - 3;
57678 // loop through cols, and setWidth
57679 for(var i =0 ; i < 7 ; i++){
57680 this.cm.setColumnWidth(i, col);
57683 setDate :function(date) {
57685 Roo.log('setDate?');
57687 this.resizeColumns();
57688 var vd = this.activeDate;
57689 this.activeDate = date;
57690 // if(vd && this.el){
57691 // var t = date.getTime();
57692 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
57693 // Roo.log('using add remove');
57695 // this.fireEvent('monthchange', this, date);
57697 // this.cells.removeClass("fc-state-highlight");
57698 // this.cells.each(function(c){
57699 // if(c.dateValue == t){
57700 // c.addClass("fc-state-highlight");
57701 // setTimeout(function(){
57702 // try{c.dom.firstChild.focus();}catch(e){}
57712 var days = date.getDaysInMonth();
57714 var firstOfMonth = date.getFirstDateOfMonth();
57715 var startingPos = firstOfMonth.getDay()-this.startDay;
57717 if(startingPos < this.startDay){
57721 var pm = date.add(Date.MONTH, -1);
57722 var prevStart = pm.getDaysInMonth()-startingPos;
57726 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57728 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57729 //this.cells.addClassOnOver('fc-state-hover');
57731 var cells = this.cells.elements;
57732 var textEls = this.textNodes;
57734 //Roo.each(cells, function(cell){
57735 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57738 days += startingPos;
57740 // convert everything to numbers so it's fast
57741 var day = 86400000;
57742 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57745 //Roo.log(prevStart);
57747 var today = new Date().clearTime().getTime();
57748 var sel = date.clearTime().getTime();
57749 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57750 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57751 var ddMatch = this.disabledDatesRE;
57752 var ddText = this.disabledDatesText;
57753 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57754 var ddaysText = this.disabledDaysText;
57755 var format = this.format;
57757 var setCellClass = function(cal, cell){
57759 //Roo.log('set Cell Class');
57761 var t = d.getTime();
57766 cell.dateValue = t;
57768 cell.className += " fc-today";
57769 cell.className += " fc-state-highlight";
57770 cell.title = cal.todayText;
57773 // disable highlight in other month..
57774 cell.className += " fc-state-highlight";
57779 //cell.className = " fc-state-disabled";
57780 cell.title = cal.minText;
57784 //cell.className = " fc-state-disabled";
57785 cell.title = cal.maxText;
57789 if(ddays.indexOf(d.getDay()) != -1){
57790 // cell.title = ddaysText;
57791 // cell.className = " fc-state-disabled";
57794 if(ddMatch && format){
57795 var fvalue = d.dateFormat(format);
57796 if(ddMatch.test(fvalue)){
57797 cell.title = ddText.replace("%0", fvalue);
57798 cell.className = " fc-state-disabled";
57802 if (!cell.initialClassName) {
57803 cell.initialClassName = cell.dom.className;
57806 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57811 for(; i < startingPos; i++) {
57812 cells[i].dayName = (++prevStart);
57813 Roo.log(textEls[i]);
57814 d.setDate(d.getDate()+1);
57816 //cells[i].className = "fc-past fc-other-month";
57817 setCellClass(this, cells[i]);
57822 for(; i < days; i++){
57823 intDay = i - startingPos + 1;
57824 cells[i].dayName = (intDay);
57825 d.setDate(d.getDate()+1);
57827 cells[i].className = ''; // "x-date-active";
57828 setCellClass(this, cells[i]);
57832 for(; i < 42; i++) {
57833 //textEls[i].innerHTML = (++extraDays);
57835 d.setDate(d.getDate()+1);
57836 cells[i].dayName = (++extraDays);
57837 cells[i].className = "fc-future fc-other-month";
57838 setCellClass(this, cells[i]);
57841 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57843 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57845 // this will cause all the cells to mis
57848 for (var r = 0;r < 6;r++) {
57849 for (var c =0;c < 7;c++) {
57850 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57854 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57855 for(i=0;i<cells.length;i++) {
57857 this.cells.elements[i].dayName = cells[i].dayName ;
57858 this.cells.elements[i].className = cells[i].className;
57859 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57860 this.cells.elements[i].title = cells[i].title ;
57861 this.cells.elements[i].dateValue = cells[i].dateValue ;
57867 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57868 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57870 ////if(totalRows != 6){
57871 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57872 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57875 this.fireEvent('monthchange', this, date);
57880 * Returns the grid's SelectionModel.
57881 * @return {SelectionModel}
57883 getSelectionModel : function(){
57884 if(!this.selModel){
57885 this.selModel = new Roo.grid.CellSelectionModel();
57887 return this.selModel;
57891 this.eventStore.load()
57897 findCell : function(dt) {
57898 dt = dt.clearTime().getTime();
57900 this.cells.each(function(c){
57901 //Roo.log("check " +c.dateValue + '?=' + dt);
57902 if(c.dateValue == dt){
57912 findCells : function(rec) {
57913 var s = rec.data.start_dt.clone().clearTime().getTime();
57915 var e= rec.data.end_dt.clone().clearTime().getTime();
57918 this.cells.each(function(c){
57919 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57921 if(c.dateValue > e){
57924 if(c.dateValue < s){
57933 findBestRow: function(cells)
57937 for (var i =0 ; i < cells.length;i++) {
57938 ret = Math.max(cells[i].rows || 0,ret);
57945 addItem : function(rec)
57947 // look for vertical location slot in
57948 var cells = this.findCells(rec);
57950 rec.row = this.findBestRow(cells);
57952 // work out the location.
57956 for(var i =0; i < cells.length; i++) {
57964 if (crow.start.getY() == cells[i].getY()) {
57966 crow.end = cells[i];
57982 for (var i = 0; i < cells.length;i++) {
57983 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57990 clearEvents: function() {
57992 if (!this.eventStore.getCount()) {
57995 // reset number of rows in cells.
57996 Roo.each(this.cells.elements, function(c){
58000 this.eventStore.each(function(e) {
58001 this.clearEvent(e);
58006 clearEvent : function(ev)
58009 Roo.each(ev.els, function(el) {
58010 el.un('mouseenter' ,this.onEventEnter, this);
58011 el.un('mouseleave' ,this.onEventLeave, this);
58019 renderEvent : function(ev,ctr) {
58021 ctr = this.view.el.select('.fc-event-container',true).first();
58025 this.clearEvent(ev);
58031 var cells = ev.cells;
58032 var rows = ev.rows;
58033 this.fireEvent('eventrender', this, ev);
58035 for(var i =0; i < rows.length; i++) {
58039 cls += ' fc-event-start';
58041 if ((i+1) == rows.length) {
58042 cls += ' fc-event-end';
58045 //Roo.log(ev.data);
58046 // how many rows should it span..
58047 var cg = this.eventTmpl.append(ctr,Roo.apply({
58050 }, ev.data) , true);
58053 cg.on('mouseenter' ,this.onEventEnter, this, ev);
58054 cg.on('mouseleave' ,this.onEventLeave, this, ev);
58055 cg.on('click', this.onEventClick, this, ev);
58059 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
58060 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
58063 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
58064 cg.setWidth(ebox.right - sbox.x -2);
58068 renderEvents: function()
58070 // first make sure there is enough space..
58072 if (!this.eventTmpl) {
58073 this.eventTmpl = new Roo.Template(
58074 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
58075 '<div class="fc-event-inner">' +
58076 '<span class="fc-event-time">{time}</span>' +
58077 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
58079 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
58087 this.cells.each(function(c) {
58088 //Roo.log(c.select('.fc-day-content div',true).first());
58089 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
58092 var ctr = this.view.el.select('.fc-event-container',true).first();
58095 this.eventStore.each(function(ev){
58097 this.renderEvent(ev);
58101 this.view.layout();
58105 onEventEnter: function (e, el,event,d) {
58106 this.fireEvent('evententer', this, el, event);
58109 onEventLeave: function (e, el,event,d) {
58110 this.fireEvent('eventleave', this, el, event);
58113 onEventClick: function (e, el,event,d) {
58114 this.fireEvent('eventclick', this, el, event);
58117 onMonthChange: function () {
58121 onLoad: function () {
58123 //Roo.log('calendar onload');
58125 if(this.eventStore.getCount() > 0){
58129 this.eventStore.each(function(d){
58134 if (typeof(add.end_dt) == 'undefined') {
58135 Roo.log("Missing End time in calendar data: ");
58139 if (typeof(add.start_dt) == 'undefined') {
58140 Roo.log("Missing Start time in calendar data: ");
58144 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
58145 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
58146 add.id = add.id || d.id;
58147 add.title = add.title || '??';
58155 this.renderEvents();
58165 render : function ()
58169 if (!this.view.el.hasClass('course-timesheet')) {
58170 this.view.el.addClass('course-timesheet');
58172 if (this.tsStyle) {
58177 Roo.log(_this.grid.view.el.getWidth());
58180 this.tsStyle = Roo.util.CSS.createStyleSheet({
58181 '.course-timesheet .x-grid-row' : {
58184 '.x-grid-row td' : {
58185 'vertical-align' : 0
58187 '.course-edit-link' : {
58189 'text-overflow' : 'ellipsis',
58190 'overflow' : 'hidden',
58191 'white-space' : 'nowrap',
58192 'cursor' : 'pointer'
58197 '.de-act-sup-link' : {
58198 'color' : 'purple',
58199 'text-decoration' : 'line-through'
58203 'text-decoration' : 'line-through'
58205 '.course-timesheet .course-highlight' : {
58206 'border-top-style': 'dashed !important',
58207 'border-bottom-bottom': 'dashed !important'
58209 '.course-timesheet .course-item' : {
58210 'font-family' : 'tahoma, arial, helvetica',
58211 'font-size' : '11px',
58212 'overflow' : 'hidden',
58213 'padding-left' : '10px',
58214 'padding-right' : '10px',
58215 'padding-top' : '10px'
58223 monitorWindowResize : false,
58224 cellrenderer : function(v,x,r)
58229 xtype: 'CellSelectionModel',
58236 beforeload : function (_self, options)
58238 options.params = options.params || {};
58239 options.params._month = _this.monthField.getValue();
58240 options.params.limit = 9999;
58241 options.params['sort'] = 'when_dt';
58242 options.params['dir'] = 'ASC';
58243 this.proxy.loadResponse = this.loadResponse;
58245 //this.addColumns();
58247 load : function (_self, records, options)
58249 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
58250 // if you click on the translation.. you can edit it...
58251 var el = Roo.get(this);
58252 var id = el.dom.getAttribute('data-id');
58253 var d = el.dom.getAttribute('data-date');
58254 var t = el.dom.getAttribute('data-time');
58255 //var id = this.child('span').dom.textContent;
58258 Pman.Dialog.CourseCalendar.show({
58262 productitem_active : id ? 1 : 0
58264 _this.grid.ds.load({});
58269 _this.panel.fireEvent('resize', [ '', '' ]);
58272 loadResponse : function(o, success, response){
58273 // this is overridden on before load..
58275 Roo.log("our code?");
58276 //Roo.log(success);
58277 //Roo.log(response)
58278 delete this.activeRequest;
58280 this.fireEvent("loadexception", this, o, response);
58281 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58286 result = o.reader.read(response);
58288 Roo.log("load exception?");
58289 this.fireEvent("loadexception", this, o, response, e);
58290 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58293 Roo.log("ready...");
58294 // loop through result.records;
58295 // and set this.tdate[date] = [] << array of records..
58297 Roo.each(result.records, function(r){
58299 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
58300 _this.tdata[r.data.when_dt.format('j')] = [];
58302 _this.tdata[r.data.when_dt.format('j')].push(r.data);
58305 //Roo.log(_this.tdata);
58307 result.records = [];
58308 result.totalRecords = 6;
58310 // let's generate some duumy records for the rows.
58311 //var st = _this.dateField.getValue();
58313 // work out monday..
58314 //st = st.add(Date.DAY, -1 * st.format('w'));
58316 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58318 var firstOfMonth = date.getFirstDayOfMonth();
58319 var days = date.getDaysInMonth();
58321 var firstAdded = false;
58322 for (var i = 0; i < result.totalRecords ; i++) {
58323 //var d= st.add(Date.DAY, i);
58326 for(var w = 0 ; w < 7 ; w++){
58327 if(!firstAdded && firstOfMonth != w){
58334 var dd = (d > 0 && d < 10) ? "0"+d : d;
58335 row['weekday'+w] = String.format(
58336 '<span style="font-size: 16px;"><b>{0}</b></span>'+
58337 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
58339 date.format('Y-m-')+dd
58342 if(typeof(_this.tdata[d]) != 'undefined'){
58343 Roo.each(_this.tdata[d], function(r){
58347 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
58348 if(r.parent_id*1>0){
58349 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
58352 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
58353 deactive = 'de-act-link';
58356 row['weekday'+w] += String.format(
58357 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
58359 r.product_id_name, //1
58360 r.when_dt.format('h:ia'), //2
58370 // only do this if something added..
58372 result.records.push(_this.grid.dataSource.reader.newRow(row));
58376 // push it twice. (second one with an hour..
58380 this.fireEvent("load", this, o, o.request.arg);
58381 o.request.callback.call(o.request.scope, result, o.request.arg, true);
58383 sortInfo : {field: 'when_dt', direction : 'ASC' },
58385 xtype: 'HttpProxy',
58388 url : baseURL + '/Roo/Shop_course.php'
58391 xtype: 'JsonReader',
58408 'name': 'parent_id',
58412 'name': 'product_id',
58416 'name': 'productitem_id',
58434 click : function (_self, e)
58436 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58437 sd.setMonth(sd.getMonth()-1);
58438 _this.monthField.setValue(sd.format('Y-m-d'));
58439 _this.grid.ds.load({});
58445 xtype: 'Separator',
58449 xtype: 'MonthField',
58452 render : function (_self)
58454 _this.monthField = _self;
58455 // _this.monthField.set today
58457 select : function (combo, date)
58459 _this.grid.ds.load({});
58462 value : (function() { return new Date(); })()
58465 xtype: 'Separator',
58471 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
58481 click : function (_self, e)
58483 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58484 sd.setMonth(sd.getMonth()+1);
58485 _this.monthField.setValue(sd.format('Y-m-d'));
58486 _this.grid.ds.load({});
58499 * Ext JS Library 1.1.1
58500 * Copyright(c) 2006-2007, Ext JS, LLC.
58502 * Originally Released Under LGPL - original licence link has changed is not relivant.
58505 * <script type="text/javascript">
58509 * @class Roo.LoadMask
58510 * A simple utility class for generically masking elements while loading data. If the element being masked has
58511 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
58512 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
58513 * element's UpdateManager load indicator and will be destroyed after the initial load.
58515 * Create a new LoadMask
58516 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
58517 * @param {Object} config The config object
58519 Roo.LoadMask = function(el, config){
58520 this.el = Roo.get(el);
58521 Roo.apply(this, config);
58523 this.store.on('beforeload', this.onBeforeLoad, this);
58524 this.store.on('load', this.onLoad, this);
58525 this.store.on('loadexception', this.onLoadException, this);
58526 this.removeMask = false;
58528 var um = this.el.getUpdateManager();
58529 um.showLoadIndicator = false; // disable the default indicator
58530 um.on('beforeupdate', this.onBeforeLoad, this);
58531 um.on('update', this.onLoad, this);
58532 um.on('failure', this.onLoad, this);
58533 this.removeMask = true;
58537 Roo.LoadMask.prototype = {
58539 * @cfg {Boolean} removeMask
58540 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
58541 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
58544 * @cfg {String} msg
58545 * The text to display in a centered loading message box (defaults to 'Loading...')
58547 msg : 'Loading...',
58549 * @cfg {String} msgCls
58550 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
58552 msgCls : 'x-mask-loading',
58555 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
58561 * Disables the mask to prevent it from being displayed
58563 disable : function(){
58564 this.disabled = true;
58568 * Enables the mask so that it can be displayed
58570 enable : function(){
58571 this.disabled = false;
58574 onLoadException : function()
58576 Roo.log(arguments);
58578 if (typeof(arguments[3]) != 'undefined') {
58579 Roo.MessageBox.alert("Error loading",arguments[3]);
58583 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
58584 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
58593 this.el.unmask(this.removeMask);
58596 onLoad : function()
58598 this.el.unmask(this.removeMask);
58602 onBeforeLoad : function(){
58603 if(!this.disabled){
58604 this.el.mask(this.msg, this.msgCls);
58609 destroy : function(){
58611 this.store.un('beforeload', this.onBeforeLoad, this);
58612 this.store.un('load', this.onLoad, this);
58613 this.store.un('loadexception', this.onLoadException, this);
58615 var um = this.el.getUpdateManager();
58616 um.un('beforeupdate', this.onBeforeLoad, this);
58617 um.un('update', this.onLoad, this);
58618 um.un('failure', this.onLoad, this);
58623 * Ext JS Library 1.1.1
58624 * Copyright(c) 2006-2007, Ext JS, LLC.
58626 * Originally Released Under LGPL - original licence link has changed is not relivant.
58629 * <script type="text/javascript">
58634 * @class Roo.XTemplate
58635 * @extends Roo.Template
58636 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
58638 var t = new Roo.XTemplate(
58639 '<select name="{name}">',
58640 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
58644 // then append, applying the master template values
58647 * Supported features:
58652 {a_variable} - output encoded.
58653 {a_variable.format:("Y-m-d")} - call a method on the variable
58654 {a_variable:raw} - unencoded output
58655 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
58656 {a_variable:this.method_on_template(...)} - call a method on the template object.
58661 <tpl for="a_variable or condition.."></tpl>
58662 <tpl if="a_variable or condition"></tpl>
58663 <tpl exec="some javascript"></tpl>
58664 <tpl name="named_template"></tpl> (experimental)
58666 <tpl for="."></tpl> - just iterate the property..
58667 <tpl for=".."></tpl> - iterates with the parent (probably the template)
58671 Roo.XTemplate = function()
58673 Roo.XTemplate.superclass.constructor.apply(this, arguments);
58680 Roo.extend(Roo.XTemplate, Roo.Template, {
58683 * The various sub templates
58688 * basic tag replacing syntax
58691 * // you can fake an object call by doing this
58695 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
58698 * compile the template
58700 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
58703 compile: function()
58707 s = ['<tpl>', s, '</tpl>'].join('');
58709 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
58710 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
58711 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
58712 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
58713 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
58718 while(true == !!(m = s.match(re))){
58719 var forMatch = m[0].match(nameRe),
58720 ifMatch = m[0].match(ifRe),
58721 execMatch = m[0].match(execRe),
58722 namedMatch = m[0].match(namedRe),
58727 name = forMatch && forMatch[1] ? forMatch[1] : '';
58730 // if - puts fn into test..
58731 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58733 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58738 // exec - calls a function... returns empty if true is returned.
58739 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58741 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58749 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58750 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58751 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58754 var uid = namedMatch ? namedMatch[1] : id;
58758 id: namedMatch ? namedMatch[1] : id,
58765 s = s.replace(m[0], '');
58767 s = s.replace(m[0], '{xtpl'+ id + '}');
58772 for(var i = tpls.length-1; i >= 0; --i){
58773 this.compileTpl(tpls[i]);
58774 this.tpls[tpls[i].id] = tpls[i];
58776 this.master = tpls[tpls.length-1];
58780 * same as applyTemplate, except it's done to one of the subTemplates
58781 * when using named templates, you can do:
58783 * var str = pl.applySubTemplate('your-name', values);
58786 * @param {Number} id of the template
58787 * @param {Object} values to apply to template
58788 * @param {Object} parent (normaly the instance of this object)
58790 applySubTemplate : function(id, values, parent)
58794 var t = this.tpls[id];
58798 if(t.test && !t.test.call(this, values, parent)){
58802 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58803 Roo.log(e.toString());
58809 if(t.exec && t.exec.call(this, values, parent)){
58813 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58814 Roo.log(e.toString());
58819 var vs = t.target ? t.target.call(this, values, parent) : values;
58820 parent = t.target ? values : parent;
58821 if(t.target && vs instanceof Array){
58823 for(var i = 0, len = vs.length; i < len; i++){
58824 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58826 return buf.join('');
58828 return t.compiled.call(this, vs, parent);
58830 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58831 Roo.log(e.toString());
58832 Roo.log(t.compiled);
58837 compileTpl : function(tpl)
58839 var fm = Roo.util.Format;
58840 var useF = this.disableFormats !== true;
58841 var sep = Roo.isGecko ? "+" : ",";
58842 var undef = function(str) {
58843 Roo.log("Property not found :" + str);
58847 var fn = function(m, name, format, args)
58849 //Roo.log(arguments);
58850 args = args ? args.replace(/\\'/g,"'") : args;
58851 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58852 if (typeof(format) == 'undefined') {
58853 format= 'htmlEncode';
58855 if (format == 'raw' ) {
58859 if(name.substr(0, 4) == 'xtpl'){
58860 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58863 // build an array of options to determine if value is undefined..
58865 // basically get 'xxxx.yyyy' then do
58866 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58867 // (function () { Roo.log("Property not found"); return ''; })() :
58872 Roo.each(name.split('.'), function(st) {
58873 lookfor += (lookfor.length ? '.': '') + st;
58874 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58877 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58880 if(format && useF){
58882 args = args ? ',' + args : "";
58884 if(format.substr(0, 5) != "this."){
58885 format = "fm." + format + '(';
58887 format = 'this.call("'+ format.substr(5) + '", ';
58891 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58895 // called with xxyx.yuu:(test,test)
58897 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58899 // raw.. - :raw modifier..
58900 return "'"+ sep + udef_st + name + ")"+sep+"'";
58904 // branched to use + in gecko and [].join() in others
58906 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58907 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58910 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58911 body.push(tpl.body.replace(/(\r\n|\n)/g,
58912 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58913 body.push("'].join('');};};");
58914 body = body.join('');
58917 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58919 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58925 applyTemplate : function(values){
58926 return this.master.compiled.call(this, values, {});
58927 //var s = this.subs;
58930 apply : function(){
58931 return this.applyTemplate.apply(this, arguments);
58936 Roo.XTemplate.from = function(el){
58937 el = Roo.getDom(el);
58938 return new Roo.XTemplate(el.value || el.innerHTML);