4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isGecko = !isSafari && ua.indexOf("gecko") > -1,
61 isBorderBox = isIE && !isStrict,
62 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64 isLinux = (ua.indexOf("linux") != -1),
65 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66 isIOS = /iphone|ipad/.test(ua),
67 isTouch = (function() {
69 document.createEvent("TouchEvent");
76 // remove css image flicker
79 document.execCommand("BackgroundImageCache", false, true);
85 * True if the browser is in strict mode
90 * True if the page is running over SSL
95 * True when the document is fully initialized and ready for action
100 * Turn on debugging output (currently only the factory uses this)
107 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
110 enableGarbageCollector : true,
113 * True to automatically purge event listeners after uncaching an element (defaults to false).
114 * Note: this only happens if enableGarbageCollector is true.
117 enableListenerCollection:false,
120 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
121 * the IE insecure content warning (defaults to javascript:false).
124 SSL_SECURE_URL : "javascript:false",
127 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
128 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
131 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
133 emptyFn : function(){},
136 * Copies all the properties of config to obj if they don't already exist.
137 * @param {Object} obj The receiver of the properties
138 * @param {Object} config The source of the properties
139 * @return {Object} returns obj
141 applyIf : function(o, c){
144 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
151 * Applies event listeners to elements by selectors when the document is ready.
152 * The event name is specified with an @ suffix.
155 // add a listener for click on all anchors in element with id foo
156 '#foo a@click' : function(e, t){
160 // add the same listener to multiple selectors (separated by comma BEFORE the @)
161 '#foo a, #bar span.some-class@mouseover' : function(){
166 * @param {Object} obj The list of behaviors to apply
168 addBehaviors : function(o){
170 Roo.onReady(function(){
175 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
177 var parts = b.split('@');
178 if(parts[1]){ // for Object prototype breakers
181 cache[s] = Roo.select(s);
183 cache[s].on(parts[1], o[b]);
190 * Generates unique ids. If the element already has an id, it is unchanged
191 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
192 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
193 * @return {String} The generated Id.
195 id : function(el, prefix){
196 prefix = prefix || "roo-gen";
198 var id = prefix + (++idSeed);
199 return el ? (el.id ? el.id : (el.id = id)) : id;
204 * Extends one class with another class and optionally overrides members with the passed literal. This class
205 * also adds the function "override()" to the class that can be used to override
206 * members on an instance.
207 * @param {Object} subclass The class inheriting the functionality
208 * @param {Object} superclass The class being extended
209 * @param {Object} overrides (optional) A literal with members
214 var io = function(o){
219 return function(sb, sp, overrides){
220 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
223 sb = function(){sp.apply(this, arguments);};
225 var F = function(){}, sbp, spp = sp.prototype;
227 sbp = sb.prototype = new F();
231 if(spp.constructor == Object.prototype.constructor){
236 sb.override = function(o){
240 Roo.override(sb, overrides);
246 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
248 Roo.override(MyClass, {
249 newMethod1: function(){
252 newMethod2: function(foo){
257 * @param {Object} origclass The class to override
258 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
259 * containing one or more methods.
262 override : function(origclass, overrides){
264 var p = origclass.prototype;
265 for(var method in overrides){
266 p[method] = overrides[method];
271 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
273 Roo.namespace('Company', 'Company.data');
274 Company.Widget = function() { ... }
275 Company.data.CustomStore = function(config) { ... }
277 * @param {String} namespace1
278 * @param {String} namespace2
279 * @param {String} etc
282 namespace : function(){
283 var a=arguments, o=null, i, j, d, rt;
284 for (i=0; i<a.length; ++i) {
288 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
289 for (j=1; j<d.length; ++j) {
290 o[d[j]]=o[d[j]] || {};
296 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
298 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
299 Roo.factory(conf, Roo.data);
301 * @param {String} classname
302 * @param {String} namespace (optional)
306 factory : function(c, ns)
308 // no xtype, no ns or c.xns - or forced off by c.xns
309 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
312 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
313 if (c.constructor == ns[c.xtype]) {// already created...
317 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
318 var ret = new ns[c.xtype](c);
322 c.xns = false; // prevent recursion..
326 * Logs to console if it can.
328 * @param {String|Object} string
333 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
340 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
344 urlEncode : function(o){
350 var ov = o[key], k = Roo.encodeURIComponent(key);
351 var type = typeof ov;
352 if(type == 'undefined'){
354 }else if(type != "function" && type != "object"){
355 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
356 }else if(ov instanceof Array){
358 for(var i = 0, len = ov.length; i < len; i++) {
359 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
370 * Safe version of encodeURIComponent
371 * @param {String} data
375 encodeURIComponent : function (data)
378 return encodeURIComponent(data);
379 } catch(e) {} // should be an uri encode error.
381 if (data == '' || data == null){
384 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
385 function nibble_to_hex(nibble){
386 var chars = '0123456789ABCDEF';
387 return chars.charAt(nibble);
389 data = data.toString();
391 for(var i=0; i<data.length; i++){
392 var c = data.charCodeAt(i);
393 var bs = new Array();
396 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
397 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
398 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
399 bs[3] = 0x80 | (c & 0x3F);
400 }else if (c > 0x800){
402 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
403 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
404 bs[2] = 0x80 | (c & 0x3F);
407 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
408 bs[1] = 0x80 | (c & 0x3F);
413 for(var j=0; j<bs.length; j++){
415 var hex = nibble_to_hex((b & 0xF0) >>> 4)
416 + nibble_to_hex(b &0x0F);
425 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
426 * @param {String} string
427 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
428 * @return {Object} A literal with members
430 urlDecode : function(string, overwrite){
431 if(!string || !string.length){
435 var pairs = string.split('&');
436 var pair, name, value;
437 for(var i = 0, len = pairs.length; i < len; i++){
438 pair = pairs[i].split('=');
439 name = decodeURIComponent(pair[0]);
440 value = decodeURIComponent(pair[1]);
441 if(overwrite !== true){
442 if(typeof obj[name] == "undefined"){
444 }else if(typeof obj[name] == "string"){
445 obj[name] = [obj[name]];
446 obj[name].push(value);
448 obj[name].push(value);
458 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
459 * passed array is not really an array, your function is called once with it.
460 * The supplied function is called with (Object item, Number index, Array allItems).
461 * @param {Array/NodeList/Mixed} array
462 * @param {Function} fn
463 * @param {Object} scope
465 each : function(array, fn, scope){
466 if(typeof array.length == "undefined" || typeof array == "string"){
469 for(var i = 0, len = array.length; i < len; i++){
470 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
475 combine : function(){
476 var as = arguments, l = as.length, r = [];
477 for(var i = 0; i < l; i++){
479 if(a instanceof Array){
481 }else if(a.length !== undefined && !a.substr){
482 r = r.concat(Array.prototype.slice.call(a, 0));
491 * Escapes the passed string for use in a regular expression
492 * @param {String} str
495 escapeRe : function(s) {
496 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
500 callback : function(cb, scope, args, delay){
501 if(typeof cb == "function"){
503 cb.defer(delay, scope, args || []);
505 cb.apply(scope, args || []);
511 * Return the dom node for the passed string (id), dom node, or Roo.Element
512 * @param {String/HTMLElement/Roo.Element} el
513 * @return HTMLElement
515 getDom : function(el){
519 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
523 * Shorthand for {@link Roo.ComponentMgr#get}
525 * @return Roo.Component
527 getCmp : function(id){
528 return Roo.ComponentMgr.get(id);
531 num : function(v, defaultValue){
532 if(typeof v != 'number'){
538 destroy : function(){
539 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
543 as.removeAllListeners();
547 if(typeof as.purgeListeners == 'function'){
550 if(typeof as.destroy == 'function'){
557 // inpired by a similar function in mootools library
559 * Returns the type of object that is passed in. If the object passed in is null or undefined it
560 * return false otherwise it returns one of the following values:<ul>
561 * <li><b>string</b>: If the object passed is a string</li>
562 * <li><b>number</b>: If the object passed is a number</li>
563 * <li><b>boolean</b>: If the object passed is a boolean value</li>
564 * <li><b>function</b>: If the object passed is a function reference</li>
565 * <li><b>object</b>: If the object passed is an object</li>
566 * <li><b>array</b>: If the object passed is an array</li>
567 * <li><b>regexp</b>: If the object passed is a regular expression</li>
568 * <li><b>element</b>: If the object passed is a DOM Element</li>
569 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
570 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
571 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
572 * @param {Mixed} object
576 if(o === undefined || o === null){
583 if(t == 'object' && o.nodeName) {
585 case 1: return 'element';
586 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
589 if(t == 'object' || t == 'function') {
590 switch(o.constructor) {
591 case Array: return 'array';
592 case RegExp: return 'regexp';
594 if(typeof o.length == 'number' && typeof o.item == 'function') {
602 * Returns true if the passed value is null, undefined or an empty string (optional).
603 * @param {Mixed} value The value to test
604 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
607 isEmpty : function(v, allowBlank){
608 return v === null || v === undefined || (!allowBlank ? v === '' : false);
616 isFirefox : isFirefox,
626 isBorderBox : isBorderBox,
628 isWindows : isWindows,
639 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
640 * you may want to set this to true.
643 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
648 * Selects a single element as a Roo Element
649 * This is about as close as you can get to jQuery's $('do crazy stuff')
650 * @param {String} selector The selector/xpath query
651 * @param {Node} root (optional) The start of the query (defaults to document).
652 * @return {Roo.Element}
654 selectNode : function(selector, root)
656 var node = Roo.DomQuery.selectNode(selector,root);
657 return node ? Roo.get(node) : new Roo.Element(false);
665 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
666 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
669 "Roo.bootstrap.dash");
672 * Ext JS Library 1.1.1
673 * Copyright(c) 2006-2007, Ext JS, LLC.
675 * Originally Released Under LGPL - original licence link has changed is not relivant.
678 * <script type="text/javascript">
682 // wrappedn so fnCleanup is not in global scope...
684 function fnCleanUp() {
685 var p = Function.prototype;
686 delete p.createSequence;
688 delete p.createDelegate;
689 delete p.createCallback;
690 delete p.createInterceptor;
692 window.detachEvent("onunload", fnCleanUp);
694 window.attachEvent("onunload", fnCleanUp);
701 * These functions are available on every Function object (any JavaScript function).
703 Roo.apply(Function.prototype, {
705 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
706 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
707 * Will create a function that is bound to those 2 args.
708 * @return {Function} The new function
710 createCallback : function(/*args...*/){
711 // make args available, in function below
712 var args = arguments;
715 return method.apply(window, args);
720 * Creates a delegate (callback) that sets the scope to obj.
721 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
722 * Will create a function that is automatically scoped to this.
723 * @param {Object} obj (optional) The object for which the scope is set
724 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
725 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
726 * if a number the args are inserted at the specified position
727 * @return {Function} The new function
729 createDelegate : function(obj, args, appendArgs){
732 var callArgs = args || arguments;
733 if(appendArgs === true){
734 callArgs = Array.prototype.slice.call(arguments, 0);
735 callArgs = callArgs.concat(args);
736 }else if(typeof appendArgs == "number"){
737 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
738 var applyArgs = [appendArgs, 0].concat(args); // create method call params
739 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
741 return method.apply(obj || window, callArgs);
746 * Calls this function after the number of millseconds specified.
747 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
748 * @param {Object} obj (optional) The object for which the scope is set
749 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
750 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
751 * if a number the args are inserted at the specified position
752 * @return {Number} The timeout id that can be used with clearTimeout
754 defer : function(millis, obj, args, appendArgs){
755 var fn = this.createDelegate(obj, args, appendArgs);
757 return setTimeout(fn, millis);
763 * Create a combined function call sequence of the original function + the passed function.
764 * The resulting function returns the results of the original function.
765 * The passed fcn is called with the parameters of the original function
766 * @param {Function} fcn The function to sequence
767 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
768 * @return {Function} The new function
770 createSequence : function(fcn, scope){
771 if(typeof fcn != "function"){
776 var retval = method.apply(this || window, arguments);
777 fcn.apply(scope || this || window, arguments);
783 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
784 * The resulting function returns the results of the original function.
785 * The passed fcn is called with the parameters of the original function.
787 * @param {Function} fcn The function to call before the original
788 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
789 * @return {Function} The new function
791 createInterceptor : function(fcn, scope){
792 if(typeof fcn != "function"){
799 if(fcn.apply(scope || this || window, arguments) === false){
802 return method.apply(this || window, arguments);
808 * Ext JS Library 1.1.1
809 * Copyright(c) 2006-2007, Ext JS, LLC.
811 * Originally Released Under LGPL - original licence link has changed is not relivant.
814 * <script type="text/javascript">
817 Roo.applyIf(String, {
822 * Escapes the passed string for ' and \
823 * @param {String} string The string to escape
824 * @return {String} The escaped string
827 escape : function(string) {
828 return string.replace(/('|\\)/g, "\\$1");
832 * Pads the left side of a string with a specified character. This is especially useful
833 * for normalizing number and date strings. Example usage:
835 var s = String.leftPad('123', 5, '0');
836 // s now contains the string: '00123'
838 * @param {String} string The original string
839 * @param {Number} size The total length of the output string
840 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
841 * @return {String} The padded string
844 leftPad : function (val, size, ch) {
845 var result = new String(val);
846 if(ch === null || ch === undefined || ch === '') {
849 while (result.length < size) {
850 result = ch + result;
856 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
857 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
859 var cls = 'my-class', text = 'Some text';
860 var s = String.format('<div class="{0}">{1}</div>', cls, text);
861 // s now contains the string: '<div class="my-class">Some text</div>'
863 * @param {String} string The tokenized string to be formatted
864 * @param {String} value1 The value to replace token {0}
865 * @param {String} value2 Etc...
866 * @return {String} The formatted string
869 format : function(format){
870 var args = Array.prototype.slice.call(arguments, 1);
871 return format.replace(/\{(\d+)\}/g, function(m, i){
872 return Roo.util.Format.htmlEncode(args[i]);
878 * Utility function that allows you to easily switch a string between two alternating values. The passed value
879 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
880 * they are already different, the first value passed in is returned. Note that this method returns the new value
881 * but does not change the current string.
883 // alternate sort directions
884 sort = sort.toggle('ASC', 'DESC');
886 // instead of conditional logic:
887 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
889 * @param {String} value The value to compare to the current string
890 * @param {String} other The new value to use if the string already equals the first value passed in
891 * @return {String} The new value
894 String.prototype.toggle = function(value, other){
895 return this == value ? other : value;
898 * Ext JS Library 1.1.1
899 * Copyright(c) 2006-2007, Ext JS, LLC.
901 * Originally Released Under LGPL - original licence link has changed is not relivant.
904 * <script type="text/javascript">
910 Roo.applyIf(Number.prototype, {
912 * Checks whether or not the current number is within a desired range. If the number is already within the
913 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
914 * exceeded. Note that this method returns the constrained value but does not change the current number.
915 * @param {Number} min The minimum number in the range
916 * @param {Number} max The maximum number in the range
917 * @return {Number} The constrained value if outside the range, otherwise the current value
919 constrain : function(min, max){
920 return Math.min(Math.max(this, min), max);
924 * Ext JS Library 1.1.1
925 * Copyright(c) 2006-2007, Ext JS, LLC.
927 * Originally Released Under LGPL - original licence link has changed is not relivant.
930 * <script type="text/javascript">
935 Roo.applyIf(Array.prototype, {
938 * Checks whether or not the specified object exists in the array.
939 * @param {Object} o The object to check for
940 * @return {Number} The index of o in the array (or -1 if it is not found)
942 indexOf : function(o){
943 for (var i = 0, len = this.length; i < len; i++){
944 if(this[i] == o) { return i; }
950 * Removes the specified object from the array. If the object is not found nothing happens.
951 * @param {Object} o The object to remove
953 remove : function(o){
954 var index = this.indexOf(o);
956 this.splice(index, 1);
960 * Map (JS 1.6 compatibility)
961 * @param {Function} function to call
965 var len = this.length >>> 0;
966 if (typeof fun != "function") {
967 throw new TypeError();
969 var res = new Array(len);
970 var thisp = arguments[1];
971 for (var i = 0; i < len; i++)
974 res[i] = fun.call(thisp, this[i], i, this);
987 * Ext JS Library 1.1.1
988 * Copyright(c) 2006-2007, Ext JS, LLC.
990 * Originally Released Under LGPL - original licence link has changed is not relivant.
993 * <script type="text/javascript">
999 * The date parsing and format syntax is a subset of
1000 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1001 * supported will provide results equivalent to their PHP versions.
1003 * Following is the list of all currently supported formats:
1006 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1008 Format Output Description
1009 ------ ---------- --------------------------------------------------------------
1010 d 10 Day of the month, 2 digits with leading zeros
1011 D Wed A textual representation of a day, three letters
1012 j 10 Day of the month without leading zeros
1013 l Wednesday A full textual representation of the day of the week
1014 S th English ordinal day of month suffix, 2 chars (use with j)
1015 w 3 Numeric representation of the day of the week
1016 z 9 The julian date, or day of the year (0-365)
1017 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1018 F January A full textual representation of the month
1019 m 01 Numeric representation of a month, with leading zeros
1020 M Jan Month name abbreviation, three letters
1021 n 1 Numeric representation of a month, without leading zeros
1022 t 31 Number of days in the given month
1023 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1024 Y 2007 A full numeric representation of a year, 4 digits
1025 y 07 A two digit representation of a year
1026 a pm Lowercase Ante meridiem and Post meridiem
1027 A PM Uppercase Ante meridiem and Post meridiem
1028 g 3 12-hour format of an hour without leading zeros
1029 G 15 24-hour format of an hour without leading zeros
1030 h 03 12-hour format of an hour with leading zeros
1031 H 15 24-hour format of an hour with leading zeros
1032 i 05 Minutes with leading zeros
1033 s 01 Seconds, with leading zeros
1034 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1035 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1036 T CST Timezone setting of the machine running the code
1037 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1040 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1042 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1043 document.write(dt.format('Y-m-d')); //2007-01-10
1044 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1045 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1048 * Here are some standard date/time patterns that you might find helpful. They
1049 * are not part of the source of Date.js, but to use them you can simply copy this
1050 * block of code into any script that is included after Date.js and they will also become
1051 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1054 ISO8601Long:"Y-m-d H:i:s",
1055 ISO8601Short:"Y-m-d",
1057 LongDate: "l, F d, Y",
1058 FullDateTime: "l, F d, Y g:i:s A",
1061 LongTime: "g:i:s A",
1062 SortableDateTime: "Y-m-d\\TH:i:s",
1063 UniversalSortableDateTime: "Y-m-d H:i:sO",
1070 var dt = new Date();
1071 document.write(dt.format(Date.patterns.ShortDate));
1076 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1077 * They generate precompiled functions from date formats instead of parsing and
1078 * processing the pattern every time you format a date. These functions are available
1079 * on every Date object (any javascript function).
1081 * The original article and download are here:
1082 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1089 Returns the number of milliseconds between this date and date
1090 @param {Date} date (optional) Defaults to now
1091 @return {Number} The diff in milliseconds
1092 @member Date getElapsed
1094 Date.prototype.getElapsed = function(date) {
1095 return Math.abs((date || new Date()).getTime()-this.getTime());
1097 // was in date file..
1101 Date.parseFunctions = {count:0};
1103 Date.parseRegexes = [];
1105 Date.formatFunctions = {count:0};
1108 Date.prototype.dateFormat = function(format) {
1109 if (Date.formatFunctions[format] == null) {
1110 Date.createNewFormat(format);
1112 var func = Date.formatFunctions[format];
1113 return this[func]();
1118 * Formats a date given the supplied format string
1119 * @param {String} format The format string
1120 * @return {String} The formatted date
1123 Date.prototype.format = Date.prototype.dateFormat;
1126 Date.createNewFormat = function(format) {
1127 var funcName = "format" + Date.formatFunctions.count++;
1128 Date.formatFunctions[format] = funcName;
1129 var code = "Date.prototype." + funcName + " = function(){return ";
1130 var special = false;
1132 for (var i = 0; i < format.length; ++i) {
1133 ch = format.charAt(i);
1134 if (!special && ch == "\\") {
1139 code += "'" + String.escape(ch) + "' + ";
1142 code += Date.getFormatCode(ch);
1145 /** eval:var:zzzzzzzzzzzzz */
1146 eval(code.substring(0, code.length - 3) + ";}");
1150 Date.getFormatCode = function(character) {
1151 switch (character) {
1153 return "String.leftPad(this.getDate(), 2, '0') + ";
1155 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1157 return "this.getDate() + ";
1159 return "Date.dayNames[this.getDay()] + ";
1161 return "this.getSuffix() + ";
1163 return "this.getDay() + ";
1165 return "this.getDayOfYear() + ";
1167 return "this.getWeekOfYear() + ";
1169 return "Date.monthNames[this.getMonth()] + ";
1171 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1173 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1175 return "(this.getMonth() + 1) + ";
1177 return "this.getDaysInMonth() + ";
1179 return "(this.isLeapYear() ? 1 : 0) + ";
1181 return "this.getFullYear() + ";
1183 return "('' + this.getFullYear()).substring(2, 4) + ";
1185 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1187 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1189 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1191 return "this.getHours() + ";
1193 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1195 return "String.leftPad(this.getHours(), 2, '0') + ";
1197 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1199 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1201 return "this.getGMTOffset() + ";
1203 return "this.getGMTColonOffset() + ";
1205 return "this.getTimezone() + ";
1207 return "(this.getTimezoneOffset() * -60) + ";
1209 return "'" + String.escape(character) + "' + ";
1214 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1215 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1216 * the date format that is not specified will default to the current date value for that part. Time parts can also
1217 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1218 * string or the parse operation will fail.
1221 //dt = Fri May 25 2007 (current date)
1222 var dt = new Date();
1224 //dt = Thu May 25 2006 (today's month/day in 2006)
1225 dt = Date.parseDate("2006", "Y");
1227 //dt = Sun Jan 15 2006 (all date parts specified)
1228 dt = Date.parseDate("2006-1-15", "Y-m-d");
1230 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1231 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1233 * @param {String} input The unparsed date as a string
1234 * @param {String} format The format the date is in
1235 * @return {Date} The parsed date
1238 Date.parseDate = function(input, format) {
1239 if (Date.parseFunctions[format] == null) {
1240 Date.createParser(format);
1242 var func = Date.parseFunctions[format];
1243 return Date[func](input);
1249 Date.createParser = function(format) {
1250 var funcName = "parse" + Date.parseFunctions.count++;
1251 var regexNum = Date.parseRegexes.length;
1252 var currentGroup = 1;
1253 Date.parseFunctions[format] = funcName;
1255 var code = "Date." + funcName + " = function(input){\n"
1256 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1257 + "var d = new Date();\n"
1258 + "y = d.getFullYear();\n"
1259 + "m = d.getMonth();\n"
1260 + "d = d.getDate();\n"
1261 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1262 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1263 + "if (results && results.length > 0) {";
1266 var special = false;
1268 for (var i = 0; i < format.length; ++i) {
1269 ch = format.charAt(i);
1270 if (!special && ch == "\\") {
1275 regex += String.escape(ch);
1278 var obj = Date.formatCodeToRegex(ch, currentGroup);
1279 currentGroup += obj.g;
1281 if (obj.g && obj.c) {
1287 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1288 + "{v = new Date(y, m, d, h, i, s);}\n"
1289 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1290 + "{v = new Date(y, m, d, h, i);}\n"
1291 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1292 + "{v = new Date(y, m, d, h);}\n"
1293 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1294 + "{v = new Date(y, m, d);}\n"
1295 + "else if (y >= 0 && m >= 0)\n"
1296 + "{v = new Date(y, m);}\n"
1297 + "else if (y >= 0)\n"
1298 + "{v = new Date(y);}\n"
1299 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1300 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1301 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1304 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1305 /** eval:var:zzzzzzzzzzzzz */
1310 Date.formatCodeToRegex = function(character, currentGroup) {
1311 switch (character) {
1315 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1318 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1319 s:"(\\d{1,2})"}; // day of month without leading zeroes
1322 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1323 s:"(\\d{2})"}; // day of month with leading zeroes
1327 s:"(?:" + Date.dayNames.join("|") + ")"};
1331 s:"(?:st|nd|rd|th)"};
1346 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1347 s:"(" + Date.monthNames.join("|") + ")"};
1350 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1351 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1354 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1355 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1358 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1359 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1370 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1374 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1375 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1379 c:"if (results[" + currentGroup + "] == 'am') {\n"
1380 + "if (h == 12) { h = 0; }\n"
1381 + "} else { if (h < 12) { h += 12; }}",
1385 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1386 + "if (h == 12) { h = 0; }\n"
1387 + "} else { if (h < 12) { h += 12; }}",
1392 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1393 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1397 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1398 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1401 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1405 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1410 "o = results[", currentGroup, "];\n",
1411 "var sn = o.substring(0,1);\n", // get + / - sign
1412 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1413 "var mn = o.substring(3,5) % 60;\n", // get minutes
1414 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1415 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1417 s:"([+\-]\\d{2,4})"};
1423 "o = results[", currentGroup, "];\n",
1424 "var sn = o.substring(0,1);\n",
1425 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1426 "var mn = o.substring(4,6) % 60;\n",
1427 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1428 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1434 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1437 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1438 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1439 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1443 s:String.escape(character)};
1448 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1449 * @return {String} The abbreviated timezone name (e.g. 'CST')
1451 Date.prototype.getTimezone = function() {
1452 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1456 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1457 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1459 Date.prototype.getGMTOffset = function() {
1460 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1461 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1462 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1466 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1467 * @return {String} 2-characters representing hours and 2-characters representing minutes
1468 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1470 Date.prototype.getGMTColonOffset = function() {
1471 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1472 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1474 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1478 * Get the numeric day number of the year, adjusted for leap year.
1479 * @return {Number} 0 through 364 (365 in leap years)
1481 Date.prototype.getDayOfYear = function() {
1483 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1484 for (var i = 0; i < this.getMonth(); ++i) {
1485 num += Date.daysInMonth[i];
1487 return num + this.getDate() - 1;
1491 * Get the string representation of the numeric week number of the year
1492 * (equivalent to the format specifier 'W').
1493 * @return {String} '00' through '52'
1495 Date.prototype.getWeekOfYear = function() {
1496 // Skip to Thursday of this week
1497 var now = this.getDayOfYear() + (4 - this.getDay());
1498 // Find the first Thursday of the year
1499 var jan1 = new Date(this.getFullYear(), 0, 1);
1500 var then = (7 - jan1.getDay() + 4);
1501 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1505 * Whether or not the current date is in a leap year.
1506 * @return {Boolean} True if the current date is in a leap year, else false
1508 Date.prototype.isLeapYear = function() {
1509 var year = this.getFullYear();
1510 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1514 * Get the first day of the current month, adjusted for leap year. The returned value
1515 * is the numeric day index within the week (0-6) which can be used in conjunction with
1516 * the {@link #monthNames} array to retrieve the textual day name.
1519 var dt = new Date('1/10/2007');
1520 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1522 * @return {Number} The day number (0-6)
1524 Date.prototype.getFirstDayOfMonth = function() {
1525 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1526 return (day < 0) ? (day + 7) : day;
1530 * Get the last day of the current month, adjusted for leap year. The returned value
1531 * is the numeric day index within the week (0-6) which can be used in conjunction with
1532 * the {@link #monthNames} array to retrieve the textual day name.
1535 var dt = new Date('1/10/2007');
1536 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1538 * @return {Number} The day number (0-6)
1540 Date.prototype.getLastDayOfMonth = function() {
1541 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1542 return (day < 0) ? (day + 7) : day;
1547 * Get the first date of this date's month
1550 Date.prototype.getFirstDateOfMonth = function() {
1551 return new Date(this.getFullYear(), this.getMonth(), 1);
1555 * Get the last date of this date's month
1558 Date.prototype.getLastDateOfMonth = function() {
1559 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1562 * Get the number of days in the current month, adjusted for leap year.
1563 * @return {Number} The number of days in the month
1565 Date.prototype.getDaysInMonth = function() {
1566 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1567 return Date.daysInMonth[this.getMonth()];
1571 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1572 * @return {String} 'st, 'nd', 'rd' or 'th'
1574 Date.prototype.getSuffix = function() {
1575 switch (this.getDate()) {
1592 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1595 * An array of textual month names.
1596 * Override these values for international dates, for example...
1597 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1616 * An array of textual day names.
1617 * Override these values for international dates, for example...
1618 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1634 Date.monthNumbers = {
1649 * Creates and returns a new Date instance with the exact same date value as the called instance.
1650 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1651 * variable will also be changed. When the intention is to create a new variable that will not
1652 * modify the original instance, you should create a clone.
1654 * Example of correctly cloning a date:
1657 var orig = new Date('10/1/2006');
1660 document.write(orig); //returns 'Thu Oct 05 2006'!
1663 var orig = new Date('10/1/2006');
1664 var copy = orig.clone();
1666 document.write(orig); //returns 'Thu Oct 01 2006'
1668 * @return {Date} The new Date instance
1670 Date.prototype.clone = function() {
1671 return new Date(this.getTime());
1675 * Clears any time information from this date
1676 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1677 @return {Date} this or the clone
1679 Date.prototype.clearTime = function(clone){
1681 return this.clone().clearTime();
1686 this.setMilliseconds(0);
1691 // safari setMonth is broken
1693 Date.brokenSetMonth = Date.prototype.setMonth;
1694 Date.prototype.setMonth = function(num){
1696 var n = Math.ceil(-num);
1697 var back_year = Math.ceil(n/12);
1698 var month = (n % 12) ? 12 - n % 12 : 0 ;
1699 this.setFullYear(this.getFullYear() - back_year);
1700 return Date.brokenSetMonth.call(this, month);
1702 return Date.brokenSetMonth.apply(this, arguments);
1707 /** Date interval constant
1711 /** Date interval constant
1715 /** Date interval constant
1719 /** Date interval constant
1723 /** Date interval constant
1727 /** Date interval constant
1731 /** Date interval constant
1737 * Provides a convenient method of performing basic date arithmetic. This method
1738 * does not modify the Date instance being called - it creates and returns
1739 * a new Date instance containing the resulting date value.
1744 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1745 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1747 //Negative values will subtract correctly:
1748 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1749 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1751 //You can even chain several calls together in one line!
1752 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1753 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1756 * @param {String} interval A valid date interval enum value
1757 * @param {Number} value The amount to add to the current date
1758 * @return {Date} The new Date instance
1760 Date.prototype.add = function(interval, value){
1761 var d = this.clone();
1762 if (!interval || value === 0) { return d; }
1763 switch(interval.toLowerCase()){
1765 d.setMilliseconds(this.getMilliseconds() + value);
1768 d.setSeconds(this.getSeconds() + value);
1771 d.setMinutes(this.getMinutes() + value);
1774 d.setHours(this.getHours() + value);
1777 d.setDate(this.getDate() + value);
1780 var day = this.getDate();
1782 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1785 d.setMonth(this.getMonth() + value);
1788 d.setFullYear(this.getFullYear() + value);
1795 * Ext JS Library 1.1.1
1796 * Copyright(c) 2006-2007, Ext JS, LLC.
1798 * Originally Released Under LGPL - original licence link has changed is not relivant.
1801 * <script type="text/javascript">
1805 * @class Roo.lib.Dom
1808 * Dom utils (from YIU afaik)
1813 * Get the view width
1814 * @param {Boolean} full True will get the full document, otherwise it's the view width
1815 * @return {Number} The width
1818 getViewWidth : function(full) {
1819 return full ? this.getDocumentWidth() : this.getViewportWidth();
1822 * Get the view height
1823 * @param {Boolean} full True will get the full document, otherwise it's the view height
1824 * @return {Number} The height
1826 getViewHeight : function(full) {
1827 return full ? this.getDocumentHeight() : this.getViewportHeight();
1830 getDocumentHeight: function() {
1831 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1832 return Math.max(scrollHeight, this.getViewportHeight());
1835 getDocumentWidth: function() {
1836 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1837 return Math.max(scrollWidth, this.getViewportWidth());
1840 getViewportHeight: function() {
1841 var height = self.innerHeight;
1842 var mode = document.compatMode;
1844 if ((mode || Roo.isIE) && !Roo.isOpera) {
1845 height = (mode == "CSS1Compat") ?
1846 document.documentElement.clientHeight :
1847 document.body.clientHeight;
1853 getViewportWidth: function() {
1854 var width = self.innerWidth;
1855 var mode = document.compatMode;
1857 if (mode || Roo.isIE) {
1858 width = (mode == "CSS1Compat") ?
1859 document.documentElement.clientWidth :
1860 document.body.clientWidth;
1865 isAncestor : function(p, c) {
1872 if (p.contains && !Roo.isSafari) {
1873 return p.contains(c);
1874 } else if (p.compareDocumentPosition) {
1875 return !!(p.compareDocumentPosition(c) & 16);
1877 var parent = c.parentNode;
1882 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1885 parent = parent.parentNode;
1891 getRegion : function(el) {
1892 return Roo.lib.Region.getRegion(el);
1895 getY : function(el) {
1896 return this.getXY(el)[1];
1899 getX : function(el) {
1900 return this.getXY(el)[0];
1903 getXY : function(el) {
1904 var p, pe, b, scroll, bd = document.body;
1905 el = Roo.getDom(el);
1906 var fly = Roo.lib.AnimBase.fly;
1907 if (el.getBoundingClientRect) {
1908 b = el.getBoundingClientRect();
1909 scroll = fly(document).getScroll();
1910 return [b.left + scroll.left, b.top + scroll.top];
1916 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1923 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1930 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1931 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1938 if (p != el && pe.getStyle('overflow') != 'visible') {
1946 if (Roo.isSafari && hasAbsolute) {
1951 if (Roo.isGecko && !hasAbsolute) {
1953 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1954 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1958 while (p && p != bd) {
1959 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1971 setXY : function(el, xy) {
1972 el = Roo.fly(el, '_setXY');
1974 var pts = el.translatePoints(xy);
1975 if (xy[0] !== false) {
1976 el.dom.style.left = pts.left + "px";
1978 if (xy[1] !== false) {
1979 el.dom.style.top = pts.top + "px";
1983 setX : function(el, x) {
1984 this.setXY(el, [x, false]);
1987 setY : function(el, y) {
1988 this.setXY(el, [false, y]);
1992 * Portions of this file are based on pieces of Yahoo User Interface Library
1993 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1994 * YUI licensed under the BSD License:
1995 * http://developer.yahoo.net/yui/license.txt
1996 * <script type="text/javascript">
2000 Roo.lib.Event = function() {
2001 var loadComplete = false;
2003 var unloadListeners = [];
2005 var onAvailStack = [];
2007 var lastError = null;
2020 startInterval: function() {
2021 if (!this._interval) {
2023 var callback = function() {
2024 self._tryPreloadAttach();
2026 this._interval = setInterval(callback, this.POLL_INTERVAL);
2031 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2032 onAvailStack.push({ id: p_id,
2035 override: p_override,
2036 checkReady: false });
2038 retryCount = this.POLL_RETRYS;
2039 this.startInterval();
2043 addListener: function(el, eventName, fn) {
2044 el = Roo.getDom(el);
2049 if ("unload" == eventName) {
2050 unloadListeners[unloadListeners.length] =
2051 [el, eventName, fn];
2055 var wrappedFn = function(e) {
2056 return fn(Roo.lib.Event.getEvent(e));
2059 var li = [el, eventName, fn, wrappedFn];
2061 var index = listeners.length;
2062 listeners[index] = li;
2064 this.doAdd(el, eventName, wrappedFn, false);
2070 removeListener: function(el, eventName, fn) {
2073 el = Roo.getDom(el);
2076 return this.purgeElement(el, false, eventName);
2080 if ("unload" == eventName) {
2082 for (i = 0,len = unloadListeners.length; i < len; i++) {
2083 var li = unloadListeners[i];
2086 li[1] == eventName &&
2088 unloadListeners.splice(i, 1);
2096 var cacheItem = null;
2099 var index = arguments[3];
2101 if ("undefined" == typeof index) {
2102 index = this._getCacheIndex(el, eventName, fn);
2106 cacheItem = listeners[index];
2109 if (!el || !cacheItem) {
2113 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2115 delete listeners[index][this.WFN];
2116 delete listeners[index][this.FN];
2117 listeners.splice(index, 1);
2124 getTarget: function(ev, resolveTextNode) {
2125 ev = ev.browserEvent || ev;
2126 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2127 var t = ev.target || ev.srcElement;
2128 return this.resolveTextNode(t);
2132 resolveTextNode: function(node) {
2133 if (Roo.isSafari && node && 3 == node.nodeType) {
2134 return node.parentNode;
2141 getPageX: function(ev) {
2142 ev = ev.browserEvent || ev;
2143 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2145 if (!x && 0 !== x) {
2146 x = ev.clientX || 0;
2149 x += this.getScroll()[1];
2157 getPageY: function(ev) {
2158 ev = ev.browserEvent || ev;
2159 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2161 if (!y && 0 !== y) {
2162 y = ev.clientY || 0;
2165 y += this.getScroll()[0];
2174 getXY: function(ev) {
2175 ev = ev.browserEvent || ev;
2176 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2177 return [this.getPageX(ev), this.getPageY(ev)];
2181 getRelatedTarget: function(ev) {
2182 ev = ev.browserEvent || ev;
2183 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2184 var t = ev.relatedTarget;
2186 if (ev.type == "mouseout") {
2188 } else if (ev.type == "mouseover") {
2193 return this.resolveTextNode(t);
2197 getTime: function(ev) {
2198 ev = ev.browserEvent || ev;
2199 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2201 var t = new Date().getTime();
2205 this.lastError = ex;
2214 stopEvent: function(ev) {
2215 this.stopPropagation(ev);
2216 this.preventDefault(ev);
2220 stopPropagation: function(ev) {
2221 ev = ev.browserEvent || ev;
2222 if (ev.stopPropagation) {
2223 ev.stopPropagation();
2225 ev.cancelBubble = true;
2230 preventDefault: function(ev) {
2231 ev = ev.browserEvent || ev;
2232 if(ev.preventDefault) {
2233 ev.preventDefault();
2235 ev.returnValue = false;
2240 getEvent: function(e) {
2241 var ev = e || window.event;
2243 var c = this.getEvent.caller;
2245 ev = c.arguments[0];
2246 if (ev && Event == ev.constructor) {
2256 getCharCode: function(ev) {
2257 ev = ev.browserEvent || ev;
2258 return ev.charCode || ev.keyCode || 0;
2262 _getCacheIndex: function(el, eventName, fn) {
2263 for (var i = 0,len = listeners.length; i < len; ++i) {
2264 var li = listeners[i];
2266 li[this.FN] == fn &&
2267 li[this.EL] == el &&
2268 li[this.TYPE] == eventName) {
2280 getEl: function(id) {
2281 return document.getElementById(id);
2285 clearCache: function() {
2289 _load: function(e) {
2290 loadComplete = true;
2291 var EU = Roo.lib.Event;
2295 EU.doRemove(window, "load", EU._load);
2300 _tryPreloadAttach: function() {
2309 var tryAgain = !loadComplete;
2311 tryAgain = (retryCount > 0);
2316 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2317 var item = onAvailStack[i];
2319 var el = this.getEl(item.id);
2322 if (!item.checkReady ||
2325 (document && document.body)) {
2328 if (item.override) {
2329 if (item.override === true) {
2332 scope = item.override;
2335 item.fn.call(scope, item.obj);
2336 onAvailStack[i] = null;
2339 notAvail.push(item);
2344 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2348 this.startInterval();
2350 clearInterval(this._interval);
2351 this._interval = null;
2354 this.locked = false;
2361 purgeElement: function(el, recurse, eventName) {
2362 var elListeners = this.getListeners(el, eventName);
2364 for (var i = 0,len = elListeners.length; i < len; ++i) {
2365 var l = elListeners[i];
2366 this.removeListener(el, l.type, l.fn);
2370 if (recurse && el && el.childNodes) {
2371 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2372 this.purgeElement(el.childNodes[i], recurse, eventName);
2378 getListeners: function(el, eventName) {
2379 var results = [], searchLists;
2381 searchLists = [listeners, unloadListeners];
2382 } else if (eventName == "unload") {
2383 searchLists = [unloadListeners];
2385 searchLists = [listeners];
2388 for (var j = 0; j < searchLists.length; ++j) {
2389 var searchList = searchLists[j];
2390 if (searchList && searchList.length > 0) {
2391 for (var i = 0,len = searchList.length; i < len; ++i) {
2392 var l = searchList[i];
2393 if (l && l[this.EL] === el &&
2394 (!eventName || eventName === l[this.TYPE])) {
2399 adjust: l[this.ADJ_SCOPE],
2407 return (results.length) ? results : null;
2411 _unload: function(e) {
2413 var EU = Roo.lib.Event, i, j, l, len, index;
2415 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2416 l = unloadListeners[i];
2419 if (l[EU.ADJ_SCOPE]) {
2420 if (l[EU.ADJ_SCOPE] === true) {
2423 scope = l[EU.ADJ_SCOPE];
2426 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2427 unloadListeners[i] = null;
2433 unloadListeners = null;
2435 if (listeners && listeners.length > 0) {
2436 j = listeners.length;
2439 l = listeners[index];
2441 EU.removeListener(l[EU.EL], l[EU.TYPE],
2451 EU.doRemove(window, "unload", EU._unload);
2456 getScroll: function() {
2457 var dd = document.documentElement, db = document.body;
2458 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2459 return [dd.scrollTop, dd.scrollLeft];
2461 return [db.scrollTop, db.scrollLeft];
2468 doAdd: function () {
2469 if (window.addEventListener) {
2470 return function(el, eventName, fn, capture) {
2471 el.addEventListener(eventName, fn, (capture));
2473 } else if (window.attachEvent) {
2474 return function(el, eventName, fn, capture) {
2475 el.attachEvent("on" + eventName, fn);
2484 doRemove: function() {
2485 if (window.removeEventListener) {
2486 return function (el, eventName, fn, capture) {
2487 el.removeEventListener(eventName, fn, (capture));
2489 } else if (window.detachEvent) {
2490 return function (el, eventName, fn) {
2491 el.detachEvent("on" + eventName, fn);
2503 var E = Roo.lib.Event;
2504 E.on = E.addListener;
2505 E.un = E.removeListener;
2507 if (document && document.body) {
2510 E.doAdd(window, "load", E._load);
2512 E.doAdd(window, "unload", E._unload);
2513 E._tryPreloadAttach();
2517 * Portions of this file are based on pieces of Yahoo User Interface Library
2518 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2519 * YUI licensed under the BSD License:
2520 * http://developer.yahoo.net/yui/license.txt
2521 * <script type="text/javascript">
2527 * @class Roo.lib.Ajax
2534 request : function(method, uri, cb, data, options) {
2536 var hs = options.headers;
2539 if(hs.hasOwnProperty(h)){
2540 this.initHeader(h, hs[h], false);
2544 if(options.xmlData){
2545 this.initHeader('Content-Type', 'text/xml', false);
2547 data = options.xmlData;
2551 return this.asyncRequest(method, uri, cb, data);
2554 serializeForm : function(form) {
2555 if(typeof form == 'string') {
2556 form = (document.getElementById(form) || document.forms[form]);
2559 var el, name, val, disabled, data = '', hasSubmit = false;
2560 for (var i = 0; i < form.elements.length; i++) {
2561 el = form.elements[i];
2562 disabled = form.elements[i].disabled;
2563 name = form.elements[i].name;
2564 val = form.elements[i].value;
2566 if (!disabled && name){
2570 case 'select-multiple':
2571 for (var j = 0; j < el.options.length; j++) {
2572 if (el.options[j].selected) {
2574 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2577 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2585 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2598 if(hasSubmit == false) {
2599 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2604 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2609 data = data.substr(0, data.length - 1);
2617 useDefaultHeader:true,
2619 defaultPostHeader:'application/x-www-form-urlencoded',
2621 useDefaultXhrHeader:true,
2623 defaultXhrHeader:'XMLHttpRequest',
2625 hasDefaultHeaders:true,
2637 setProgId:function(id)
2639 this.activeX.unshift(id);
2642 setDefaultPostHeader:function(b)
2644 this.useDefaultHeader = b;
2647 setDefaultXhrHeader:function(b)
2649 this.useDefaultXhrHeader = b;
2652 setPollingInterval:function(i)
2654 if (typeof i == 'number' && isFinite(i)) {
2655 this.pollInterval = i;
2659 createXhrObject:function(transactionId)
2665 http = new XMLHttpRequest();
2667 obj = { conn:http, tId:transactionId };
2671 for (var i = 0; i < this.activeX.length; ++i) {
2675 http = new ActiveXObject(this.activeX[i]);
2677 obj = { conn:http, tId:transactionId };
2690 getConnectionObject:function()
2693 var tId = this.transactionId;
2697 o = this.createXhrObject(tId);
2699 this.transactionId++;
2710 asyncRequest:function(method, uri, callback, postData)
2712 var o = this.getConnectionObject();
2718 o.conn.open(method, uri, true);
2720 if (this.useDefaultXhrHeader) {
2721 if (!this.defaultHeaders['X-Requested-With']) {
2722 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2726 if(postData && this.useDefaultHeader){
2727 this.initHeader('Content-Type', this.defaultPostHeader);
2730 if (this.hasDefaultHeaders || this.hasHeaders) {
2734 this.handleReadyState(o, callback);
2735 o.conn.send(postData || null);
2741 handleReadyState:function(o, callback)
2745 if (callback && callback.timeout) {
2747 this.timeout[o.tId] = window.setTimeout(function() {
2748 oConn.abort(o, callback, true);
2749 }, callback.timeout);
2752 this.poll[o.tId] = window.setInterval(
2754 if (o.conn && o.conn.readyState == 4) {
2755 window.clearInterval(oConn.poll[o.tId]);
2756 delete oConn.poll[o.tId];
2758 if(callback && callback.timeout) {
2759 window.clearTimeout(oConn.timeout[o.tId]);
2760 delete oConn.timeout[o.tId];
2763 oConn.handleTransactionResponse(o, callback);
2766 , this.pollInterval);
2769 handleTransactionResponse:function(o, callback, isAbort)
2773 this.releaseObject(o);
2777 var httpStatus, responseObject;
2781 if (o.conn.status !== undefined && o.conn.status != 0) {
2782 httpStatus = o.conn.status;
2794 if (httpStatus >= 200 && httpStatus < 300) {
2795 responseObject = this.createResponseObject(o, callback.argument);
2796 if (callback.success) {
2797 if (!callback.scope) {
2798 callback.success(responseObject);
2803 callback.success.apply(callback.scope, [responseObject]);
2808 switch (httpStatus) {
2816 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2817 if (callback.failure) {
2818 if (!callback.scope) {
2819 callback.failure(responseObject);
2822 callback.failure.apply(callback.scope, [responseObject]);
2827 responseObject = this.createResponseObject(o, callback.argument);
2828 if (callback.failure) {
2829 if (!callback.scope) {
2830 callback.failure(responseObject);
2833 callback.failure.apply(callback.scope, [responseObject]);
2839 this.releaseObject(o);
2840 responseObject = null;
2843 createResponseObject:function(o, callbackArg)
2850 var headerStr = o.conn.getAllResponseHeaders();
2851 var header = headerStr.split('\n');
2852 for (var i = 0; i < header.length; i++) {
2853 var delimitPos = header[i].indexOf(':');
2854 if (delimitPos != -1) {
2855 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2863 obj.status = o.conn.status;
2864 obj.statusText = o.conn.statusText;
2865 obj.getResponseHeader = headerObj;
2866 obj.getAllResponseHeaders = headerStr;
2867 obj.responseText = o.conn.responseText;
2868 obj.responseXML = o.conn.responseXML;
2870 if (typeof callbackArg !== undefined) {
2871 obj.argument = callbackArg;
2877 createExceptionObject:function(tId, callbackArg, isAbort)
2880 var COMM_ERROR = 'communication failure';
2881 var ABORT_CODE = -1;
2882 var ABORT_ERROR = 'transaction aborted';
2888 obj.status = ABORT_CODE;
2889 obj.statusText = ABORT_ERROR;
2892 obj.status = COMM_CODE;
2893 obj.statusText = COMM_ERROR;
2897 obj.argument = callbackArg;
2903 initHeader:function(label, value, isDefault)
2905 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2907 if (headerObj[label] === undefined) {
2908 headerObj[label] = value;
2913 headerObj[label] = value + "," + headerObj[label];
2917 this.hasDefaultHeaders = true;
2920 this.hasHeaders = true;
2925 setHeader:function(o)
2927 if (this.hasDefaultHeaders) {
2928 for (var prop in this.defaultHeaders) {
2929 if (this.defaultHeaders.hasOwnProperty(prop)) {
2930 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2935 if (this.hasHeaders) {
2936 for (var prop in this.headers) {
2937 if (this.headers.hasOwnProperty(prop)) {
2938 o.conn.setRequestHeader(prop, this.headers[prop]);
2942 this.hasHeaders = false;
2946 resetDefaultHeaders:function() {
2947 delete this.defaultHeaders;
2948 this.defaultHeaders = {};
2949 this.hasDefaultHeaders = false;
2952 abort:function(o, callback, isTimeout)
2954 if(this.isCallInProgress(o)) {
2956 window.clearInterval(this.poll[o.tId]);
2957 delete this.poll[o.tId];
2959 delete this.timeout[o.tId];
2962 this.handleTransactionResponse(o, callback, true);
2972 isCallInProgress:function(o)
2975 return o.conn.readyState != 4 && o.conn.readyState != 0;
2984 releaseObject:function(o)
2993 'MSXML2.XMLHTTP.3.0',
3001 * Portions of this file are based on pieces of Yahoo User Interface Library
3002 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3003 * YUI licensed under the BSD License:
3004 * http://developer.yahoo.net/yui/license.txt
3005 * <script type="text/javascript">
3009 Roo.lib.Region = function(t, r, b, l) {
3019 Roo.lib.Region.prototype = {
3020 contains : function(region) {
3021 return ( region.left >= this.left &&
3022 region.right <= this.right &&
3023 region.top >= this.top &&
3024 region.bottom <= this.bottom );
3028 getArea : function() {
3029 return ( (this.bottom - this.top) * (this.right - this.left) );
3032 intersect : function(region) {
3033 var t = Math.max(this.top, region.top);
3034 var r = Math.min(this.right, region.right);
3035 var b = Math.min(this.bottom, region.bottom);
3036 var l = Math.max(this.left, region.left);
3038 if (b >= t && r >= l) {
3039 return new Roo.lib.Region(t, r, b, l);
3044 union : function(region) {
3045 var t = Math.min(this.top, region.top);
3046 var r = Math.max(this.right, region.right);
3047 var b = Math.max(this.bottom, region.bottom);
3048 var l = Math.min(this.left, region.left);
3050 return new Roo.lib.Region(t, r, b, l);
3053 adjust : function(t, l, b, r) {
3062 Roo.lib.Region.getRegion = function(el) {
3063 var p = Roo.lib.Dom.getXY(el);
3066 var r = p[0] + el.offsetWidth;
3067 var b = p[1] + el.offsetHeight;
3070 return new Roo.lib.Region(t, r, b, l);
3073 * Portions of this file are based on pieces of Yahoo User Interface Library
3074 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3075 * YUI licensed under the BSD License:
3076 * http://developer.yahoo.net/yui/license.txt
3077 * <script type="text/javascript">
3080 //@@dep Roo.lib.Region
3083 Roo.lib.Point = function(x, y) {
3084 if (x instanceof Array) {
3088 this.x = this.right = this.left = this[0] = x;
3089 this.y = this.top = this.bottom = this[1] = y;
3092 Roo.lib.Point.prototype = new Roo.lib.Region();
3094 * Portions of this file are based on pieces of Yahoo User Interface Library
3095 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3096 * YUI licensed under the BSD License:
3097 * http://developer.yahoo.net/yui/license.txt
3098 * <script type="text/javascript">
3105 scroll : function(el, args, duration, easing, cb, scope) {
3106 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3109 motion : function(el, args, duration, easing, cb, scope) {
3110 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3113 color : function(el, args, duration, easing, cb, scope) {
3114 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3117 run : function(el, args, duration, easing, cb, scope, type) {
3118 type = type || Roo.lib.AnimBase;
3119 if (typeof easing == "string") {
3120 easing = Roo.lib.Easing[easing];
3122 var anim = new type(el, args, duration, easing);
3123 anim.animateX(function() {
3124 Roo.callback(cb, scope);
3130 * Portions of this file are based on pieces of Yahoo User Interface Library
3131 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3132 * YUI licensed under the BSD License:
3133 * http://developer.yahoo.net/yui/license.txt
3134 * <script type="text/javascript">
3142 if (!libFlyweight) {
3143 libFlyweight = new Roo.Element.Flyweight();
3145 libFlyweight.dom = el;
3146 return libFlyweight;
3149 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3153 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3155 this.init(el, attributes, duration, method);
3159 Roo.lib.AnimBase.fly = fly;
3163 Roo.lib.AnimBase.prototype = {
3165 toString: function() {
3166 var el = this.getEl();
3167 var id = el.id || el.tagName;
3168 return ("Anim " + id);
3172 noNegatives: /width|height|opacity|padding/i,
3173 offsetAttribute: /^((width|height)|(top|left))$/,
3174 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3175 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3179 doMethod: function(attr, start, end) {
3180 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3184 setAttribute: function(attr, val, unit) {
3185 if (this.patterns.noNegatives.test(attr)) {
3186 val = (val > 0) ? val : 0;
3189 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3193 getAttribute: function(attr) {
3194 var el = this.getEl();
3195 var val = fly(el).getStyle(attr);
3197 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3198 return parseFloat(val);
3201 var a = this.patterns.offsetAttribute.exec(attr) || [];
3202 var pos = !!( a[3] );
3203 var box = !!( a[2] );
3206 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3207 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3216 getDefaultUnit: function(attr) {
3217 if (this.patterns.defaultUnit.test(attr)) {
3224 animateX : function(callback, scope) {
3225 var f = function() {
3226 this.onComplete.removeListener(f);
3227 if (typeof callback == "function") {
3228 callback.call(scope || this, this);
3231 this.onComplete.addListener(f, this);
3236 setRuntimeAttribute: function(attr) {
3239 var attributes = this.attributes;
3241 this.runtimeAttributes[attr] = {};
3243 var isset = function(prop) {
3244 return (typeof prop !== 'undefined');
3247 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3251 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3254 if (isset(attributes[attr]['to'])) {
3255 end = attributes[attr]['to'];
3256 } else if (isset(attributes[attr]['by'])) {
3257 if (start.constructor == Array) {
3259 for (var i = 0, len = start.length; i < len; ++i) {
3260 end[i] = start[i] + attributes[attr]['by'][i];
3263 end = start + attributes[attr]['by'];
3267 this.runtimeAttributes[attr].start = start;
3268 this.runtimeAttributes[attr].end = end;
3271 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3275 init: function(el, attributes, duration, method) {
3277 var isAnimated = false;
3280 var startTime = null;
3283 var actualFrames = 0;
3286 el = Roo.getDom(el);
3289 this.attributes = attributes || {};
3292 this.duration = duration || 1;
3295 this.method = method || Roo.lib.Easing.easeNone;
3298 this.useSeconds = true;
3301 this.currentFrame = 0;
3304 this.totalFrames = Roo.lib.AnimMgr.fps;
3307 this.getEl = function() {
3312 this.isAnimated = function() {
3317 this.getStartTime = function() {
3321 this.runtimeAttributes = {};
3324 this.animate = function() {
3325 if (this.isAnimated()) {
3329 this.currentFrame = 0;
3331 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3333 Roo.lib.AnimMgr.registerElement(this);
3337 this.stop = function(finish) {
3339 this.currentFrame = this.totalFrames;
3340 this._onTween.fire();
3342 Roo.lib.AnimMgr.stop(this);
3345 var onStart = function() {
3346 this.onStart.fire();
3348 this.runtimeAttributes = {};
3349 for (var attr in this.attributes) {
3350 this.setRuntimeAttribute(attr);
3355 startTime = new Date();
3359 var onTween = function() {
3361 duration: new Date() - this.getStartTime(),
3362 currentFrame: this.currentFrame
3365 data.toString = function() {
3367 'duration: ' + data.duration +
3368 ', currentFrame: ' + data.currentFrame
3372 this.onTween.fire(data);
3374 var runtimeAttributes = this.runtimeAttributes;
3376 for (var attr in runtimeAttributes) {
3377 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3383 var onComplete = function() {
3384 var actual_duration = (new Date() - startTime) / 1000 ;
3387 duration: actual_duration,
3388 frames: actualFrames,
3389 fps: actualFrames / actual_duration
3392 data.toString = function() {
3394 'duration: ' + data.duration +
3395 ', frames: ' + data.frames +
3396 ', fps: ' + data.fps
3402 this.onComplete.fire(data);
3406 this._onStart = new Roo.util.Event(this);
3407 this.onStart = new Roo.util.Event(this);
3408 this.onTween = new Roo.util.Event(this);
3409 this._onTween = new Roo.util.Event(this);
3410 this.onComplete = new Roo.util.Event(this);
3411 this._onComplete = new Roo.util.Event(this);
3412 this._onStart.addListener(onStart);
3413 this._onTween.addListener(onTween);
3414 this._onComplete.addListener(onComplete);
3419 * Portions of this file are based on pieces of Yahoo User Interface Library
3420 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3421 * YUI licensed under the BSD License:
3422 * http://developer.yahoo.net/yui/license.txt
3423 * <script type="text/javascript">
3427 Roo.lib.AnimMgr = new function() {
3444 this.registerElement = function(tween) {
3445 queue[queue.length] = tween;
3447 tween._onStart.fire();
3452 this.unRegister = function(tween, index) {
3453 tween._onComplete.fire();
3454 index = index || getIndex(tween);
3456 queue.splice(index, 1);
3460 if (tweenCount <= 0) {
3466 this.start = function() {
3467 if (thread === null) {
3468 thread = setInterval(this.run, this.delay);
3473 this.stop = function(tween) {
3475 clearInterval(thread);
3477 for (var i = 0, len = queue.length; i < len; ++i) {
3478 if (queue[0].isAnimated()) {
3479 this.unRegister(queue[0], 0);
3488 this.unRegister(tween);
3493 this.run = function() {
3494 for (var i = 0, len = queue.length; i < len; ++i) {
3495 var tween = queue[i];
3496 if (!tween || !tween.isAnimated()) {
3500 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3502 tween.currentFrame += 1;
3504 if (tween.useSeconds) {
3505 correctFrame(tween);
3507 tween._onTween.fire();
3510 Roo.lib.AnimMgr.stop(tween, i);
3515 var getIndex = function(anim) {
3516 for (var i = 0, len = queue.length; i < len; ++i) {
3517 if (queue[i] == anim) {
3525 var correctFrame = function(tween) {
3526 var frames = tween.totalFrames;
3527 var frame = tween.currentFrame;
3528 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3529 var elapsed = (new Date() - tween.getStartTime());
3532 if (elapsed < tween.duration * 1000) {
3533 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3535 tweak = frames - (frame + 1);
3537 if (tweak > 0 && isFinite(tweak)) {
3538 if (tween.currentFrame + tweak >= frames) {
3539 tweak = frames - (frame + 1);
3542 tween.currentFrame += tweak;
3548 * Portions of this file are based on pieces of Yahoo User Interface Library
3549 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3550 * YUI licensed under the BSD License:
3551 * http://developer.yahoo.net/yui/license.txt
3552 * <script type="text/javascript">
3555 Roo.lib.Bezier = new function() {
3557 this.getPosition = function(points, t) {
3558 var n = points.length;
3561 for (var i = 0; i < n; ++i) {
3562 tmp[i] = [points[i][0], points[i][1]];
3565 for (var j = 1; j < n; ++j) {
3566 for (i = 0; i < n - j; ++i) {
3567 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3568 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3572 return [ tmp[0][0], tmp[0][1] ];
3576 * Portions of this file are based on pieces of Yahoo User Interface Library
3577 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3578 * YUI licensed under the BSD License:
3579 * http://developer.yahoo.net/yui/license.txt
3580 * <script type="text/javascript">
3585 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3586 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3589 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3591 var fly = Roo.lib.AnimBase.fly;
3593 var superclass = Y.ColorAnim.superclass;
3594 var proto = Y.ColorAnim.prototype;
3596 proto.toString = function() {
3597 var el = this.getEl();
3598 var id = el.id || el.tagName;
3599 return ("ColorAnim " + id);
3602 proto.patterns.color = /color$/i;
3603 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3604 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3605 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3606 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3609 proto.parseColor = function(s) {
3610 if (s.length == 3) {
3614 var c = this.patterns.hex.exec(s);
3615 if (c && c.length == 4) {
3616 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3619 c = this.patterns.rgb.exec(s);
3620 if (c && c.length == 4) {
3621 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3624 c = this.patterns.hex3.exec(s);
3625 if (c && c.length == 4) {
3626 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3631 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3632 proto.getAttribute = function(attr) {
3633 var el = this.getEl();
3634 if (this.patterns.color.test(attr)) {
3635 var val = fly(el).getStyle(attr);
3637 if (this.patterns.transparent.test(val)) {
3638 var parent = el.parentNode;
3639 val = fly(parent).getStyle(attr);
3641 while (parent && this.patterns.transparent.test(val)) {
3642 parent = parent.parentNode;
3643 val = fly(parent).getStyle(attr);
3644 if (parent.tagName.toUpperCase() == 'HTML') {
3650 val = superclass.getAttribute.call(this, attr);
3655 proto.getAttribute = function(attr) {
3656 var el = this.getEl();
3657 if (this.patterns.color.test(attr)) {
3658 var val = fly(el).getStyle(attr);
3660 if (this.patterns.transparent.test(val)) {
3661 var parent = el.parentNode;
3662 val = fly(parent).getStyle(attr);
3664 while (parent && this.patterns.transparent.test(val)) {
3665 parent = parent.parentNode;
3666 val = fly(parent).getStyle(attr);
3667 if (parent.tagName.toUpperCase() == 'HTML') {
3673 val = superclass.getAttribute.call(this, attr);
3679 proto.doMethod = function(attr, start, end) {
3682 if (this.patterns.color.test(attr)) {
3684 for (var i = 0, len = start.length; i < len; ++i) {
3685 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3688 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3691 val = superclass.doMethod.call(this, attr, start, end);
3697 proto.setRuntimeAttribute = function(attr) {
3698 superclass.setRuntimeAttribute.call(this, attr);
3700 if (this.patterns.color.test(attr)) {
3701 var attributes = this.attributes;
3702 var start = this.parseColor(this.runtimeAttributes[attr].start);
3703 var end = this.parseColor(this.runtimeAttributes[attr].end);
3705 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3706 end = this.parseColor(attributes[attr].by);
3708 for (var i = 0, len = start.length; i < len; ++i) {
3709 end[i] = start[i] + end[i];
3713 this.runtimeAttributes[attr].start = start;
3714 this.runtimeAttributes[attr].end = end;
3720 * Portions of this file are based on pieces of Yahoo User Interface Library
3721 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3722 * YUI licensed under the BSD License:
3723 * http://developer.yahoo.net/yui/license.txt
3724 * <script type="text/javascript">
3730 easeNone: function (t, b, c, d) {
3731 return c * t / d + b;
3735 easeIn: function (t, b, c, d) {
3736 return c * (t /= d) * t + b;
3740 easeOut: function (t, b, c, d) {
3741 return -c * (t /= d) * (t - 2) + b;
3745 easeBoth: function (t, b, c, d) {
3746 if ((t /= d / 2) < 1) {
3747 return c / 2 * t * t + b;
3750 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3754 easeInStrong: function (t, b, c, d) {
3755 return c * (t /= d) * t * t * t + b;
3759 easeOutStrong: function (t, b, c, d) {
3760 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3764 easeBothStrong: function (t, b, c, d) {
3765 if ((t /= d / 2) < 1) {
3766 return c / 2 * t * t * t * t + b;
3769 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3774 elasticIn: function (t, b, c, d, a, p) {
3778 if ((t /= d) == 1) {
3785 if (!a || a < Math.abs(c)) {
3790 var s = p / (2 * Math.PI) * Math.asin(c / a);
3793 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3797 elasticOut: function (t, b, c, d, a, p) {
3801 if ((t /= d) == 1) {
3808 if (!a || a < Math.abs(c)) {
3813 var s = p / (2 * Math.PI) * Math.asin(c / a);
3816 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3820 elasticBoth: function (t, b, c, d, a, p) {
3825 if ((t /= d / 2) == 2) {
3833 if (!a || a < Math.abs(c)) {
3838 var s = p / (2 * Math.PI) * Math.asin(c / a);
3842 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3843 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3845 return a * Math.pow(2, -10 * (t -= 1)) *
3846 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3851 backIn: function (t, b, c, d, s) {
3852 if (typeof s == 'undefined') {
3855 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3859 backOut: function (t, b, c, d, s) {
3860 if (typeof s == 'undefined') {
3863 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3867 backBoth: function (t, b, c, d, s) {
3868 if (typeof s == 'undefined') {
3872 if ((t /= d / 2 ) < 1) {
3873 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3875 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3879 bounceIn: function (t, b, c, d) {
3880 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3884 bounceOut: function (t, b, c, d) {
3885 if ((t /= d) < (1 / 2.75)) {
3886 return c * (7.5625 * t * t) + b;
3887 } else if (t < (2 / 2.75)) {
3888 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3889 } else if (t < (2.5 / 2.75)) {
3890 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3892 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3896 bounceBoth: function (t, b, c, d) {
3898 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3900 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3903 * Portions of this file are based on pieces of Yahoo User Interface Library
3904 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3905 * YUI licensed under the BSD License:
3906 * http://developer.yahoo.net/yui/license.txt
3907 * <script type="text/javascript">
3911 Roo.lib.Motion = function(el, attributes, duration, method) {
3913 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3917 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3921 var superclass = Y.Motion.superclass;
3922 var proto = Y.Motion.prototype;
3924 proto.toString = function() {
3925 var el = this.getEl();
3926 var id = el.id || el.tagName;
3927 return ("Motion " + id);
3930 proto.patterns.points = /^points$/i;
3932 proto.setAttribute = function(attr, val, unit) {
3933 if (this.patterns.points.test(attr)) {
3934 unit = unit || 'px';
3935 superclass.setAttribute.call(this, 'left', val[0], unit);
3936 superclass.setAttribute.call(this, 'top', val[1], unit);
3938 superclass.setAttribute.call(this, attr, val, unit);
3942 proto.getAttribute = function(attr) {
3943 if (this.patterns.points.test(attr)) {
3945 superclass.getAttribute.call(this, 'left'),
3946 superclass.getAttribute.call(this, 'top')
3949 val = superclass.getAttribute.call(this, attr);
3955 proto.doMethod = function(attr, start, end) {
3958 if (this.patterns.points.test(attr)) {
3959 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3960 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3962 val = superclass.doMethod.call(this, attr, start, end);
3967 proto.setRuntimeAttribute = function(attr) {
3968 if (this.patterns.points.test(attr)) {
3969 var el = this.getEl();
3970 var attributes = this.attributes;
3972 var control = attributes['points']['control'] || [];
3976 if (control.length > 0 && !(control[0] instanceof Array)) {
3977 control = [control];
3980 for (i = 0,len = control.length; i < len; ++i) {
3981 tmp[i] = control[i];
3986 Roo.fly(el).position();
3988 if (isset(attributes['points']['from'])) {
3989 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3992 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3995 start = this.getAttribute('points');
3998 if (isset(attributes['points']['to'])) {
3999 end = translateValues.call(this, attributes['points']['to'], start);
4001 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4002 for (i = 0,len = control.length; i < len; ++i) {
4003 control[i] = translateValues.call(this, control[i], start);
4007 } else if (isset(attributes['points']['by'])) {
4008 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4010 for (i = 0,len = control.length; i < len; ++i) {
4011 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4015 this.runtimeAttributes[attr] = [start];
4017 if (control.length > 0) {
4018 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4021 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4024 superclass.setRuntimeAttribute.call(this, attr);
4028 var translateValues = function(val, start) {
4029 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4030 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4035 var isset = function(prop) {
4036 return (typeof prop !== 'undefined');
4040 * Portions of this file are based on pieces of Yahoo User Interface Library
4041 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4042 * YUI licensed under the BSD License:
4043 * http://developer.yahoo.net/yui/license.txt
4044 * <script type="text/javascript">
4048 Roo.lib.Scroll = function(el, attributes, duration, method) {
4050 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4054 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4058 var superclass = Y.Scroll.superclass;
4059 var proto = Y.Scroll.prototype;
4061 proto.toString = function() {
4062 var el = this.getEl();
4063 var id = el.id || el.tagName;
4064 return ("Scroll " + id);
4067 proto.doMethod = function(attr, start, end) {
4070 if (attr == 'scroll') {
4072 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4073 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4077 val = superclass.doMethod.call(this, attr, start, end);
4082 proto.getAttribute = function(attr) {
4084 var el = this.getEl();
4086 if (attr == 'scroll') {
4087 val = [ el.scrollLeft, el.scrollTop ];
4089 val = superclass.getAttribute.call(this, attr);
4095 proto.setAttribute = function(attr, val, unit) {
4096 var el = this.getEl();
4098 if (attr == 'scroll') {
4099 el.scrollLeft = val[0];
4100 el.scrollTop = val[1];
4102 superclass.setAttribute.call(this, attr, val, unit);
4108 * Ext JS Library 1.1.1
4109 * Copyright(c) 2006-2007, Ext JS, LLC.
4111 * Originally Released Under LGPL - original licence link has changed is not relivant.
4114 * <script type="text/javascript">
4118 // nasty IE9 hack - what a pile of crap that is..
4120 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4121 Range.prototype.createContextualFragment = function (html) {
4122 var doc = window.document;
4123 var container = doc.createElement("div");
4124 container.innerHTML = html;
4125 var frag = doc.createDocumentFragment(), n;
4126 while ((n = container.firstChild)) {
4127 frag.appendChild(n);
4134 * @class Roo.DomHelper
4135 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4136 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4139 Roo.DomHelper = function(){
4140 var tempTableEl = null;
4141 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4142 var tableRe = /^table|tbody|tr|td$/i;
4144 // build as innerHTML where available
4146 var createHtml = function(o){
4147 if(typeof o == 'string'){
4156 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4157 if(attr == "style"){
4159 if(typeof s == "function"){
4162 if(typeof s == "string"){
4163 b += ' style="' + s + '"';
4164 }else if(typeof s == "object"){
4167 if(typeof s[key] != "function"){
4168 b += key + ":" + s[key] + ";";
4175 b += ' class="' + o["cls"] + '"';
4176 }else if(attr == "htmlFor"){
4177 b += ' for="' + o["htmlFor"] + '"';
4179 b += " " + attr + '="' + o[attr] + '"';
4183 if(emptyTags.test(o.tag)){
4187 var cn = o.children || o.cn;
4189 //http://bugs.kde.org/show_bug.cgi?id=71506
4190 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4191 for(var i = 0, len = cn.length; i < len; i++) {
4192 b += createHtml(cn[i], b);
4195 b += createHtml(cn, b);
4201 b += "</" + o.tag + ">";
4208 var createDom = function(o, parentNode){
4210 // defininition craeted..
4212 if (o.ns && o.ns != 'html') {
4214 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4215 xmlns[o.ns] = o.xmlns;
4218 if (typeof(xmlns[o.ns]) == 'undefined') {
4219 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4225 if (typeof(o) == 'string') {
4226 return parentNode.appendChild(document.createTextNode(o));
4228 o.tag = o.tag || div;
4229 if (o.ns && Roo.isIE) {
4231 o.tag = o.ns + ':' + o.tag;
4234 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4235 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4238 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4239 attr == "style" || typeof o[attr] == "function") { continue; }
4241 if(attr=="cls" && Roo.isIE){
4242 el.className = o["cls"];
4244 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4250 Roo.DomHelper.applyStyles(el, o.style);
4251 var cn = o.children || o.cn;
4253 //http://bugs.kde.org/show_bug.cgi?id=71506
4254 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4255 for(var i = 0, len = cn.length; i < len; i++) {
4256 createDom(cn[i], el);
4263 el.innerHTML = o.html;
4266 parentNode.appendChild(el);
4271 var ieTable = function(depth, s, h, e){
4272 tempTableEl.innerHTML = [s, h, e].join('');
4273 var i = -1, el = tempTableEl;
4280 // kill repeat to save bytes
4284 tbe = '</tbody>'+te,
4290 * Nasty code for IE's broken table implementation
4292 var insertIntoTable = function(tag, where, el, html){
4294 tempTableEl = document.createElement('div');
4299 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4302 if(where == 'beforebegin'){
4306 before = el.nextSibling;
4309 node = ieTable(4, trs, html, tre);
4311 else if(tag == 'tr'){
4312 if(where == 'beforebegin'){
4315 node = ieTable(3, tbs, html, tbe);
4316 } else if(where == 'afterend'){
4317 before = el.nextSibling;
4319 node = ieTable(3, tbs, html, tbe);
4320 } else{ // INTO a TR
4321 if(where == 'afterbegin'){
4322 before = el.firstChild;
4324 node = ieTable(4, trs, html, tre);
4326 } else if(tag == 'tbody'){
4327 if(where == 'beforebegin'){
4330 node = ieTable(2, ts, html, te);
4331 } else if(where == 'afterend'){
4332 before = el.nextSibling;
4334 node = ieTable(2, ts, html, te);
4336 if(where == 'afterbegin'){
4337 before = el.firstChild;
4339 node = ieTable(3, tbs, html, tbe);
4342 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4345 if(where == 'afterbegin'){
4346 before = el.firstChild;
4348 node = ieTable(2, ts, html, te);
4350 el.insertBefore(node, before);
4355 /** True to force the use of DOM instead of html fragments @type Boolean */
4359 * Returns the markup for the passed Element(s) config
4360 * @param {Object} o The Dom object spec (and children)
4363 markup : function(o){
4364 return createHtml(o);
4368 * Applies a style specification to an element
4369 * @param {String/HTMLElement} el The element to apply styles to
4370 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4371 * a function which returns such a specification.
4373 applyStyles : function(el, styles){
4376 if(typeof styles == "string"){
4377 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4379 while ((matches = re.exec(styles)) != null){
4380 el.setStyle(matches[1], matches[2]);
4382 }else if (typeof styles == "object"){
4383 for (var style in styles){
4384 el.setStyle(style, styles[style]);
4386 }else if (typeof styles == "function"){
4387 Roo.DomHelper.applyStyles(el, styles.call());
4393 * Inserts an HTML fragment into the Dom
4394 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4395 * @param {HTMLElement} el The context element
4396 * @param {String} html The HTML fragmenet
4397 * @return {HTMLElement} The new node
4399 insertHtml : function(where, el, html){
4400 where = where.toLowerCase();
4401 if(el.insertAdjacentHTML){
4402 if(tableRe.test(el.tagName)){
4404 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4410 el.insertAdjacentHTML('BeforeBegin', html);
4411 return el.previousSibling;
4413 el.insertAdjacentHTML('AfterBegin', html);
4414 return el.firstChild;
4416 el.insertAdjacentHTML('BeforeEnd', html);
4417 return el.lastChild;
4419 el.insertAdjacentHTML('AfterEnd', html);
4420 return el.nextSibling;
4422 throw 'Illegal insertion point -> "' + where + '"';
4424 var range = el.ownerDocument.createRange();
4428 range.setStartBefore(el);
4429 frag = range.createContextualFragment(html);
4430 el.parentNode.insertBefore(frag, el);
4431 return el.previousSibling;
4434 range.setStartBefore(el.firstChild);
4435 frag = range.createContextualFragment(html);
4436 el.insertBefore(frag, el.firstChild);
4437 return el.firstChild;
4439 el.innerHTML = html;
4440 return el.firstChild;
4444 range.setStartAfter(el.lastChild);
4445 frag = range.createContextualFragment(html);
4446 el.appendChild(frag);
4447 return el.lastChild;
4449 el.innerHTML = html;
4450 return el.lastChild;
4453 range.setStartAfter(el);
4454 frag = range.createContextualFragment(html);
4455 el.parentNode.insertBefore(frag, el.nextSibling);
4456 return el.nextSibling;
4458 throw 'Illegal insertion point -> "' + where + '"';
4462 * Creates new Dom element(s) and inserts them before el
4463 * @param {String/HTMLElement/Element} el The context element
4464 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4465 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4466 * @return {HTMLElement/Roo.Element} The new node
4468 insertBefore : function(el, o, returnElement){
4469 return this.doInsert(el, o, returnElement, "beforeBegin");
4473 * Creates new Dom element(s) and inserts them after el
4474 * @param {String/HTMLElement/Element} el The context element
4475 * @param {Object} o The Dom object spec (and children)
4476 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4477 * @return {HTMLElement/Roo.Element} The new node
4479 insertAfter : function(el, o, returnElement){
4480 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4484 * Creates new Dom element(s) and inserts them as the first child of el
4485 * @param {String/HTMLElement/Element} el The context element
4486 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4487 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4488 * @return {HTMLElement/Roo.Element} The new node
4490 insertFirst : function(el, o, returnElement){
4491 return this.doInsert(el, o, returnElement, "afterBegin");
4495 doInsert : function(el, o, returnElement, pos, sibling){
4496 el = Roo.getDom(el);
4498 if(this.useDom || o.ns){
4499 newNode = createDom(o, null);
4500 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4502 var html = createHtml(o);
4503 newNode = this.insertHtml(pos, el, html);
4505 return returnElement ? Roo.get(newNode, true) : newNode;
4509 * Creates new Dom element(s) and appends them to el
4510 * @param {String/HTMLElement/Element} el The context element
4511 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4512 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4513 * @return {HTMLElement/Roo.Element} The new node
4515 append : function(el, o, returnElement){
4516 el = Roo.getDom(el);
4518 if(this.useDom || o.ns){
4519 newNode = createDom(o, null);
4520 el.appendChild(newNode);
4522 var html = createHtml(o);
4523 newNode = this.insertHtml("beforeEnd", el, html);
4525 return returnElement ? Roo.get(newNode, true) : newNode;
4529 * Creates new Dom element(s) and overwrites the contents of el with them
4530 * @param {String/HTMLElement/Element} el The context element
4531 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4532 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4533 * @return {HTMLElement/Roo.Element} The new node
4535 overwrite : function(el, o, returnElement){
4536 el = Roo.getDom(el);
4539 while (el.childNodes.length) {
4540 el.removeChild(el.firstChild);
4544 el.innerHTML = createHtml(o);
4547 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4551 * Creates a new Roo.DomHelper.Template from the Dom object spec
4552 * @param {Object} o The Dom object spec (and children)
4553 * @return {Roo.DomHelper.Template} The new template
4555 createTemplate : function(o){
4556 var html = createHtml(o);
4557 return new Roo.Template(html);
4563 * Ext JS Library 1.1.1
4564 * Copyright(c) 2006-2007, Ext JS, LLC.
4566 * Originally Released Under LGPL - original licence link has changed is not relivant.
4569 * <script type="text/javascript">
4573 * @class Roo.Template
4574 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4575 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4578 var t = new Roo.Template({
4579 html : '<div name="{id}">' +
4580 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4582 myformat: function (value, allValues) {
4583 return 'XX' + value;
4586 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4588 * For more information see this blog post with examples:
4589 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4590 - Create Elements using DOM, HTML fragments and Templates</a>.
4592 * @param {Object} cfg - Configuration object.
4594 Roo.Template = function(cfg){
4596 if(cfg instanceof Array){
4598 }else if(arguments.length > 1){
4599 cfg = Array.prototype.join.call(arguments, "");
4603 if (typeof(cfg) == 'object') {
4614 Roo.Template.prototype = {
4617 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4618 * it should be fixed so that template is observable...
4622 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4626 * Returns an HTML fragment of this template with the specified values applied.
4627 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4628 * @return {String} The HTML fragment
4630 applyTemplate : function(values){
4634 return this.compiled(values);
4636 var useF = this.disableFormats !== true;
4637 var fm = Roo.util.Format, tpl = this;
4638 var fn = function(m, name, format, args){
4640 if(format.substr(0, 5) == "this."){
4641 return tpl.call(format.substr(5), values[name], values);
4644 // quoted values are required for strings in compiled templates,
4645 // but for non compiled we need to strip them
4646 // quoted reversed for jsmin
4647 var re = /^\s*['"](.*)["']\s*$/;
4648 args = args.split(',');
4649 for(var i = 0, len = args.length; i < len; i++){
4650 args[i] = args[i].replace(re, "$1");
4652 args = [values[name]].concat(args);
4654 args = [values[name]];
4656 return fm[format].apply(fm, args);
4659 return values[name] !== undefined ? values[name] : "";
4662 return this.html.replace(this.re, fn);
4680 this.loading = true;
4681 this.compiled = false;
4683 var cx = new Roo.data.Connection();
4687 success : function (response) {
4689 _t.html = response.responseText;
4693 failure : function(response) {
4694 Roo.log("Template failed to load from " + _t.url);
4701 * Sets the HTML used as the template and optionally compiles it.
4702 * @param {String} html
4703 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4704 * @return {Roo.Template} this
4706 set : function(html, compile){
4708 this.compiled = null;
4716 * True to disable format functions (defaults to false)
4719 disableFormats : false,
4722 * The regular expression used to match template variables
4726 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4729 * Compiles the template into an internal function, eliminating the RegEx overhead.
4730 * @return {Roo.Template} this
4732 compile : function(){
4733 var fm = Roo.util.Format;
4734 var useF = this.disableFormats !== true;
4735 var sep = Roo.isGecko ? "+" : ",";
4736 var fn = function(m, name, format, args){
4738 args = args ? ',' + args : "";
4739 if(format.substr(0, 5) != "this."){
4740 format = "fm." + format + '(';
4742 format = 'this.call("'+ format.substr(5) + '", ';
4746 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4748 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4751 // branched to use + in gecko and [].join() in others
4753 body = "this.compiled = function(values){ return '" +
4754 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4757 body = ["this.compiled = function(values){ return ['"];
4758 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4759 body.push("'].join('');};");
4760 body = body.join('');
4770 // private function used to call members
4771 call : function(fnName, value, allValues){
4772 return this[fnName](value, allValues);
4776 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4777 * @param {String/HTMLElement/Roo.Element} el The context element
4778 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4779 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4780 * @return {HTMLElement/Roo.Element} The new node or Element
4782 insertFirst: function(el, values, returnElement){
4783 return this.doInsert('afterBegin', el, values, returnElement);
4787 * Applies the supplied values to the template and inserts the new node(s) before el.
4788 * @param {String/HTMLElement/Roo.Element} el The context element
4789 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4790 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4791 * @return {HTMLElement/Roo.Element} The new node or Element
4793 insertBefore: function(el, values, returnElement){
4794 return this.doInsert('beforeBegin', el, values, returnElement);
4798 * Applies the supplied values to the template and inserts the new node(s) after el.
4799 * @param {String/HTMLElement/Roo.Element} el The context element
4800 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4801 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4802 * @return {HTMLElement/Roo.Element} The new node or Element
4804 insertAfter : function(el, values, returnElement){
4805 return this.doInsert('afterEnd', el, values, returnElement);
4809 * Applies the supplied values to the template and appends the new node(s) to el.
4810 * @param {String/HTMLElement/Roo.Element} el The context element
4811 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4812 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4813 * @return {HTMLElement/Roo.Element} The new node or Element
4815 append : function(el, values, returnElement){
4816 return this.doInsert('beforeEnd', el, values, returnElement);
4819 doInsert : function(where, el, values, returnEl){
4820 el = Roo.getDom(el);
4821 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4822 return returnEl ? Roo.get(newNode, true) : newNode;
4826 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4827 * @param {String/HTMLElement/Roo.Element} el The context element
4828 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4829 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4830 * @return {HTMLElement/Roo.Element} The new node or Element
4832 overwrite : function(el, values, returnElement){
4833 el = Roo.getDom(el);
4834 el.innerHTML = this.applyTemplate(values);
4835 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4839 * Alias for {@link #applyTemplate}
4842 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4845 Roo.DomHelper.Template = Roo.Template;
4848 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4849 * @param {String/HTMLElement} el A DOM element or its id
4850 * @returns {Roo.Template} The created template
4853 Roo.Template.from = function(el){
4854 el = Roo.getDom(el);
4855 return new Roo.Template(el.value || el.innerHTML);
4858 * Ext JS Library 1.1.1
4859 * Copyright(c) 2006-2007, Ext JS, LLC.
4861 * Originally Released Under LGPL - original licence link has changed is not relivant.
4864 * <script type="text/javascript">
4869 * This is code is also distributed under MIT license for use
4870 * with jQuery and prototype JavaScript libraries.
4873 * @class Roo.DomQuery
4874 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4876 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4879 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4881 <h4>Element Selectors:</h4>
4883 <li> <b>*</b> any element</li>
4884 <li> <b>E</b> an element with the tag E</li>
4885 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4886 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4887 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4888 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4890 <h4>Attribute Selectors:</h4>
4891 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4893 <li> <b>E[foo]</b> has an attribute "foo"</li>
4894 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4895 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4896 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4897 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4898 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4899 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4901 <h4>Pseudo Classes:</h4>
4903 <li> <b>E:first-child</b> E is the first child of its parent</li>
4904 <li> <b>E:last-child</b> E is the last child of its parent</li>
4905 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4906 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4907 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4908 <li> <b>E:only-child</b> E is the only child of its parent</li>
4909 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4910 <li> <b>E:first</b> the first E in the resultset</li>
4911 <li> <b>E:last</b> the last E in the resultset</li>
4912 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4913 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4914 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4915 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4916 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4917 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4918 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4919 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4920 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4922 <h4>CSS Value Selectors:</h4>
4924 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4925 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4926 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4927 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4928 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4929 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4933 Roo.DomQuery = function(){
4934 var cache = {}, simpleCache = {}, valueCache = {};
4935 var nonSpace = /\S/;
4936 var trimRe = /^\s+|\s+$/g;
4937 var tplRe = /\{(\d+)\}/g;
4938 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4939 var tagTokenRe = /^(#)?([\w-\*]+)/;
4940 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4942 function child(p, index){
4944 var n = p.firstChild;
4946 if(n.nodeType == 1){
4957 while((n = n.nextSibling) && n.nodeType != 1);
4962 while((n = n.previousSibling) && n.nodeType != 1);
4966 function children(d){
4967 var n = d.firstChild, ni = -1;
4969 var nx = n.nextSibling;
4970 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4980 function byClassName(c, a, v){
4984 var r = [], ri = -1, cn;
4985 for(var i = 0, ci; ci = c[i]; i++){
4986 if((' '+ci.className+' ').indexOf(v) != -1){
4993 function attrValue(n, attr){
4994 if(!n.tagName && typeof n.length != "undefined"){
5003 if(attr == "class" || attr == "className"){
5006 return n.getAttribute(attr) || n[attr];
5010 function getNodes(ns, mode, tagName){
5011 var result = [], ri = -1, cs;
5015 tagName = tagName || "*";
5016 if(typeof ns.getElementsByTagName != "undefined"){
5020 for(var i = 0, ni; ni = ns[i]; i++){
5021 cs = ni.getElementsByTagName(tagName);
5022 for(var j = 0, ci; ci = cs[j]; j++){
5026 }else if(mode == "/" || mode == ">"){
5027 var utag = tagName.toUpperCase();
5028 for(var i = 0, ni, cn; ni = ns[i]; i++){
5029 cn = ni.children || ni.childNodes;
5030 for(var j = 0, cj; cj = cn[j]; j++){
5031 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5036 }else if(mode == "+"){
5037 var utag = tagName.toUpperCase();
5038 for(var i = 0, n; n = ns[i]; i++){
5039 while((n = n.nextSibling) && n.nodeType != 1);
5040 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5044 }else if(mode == "~"){
5045 for(var i = 0, n; n = ns[i]; i++){
5046 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5055 function concat(a, b){
5059 for(var i = 0, l = b.length; i < l; i++){
5065 function byTag(cs, tagName){
5066 if(cs.tagName || cs == document){
5072 var r = [], ri = -1;
5073 tagName = tagName.toLowerCase();
5074 for(var i = 0, ci; ci = cs[i]; i++){
5075 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5082 function byId(cs, attr, id){
5083 if(cs.tagName || cs == document){
5089 var r = [], ri = -1;
5090 for(var i = 0,ci; ci = cs[i]; i++){
5091 if(ci && ci.id == id){
5099 function byAttribute(cs, attr, value, op, custom){
5100 var r = [], ri = -1, st = custom=="{";
5101 var f = Roo.DomQuery.operators[op];
5102 for(var i = 0, ci; ci = cs[i]; i++){
5105 a = Roo.DomQuery.getStyle(ci, attr);
5107 else if(attr == "class" || attr == "className"){
5109 }else if(attr == "for"){
5111 }else if(attr == "href"){
5112 a = ci.getAttribute("href", 2);
5114 a = ci.getAttribute(attr);
5116 if((f && f(a, value)) || (!f && a)){
5123 function byPseudo(cs, name, value){
5124 return Roo.DomQuery.pseudos[name](cs, value);
5127 // This is for IE MSXML which does not support expandos.
5128 // IE runs the same speed using setAttribute, however FF slows way down
5129 // and Safari completely fails so they need to continue to use expandos.
5130 var isIE = window.ActiveXObject ? true : false;
5132 // this eval is stop the compressor from
5133 // renaming the variable to something shorter
5135 /** eval:var:batch */
5140 function nodupIEXml(cs){
5142 cs[0].setAttribute("_nodup", d);
5144 for(var i = 1, len = cs.length; i < len; i++){
5146 if(!c.getAttribute("_nodup") != d){
5147 c.setAttribute("_nodup", d);
5151 for(var i = 0, len = cs.length; i < len; i++){
5152 cs[i].removeAttribute("_nodup");
5161 var len = cs.length, c, i, r = cs, cj, ri = -1;
5162 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5165 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5166 return nodupIEXml(cs);
5170 for(i = 1; c = cs[i]; i++){
5175 for(var j = 0; j < i; j++){
5178 for(j = i+1; cj = cs[j]; j++){
5190 function quickDiffIEXml(c1, c2){
5192 for(var i = 0, len = c1.length; i < len; i++){
5193 c1[i].setAttribute("_qdiff", d);
5196 for(var i = 0, len = c2.length; i < len; i++){
5197 if(c2[i].getAttribute("_qdiff") != d){
5198 r[r.length] = c2[i];
5201 for(var i = 0, len = c1.length; i < len; i++){
5202 c1[i].removeAttribute("_qdiff");
5207 function quickDiff(c1, c2){
5208 var len1 = c1.length;
5212 if(isIE && c1[0].selectSingleNode){
5213 return quickDiffIEXml(c1, c2);
5216 for(var i = 0; i < len1; i++){
5220 for(var i = 0, len = c2.length; i < len; i++){
5221 if(c2[i]._qdiff != d){
5222 r[r.length] = c2[i];
5228 function quickId(ns, mode, root, id){
5230 var d = root.ownerDocument || root;
5231 return d.getElementById(id);
5233 ns = getNodes(ns, mode, "*");
5234 return byId(ns, null, id);
5238 getStyle : function(el, name){
5239 return Roo.fly(el).getStyle(name);
5242 * Compiles a selector/xpath query into a reusable function. The returned function
5243 * takes one parameter "root" (optional), which is the context node from where the query should start.
5244 * @param {String} selector The selector/xpath query
5245 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5246 * @return {Function}
5248 compile : function(path, type){
5249 type = type || "select";
5251 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5252 var q = path, mode, lq;
5253 var tk = Roo.DomQuery.matchers;
5254 var tklen = tk.length;
5257 // accept leading mode switch
5258 var lmode = q.match(modeRe);
5259 if(lmode && lmode[1]){
5260 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5261 q = q.replace(lmode[1], "");
5263 // strip leading slashes
5264 while(path.substr(0, 1)=="/"){
5265 path = path.substr(1);
5268 while(q && lq != q){
5270 var tm = q.match(tagTokenRe);
5271 if(type == "select"){
5274 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5276 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5278 q = q.replace(tm[0], "");
5279 }else if(q.substr(0, 1) != '@'){
5280 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5285 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5287 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5289 q = q.replace(tm[0], "");
5292 while(!(mm = q.match(modeRe))){
5293 var matched = false;
5294 for(var j = 0; j < tklen; j++){
5296 var m = q.match(t.re);
5298 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5301 q = q.replace(m[0], "");
5306 // prevent infinite loop on bad selector
5308 throw 'Error parsing selector, parsing failed at "' + q + '"';
5312 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5313 q = q.replace(mm[1], "");
5316 fn[fn.length] = "return nodup(n);\n}";
5319 * list of variables that need from compression as they are used by eval.
5329 * eval:var:byClassName
5331 * eval:var:byAttribute
5332 * eval:var:attrValue
5340 * Selects a group of elements.
5341 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5342 * @param {Node} root (optional) The start of the query (defaults to document).
5345 select : function(path, root, type){
5346 if(!root || root == document){
5349 if(typeof root == "string"){
5350 root = document.getElementById(root);
5352 var paths = path.split(",");
5354 for(var i = 0, len = paths.length; i < len; i++){
5355 var p = paths[i].replace(trimRe, "");
5357 cache[p] = Roo.DomQuery.compile(p);
5359 throw p + " is not a valid selector";
5362 var result = cache[p](root);
5363 if(result && result != document){
5364 results = results.concat(result);
5367 if(paths.length > 1){
5368 return nodup(results);
5374 * Selects a single element.
5375 * @param {String} selector The selector/xpath query
5376 * @param {Node} root (optional) The start of the query (defaults to document).
5379 selectNode : function(path, root){
5380 return Roo.DomQuery.select(path, root)[0];
5384 * Selects the value of a node, optionally replacing null with the defaultValue.
5385 * @param {String} selector The selector/xpath query
5386 * @param {Node} root (optional) The start of the query (defaults to document).
5387 * @param {String} defaultValue
5389 selectValue : function(path, root, defaultValue){
5390 path = path.replace(trimRe, "");
5391 if(!valueCache[path]){
5392 valueCache[path] = Roo.DomQuery.compile(path, "select");
5394 var n = valueCache[path](root);
5395 n = n[0] ? n[0] : n;
5396 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5397 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5401 * Selects the value of a node, parsing integers and floats.
5402 * @param {String} selector The selector/xpath query
5403 * @param {Node} root (optional) The start of the query (defaults to document).
5404 * @param {Number} defaultValue
5407 selectNumber : function(path, root, defaultValue){
5408 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5409 return parseFloat(v);
5413 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5414 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5415 * @param {String} selector The simple selector to test
5418 is : function(el, ss){
5419 if(typeof el == "string"){
5420 el = document.getElementById(el);
5422 var isArray = (el instanceof Array);
5423 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5424 return isArray ? (result.length == el.length) : (result.length > 0);
5428 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5429 * @param {Array} el An array of elements to filter
5430 * @param {String} selector The simple selector to test
5431 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5432 * the selector instead of the ones that match
5435 filter : function(els, ss, nonMatches){
5436 ss = ss.replace(trimRe, "");
5437 if(!simpleCache[ss]){
5438 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5440 var result = simpleCache[ss](els);
5441 return nonMatches ? quickDiff(result, els) : result;
5445 * Collection of matching regular expressions and code snippets.
5449 select: 'n = byClassName(n, null, " {1} ");'
5451 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5452 select: 'n = byPseudo(n, "{1}", "{2}");'
5454 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5455 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5458 select: 'n = byId(n, null, "{1}");'
5461 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5466 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5467 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5470 "=" : function(a, v){
5473 "!=" : function(a, v){
5476 "^=" : function(a, v){
5477 return a && a.substr(0, v.length) == v;
5479 "$=" : function(a, v){
5480 return a && a.substr(a.length-v.length) == v;
5482 "*=" : function(a, v){
5483 return a && a.indexOf(v) !== -1;
5485 "%=" : function(a, v){
5486 return (a % v) == 0;
5488 "|=" : function(a, v){
5489 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5491 "~=" : function(a, v){
5492 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5497 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5498 * and the argument (if any) supplied in the selector.
5501 "first-child" : function(c){
5502 var r = [], ri = -1, n;
5503 for(var i = 0, ci; ci = n = c[i]; i++){
5504 while((n = n.previousSibling) && n.nodeType != 1);
5512 "last-child" : function(c){
5513 var r = [], ri = -1, n;
5514 for(var i = 0, ci; ci = n = c[i]; i++){
5515 while((n = n.nextSibling) && n.nodeType != 1);
5523 "nth-child" : function(c, a) {
5524 var r = [], ri = -1;
5525 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5526 var f = (m[1] || 1) - 0, l = m[2] - 0;
5527 for(var i = 0, n; n = c[i]; i++){
5528 var pn = n.parentNode;
5529 if (batch != pn._batch) {
5531 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5532 if(cn.nodeType == 1){
5539 if (l == 0 || n.nodeIndex == l){
5542 } else if ((n.nodeIndex + l) % f == 0){
5550 "only-child" : function(c){
5551 var r = [], ri = -1;;
5552 for(var i = 0, ci; ci = c[i]; i++){
5553 if(!prev(ci) && !next(ci)){
5560 "empty" : function(c){
5561 var r = [], ri = -1;
5562 for(var i = 0, ci; ci = c[i]; i++){
5563 var cns = ci.childNodes, j = 0, cn, empty = true;
5566 if(cn.nodeType == 1 || cn.nodeType == 3){
5578 "contains" : function(c, v){
5579 var r = [], ri = -1;
5580 for(var i = 0, ci; ci = c[i]; i++){
5581 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5588 "nodeValue" : function(c, v){
5589 var r = [], ri = -1;
5590 for(var i = 0, ci; ci = c[i]; i++){
5591 if(ci.firstChild && ci.firstChild.nodeValue == v){
5598 "checked" : function(c){
5599 var r = [], ri = -1;
5600 for(var i = 0, ci; ci = c[i]; i++){
5601 if(ci.checked == true){
5608 "not" : function(c, ss){
5609 return Roo.DomQuery.filter(c, ss, true);
5612 "odd" : function(c){
5613 return this["nth-child"](c, "odd");
5616 "even" : function(c){
5617 return this["nth-child"](c, "even");
5620 "nth" : function(c, a){
5621 return c[a-1] || [];
5624 "first" : function(c){
5628 "last" : function(c){
5629 return c[c.length-1] || [];
5632 "has" : function(c, ss){
5633 var s = Roo.DomQuery.select;
5634 var r = [], ri = -1;
5635 for(var i = 0, ci; ci = c[i]; i++){
5636 if(s(ss, ci).length > 0){
5643 "next" : function(c, ss){
5644 var is = Roo.DomQuery.is;
5645 var r = [], ri = -1;
5646 for(var i = 0, ci; ci = c[i]; i++){
5655 "prev" : function(c, ss){
5656 var is = Roo.DomQuery.is;
5657 var r = [], ri = -1;
5658 for(var i = 0, ci; ci = c[i]; i++){
5671 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5672 * @param {String} path The selector/xpath query
5673 * @param {Node} root (optional) The start of the query (defaults to document).
5678 Roo.query = Roo.DomQuery.select;
5681 * Ext JS Library 1.1.1
5682 * Copyright(c) 2006-2007, Ext JS, LLC.
5684 * Originally Released Under LGPL - original licence link has changed is not relivant.
5687 * <script type="text/javascript">
5691 * @class Roo.util.Observable
5692 * Base class that provides a common interface for publishing events. Subclasses are expected to
5693 * to have a property "events" with all the events defined.<br>
5696 Employee = function(name){
5703 Roo.extend(Employee, Roo.util.Observable);
5705 * @param {Object} config properties to use (incuding events / listeners)
5708 Roo.util.Observable = function(cfg){
5711 this.addEvents(cfg.events || {});
5713 delete cfg.events; // make sure
5716 Roo.apply(this, cfg);
5719 this.on(this.listeners);
5720 delete this.listeners;
5723 Roo.util.Observable.prototype = {
5725 * @cfg {Object} listeners list of events and functions to call for this object,
5729 'click' : function(e) {
5739 * Fires the specified event with the passed parameters (minus the event name).
5740 * @param {String} eventName
5741 * @param {Object...} args Variable number of parameters are passed to handlers
5742 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5744 fireEvent : function(){
5745 var ce = this.events[arguments[0].toLowerCase()];
5746 if(typeof ce == "object"){
5747 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5754 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5757 * Appends an event handler to this component
5758 * @param {String} eventName The type of event to listen for
5759 * @param {Function} handler The method the event invokes
5760 * @param {Object} scope (optional) The scope in which to execute the handler
5761 * function. The handler function's "this" context.
5762 * @param {Object} options (optional) An object containing handler configuration
5763 * properties. This may contain any of the following properties:<ul>
5764 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5765 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5766 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5767 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5768 * by the specified number of milliseconds. If the event fires again within that time, the original
5769 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5772 * <b>Combining Options</b><br>
5773 * Using the options argument, it is possible to combine different types of listeners:<br>
5775 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5777 el.on('click', this.onClick, this, {
5784 * <b>Attaching multiple handlers in 1 call</b><br>
5785 * The method also allows for a single argument to be passed which is a config object containing properties
5786 * which specify multiple handlers.
5795 fn: this.onMouseOver,
5799 fn: this.onMouseOut,
5805 * Or a shorthand syntax which passes the same scope object to all handlers:
5808 'click': this.onClick,
5809 'mouseover': this.onMouseOver,
5810 'mouseout': this.onMouseOut,
5815 addListener : function(eventName, fn, scope, o){
5816 if(typeof eventName == "object"){
5819 if(this.filterOptRe.test(e)){
5822 if(typeof o[e] == "function"){
5824 this.addListener(e, o[e], o.scope, o);
5826 // individual options
5827 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5832 o = (!o || typeof o == "boolean") ? {} : o;
5833 eventName = eventName.toLowerCase();
5834 var ce = this.events[eventName] || true;
5835 if(typeof ce == "boolean"){
5836 ce = new Roo.util.Event(this, eventName);
5837 this.events[eventName] = ce;
5839 ce.addListener(fn, scope, o);
5843 * Removes a listener
5844 * @param {String} eventName The type of event to listen for
5845 * @param {Function} handler The handler to remove
5846 * @param {Object} scope (optional) The scope (this object) for the handler
5848 removeListener : function(eventName, fn, scope){
5849 var ce = this.events[eventName.toLowerCase()];
5850 if(typeof ce == "object"){
5851 ce.removeListener(fn, scope);
5856 * Removes all listeners for this object
5858 purgeListeners : function(){
5859 for(var evt in this.events){
5860 if(typeof this.events[evt] == "object"){
5861 this.events[evt].clearListeners();
5866 relayEvents : function(o, events){
5867 var createHandler = function(ename){
5869 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5872 for(var i = 0, len = events.length; i < len; i++){
5873 var ename = events[i];
5874 if(!this.events[ename]){ this.events[ename] = true; };
5875 o.on(ename, createHandler(ename), this);
5880 * Used to define events on this Observable
5881 * @param {Object} object The object with the events defined
5883 addEvents : function(o){
5887 Roo.applyIf(this.events, o);
5891 * Checks to see if this object has any listeners for a specified event
5892 * @param {String} eventName The name of the event to check for
5893 * @return {Boolean} True if the event is being listened for, else false
5895 hasListener : function(eventName){
5896 var e = this.events[eventName];
5897 return typeof e == "object" && e.listeners.length > 0;
5901 * Appends an event handler to this element (shorthand for addListener)
5902 * @param {String} eventName The type of event to listen for
5903 * @param {Function} handler The method the event invokes
5904 * @param {Object} scope (optional) The scope in which to execute the handler
5905 * function. The handler function's "this" context.
5906 * @param {Object} options (optional)
5909 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5911 * Removes a listener (shorthand for removeListener)
5912 * @param {String} eventName The type of event to listen for
5913 * @param {Function} handler The handler to remove
5914 * @param {Object} scope (optional) The scope (this object) for the handler
5917 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5920 * Starts capture on the specified Observable. All events will be passed
5921 * to the supplied function with the event name + standard signature of the event
5922 * <b>before</b> the event is fired. If the supplied function returns false,
5923 * the event will not fire.
5924 * @param {Observable} o The Observable to capture
5925 * @param {Function} fn The function to call
5926 * @param {Object} scope (optional) The scope (this object) for the fn
5929 Roo.util.Observable.capture = function(o, fn, scope){
5930 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5934 * Removes <b>all</b> added captures from the Observable.
5935 * @param {Observable} o The Observable to release
5938 Roo.util.Observable.releaseCapture = function(o){
5939 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5944 var createBuffered = function(h, o, scope){
5945 var task = new Roo.util.DelayedTask();
5947 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5951 var createSingle = function(h, e, fn, scope){
5953 e.removeListener(fn, scope);
5954 return h.apply(scope, arguments);
5958 var createDelayed = function(h, o, scope){
5960 var args = Array.prototype.slice.call(arguments, 0);
5961 setTimeout(function(){
5962 h.apply(scope, args);
5967 Roo.util.Event = function(obj, name){
5970 this.listeners = [];
5973 Roo.util.Event.prototype = {
5974 addListener : function(fn, scope, options){
5975 var o = options || {};
5976 scope = scope || this.obj;
5977 if(!this.isListening(fn, scope)){
5978 var l = {fn: fn, scope: scope, options: o};
5981 h = createDelayed(h, o, scope);
5984 h = createSingle(h, this, fn, scope);
5987 h = createBuffered(h, o, scope);
5990 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5991 this.listeners.push(l);
5993 this.listeners = this.listeners.slice(0);
5994 this.listeners.push(l);
5999 findListener : function(fn, scope){
6000 scope = scope || this.obj;
6001 var ls = this.listeners;
6002 for(var i = 0, len = ls.length; i < len; i++){
6004 if(l.fn == fn && l.scope == scope){
6011 isListening : function(fn, scope){
6012 return this.findListener(fn, scope) != -1;
6015 removeListener : function(fn, scope){
6017 if((index = this.findListener(fn, scope)) != -1){
6019 this.listeners.splice(index, 1);
6021 this.listeners = this.listeners.slice(0);
6022 this.listeners.splice(index, 1);
6029 clearListeners : function(){
6030 this.listeners = [];
6034 var ls = this.listeners, scope, len = ls.length;
6037 var args = Array.prototype.slice.call(arguments, 0);
6038 for(var i = 0; i < len; i++){
6040 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6041 this.firing = false;
6045 this.firing = false;
6052 * Ext JS Library 1.1.1
6053 * Copyright(c) 2006-2007, Ext JS, LLC.
6055 * Originally Released Under LGPL - original licence link has changed is not relivant.
6058 * <script type="text/javascript">
6062 * @class Roo.EventManager
6063 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6064 * several useful events directly.
6065 * See {@link Roo.EventObject} for more details on normalized event objects.
6068 Roo.EventManager = function(){
6069 var docReadyEvent, docReadyProcId, docReadyState = false;
6070 var resizeEvent, resizeTask, textEvent, textSize;
6071 var E = Roo.lib.Event;
6072 var D = Roo.lib.Dom;
6077 var fireDocReady = function(){
6079 docReadyState = true;
6082 clearInterval(docReadyProcId);
6084 if(Roo.isGecko || Roo.isOpera) {
6085 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6088 var defer = document.getElementById("ie-deferred-loader");
6090 defer.onreadystatechange = null;
6091 defer.parentNode.removeChild(defer);
6095 docReadyEvent.fire();
6096 docReadyEvent.clearListeners();
6101 var initDocReady = function(){
6102 docReadyEvent = new Roo.util.Event();
6103 if(Roo.isGecko || Roo.isOpera) {
6104 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6106 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6107 var defer = document.getElementById("ie-deferred-loader");
6108 defer.onreadystatechange = function(){
6109 if(this.readyState == "complete"){
6113 }else if(Roo.isSafari){
6114 docReadyProcId = setInterval(function(){
6115 var rs = document.readyState;
6116 if(rs == "complete") {
6121 // no matter what, make sure it fires on load
6122 E.on(window, "load", fireDocReady);
6125 var createBuffered = function(h, o){
6126 var task = new Roo.util.DelayedTask(h);
6128 // create new event object impl so new events don't wipe out properties
6129 e = new Roo.EventObjectImpl(e);
6130 task.delay(o.buffer, h, null, [e]);
6134 var createSingle = function(h, el, ename, fn){
6136 Roo.EventManager.removeListener(el, ename, fn);
6141 var createDelayed = function(h, o){
6143 // create new event object impl so new events don't wipe out properties
6144 e = new Roo.EventObjectImpl(e);
6145 setTimeout(function(){
6150 var transitionEndVal = false;
6152 var transitionEnd = function()
6154 if (transitionEndVal) {
6155 return transitionEndVal;
6157 var el = document.createElement('div');
6159 var transEndEventNames = {
6160 WebkitTransition : 'webkitTransitionEnd',
6161 MozTransition : 'transitionend',
6162 OTransition : 'oTransitionEnd otransitionend',
6163 transition : 'transitionend'
6166 for (var name in transEndEventNames) {
6167 if (el.style[name] !== undefined) {
6168 transitionEndVal = transEndEventNames[name];
6169 return transitionEndVal ;
6175 var listen = function(element, ename, opt, fn, scope){
6176 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6177 fn = fn || o.fn; scope = scope || o.scope;
6178 var el = Roo.getDom(element);
6182 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6185 if (ename == 'transitionend') {
6186 ename = transitionEnd();
6188 var h = function(e){
6189 e = Roo.EventObject.setEvent(e);
6192 t = e.getTarget(o.delegate, el);
6199 if(o.stopEvent === true){
6202 if(o.preventDefault === true){
6205 if(o.stopPropagation === true){
6206 e.stopPropagation();
6209 if(o.normalized === false){
6213 fn.call(scope || el, e, t, o);
6216 h = createDelayed(h, o);
6219 h = createSingle(h, el, ename, fn);
6222 h = createBuffered(h, o);
6224 fn._handlers = fn._handlers || [];
6227 fn._handlers.push([Roo.id(el), ename, h]);
6232 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6233 el.addEventListener("DOMMouseScroll", h, false);
6234 E.on(window, 'unload', function(){
6235 el.removeEventListener("DOMMouseScroll", h, false);
6238 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6239 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6244 var stopListening = function(el, ename, fn){
6245 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6247 for(var i = 0, len = hds.length; i < len; i++){
6249 if(h[0] == id && h[1] == ename){
6256 E.un(el, ename, hd);
6257 el = Roo.getDom(el);
6258 if(ename == "mousewheel" && el.addEventListener){
6259 el.removeEventListener("DOMMouseScroll", hd, false);
6261 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6262 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6266 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6273 * @scope Roo.EventManager
6278 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6279 * object with a Roo.EventObject
6280 * @param {Function} fn The method the event invokes
6281 * @param {Object} scope An object that becomes the scope of the handler
6282 * @param {boolean} override If true, the obj passed in becomes
6283 * the execution scope of the listener
6284 * @return {Function} The wrapped function
6287 wrap : function(fn, scope, override){
6289 Roo.EventObject.setEvent(e);
6290 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6295 * Appends an event handler to an element (shorthand for addListener)
6296 * @param {String/HTMLElement} element The html element or id to assign the
6297 * @param {String} eventName The type of event to listen for
6298 * @param {Function} handler The method the event invokes
6299 * @param {Object} scope (optional) The scope in which to execute the handler
6300 * function. The handler function's "this" context.
6301 * @param {Object} options (optional) An object containing handler configuration
6302 * properties. This may contain any of the following properties:<ul>
6303 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6304 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6305 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6306 * <li>preventDefault {Boolean} True to prevent the default action</li>
6307 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6308 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6309 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6310 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6311 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6312 * by the specified number of milliseconds. If the event fires again within that time, the original
6313 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6316 * <b>Combining Options</b><br>
6317 * Using the options argument, it is possible to combine different types of listeners:<br>
6319 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6321 el.on('click', this.onClick, this, {
6328 * <b>Attaching multiple handlers in 1 call</b><br>
6329 * The method also allows for a single argument to be passed which is a config object containing properties
6330 * which specify multiple handlers.
6340 fn: this.onMouseOver
6349 * Or a shorthand syntax:<br>
6352 'click' : this.onClick,
6353 'mouseover' : this.onMouseOver,
6354 'mouseout' : this.onMouseOut
6358 addListener : function(element, eventName, fn, scope, options){
6359 if(typeof eventName == "object"){
6365 if(typeof o[e] == "function"){
6367 listen(element, e, o, o[e], o.scope);
6369 // individual options
6370 listen(element, e, o[e]);
6375 return listen(element, eventName, options, fn, scope);
6379 * Removes an event handler
6381 * @param {String/HTMLElement} element The id or html element to remove the
6383 * @param {String} eventName The type of event
6384 * @param {Function} fn
6385 * @return {Boolean} True if a listener was actually removed
6387 removeListener : function(element, eventName, fn){
6388 return stopListening(element, eventName, fn);
6392 * Fires when the document is ready (before onload and before images are loaded). Can be
6393 * accessed shorthanded Roo.onReady().
6394 * @param {Function} fn The method the event invokes
6395 * @param {Object} scope An object that becomes the scope of the handler
6396 * @param {boolean} options
6398 onDocumentReady : function(fn, scope, options){
6399 if(docReadyState){ // if it already fired
6400 docReadyEvent.addListener(fn, scope, options);
6401 docReadyEvent.fire();
6402 docReadyEvent.clearListeners();
6408 docReadyEvent.addListener(fn, scope, options);
6412 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6413 * @param {Function} fn The method the event invokes
6414 * @param {Object} scope An object that becomes the scope of the handler
6415 * @param {boolean} options
6417 onWindowResize : function(fn, scope, options){
6419 resizeEvent = new Roo.util.Event();
6420 resizeTask = new Roo.util.DelayedTask(function(){
6421 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6423 E.on(window, "resize", function(){
6425 resizeTask.delay(50);
6427 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6431 resizeEvent.addListener(fn, scope, options);
6435 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6436 * @param {Function} fn The method the event invokes
6437 * @param {Object} scope An object that becomes the scope of the handler
6438 * @param {boolean} options
6440 onTextResize : function(fn, scope, options){
6442 textEvent = new Roo.util.Event();
6443 var textEl = new Roo.Element(document.createElement('div'));
6444 textEl.dom.className = 'x-text-resize';
6445 textEl.dom.innerHTML = 'X';
6446 textEl.appendTo(document.body);
6447 textSize = textEl.dom.offsetHeight;
6448 setInterval(function(){
6449 if(textEl.dom.offsetHeight != textSize){
6450 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6452 }, this.textResizeInterval);
6454 textEvent.addListener(fn, scope, options);
6458 * Removes the passed window resize listener.
6459 * @param {Function} fn The method the event invokes
6460 * @param {Object} scope The scope of handler
6462 removeResizeListener : function(fn, scope){
6464 resizeEvent.removeListener(fn, scope);
6469 fireResize : function(){
6471 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6475 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6479 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6481 textResizeInterval : 50
6486 * @scopeAlias pub=Roo.EventManager
6490 * Appends an event handler to an element (shorthand for addListener)
6491 * @param {String/HTMLElement} element The html element or id to assign the
6492 * @param {String} eventName The type of event to listen for
6493 * @param {Function} handler The method the event invokes
6494 * @param {Object} scope (optional) The scope in which to execute the handler
6495 * function. The handler function's "this" context.
6496 * @param {Object} options (optional) An object containing handler configuration
6497 * properties. This may contain any of the following properties:<ul>
6498 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6499 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6500 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6501 * <li>preventDefault {Boolean} True to prevent the default action</li>
6502 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6503 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6504 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6505 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6506 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6507 * by the specified number of milliseconds. If the event fires again within that time, the original
6508 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6511 * <b>Combining Options</b><br>
6512 * Using the options argument, it is possible to combine different types of listeners:<br>
6514 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6516 el.on('click', this.onClick, this, {
6523 * <b>Attaching multiple handlers in 1 call</b><br>
6524 * The method also allows for a single argument to be passed which is a config object containing properties
6525 * which specify multiple handlers.
6535 fn: this.onMouseOver
6544 * Or a shorthand syntax:<br>
6547 'click' : this.onClick,
6548 'mouseover' : this.onMouseOver,
6549 'mouseout' : this.onMouseOut
6553 pub.on = pub.addListener;
6554 pub.un = pub.removeListener;
6556 pub.stoppedMouseDownEvent = new Roo.util.Event();
6560 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6561 * @param {Function} fn The method the event invokes
6562 * @param {Object} scope An object that becomes the scope of the handler
6563 * @param {boolean} override If true, the obj passed in becomes
6564 * the execution scope of the listener
6568 Roo.onReady = Roo.EventManager.onDocumentReady;
6570 Roo.onReady(function(){
6571 var bd = Roo.get(document.body);
6576 : Roo.isGecko ? "roo-gecko"
6577 : Roo.isOpera ? "roo-opera"
6578 : Roo.isSafari ? "roo-safari" : ""];
6581 cls.push("roo-mac");
6584 cls.push("roo-linux");
6587 cls.push("roo-ios");
6590 cls.push("roo-touch");
6592 if(Roo.isBorderBox){
6593 cls.push('roo-border-box');
6595 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6596 var p = bd.dom.parentNode;
6598 p.className += ' roo-strict';
6601 bd.addClass(cls.join(' '));
6605 * @class Roo.EventObject
6606 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6607 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6610 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6612 var target = e.getTarget();
6615 var myDiv = Roo.get("myDiv");
6616 myDiv.on("click", handleClick);
6618 Roo.EventManager.on("myDiv", 'click', handleClick);
6619 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6623 Roo.EventObject = function(){
6625 var E = Roo.lib.Event;
6627 // safari keypress events for special keys return bad keycodes
6630 63235 : 39, // right
6633 63276 : 33, // page up
6634 63277 : 34, // page down
6635 63272 : 46, // delete
6640 // normalize button clicks
6641 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6642 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6644 Roo.EventObjectImpl = function(e){
6646 this.setEvent(e.browserEvent || e);
6649 Roo.EventObjectImpl.prototype = {
6651 * Used to fix doc tools.
6652 * @scope Roo.EventObject.prototype
6658 /** The normal browser event */
6659 browserEvent : null,
6660 /** The button pressed in a mouse event */
6662 /** True if the shift key was down during the event */
6664 /** True if the control key was down during the event */
6666 /** True if the alt key was down during the event */
6725 setEvent : function(e){
6726 if(e == this || (e && e.browserEvent)){ // already wrapped
6729 this.browserEvent = e;
6731 // normalize buttons
6732 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6733 if(e.type == 'click' && this.button == -1){
6737 this.shiftKey = e.shiftKey;
6738 // mac metaKey behaves like ctrlKey
6739 this.ctrlKey = e.ctrlKey || e.metaKey;
6740 this.altKey = e.altKey;
6741 // in getKey these will be normalized for the mac
6742 this.keyCode = e.keyCode;
6743 // keyup warnings on firefox.
6744 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6745 // cache the target for the delayed and or buffered events
6746 this.target = E.getTarget(e);
6748 this.xy = E.getXY(e);
6751 this.shiftKey = false;
6752 this.ctrlKey = false;
6753 this.altKey = false;
6763 * Stop the event (preventDefault and stopPropagation)
6765 stopEvent : function(){
6766 if(this.browserEvent){
6767 if(this.browserEvent.type == 'mousedown'){
6768 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6770 E.stopEvent(this.browserEvent);
6775 * Prevents the browsers default handling of the event.
6777 preventDefault : function(){
6778 if(this.browserEvent){
6779 E.preventDefault(this.browserEvent);
6784 isNavKeyPress : function(){
6785 var k = this.keyCode;
6786 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6787 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6790 isSpecialKey : function(){
6791 var k = this.keyCode;
6792 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6793 (k == 16) || (k == 17) ||
6794 (k >= 18 && k <= 20) ||
6795 (k >= 33 && k <= 35) ||
6796 (k >= 36 && k <= 39) ||
6797 (k >= 44 && k <= 45);
6800 * Cancels bubbling of the event.
6802 stopPropagation : function(){
6803 if(this.browserEvent){
6804 if(this.type == 'mousedown'){
6805 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6807 E.stopPropagation(this.browserEvent);
6812 * Gets the key code for the event.
6815 getCharCode : function(){
6816 return this.charCode || this.keyCode;
6820 * Returns a normalized keyCode for the event.
6821 * @return {Number} The key code
6823 getKey : function(){
6824 var k = this.keyCode || this.charCode;
6825 return Roo.isSafari ? (safariKeys[k] || k) : k;
6829 * Gets the x coordinate of the event.
6832 getPageX : function(){
6837 * Gets the y coordinate of the event.
6840 getPageY : function(){
6845 * Gets the time of the event.
6848 getTime : function(){
6849 if(this.browserEvent){
6850 return E.getTime(this.browserEvent);
6856 * Gets the page coordinates of the event.
6857 * @return {Array} The xy values like [x, y]
6864 * Gets the target for the event.
6865 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6866 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6867 search as a number or element (defaults to 10 || document.body)
6868 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6869 * @return {HTMLelement}
6871 getTarget : function(selector, maxDepth, returnEl){
6872 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6875 * Gets the related target.
6876 * @return {HTMLElement}
6878 getRelatedTarget : function(){
6879 if(this.browserEvent){
6880 return E.getRelatedTarget(this.browserEvent);
6886 * Normalizes mouse wheel delta across browsers
6887 * @return {Number} The delta
6889 getWheelDelta : function(){
6890 var e = this.browserEvent;
6892 if(e.wheelDelta){ /* IE/Opera. */
6893 delta = e.wheelDelta/120;
6894 }else if(e.detail){ /* Mozilla case. */
6895 delta = -e.detail/3;
6901 * Returns true if the control, meta, shift or alt key was pressed during this event.
6904 hasModifier : function(){
6905 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6909 * Returns true if the target of this event equals el or is a child of el
6910 * @param {String/HTMLElement/Element} el
6911 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6914 within : function(el, related){
6915 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6916 return t && Roo.fly(el).contains(t);
6919 getPoint : function(){
6920 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6924 return new Roo.EventObjectImpl();
6929 * Ext JS Library 1.1.1
6930 * Copyright(c) 2006-2007, Ext JS, LLC.
6932 * Originally Released Under LGPL - original licence link has changed is not relivant.
6935 * <script type="text/javascript">
6939 // was in Composite Element!??!?!
6942 var D = Roo.lib.Dom;
6943 var E = Roo.lib.Event;
6944 var A = Roo.lib.Anim;
6946 // local style camelizing for speed
6948 var camelRe = /(-[a-z])/gi;
6949 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6950 var view = document.defaultView;
6953 * @class Roo.Element
6954 * Represents an Element in the DOM.<br><br>
6957 var el = Roo.get("my-div");
6960 var el = getEl("my-div");
6962 // or with a DOM element
6963 var el = Roo.get(myDivElement);
6965 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6966 * each call instead of constructing a new one.<br><br>
6967 * <b>Animations</b><br />
6968 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6969 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6971 Option Default Description
6972 --------- -------- ---------------------------------------------
6973 duration .35 The duration of the animation in seconds
6974 easing easeOut The YUI easing method
6975 callback none A function to execute when the anim completes
6976 scope this The scope (this) of the callback function
6978 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6979 * manipulate the animation. Here's an example:
6981 var el = Roo.get("my-div");
6986 // default animation
6987 el.setWidth(100, true);
6989 // animation with some options set
6996 // using the "anim" property to get the Anim object
7002 el.setWidth(100, opt);
7004 if(opt.anim.isAnimated()){
7008 * <b> Composite (Collections of) Elements</b><br />
7009 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7010 * @constructor Create a new Element directly.
7011 * @param {String/HTMLElement} element
7012 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
7014 Roo.Element = function(element, forceNew){
7015 var dom = typeof element == "string" ?
7016 document.getElementById(element) : element;
7017 if(!dom){ // invalid id/element
7021 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7022 return Roo.Element.cache[id];
7032 * The DOM element ID
7035 this.id = id || Roo.id(dom);
7038 var El = Roo.Element;
7042 * The element's default display mode (defaults to "")
7045 originalDisplay : "",
7049 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7055 * Sets the element's visibility mode. When setVisible() is called it
7056 * will use this to determine whether to set the visibility or the display property.
7057 * @param visMode Element.VISIBILITY or Element.DISPLAY
7058 * @return {Roo.Element} this
7060 setVisibilityMode : function(visMode){
7061 this.visibilityMode = visMode;
7065 * Convenience method for setVisibilityMode(Element.DISPLAY)
7066 * @param {String} display (optional) What to set display to when visible
7067 * @return {Roo.Element} this
7069 enableDisplayMode : function(display){
7070 this.setVisibilityMode(El.DISPLAY);
7071 if(typeof display != "undefined") { this.originalDisplay = display; }
7076 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7077 * @param {String} selector The simple selector to test
7078 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7079 search as a number or element (defaults to 10 || document.body)
7080 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7081 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7083 findParent : function(simpleSelector, maxDepth, returnEl){
7084 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7085 maxDepth = maxDepth || 50;
7086 if(typeof maxDepth != "number"){
7087 stopEl = Roo.getDom(maxDepth);
7090 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7091 if(dq.is(p, simpleSelector)){
7092 return returnEl ? Roo.get(p) : p;
7102 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7103 * @param {String} selector The simple selector to test
7104 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7105 search as a number or element (defaults to 10 || document.body)
7106 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7107 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7109 findParentNode : function(simpleSelector, maxDepth, returnEl){
7110 var p = Roo.fly(this.dom.parentNode, '_internal');
7111 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7115 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7116 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7117 * @param {String} selector The simple selector to test
7118 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7119 search as a number or element (defaults to 10 || document.body)
7120 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7122 up : function(simpleSelector, maxDepth){
7123 return this.findParentNode(simpleSelector, maxDepth, true);
7129 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7130 * @param {String} selector The simple selector to test
7131 * @return {Boolean} True if this element matches the selector, else false
7133 is : function(simpleSelector){
7134 return Roo.DomQuery.is(this.dom, simpleSelector);
7138 * Perform animation on this element.
7139 * @param {Object} args The YUI animation control args
7140 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7141 * @param {Function} onComplete (optional) Function to call when animation completes
7142 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7143 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7144 * @return {Roo.Element} this
7146 animate : function(args, duration, onComplete, easing, animType){
7147 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7152 * @private Internal animation call
7154 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7155 animType = animType || 'run';
7157 var anim = Roo.lib.Anim[animType](
7159 (opt.duration || defaultDur) || .35,
7160 (opt.easing || defaultEase) || 'easeOut',
7162 Roo.callback(cb, this);
7163 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7171 // private legacy anim prep
7172 preanim : function(a, i){
7173 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7177 * Removes worthless text nodes
7178 * @param {Boolean} forceReclean (optional) By default the element
7179 * keeps track if it has been cleaned already so
7180 * you can call this over and over. However, if you update the element and
7181 * need to force a reclean, you can pass true.
7183 clean : function(forceReclean){
7184 if(this.isCleaned && forceReclean !== true){
7188 var d = this.dom, n = d.firstChild, ni = -1;
7190 var nx = n.nextSibling;
7191 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7198 this.isCleaned = true;
7203 calcOffsetsTo : function(el){
7206 var restorePos = false;
7207 if(el.getStyle('position') == 'static'){
7208 el.position('relative');
7213 while(op && op != d && op.tagName != 'HTML'){
7216 op = op.offsetParent;
7219 el.position('static');
7225 * Scrolls this element into view within the passed container.
7226 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7227 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7228 * @return {Roo.Element} this
7230 scrollIntoView : function(container, hscroll){
7231 var c = Roo.getDom(container) || document.body;
7234 var o = this.calcOffsetsTo(c),
7237 b = t+el.offsetHeight,
7238 r = l+el.offsetWidth;
7240 var ch = c.clientHeight;
7241 var ct = parseInt(c.scrollTop, 10);
7242 var cl = parseInt(c.scrollLeft, 10);
7244 var cr = cl + c.clientWidth;
7252 if(hscroll !== false){
7256 c.scrollLeft = r-c.clientWidth;
7263 scrollChildIntoView : function(child, hscroll){
7264 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7268 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7269 * the new height may not be available immediately.
7270 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7271 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7272 * @param {Function} onComplete (optional) Function to call when animation completes
7273 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7274 * @return {Roo.Element} this
7276 autoHeight : function(animate, duration, onComplete, easing){
7277 var oldHeight = this.getHeight();
7279 this.setHeight(1); // force clipping
7280 setTimeout(function(){
7281 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7283 this.setHeight(height);
7285 if(typeof onComplete == "function"){
7289 this.setHeight(oldHeight); // restore original height
7290 this.setHeight(height, animate, duration, function(){
7292 if(typeof onComplete == "function") { onComplete(); }
7293 }.createDelegate(this), easing);
7295 }.createDelegate(this), 0);
7300 * Returns true if this element is an ancestor of the passed element
7301 * @param {HTMLElement/String} el The element to check
7302 * @return {Boolean} True if this element is an ancestor of el, else false
7304 contains : function(el){
7305 if(!el){return false;}
7306 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7310 * Checks whether the element is currently visible using both visibility and display properties.
7311 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7312 * @return {Boolean} True if the element is currently visible, else false
7314 isVisible : function(deep) {
7315 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7316 if(deep !== true || !vis){
7319 var p = this.dom.parentNode;
7320 while(p && p.tagName.toLowerCase() != "body"){
7321 if(!Roo.fly(p, '_isVisible').isVisible()){
7330 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7331 * @param {String} selector The CSS selector
7332 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7333 * @return {CompositeElement/CompositeElementLite} The composite element
7335 select : function(selector, unique){
7336 return El.select(selector, unique, this.dom);
7340 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7341 * @param {String} selector The CSS selector
7342 * @return {Array} An array of the matched nodes
7344 query : function(selector, unique){
7345 return Roo.DomQuery.select(selector, this.dom);
7349 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7350 * @param {String} selector The CSS selector
7351 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7352 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7354 child : function(selector, returnDom){
7355 var n = Roo.DomQuery.selectNode(selector, this.dom);
7356 return returnDom ? n : Roo.get(n);
7360 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7361 * @param {String} selector The CSS selector
7362 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7363 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7365 down : function(selector, returnDom){
7366 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7367 return returnDom ? n : Roo.get(n);
7371 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7372 * @param {String} group The group the DD object is member of
7373 * @param {Object} config The DD config object
7374 * @param {Object} overrides An object containing methods to override/implement on the DD object
7375 * @return {Roo.dd.DD} The DD object
7377 initDD : function(group, config, overrides){
7378 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7379 return Roo.apply(dd, overrides);
7383 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7384 * @param {String} group The group the DDProxy object is member of
7385 * @param {Object} config The DDProxy config object
7386 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7387 * @return {Roo.dd.DDProxy} The DDProxy object
7389 initDDProxy : function(group, config, overrides){
7390 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7391 return Roo.apply(dd, overrides);
7395 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7396 * @param {String} group The group the DDTarget object is member of
7397 * @param {Object} config The DDTarget config object
7398 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7399 * @return {Roo.dd.DDTarget} The DDTarget object
7401 initDDTarget : function(group, config, overrides){
7402 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7403 return Roo.apply(dd, overrides);
7407 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7408 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7409 * @param {Boolean} visible Whether the element is visible
7410 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7411 * @return {Roo.Element} this
7413 setVisible : function(visible, animate){
7415 if(this.visibilityMode == El.DISPLAY){
7416 this.setDisplayed(visible);
7419 this.dom.style.visibility = visible ? "visible" : "hidden";
7422 // closure for composites
7424 var visMode = this.visibilityMode;
7426 this.setOpacity(.01);
7427 this.setVisible(true);
7429 this.anim({opacity: { to: (visible?1:0) }},
7430 this.preanim(arguments, 1),
7431 null, .35, 'easeIn', function(){
7433 if(visMode == El.DISPLAY){
7434 dom.style.display = "none";
7436 dom.style.visibility = "hidden";
7438 Roo.get(dom).setOpacity(1);
7446 * Returns true if display is not "none"
7449 isDisplayed : function() {
7450 return this.getStyle("display") != "none";
7454 * Toggles the element's visibility or display, depending on visibility mode.
7455 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7456 * @return {Roo.Element} this
7458 toggle : function(animate){
7459 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7464 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7465 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7466 * @return {Roo.Element} this
7468 setDisplayed : function(value) {
7469 if(typeof value == "boolean"){
7470 value = value ? this.originalDisplay : "none";
7472 this.setStyle("display", value);
7477 * Tries to focus the element. Any exceptions are caught and ignored.
7478 * @return {Roo.Element} this
7480 focus : function() {
7488 * Tries to blur the element. Any exceptions are caught and ignored.
7489 * @return {Roo.Element} this
7499 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7500 * @param {String/Array} className The CSS class to add, or an array of classes
7501 * @return {Roo.Element} this
7503 addClass : function(className){
7504 if(className instanceof Array){
7505 for(var i = 0, len = className.length; i < len; i++) {
7506 this.addClass(className[i]);
7509 if(className && !this.hasClass(className)){
7510 this.dom.className = this.dom.className + " " + className;
7517 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7518 * @param {String/Array} className The CSS class to add, or an array of classes
7519 * @return {Roo.Element} this
7521 radioClass : function(className){
7522 var siblings = this.dom.parentNode.childNodes;
7523 for(var i = 0; i < siblings.length; i++) {
7524 var s = siblings[i];
7525 if(s.nodeType == 1){
7526 Roo.get(s).removeClass(className);
7529 this.addClass(className);
7534 * Removes one or more CSS classes from the element.
7535 * @param {String/Array} className The CSS class to remove, or an array of classes
7536 * @return {Roo.Element} this
7538 removeClass : function(className){
7539 if(!className || !this.dom.className){
7542 if(className instanceof Array){
7543 for(var i = 0, len = className.length; i < len; i++) {
7544 this.removeClass(className[i]);
7547 if(this.hasClass(className)){
7548 var re = this.classReCache[className];
7550 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7551 this.classReCache[className] = re;
7553 this.dom.className =
7554 this.dom.className.replace(re, " ");
7564 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7565 * @param {String} className The CSS class to toggle
7566 * @return {Roo.Element} this
7568 toggleClass : function(className){
7569 if(this.hasClass(className)){
7570 this.removeClass(className);
7572 this.addClass(className);
7578 * Checks if the specified CSS class exists on this element's DOM node.
7579 * @param {String} className The CSS class to check for
7580 * @return {Boolean} True if the class exists, else false
7582 hasClass : function(className){
7583 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7587 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7588 * @param {String} oldClassName The CSS class to replace
7589 * @param {String} newClassName The replacement CSS class
7590 * @return {Roo.Element} this
7592 replaceClass : function(oldClassName, newClassName){
7593 this.removeClass(oldClassName);
7594 this.addClass(newClassName);
7599 * Returns an object with properties matching the styles requested.
7600 * For example, el.getStyles('color', 'font-size', 'width') might return
7601 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7602 * @param {String} style1 A style name
7603 * @param {String} style2 A style name
7604 * @param {String} etc.
7605 * @return {Object} The style object
7607 getStyles : function(){
7608 var a = arguments, len = a.length, r = {};
7609 for(var i = 0; i < len; i++){
7610 r[a[i]] = this.getStyle(a[i]);
7616 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7617 * @param {String} property The style property whose value is returned.
7618 * @return {String} The current value of the style property for this element.
7620 getStyle : function(){
7621 return view && view.getComputedStyle ?
7623 var el = this.dom, v, cs, camel;
7624 if(prop == 'float'){
7627 if(el.style && (v = el.style[prop])){
7630 if(cs = view.getComputedStyle(el, "")){
7631 if(!(camel = propCache[prop])){
7632 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7639 var el = this.dom, v, cs, camel;
7640 if(prop == 'opacity'){
7641 if(typeof el.style.filter == 'string'){
7642 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7644 var fv = parseFloat(m[1]);
7646 return fv ? fv / 100 : 0;
7651 }else if(prop == 'float'){
7652 prop = "styleFloat";
7654 if(!(camel = propCache[prop])){
7655 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7657 if(v = el.style[camel]){
7660 if(cs = el.currentStyle){
7668 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7669 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7670 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7671 * @return {Roo.Element} this
7673 setStyle : function(prop, value){
7674 if(typeof prop == "string"){
7676 if (prop == 'float') {
7677 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7682 if(!(camel = propCache[prop])){
7683 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7686 if(camel == 'opacity') {
7687 this.setOpacity(value);
7689 this.dom.style[camel] = value;
7692 for(var style in prop){
7693 if(typeof prop[style] != "function"){
7694 this.setStyle(style, prop[style]);
7702 * More flexible version of {@link #setStyle} for setting style properties.
7703 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7704 * a function which returns such a specification.
7705 * @return {Roo.Element} this
7707 applyStyles : function(style){
7708 Roo.DomHelper.applyStyles(this.dom, style);
7713 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7714 * @return {Number} The X position of the element
7717 return D.getX(this.dom);
7721 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7722 * @return {Number} The Y position of the element
7725 return D.getY(this.dom);
7729 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7730 * @return {Array} The XY position of the element
7733 return D.getXY(this.dom);
7737 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7738 * @param {Number} The X position of the element
7739 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7740 * @return {Roo.Element} this
7742 setX : function(x, animate){
7744 D.setX(this.dom, x);
7746 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7752 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7753 * @param {Number} The Y position of the element
7754 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7755 * @return {Roo.Element} this
7757 setY : function(y, animate){
7759 D.setY(this.dom, y);
7761 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7767 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7768 * @param {String} left The left CSS property value
7769 * @return {Roo.Element} this
7771 setLeft : function(left){
7772 this.setStyle("left", this.addUnits(left));
7777 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7778 * @param {String} top The top CSS property value
7779 * @return {Roo.Element} this
7781 setTop : function(top){
7782 this.setStyle("top", this.addUnits(top));
7787 * Sets the element's CSS right style.
7788 * @param {String} right The right CSS property value
7789 * @return {Roo.Element} this
7791 setRight : function(right){
7792 this.setStyle("right", this.addUnits(right));
7797 * Sets the element's CSS bottom style.
7798 * @param {String} bottom The bottom CSS property value
7799 * @return {Roo.Element} this
7801 setBottom : function(bottom){
7802 this.setStyle("bottom", this.addUnits(bottom));
7807 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7808 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7809 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7810 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7811 * @return {Roo.Element} this
7813 setXY : function(pos, animate){
7815 D.setXY(this.dom, pos);
7817 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7823 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7824 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7825 * @param {Number} x X value for new position (coordinates are page-based)
7826 * @param {Number} y Y value for new position (coordinates are page-based)
7827 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7828 * @return {Roo.Element} this
7830 setLocation : function(x, y, animate){
7831 this.setXY([x, y], this.preanim(arguments, 2));
7836 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7837 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7838 * @param {Number} x X value for new position (coordinates are page-based)
7839 * @param {Number} y Y value for new position (coordinates are page-based)
7840 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7841 * @return {Roo.Element} this
7843 moveTo : function(x, y, animate){
7844 this.setXY([x, y], this.preanim(arguments, 2));
7849 * Returns the region of the given element.
7850 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7851 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7853 getRegion : function(){
7854 return D.getRegion(this.dom);
7858 * Returns the offset height of the element
7859 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7860 * @return {Number} The element's height
7862 getHeight : function(contentHeight){
7863 var h = this.dom.offsetHeight || 0;
7864 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7868 * Returns the offset width of the element
7869 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7870 * @return {Number} The element's width
7872 getWidth : function(contentWidth){
7873 var w = this.dom.offsetWidth || 0;
7874 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7878 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7879 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7880 * if a height has not been set using CSS.
7883 getComputedHeight : function(){
7884 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7886 h = parseInt(this.getStyle('height'), 10) || 0;
7887 if(!this.isBorderBox()){
7888 h += this.getFrameWidth('tb');
7895 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7896 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7897 * if a width has not been set using CSS.
7900 getComputedWidth : function(){
7901 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7903 w = parseInt(this.getStyle('width'), 10) || 0;
7904 if(!this.isBorderBox()){
7905 w += this.getFrameWidth('lr');
7912 * Returns the size of the element.
7913 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7914 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7916 getSize : function(contentSize){
7917 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7921 * Returns the width and height of the viewport.
7922 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7924 getViewSize : function(){
7925 var d = this.dom, doc = document, aw = 0, ah = 0;
7926 if(d == doc || d == doc.body){
7927 return {width : D.getViewWidth(), height: D.getViewHeight()};
7930 width : d.clientWidth,
7931 height: d.clientHeight
7937 * Returns the value of the "value" attribute
7938 * @param {Boolean} asNumber true to parse the value as a number
7939 * @return {String/Number}
7941 getValue : function(asNumber){
7942 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7946 adjustWidth : function(width){
7947 if(typeof width == "number"){
7948 if(this.autoBoxAdjust && !this.isBorderBox()){
7949 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7959 adjustHeight : function(height){
7960 if(typeof height == "number"){
7961 if(this.autoBoxAdjust && !this.isBorderBox()){
7962 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7972 * Set the width of the element
7973 * @param {Number} width The new width
7974 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7975 * @return {Roo.Element} this
7977 setWidth : function(width, animate){
7978 width = this.adjustWidth(width);
7980 this.dom.style.width = this.addUnits(width);
7982 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7988 * Set the height of the element
7989 * @param {Number} height The new height
7990 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7991 * @return {Roo.Element} this
7993 setHeight : function(height, animate){
7994 height = this.adjustHeight(height);
7996 this.dom.style.height = this.addUnits(height);
7998 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8004 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8005 * @param {Number} width The new width
8006 * @param {Number} height The new height
8007 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8008 * @return {Roo.Element} this
8010 setSize : function(width, height, animate){
8011 if(typeof width == "object"){ // in case of object from getSize()
8012 height = width.height; width = width.width;
8014 width = this.adjustWidth(width); height = this.adjustHeight(height);
8016 this.dom.style.width = this.addUnits(width);
8017 this.dom.style.height = this.addUnits(height);
8019 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8025 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8026 * @param {Number} x X value for new position (coordinates are page-based)
8027 * @param {Number} y Y value for new position (coordinates are page-based)
8028 * @param {Number} width The new width
8029 * @param {Number} height The new height
8030 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8031 * @return {Roo.Element} this
8033 setBounds : function(x, y, width, height, animate){
8035 this.setSize(width, height);
8036 this.setLocation(x, y);
8038 width = this.adjustWidth(width); height = this.adjustHeight(height);
8039 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8040 this.preanim(arguments, 4), 'motion');
8046 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
8047 * @param {Roo.lib.Region} region The region to fill
8048 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8049 * @return {Roo.Element} this
8051 setRegion : function(region, animate){
8052 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8057 * Appends an event handler
8059 * @param {String} eventName The type of event to append
8060 * @param {Function} fn The method the event invokes
8061 * @param {Object} scope (optional) The scope (this object) of the fn
8062 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8064 addListener : function(eventName, fn, scope, options){
8066 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8071 * Removes an event handler from this element
8072 * @param {String} eventName the type of event to remove
8073 * @param {Function} fn the method the event invokes
8074 * @return {Roo.Element} this
8076 removeListener : function(eventName, fn){
8077 Roo.EventManager.removeListener(this.dom, eventName, fn);
8082 * Removes all previous added listeners from this element
8083 * @return {Roo.Element} this
8085 removeAllListeners : function(){
8086 E.purgeElement(this.dom);
8090 relayEvent : function(eventName, observable){
8091 this.on(eventName, function(e){
8092 observable.fireEvent(eventName, e);
8097 * Set the opacity of the element
8098 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8099 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8100 * @return {Roo.Element} this
8102 setOpacity : function(opacity, animate){
8104 var s = this.dom.style;
8107 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8108 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8110 s.opacity = opacity;
8113 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8119 * Gets the left X coordinate
8120 * @param {Boolean} local True to get the local css position instead of page coordinate
8123 getLeft : function(local){
8127 return parseInt(this.getStyle("left"), 10) || 0;
8132 * Gets the right X coordinate of the element (element X position + element width)
8133 * @param {Boolean} local True to get the local css position instead of page coordinate
8136 getRight : function(local){
8138 return this.getX() + this.getWidth();
8140 return (this.getLeft(true) + this.getWidth()) || 0;
8145 * Gets the top Y coordinate
8146 * @param {Boolean} local True to get the local css position instead of page coordinate
8149 getTop : function(local) {
8153 return parseInt(this.getStyle("top"), 10) || 0;
8158 * Gets the bottom Y coordinate of the element (element Y position + element height)
8159 * @param {Boolean} local True to get the local css position instead of page coordinate
8162 getBottom : function(local){
8164 return this.getY() + this.getHeight();
8166 return (this.getTop(true) + this.getHeight()) || 0;
8171 * Initializes positioning on this element. If a desired position is not passed, it will make the
8172 * the element positioned relative IF it is not already positioned.
8173 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8174 * @param {Number} zIndex (optional) The zIndex to apply
8175 * @param {Number} x (optional) Set the page X position
8176 * @param {Number} y (optional) Set the page Y position
8178 position : function(pos, zIndex, x, y){
8180 if(this.getStyle('position') == 'static'){
8181 this.setStyle('position', 'relative');
8184 this.setStyle("position", pos);
8187 this.setStyle("z-index", zIndex);
8189 if(x !== undefined && y !== undefined){
8191 }else if(x !== undefined){
8193 }else if(y !== undefined){
8199 * Clear positioning back to the default when the document was loaded
8200 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8201 * @return {Roo.Element} this
8203 clearPositioning : function(value){
8211 "position" : "static"
8217 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8218 * snapshot before performing an update and then restoring the element.
8221 getPositioning : function(){
8222 var l = this.getStyle("left");
8223 var t = this.getStyle("top");
8225 "position" : this.getStyle("position"),
8227 "right" : l ? "" : this.getStyle("right"),
8229 "bottom" : t ? "" : this.getStyle("bottom"),
8230 "z-index" : this.getStyle("z-index")
8235 * Gets the width of the border(s) for the specified side(s)
8236 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8237 * passing lr would get the border (l)eft width + the border (r)ight width.
8238 * @return {Number} The width of the sides passed added together
8240 getBorderWidth : function(side){
8241 return this.addStyles(side, El.borders);
8245 * Gets the width of the padding(s) for the specified side(s)
8246 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8247 * passing lr would get the padding (l)eft + the padding (r)ight.
8248 * @return {Number} The padding of the sides passed added together
8250 getPadding : function(side){
8251 return this.addStyles(side, El.paddings);
8255 * Set positioning with an object returned by getPositioning().
8256 * @param {Object} posCfg
8257 * @return {Roo.Element} this
8259 setPositioning : function(pc){
8260 this.applyStyles(pc);
8261 if(pc.right == "auto"){
8262 this.dom.style.right = "";
8264 if(pc.bottom == "auto"){
8265 this.dom.style.bottom = "";
8271 fixDisplay : function(){
8272 if(this.getStyle("display") == "none"){
8273 this.setStyle("visibility", "hidden");
8274 this.setStyle("display", this.originalDisplay); // first try reverting to default
8275 if(this.getStyle("display") == "none"){ // if that fails, default to block
8276 this.setStyle("display", "block");
8282 * Quick set left and top adding default units
8283 * @param {String} left The left CSS property value
8284 * @param {String} top The top CSS property value
8285 * @return {Roo.Element} this
8287 setLeftTop : function(left, top){
8288 this.dom.style.left = this.addUnits(left);
8289 this.dom.style.top = this.addUnits(top);
8294 * Move this element relative to its current position.
8295 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8296 * @param {Number} distance How far to move the element in pixels
8297 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8298 * @return {Roo.Element} this
8300 move : function(direction, distance, animate){
8301 var xy = this.getXY();
8302 direction = direction.toLowerCase();
8306 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8310 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8315 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8320 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8327 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8328 * @return {Roo.Element} this
8331 if(!this.isClipped){
8332 this.isClipped = true;
8333 this.originalClip = {
8334 "o": this.getStyle("overflow"),
8335 "x": this.getStyle("overflow-x"),
8336 "y": this.getStyle("overflow-y")
8338 this.setStyle("overflow", "hidden");
8339 this.setStyle("overflow-x", "hidden");
8340 this.setStyle("overflow-y", "hidden");
8346 * Return clipping (overflow) to original clipping before clip() was called
8347 * @return {Roo.Element} this
8349 unclip : function(){
8351 this.isClipped = false;
8352 var o = this.originalClip;
8353 if(o.o){this.setStyle("overflow", o.o);}
8354 if(o.x){this.setStyle("overflow-x", o.x);}
8355 if(o.y){this.setStyle("overflow-y", o.y);}
8362 * Gets the x,y coordinates specified by the anchor position on the element.
8363 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8364 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8365 * {width: (target width), height: (target height)} (defaults to the element's current size)
8366 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8367 * @return {Array} [x, y] An array containing the element's x and y coordinates
8369 getAnchorXY : function(anchor, local, s){
8370 //Passing a different size is useful for pre-calculating anchors,
8371 //especially for anchored animations that change the el size.
8373 var w, h, vp = false;
8376 if(d == document.body || d == document){
8378 w = D.getViewWidth(); h = D.getViewHeight();
8380 w = this.getWidth(); h = this.getHeight();
8383 w = s.width; h = s.height;
8385 var x = 0, y = 0, r = Math.round;
8386 switch((anchor || "tl").toLowerCase()){
8428 var sc = this.getScroll();
8429 return [x + sc.left, y + sc.top];
8431 //Add the element's offset xy
8432 var o = this.getXY();
8433 return [x+o[0], y+o[1]];
8437 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8438 * supported position values.
8439 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8440 * @param {String} position The position to align to.
8441 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8442 * @return {Array} [x, y]
8444 getAlignToXY : function(el, p, o){
8448 throw "Element.alignTo with an element that doesn't exist";
8450 var c = false; //constrain to viewport
8451 var p1 = "", p2 = "";
8458 }else if(p.indexOf("-") == -1){
8461 p = p.toLowerCase();
8462 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8464 throw "Element.alignTo with an invalid alignment " + p;
8466 p1 = m[1]; p2 = m[2]; c = !!m[3];
8468 //Subtract the aligned el's internal xy from the target's offset xy
8469 //plus custom offset to get the aligned el's new offset xy
8470 var a1 = this.getAnchorXY(p1, true);
8471 var a2 = el.getAnchorXY(p2, false);
8472 var x = a2[0] - a1[0] + o[0];
8473 var y = a2[1] - a1[1] + o[1];
8475 //constrain the aligned el to viewport if necessary
8476 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8477 // 5px of margin for ie
8478 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8480 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8481 //perpendicular to the vp border, allow the aligned el to slide on that border,
8482 //otherwise swap the aligned el to the opposite border of the target.
8483 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8484 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8485 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8486 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8489 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8490 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8492 if((x+w) > dw + scrollX){
8493 x = swapX ? r.left-w : dw+scrollX-w;
8496 x = swapX ? r.right : scrollX;
8498 if((y+h) > dh + scrollY){
8499 y = swapY ? r.top-h : dh+scrollY-h;
8502 y = swapY ? r.bottom : scrollY;
8509 getConstrainToXY : function(){
8510 var os = {top:0, left:0, bottom:0, right: 0};
8512 return function(el, local, offsets, proposedXY){
8514 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8516 var vw, vh, vx = 0, vy = 0;
8517 if(el.dom == document.body || el.dom == document){
8518 vw = Roo.lib.Dom.getViewWidth();
8519 vh = Roo.lib.Dom.getViewHeight();
8521 vw = el.dom.clientWidth;
8522 vh = el.dom.clientHeight;
8524 var vxy = el.getXY();
8530 var s = el.getScroll();
8532 vx += offsets.left + s.left;
8533 vy += offsets.top + s.top;
8535 vw -= offsets.right;
8536 vh -= offsets.bottom;
8541 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8542 var x = xy[0], y = xy[1];
8543 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8545 // only move it if it needs it
8548 // first validate right/bottom
8557 // then make sure top/left isn't negative
8566 return moved ? [x, y] : false;
8571 adjustForConstraints : function(xy, parent, offsets){
8572 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8576 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8577 * document it aligns it to the viewport.
8578 * The position parameter is optional, and can be specified in any one of the following formats:
8580 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8581 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8582 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8583 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8584 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8585 * element's anchor point, and the second value is used as the target's anchor point.</li>
8587 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8588 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8589 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8590 * that specified in order to enforce the viewport constraints.
8591 * Following are all of the supported anchor positions:
8594 ----- -----------------------------
8595 tl The top left corner (default)
8596 t The center of the top edge
8597 tr The top right corner
8598 l The center of the left edge
8599 c In the center of the element
8600 r The center of the right edge
8601 bl The bottom left corner
8602 b The center of the bottom edge
8603 br The bottom right corner
8607 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8608 el.alignTo("other-el");
8610 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8611 el.alignTo("other-el", "tr?");
8613 // align the bottom right corner of el with the center left edge of other-el
8614 el.alignTo("other-el", "br-l?");
8616 // align the center of el with the bottom left corner of other-el and
8617 // adjust the x position by -6 pixels (and the y position by 0)
8618 el.alignTo("other-el", "c-bl", [-6, 0]);
8620 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8621 * @param {String} position The position to align to.
8622 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8623 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8624 * @return {Roo.Element} this
8626 alignTo : function(element, position, offsets, animate){
8627 var xy = this.getAlignToXY(element, position, offsets);
8628 this.setXY(xy, this.preanim(arguments, 3));
8633 * Anchors an element to another element and realigns it when the window is resized.
8634 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8635 * @param {String} position The position to align to.
8636 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8637 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8638 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8639 * is a number, it is used as the buffer delay (defaults to 50ms).
8640 * @param {Function} callback The function to call after the animation finishes
8641 * @return {Roo.Element} this
8643 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8644 var action = function(){
8645 this.alignTo(el, alignment, offsets, animate);
8646 Roo.callback(callback, this);
8648 Roo.EventManager.onWindowResize(action, this);
8649 var tm = typeof monitorScroll;
8650 if(tm != 'undefined'){
8651 Roo.EventManager.on(window, 'scroll', action, this,
8652 {buffer: tm == 'number' ? monitorScroll : 50});
8654 action.call(this); // align immediately
8658 * Clears any opacity settings from this element. Required in some cases for IE.
8659 * @return {Roo.Element} this
8661 clearOpacity : function(){
8662 if (window.ActiveXObject) {
8663 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8664 this.dom.style.filter = "";
8667 this.dom.style.opacity = "";
8668 this.dom.style["-moz-opacity"] = "";
8669 this.dom.style["-khtml-opacity"] = "";
8675 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8676 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8677 * @return {Roo.Element} this
8679 hide : function(animate){
8680 this.setVisible(false, this.preanim(arguments, 0));
8685 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8686 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8687 * @return {Roo.Element} this
8689 show : function(animate){
8690 this.setVisible(true, this.preanim(arguments, 0));
8695 * @private Test if size has a unit, otherwise appends the default
8697 addUnits : function(size){
8698 return Roo.Element.addUnits(size, this.defaultUnit);
8702 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8703 * @return {Roo.Element} this
8705 beginMeasure : function(){
8707 if(el.offsetWidth || el.offsetHeight){
8708 return this; // offsets work already
8711 var p = this.dom, b = document.body; // start with this element
8712 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8713 var pe = Roo.get(p);
8714 if(pe.getStyle('display') == 'none'){
8715 changed.push({el: p, visibility: pe.getStyle("visibility")});
8716 p.style.visibility = "hidden";
8717 p.style.display = "block";
8721 this._measureChanged = changed;
8727 * Restores displays to before beginMeasure was called
8728 * @return {Roo.Element} this
8730 endMeasure : function(){
8731 var changed = this._measureChanged;
8733 for(var i = 0, len = changed.length; i < len; i++) {
8735 r.el.style.visibility = r.visibility;
8736 r.el.style.display = "none";
8738 this._measureChanged = null;
8744 * Update the innerHTML of this element, optionally searching for and processing scripts
8745 * @param {String} html The new HTML
8746 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8747 * @param {Function} callback For async script loading you can be noticed when the update completes
8748 * @return {Roo.Element} this
8750 update : function(html, loadScripts, callback){
8751 if(typeof html == "undefined"){
8754 if(loadScripts !== true){
8755 this.dom.innerHTML = html;
8756 if(typeof callback == "function"){
8764 html += '<span id="' + id + '"></span>';
8766 E.onAvailable(id, function(){
8767 var hd = document.getElementsByTagName("head")[0];
8768 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8769 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8770 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8773 while(match = re.exec(html)){
8774 var attrs = match[1];
8775 var srcMatch = attrs ? attrs.match(srcRe) : false;
8776 if(srcMatch && srcMatch[2]){
8777 var s = document.createElement("script");
8778 s.src = srcMatch[2];
8779 var typeMatch = attrs.match(typeRe);
8780 if(typeMatch && typeMatch[2]){
8781 s.type = typeMatch[2];
8784 }else if(match[2] && match[2].length > 0){
8785 if(window.execScript) {
8786 window.execScript(match[2]);
8794 window.eval(match[2]);
8798 var el = document.getElementById(id);
8799 if(el){el.parentNode.removeChild(el);}
8800 if(typeof callback == "function"){
8804 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8809 * Direct access to the UpdateManager update() method (takes the same parameters).
8810 * @param {String/Function} url The url for this request or a function to call to get the url
8811 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8812 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8813 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8814 * @return {Roo.Element} this
8817 var um = this.getUpdateManager();
8818 um.update.apply(um, arguments);
8823 * Gets this element's UpdateManager
8824 * @return {Roo.UpdateManager} The UpdateManager
8826 getUpdateManager : function(){
8827 if(!this.updateManager){
8828 this.updateManager = new Roo.UpdateManager(this);
8830 return this.updateManager;
8834 * Disables text selection for this element (normalized across browsers)
8835 * @return {Roo.Element} this
8837 unselectable : function(){
8838 this.dom.unselectable = "on";
8839 this.swallowEvent("selectstart", true);
8840 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8841 this.addClass("x-unselectable");
8846 * Calculates the x, y to center this element on the screen
8847 * @return {Array} The x, y values [x, y]
8849 getCenterXY : function(){
8850 return this.getAlignToXY(document, 'c-c');
8854 * Centers the Element in either the viewport, or another Element.
8855 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8857 center : function(centerIn){
8858 this.alignTo(centerIn || document, 'c-c');
8863 * Tests various css rules/browsers to determine if this element uses a border box
8866 isBorderBox : function(){
8867 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8871 * Return a box {x, y, width, height} that can be used to set another elements
8872 * size/location to match this element.
8873 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8874 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8875 * @return {Object} box An object in the format {x, y, width, height}
8877 getBox : function(contentBox, local){
8882 var left = parseInt(this.getStyle("left"), 10) || 0;
8883 var top = parseInt(this.getStyle("top"), 10) || 0;
8886 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8888 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8890 var l = this.getBorderWidth("l")+this.getPadding("l");
8891 var r = this.getBorderWidth("r")+this.getPadding("r");
8892 var t = this.getBorderWidth("t")+this.getPadding("t");
8893 var b = this.getBorderWidth("b")+this.getPadding("b");
8894 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8896 bx.right = bx.x + bx.width;
8897 bx.bottom = bx.y + bx.height;
8902 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8903 for more information about the sides.
8904 * @param {String} sides
8907 getFrameWidth : function(sides, onlyContentBox){
8908 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8912 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8913 * @param {Object} box The box to fill {x, y, width, height}
8914 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8915 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8916 * @return {Roo.Element} this
8918 setBox : function(box, adjust, animate){
8919 var w = box.width, h = box.height;
8920 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8921 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8922 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8924 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8929 * Forces the browser to repaint this element
8930 * @return {Roo.Element} this
8932 repaint : function(){
8934 this.addClass("x-repaint");
8935 setTimeout(function(){
8936 Roo.get(dom).removeClass("x-repaint");
8942 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8943 * then it returns the calculated width of the sides (see getPadding)
8944 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8945 * @return {Object/Number}
8947 getMargins : function(side){
8950 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8951 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8952 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8953 right: parseInt(this.getStyle("margin-right"), 10) || 0
8956 return this.addStyles(side, El.margins);
8961 addStyles : function(sides, styles){
8963 for(var i = 0, len = sides.length; i < len; i++){
8964 v = this.getStyle(styles[sides.charAt(i)]);
8966 w = parseInt(v, 10);
8974 * Creates a proxy element of this element
8975 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8976 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8977 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8978 * @return {Roo.Element} The new proxy element
8980 createProxy : function(config, renderTo, matchBox){
8982 renderTo = Roo.getDom(renderTo);
8984 renderTo = document.body;
8986 config = typeof config == "object" ?
8987 config : {tag : "div", cls: config};
8988 var proxy = Roo.DomHelper.append(renderTo, config, true);
8990 proxy.setBox(this.getBox());
8996 * Puts a mask over this element to disable user interaction. Requires core.css.
8997 * This method can only be applied to elements which accept child nodes.
8998 * @param {String} msg (optional) A message to display in the mask
8999 * @param {String} msgCls (optional) A css class to apply to the msg element
9000 * @return {Element} The mask element
9002 mask : function(msg, msgCls)
9004 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9005 this.setStyle("position", "relative");
9008 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9010 this.addClass("x-masked");
9011 this._mask.setDisplayed(true);
9016 while (dom && dom.style) {
9017 if (!isNaN(parseInt(dom.style.zIndex))) {
9018 z = Math.max(z, parseInt(dom.style.zIndex));
9020 dom = dom.parentNode;
9022 // if we are masking the body - then it hides everything..
9023 if (this.dom == document.body) {
9025 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9026 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9029 if(typeof msg == 'string'){
9031 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9033 var mm = this._maskMsg;
9034 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9035 if (mm.dom.firstChild) { // weird IE issue?
9036 mm.dom.firstChild.innerHTML = msg;
9038 mm.setDisplayed(true);
9040 mm.setStyle('z-index', z + 102);
9042 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9043 this._mask.setHeight(this.getHeight());
9045 this._mask.setStyle('z-index', z + 100);
9051 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9052 * it is cached for reuse.
9054 unmask : function(removeEl){
9056 if(removeEl === true){
9057 this._mask.remove();
9060 this._maskMsg.remove();
9061 delete this._maskMsg;
9064 this._mask.setDisplayed(false);
9066 this._maskMsg.setDisplayed(false);
9070 this.removeClass("x-masked");
9074 * Returns true if this element is masked
9077 isMasked : function(){
9078 return this._mask && this._mask.isVisible();
9082 * Creates an iframe shim for this element to keep selects and other windowed objects from
9084 * @return {Roo.Element} The new shim element
9086 createShim : function(){
9087 var el = document.createElement('iframe');
9088 el.frameBorder = 'no';
9089 el.className = 'roo-shim';
9090 if(Roo.isIE && Roo.isSecure){
9091 el.src = Roo.SSL_SECURE_URL;
9093 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9094 shim.autoBoxAdjust = false;
9099 * Removes this element from the DOM and deletes it from the cache
9101 remove : function(){
9102 if(this.dom.parentNode){
9103 this.dom.parentNode.removeChild(this.dom);
9105 delete El.cache[this.dom.id];
9109 * Sets up event handlers to add and remove a css class when the mouse is over this element
9110 * @param {String} className
9111 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9112 * mouseout events for children elements
9113 * @return {Roo.Element} this
9115 addClassOnOver : function(className, preventFlicker){
9116 this.on("mouseover", function(){
9117 Roo.fly(this, '_internal').addClass(className);
9119 var removeFn = function(e){
9120 if(preventFlicker !== true || !e.within(this, true)){
9121 Roo.fly(this, '_internal').removeClass(className);
9124 this.on("mouseout", removeFn, this.dom);
9129 * Sets up event handlers to add and remove a css class when this element has the focus
9130 * @param {String} className
9131 * @return {Roo.Element} this
9133 addClassOnFocus : function(className){
9134 this.on("focus", function(){
9135 Roo.fly(this, '_internal').addClass(className);
9137 this.on("blur", function(){
9138 Roo.fly(this, '_internal').removeClass(className);
9143 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
9144 * @param {String} className
9145 * @return {Roo.Element} this
9147 addClassOnClick : function(className){
9149 this.on("mousedown", function(){
9150 Roo.fly(dom, '_internal').addClass(className);
9151 var d = Roo.get(document);
9152 var fn = function(){
9153 Roo.fly(dom, '_internal').removeClass(className);
9154 d.removeListener("mouseup", fn);
9156 d.on("mouseup", fn);
9162 * Stops the specified event from bubbling and optionally prevents the default action
9163 * @param {String} eventName
9164 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9165 * @return {Roo.Element} this
9167 swallowEvent : function(eventName, preventDefault){
9168 var fn = function(e){
9169 e.stopPropagation();
9174 if(eventName instanceof Array){
9175 for(var i = 0, len = eventName.length; i < len; i++){
9176 this.on(eventName[i], fn);
9180 this.on(eventName, fn);
9187 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9190 * Sizes this element to its parent element's dimensions performing
9191 * neccessary box adjustments.
9192 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9193 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9194 * @return {Roo.Element} this
9196 fitToParent : function(monitorResize, targetParent) {
9197 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9198 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9199 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9202 var p = Roo.get(targetParent || this.dom.parentNode);
9203 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9204 if (monitorResize === true) {
9205 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9206 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9212 * Gets the next sibling, skipping text nodes
9213 * @return {HTMLElement} The next sibling or null
9215 getNextSibling : function(){
9216 var n = this.dom.nextSibling;
9217 while(n && n.nodeType != 1){
9224 * Gets the previous sibling, skipping text nodes
9225 * @return {HTMLElement} The previous sibling or null
9227 getPrevSibling : function(){
9228 var n = this.dom.previousSibling;
9229 while(n && n.nodeType != 1){
9230 n = n.previousSibling;
9237 * Appends the passed element(s) to this element
9238 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9239 * @return {Roo.Element} this
9241 appendChild: function(el){
9248 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9249 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9250 * automatically generated with the specified attributes.
9251 * @param {HTMLElement} insertBefore (optional) a child element of this element
9252 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9253 * @return {Roo.Element} The new child element
9255 createChild: function(config, insertBefore, returnDom){
9256 config = config || {tag:'div'};
9258 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9260 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9264 * Appends this element to the passed element
9265 * @param {String/HTMLElement/Element} el The new parent element
9266 * @return {Roo.Element} this
9268 appendTo: function(el){
9269 el = Roo.getDom(el);
9270 el.appendChild(this.dom);
9275 * Inserts this element before the passed element in the DOM
9276 * @param {String/HTMLElement/Element} el The element to insert before
9277 * @return {Roo.Element} this
9279 insertBefore: function(el){
9280 el = Roo.getDom(el);
9281 el.parentNode.insertBefore(this.dom, el);
9286 * Inserts this element after the passed element in the DOM
9287 * @param {String/HTMLElement/Element} el The element to insert after
9288 * @return {Roo.Element} this
9290 insertAfter: function(el){
9291 el = Roo.getDom(el);
9292 el.parentNode.insertBefore(this.dom, el.nextSibling);
9297 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9298 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9299 * @return {Roo.Element} The new child
9301 insertFirst: function(el, returnDom){
9303 if(typeof el == 'object' && !el.nodeType){ // dh config
9304 return this.createChild(el, this.dom.firstChild, returnDom);
9306 el = Roo.getDom(el);
9307 this.dom.insertBefore(el, this.dom.firstChild);
9308 return !returnDom ? Roo.get(el) : el;
9313 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9314 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9315 * @param {String} where (optional) 'before' or 'after' defaults to before
9316 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9317 * @return {Roo.Element} the inserted Element
9319 insertSibling: function(el, where, returnDom){
9320 where = where ? where.toLowerCase() : 'before';
9322 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9324 if(typeof el == 'object' && !el.nodeType){ // dh config
9325 if(where == 'after' && !this.dom.nextSibling){
9326 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9328 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9332 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9333 where == 'before' ? this.dom : this.dom.nextSibling);
9342 * Creates and wraps this element with another element
9343 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9344 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9345 * @return {HTMLElement/Element} The newly created wrapper element
9347 wrap: function(config, returnDom){
9349 config = {tag: "div"};
9351 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9352 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9357 * Replaces the passed element with this element
9358 * @param {String/HTMLElement/Element} el The element to replace
9359 * @return {Roo.Element} this
9361 replace: function(el){
9363 this.insertBefore(el);
9369 * Inserts an html fragment into this element
9370 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9371 * @param {String} html The HTML fragment
9372 * @param {Boolean} returnEl True to return an Roo.Element
9373 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9375 insertHtml : function(where, html, returnEl){
9376 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9377 return returnEl ? Roo.get(el) : el;
9381 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9382 * @param {Object} o The object with the attributes
9383 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9384 * @return {Roo.Element} this
9386 set : function(o, useSet){
9388 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9390 if(attr == "style" || typeof o[attr] == "function") { continue; }
9392 el.className = o["cls"];
9395 el.setAttribute(attr, o[attr]);
9402 Roo.DomHelper.applyStyles(el, o.style);
9408 * Convenience method for constructing a KeyMap
9409 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9410 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9411 * @param {Function} fn The function to call
9412 * @param {Object} scope (optional) The scope of the function
9413 * @return {Roo.KeyMap} The KeyMap created
9415 addKeyListener : function(key, fn, scope){
9417 if(typeof key != "object" || key instanceof Array){
9433 return new Roo.KeyMap(this, config);
9437 * Creates a KeyMap for this element
9438 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9439 * @return {Roo.KeyMap} The KeyMap created
9441 addKeyMap : function(config){
9442 return new Roo.KeyMap(this, config);
9446 * Returns true if this element is scrollable.
9449 isScrollable : function(){
9451 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9455 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9456 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9457 * @param {Number} value The new scroll value
9458 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9459 * @return {Element} this
9462 scrollTo : function(side, value, animate){
9463 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9465 this.dom[prop] = value;
9467 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9468 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9474 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9475 * within this element's scrollable range.
9476 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9477 * @param {Number} distance How far to scroll the element in pixels
9478 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9479 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9480 * was scrolled as far as it could go.
9482 scroll : function(direction, distance, animate){
9483 if(!this.isScrollable()){
9487 var l = el.scrollLeft, t = el.scrollTop;
9488 var w = el.scrollWidth, h = el.scrollHeight;
9489 var cw = el.clientWidth, ch = el.clientHeight;
9490 direction = direction.toLowerCase();
9491 var scrolled = false;
9492 var a = this.preanim(arguments, 2);
9497 var v = Math.min(l + distance, w-cw);
9498 this.scrollTo("left", v, a);
9505 var v = Math.max(l - distance, 0);
9506 this.scrollTo("left", v, a);
9514 var v = Math.max(t - distance, 0);
9515 this.scrollTo("top", v, a);
9523 var v = Math.min(t + distance, h-ch);
9524 this.scrollTo("top", v, a);
9533 * Translates the passed page coordinates into left/top css values for this element
9534 * @param {Number/Array} x The page x or an array containing [x, y]
9535 * @param {Number} y The page y
9536 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9538 translatePoints : function(x, y){
9539 if(typeof x == 'object' || x instanceof Array){
9542 var p = this.getStyle('position');
9543 var o = this.getXY();
9545 var l = parseInt(this.getStyle('left'), 10);
9546 var t = parseInt(this.getStyle('top'), 10);
9549 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9552 t = (p == "relative") ? 0 : this.dom.offsetTop;
9555 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9559 * Returns the current scroll position of the element.
9560 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9562 getScroll : function(){
9563 var d = this.dom, doc = document;
9564 if(d == doc || d == doc.body){
9565 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9566 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9567 return {left: l, top: t};
9569 return {left: d.scrollLeft, top: d.scrollTop};
9574 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9575 * are convert to standard 6 digit hex color.
9576 * @param {String} attr The css attribute
9577 * @param {String} defaultValue The default value to use when a valid color isn't found
9578 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9581 getColor : function(attr, defaultValue, prefix){
9582 var v = this.getStyle(attr);
9583 if(!v || v == "transparent" || v == "inherit") {
9584 return defaultValue;
9586 var color = typeof prefix == "undefined" ? "#" : prefix;
9587 if(v.substr(0, 4) == "rgb("){
9588 var rvs = v.slice(4, v.length -1).split(",");
9589 for(var i = 0; i < 3; i++){
9590 var h = parseInt(rvs[i]).toString(16);
9597 if(v.substr(0, 1) == "#"){
9599 for(var i = 1; i < 4; i++){
9600 var c = v.charAt(i);
9603 }else if(v.length == 7){
9604 color += v.substr(1);
9608 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9612 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9613 * gradient background, rounded corners and a 4-way shadow.
9614 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9615 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9616 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9617 * @return {Roo.Element} this
9619 boxWrap : function(cls){
9620 cls = cls || 'x-box';
9621 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9622 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9627 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9628 * @param {String} namespace The namespace in which to look for the attribute
9629 * @param {String} name The attribute name
9630 * @return {String} The attribute value
9632 getAttributeNS : Roo.isIE ? function(ns, name){
9634 var type = typeof d[ns+":"+name];
9635 if(type != 'undefined' && type != 'unknown'){
9636 return d[ns+":"+name];
9639 } : function(ns, name){
9641 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9646 * Sets or Returns the value the dom attribute value
9647 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9648 * @param {String} value (optional) The value to set the attribute to
9649 * @return {String} The attribute value
9651 attr : function(name){
9652 if (arguments.length > 1) {
9653 this.dom.setAttribute(name, arguments[1]);
9654 return arguments[1];
9656 if (typeof(name) == 'object') {
9657 for(var i in name) {
9658 this.attr(i, name[i]);
9664 if (!this.dom.hasAttribute(name)) {
9667 return this.dom.getAttribute(name);
9674 var ep = El.prototype;
9677 * Appends an event handler (Shorthand for addListener)
9678 * @param {String} eventName The type of event to append
9679 * @param {Function} fn The method the event invokes
9680 * @param {Object} scope (optional) The scope (this object) of the fn
9681 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9684 ep.on = ep.addListener;
9686 ep.mon = ep.addListener;
9689 * Removes an event handler from this element (shorthand for removeListener)
9690 * @param {String} eventName the type of event to remove
9691 * @param {Function} fn the method the event invokes
9692 * @return {Roo.Element} this
9695 ep.un = ep.removeListener;
9698 * true to automatically adjust width and height settings for box-model issues (default to true)
9700 ep.autoBoxAdjust = true;
9703 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9706 El.addUnits = function(v, defaultUnit){
9707 if(v === "" || v == "auto"){
9710 if(v === undefined){
9713 if(typeof v == "number" || !El.unitPattern.test(v)){
9714 return v + (defaultUnit || 'px');
9719 // special markup used throughout Roo when box wrapping elements
9720 El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9722 * Visibility mode constant - Use visibility to hide element
9728 * Visibility mode constant - Use display to hide element
9734 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9735 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9736 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9748 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9749 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9750 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9751 * @return {Element} The Element object
9754 El.get = function(el){
9756 if(!el){ return null; }
9757 if(typeof el == "string"){ // element id
9758 if(!(elm = document.getElementById(el))){
9761 if(ex = El.cache[el]){
9764 ex = El.cache[el] = new El(elm);
9767 }else if(el.tagName){ // dom element
9771 if(ex = El.cache[id]){
9774 ex = El.cache[id] = new El(el);
9777 }else if(el instanceof El){
9779 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9780 // catch case where it hasn't been appended
9781 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9784 }else if(el.isComposite){
9786 }else if(el instanceof Array){
9787 return El.select(el);
9788 }else if(el == document){
9789 // create a bogus element object representing the document object
9791 var f = function(){};
9792 f.prototype = El.prototype;
9794 docEl.dom = document;
9802 El.uncache = function(el){
9803 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9805 delete El.cache[a[i].id || a[i]];
9811 // Garbage collection - uncache elements/purge listeners on orphaned elements
9812 // so we don't hold a reference and cause the browser to retain them
9813 El.garbageCollect = function(){
9814 if(!Roo.enableGarbageCollector){
9815 clearInterval(El.collectorThread);
9818 for(var eid in El.cache){
9819 var el = El.cache[eid], d = el.dom;
9820 // -------------------------------------------------------
9821 // Determining what is garbage:
9822 // -------------------------------------------------------
9824 // dom node is null, definitely garbage
9825 // -------------------------------------------------------
9827 // no parentNode == direct orphan, definitely garbage
9828 // -------------------------------------------------------
9829 // !d.offsetParent && !document.getElementById(eid)
9830 // display none elements have no offsetParent so we will
9831 // also try to look it up by it's id. However, check
9832 // offsetParent first so we don't do unneeded lookups.
9833 // This enables collection of elements that are not orphans
9834 // directly, but somewhere up the line they have an orphan
9836 // -------------------------------------------------------
9837 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9838 delete El.cache[eid];
9839 if(d && Roo.enableListenerCollection){
9845 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9849 El.Flyweight = function(dom){
9852 El.Flyweight.prototype = El.prototype;
9854 El._flyweights = {};
9856 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9857 * the dom node can be overwritten by other code.
9858 * @param {String/HTMLElement} el The dom node or id
9859 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9860 * prevent conflicts (e.g. internally Roo uses "_internal")
9862 * @return {Element} The shared Element object
9864 El.fly = function(el, named){
9865 named = named || '_global';
9866 el = Roo.getDom(el);
9870 if(!El._flyweights[named]){
9871 El._flyweights[named] = new El.Flyweight();
9873 El._flyweights[named].dom = el;
9874 return El._flyweights[named];
9878 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9879 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9880 * Shorthand of {@link Roo.Element#get}
9881 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9882 * @return {Element} The Element object
9888 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9889 * the dom node can be overwritten by other code.
9890 * Shorthand of {@link Roo.Element#fly}
9891 * @param {String/HTMLElement} el The dom node or id
9892 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9893 * prevent conflicts (e.g. internally Roo uses "_internal")
9895 * @return {Element} The shared Element object
9901 // speedy lookup for elements never to box adjust
9902 var noBoxAdjust = Roo.isStrict ? {
9905 input:1, select:1, textarea:1
9907 if(Roo.isIE || Roo.isGecko){
9908 noBoxAdjust['button'] = 1;
9912 Roo.EventManager.on(window, 'unload', function(){
9914 delete El._flyweights;
9922 Roo.Element.selectorFunction = Roo.DomQuery.select;
9925 Roo.Element.select = function(selector, unique, root){
9927 if(typeof selector == "string"){
9928 els = Roo.Element.selectorFunction(selector, root);
9929 }else if(selector.length !== undefined){
9932 throw "Invalid selector";
9934 if(unique === true){
9935 return new Roo.CompositeElement(els);
9937 return new Roo.CompositeElementLite(els);
9941 * Selects elements based on the passed CSS selector to enable working on them as 1.
9942 * @param {String/Array} selector The CSS selector or an array of elements
9943 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9944 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9945 * @return {CompositeElementLite/CompositeElement}
9949 Roo.select = Roo.Element.select;
9966 * Ext JS Library 1.1.1
9967 * Copyright(c) 2006-2007, Ext JS, LLC.
9969 * Originally Released Under LGPL - original licence link has changed is not relivant.
9972 * <script type="text/javascript">
9977 //Notifies Element that fx methods are available
9978 Roo.enableFx = true;
9982 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9983 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9984 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9985 * Element effects to work.</p><br/>
9987 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9988 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9989 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9990 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9991 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9992 * expected results and should be done with care.</p><br/>
9994 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9995 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9998 ----- -----------------------------
9999 tl The top left corner
10000 t The center of the top edge
10001 tr The top right corner
10002 l The center of the left edge
10003 r The center of the right edge
10004 bl The bottom left corner
10005 b The center of the bottom edge
10006 br The bottom right corner
10008 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10009 * below are common options that can be passed to any Fx method.</b>
10010 * @cfg {Function} callback A function called when the effect is finished
10011 * @cfg {Object} scope The scope of the effect function
10012 * @cfg {String} easing A valid Easing value for the effect
10013 * @cfg {String} afterCls A css class to apply after the effect
10014 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10015 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10016 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10017 * effects that end with the element being visually hidden, ignored otherwise)
10018 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10019 * a function which returns such a specification that will be applied to the Element after the effect finishes
10020 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10021 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
10022 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10026 * Slides the element into view. An anchor point can be optionally passed to set the point of
10027 * origin for the slide effect. This function automatically handles wrapping the element with
10028 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10031 // default: slide the element in from the top
10034 // custom: slide the element in from the right with a 2-second duration
10035 el.slideIn('r', { duration: 2 });
10037 // common config options shown with default values
10043 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10044 * @param {Object} options (optional) Object literal with any of the Fx config options
10045 * @return {Roo.Element} The Element
10047 slideIn : function(anchor, o){
10048 var el = this.getFxEl();
10051 el.queueFx(o, function(){
10053 anchor = anchor || "t";
10055 // fix display to visibility
10058 // restore values after effect
10059 var r = this.getFxRestore();
10060 var b = this.getBox();
10061 // fixed size for slide
10065 var wrap = this.fxWrap(r.pos, o, "hidden");
10067 var st = this.dom.style;
10068 st.visibility = "visible";
10069 st.position = "absolute";
10071 // clear out temp styles after slide and unwrap
10072 var after = function(){
10073 el.fxUnwrap(wrap, r.pos, o);
10074 st.width = r.width;
10075 st.height = r.height;
10078 // time to calc the positions
10079 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10081 switch(anchor.toLowerCase()){
10083 wrap.setSize(b.width, 0);
10084 st.left = st.bottom = "0";
10088 wrap.setSize(0, b.height);
10089 st.right = st.top = "0";
10093 wrap.setSize(0, b.height);
10094 wrap.setX(b.right);
10095 st.left = st.top = "0";
10096 a = {width: bw, points: pt};
10099 wrap.setSize(b.width, 0);
10100 wrap.setY(b.bottom);
10101 st.left = st.top = "0";
10102 a = {height: bh, points: pt};
10105 wrap.setSize(0, 0);
10106 st.right = st.bottom = "0";
10107 a = {width: bw, height: bh};
10110 wrap.setSize(0, 0);
10111 wrap.setY(b.y+b.height);
10112 st.right = st.top = "0";
10113 a = {width: bw, height: bh, points: pt};
10116 wrap.setSize(0, 0);
10117 wrap.setXY([b.right, b.bottom]);
10118 st.left = st.top = "0";
10119 a = {width: bw, height: bh, points: pt};
10122 wrap.setSize(0, 0);
10123 wrap.setX(b.x+b.width);
10124 st.left = st.bottom = "0";
10125 a = {width: bw, height: bh, points: pt};
10128 this.dom.style.visibility = "visible";
10131 arguments.callee.anim = wrap.fxanim(a,
10141 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10142 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10143 * 'hidden') but block elements will still take up space in the document. The element must be removed
10144 * from the DOM using the 'remove' config option if desired. This function automatically handles
10145 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10148 // default: slide the element out to the top
10151 // custom: slide the element out to the right with a 2-second duration
10152 el.slideOut('r', { duration: 2 });
10154 // common config options shown with default values
10162 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10163 * @param {Object} options (optional) Object literal with any of the Fx config options
10164 * @return {Roo.Element} The Element
10166 slideOut : function(anchor, o){
10167 var el = this.getFxEl();
10170 el.queueFx(o, function(){
10172 anchor = anchor || "t";
10174 // restore values after effect
10175 var r = this.getFxRestore();
10177 var b = this.getBox();
10178 // fixed size for slide
10182 var wrap = this.fxWrap(r.pos, o, "visible");
10184 var st = this.dom.style;
10185 st.visibility = "visible";
10186 st.position = "absolute";
10190 var after = function(){
10192 el.setDisplayed(false);
10197 el.fxUnwrap(wrap, r.pos, o);
10199 st.width = r.width;
10200 st.height = r.height;
10205 var a, zero = {to: 0};
10206 switch(anchor.toLowerCase()){
10208 st.left = st.bottom = "0";
10209 a = {height: zero};
10212 st.right = st.top = "0";
10216 st.left = st.top = "0";
10217 a = {width: zero, points: {to:[b.right, b.y]}};
10220 st.left = st.top = "0";
10221 a = {height: zero, points: {to:[b.x, b.bottom]}};
10224 st.right = st.bottom = "0";
10225 a = {width: zero, height: zero};
10228 st.right = st.top = "0";
10229 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10232 st.left = st.top = "0";
10233 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10236 st.left = st.bottom = "0";
10237 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10241 arguments.callee.anim = wrap.fxanim(a,
10251 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10252 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10253 * The element must be removed from the DOM using the 'remove' config option if desired.
10259 // common config options shown with default values
10267 * @param {Object} options (optional) Object literal with any of the Fx config options
10268 * @return {Roo.Element} The Element
10270 puff : function(o){
10271 var el = this.getFxEl();
10274 el.queueFx(o, function(){
10275 this.clearOpacity();
10278 // restore values after effect
10279 var r = this.getFxRestore();
10280 var st = this.dom.style;
10282 var after = function(){
10284 el.setDisplayed(false);
10291 el.setPositioning(r.pos);
10292 st.width = r.width;
10293 st.height = r.height;
10298 var width = this.getWidth();
10299 var height = this.getHeight();
10301 arguments.callee.anim = this.fxanim({
10302 width : {to: this.adjustWidth(width * 2)},
10303 height : {to: this.adjustHeight(height * 2)},
10304 points : {by: [-(width * .5), -(height * .5)]},
10306 fontSize: {to:200, unit: "%"}
10317 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10318 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10319 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10325 // all config options shown with default values
10333 * @param {Object} options (optional) Object literal with any of the Fx config options
10334 * @return {Roo.Element} The Element
10336 switchOff : function(o){
10337 var el = this.getFxEl();
10340 el.queueFx(o, function(){
10341 this.clearOpacity();
10344 // restore values after effect
10345 var r = this.getFxRestore();
10346 var st = this.dom.style;
10348 var after = function(){
10350 el.setDisplayed(false);
10356 el.setPositioning(r.pos);
10357 st.width = r.width;
10358 st.height = r.height;
10363 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10364 this.clearOpacity();
10368 points:{by:[0, this.getHeight() * .5]}
10369 }, o, 'motion', 0.3, 'easeIn', after);
10370 }).defer(100, this);
10377 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10378 * changed using the "attr" config option) and then fading back to the original color. If no original
10379 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10382 // default: highlight background to yellow
10385 // custom: highlight foreground text to blue for 2 seconds
10386 el.highlight("0000ff", { attr: 'color', duration: 2 });
10388 // common config options shown with default values
10389 el.highlight("ffff9c", {
10390 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10391 endColor: (current color) or "ffffff",
10396 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10397 * @param {Object} options (optional) Object literal with any of the Fx config options
10398 * @return {Roo.Element} The Element
10400 highlight : function(color, o){
10401 var el = this.getFxEl();
10404 el.queueFx(o, function(){
10405 color = color || "ffff9c";
10406 attr = o.attr || "backgroundColor";
10408 this.clearOpacity();
10411 var origColor = this.getColor(attr);
10412 var restoreColor = this.dom.style[attr];
10413 endColor = (o.endColor || origColor) || "ffffff";
10415 var after = function(){
10416 el.dom.style[attr] = restoreColor;
10421 a[attr] = {from: color, to: endColor};
10422 arguments.callee.anim = this.fxanim(a,
10432 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10435 // default: a single light blue ripple
10438 // custom: 3 red ripples lasting 3 seconds total
10439 el.frame("ff0000", 3, { duration: 3 });
10441 // common config options shown with default values
10442 el.frame("C3DAF9", 1, {
10443 duration: 1 //duration of entire animation (not each individual ripple)
10444 // Note: Easing is not configurable and will be ignored if included
10447 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10448 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10449 * @param {Object} options (optional) Object literal with any of the Fx config options
10450 * @return {Roo.Element} The Element
10452 frame : function(color, count, o){
10453 var el = this.getFxEl();
10456 el.queueFx(o, function(){
10457 color = color || "#C3DAF9";
10458 if(color.length == 6){
10459 color = "#" + color;
10461 count = count || 1;
10462 duration = o.duration || 1;
10465 var b = this.getBox();
10466 var animFn = function(){
10467 var proxy = this.createProxy({
10470 visbility:"hidden",
10471 position:"absolute",
10472 "z-index":"35000", // yee haw
10473 border:"0px solid " + color
10476 var scale = Roo.isBorderBox ? 2 : 1;
10478 top:{from:b.y, to:b.y - 20},
10479 left:{from:b.x, to:b.x - 20},
10480 borderWidth:{from:0, to:10},
10481 opacity:{from:1, to:0},
10482 height:{from:b.height, to:(b.height + (20*scale))},
10483 width:{from:b.width, to:(b.width + (20*scale))}
10484 }, duration, function(){
10488 animFn.defer((duration/2)*1000, this);
10499 * Creates a pause before any subsequent queued effects begin. If there are
10500 * no effects queued after the pause it will have no effect.
10505 * @param {Number} seconds The length of time to pause (in seconds)
10506 * @return {Roo.Element} The Element
10508 pause : function(seconds){
10509 var el = this.getFxEl();
10512 el.queueFx(o, function(){
10513 setTimeout(function(){
10515 }, seconds * 1000);
10521 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10522 * using the "endOpacity" config option.
10525 // default: fade in from opacity 0 to 100%
10528 // custom: fade in from opacity 0 to 75% over 2 seconds
10529 el.fadeIn({ endOpacity: .75, duration: 2});
10531 // common config options shown with default values
10533 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10538 * @param {Object} options (optional) Object literal with any of the Fx config options
10539 * @return {Roo.Element} The Element
10541 fadeIn : function(o){
10542 var el = this.getFxEl();
10544 el.queueFx(o, function(){
10545 this.setOpacity(0);
10547 this.dom.style.visibility = 'visible';
10548 var to = o.endOpacity || 1;
10549 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10550 o, null, .5, "easeOut", function(){
10552 this.clearOpacity();
10561 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10562 * using the "endOpacity" config option.
10565 // default: fade out from the element's current opacity to 0
10568 // custom: fade out from the element's current opacity to 25% over 2 seconds
10569 el.fadeOut({ endOpacity: .25, duration: 2});
10571 // common config options shown with default values
10573 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10580 * @param {Object} options (optional) Object literal with any of the Fx config options
10581 * @return {Roo.Element} The Element
10583 fadeOut : function(o){
10584 var el = this.getFxEl();
10586 el.queueFx(o, function(){
10587 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10588 o, null, .5, "easeOut", function(){
10589 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10590 this.dom.style.display = "none";
10592 this.dom.style.visibility = "hidden";
10594 this.clearOpacity();
10602 * Animates the transition of an element's dimensions from a starting height/width
10603 * to an ending height/width.
10606 // change height and width to 100x100 pixels
10607 el.scale(100, 100);
10609 // common config options shown with default values. The height and width will default to
10610 // the element's existing values if passed as null.
10613 [element's height], {
10618 * @param {Number} width The new width (pass undefined to keep the original width)
10619 * @param {Number} height The new height (pass undefined to keep the original height)
10620 * @param {Object} options (optional) Object literal with any of the Fx config options
10621 * @return {Roo.Element} The Element
10623 scale : function(w, h, o){
10624 this.shift(Roo.apply({}, o, {
10632 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10633 * Any of these properties not specified in the config object will not be changed. This effect
10634 * requires that at least one new dimension, position or opacity setting must be passed in on
10635 * the config object in order for the function to have any effect.
10638 // slide the element horizontally to x position 200 while changing the height and opacity
10639 el.shift({ x: 200, height: 50, opacity: .8 });
10641 // common config options shown with default values.
10643 width: [element's width],
10644 height: [element's height],
10645 x: [element's x position],
10646 y: [element's y position],
10647 opacity: [element's opacity],
10652 * @param {Object} options Object literal with any of the Fx config options
10653 * @return {Roo.Element} The Element
10655 shift : function(o){
10656 var el = this.getFxEl();
10658 el.queueFx(o, function(){
10659 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10660 if(w !== undefined){
10661 a.width = {to: this.adjustWidth(w)};
10663 if(h !== undefined){
10664 a.height = {to: this.adjustHeight(h)};
10666 if(x !== undefined || y !== undefined){
10668 x !== undefined ? x : this.getX(),
10669 y !== undefined ? y : this.getY()
10672 if(op !== undefined){
10673 a.opacity = {to: op};
10675 if(o.xy !== undefined){
10676 a.points = {to: o.xy};
10678 arguments.callee.anim = this.fxanim(a,
10679 o, 'motion', .35, "easeOut", function(){
10687 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10688 * ending point of the effect.
10691 // default: slide the element downward while fading out
10694 // custom: slide the element out to the right with a 2-second duration
10695 el.ghost('r', { duration: 2 });
10697 // common config options shown with default values
10705 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10706 * @param {Object} options (optional) Object literal with any of the Fx config options
10707 * @return {Roo.Element} The Element
10709 ghost : function(anchor, o){
10710 var el = this.getFxEl();
10713 el.queueFx(o, function(){
10714 anchor = anchor || "b";
10716 // restore values after effect
10717 var r = this.getFxRestore();
10718 var w = this.getWidth(),
10719 h = this.getHeight();
10721 var st = this.dom.style;
10723 var after = function(){
10725 el.setDisplayed(false);
10731 el.setPositioning(r.pos);
10732 st.width = r.width;
10733 st.height = r.height;
10738 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10739 switch(anchor.toLowerCase()){
10766 arguments.callee.anim = this.fxanim(a,
10776 * Ensures that all effects queued after syncFx is called on the element are
10777 * run concurrently. This is the opposite of {@link #sequenceFx}.
10778 * @return {Roo.Element} The Element
10780 syncFx : function(){
10781 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10790 * Ensures that all effects queued after sequenceFx is called on the element are
10791 * run in sequence. This is the opposite of {@link #syncFx}.
10792 * @return {Roo.Element} The Element
10794 sequenceFx : function(){
10795 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10797 concurrent : false,
10804 nextFx : function(){
10805 var ef = this.fxQueue[0];
10812 * Returns true if the element has any effects actively running or queued, else returns false.
10813 * @return {Boolean} True if element has active effects, else false
10815 hasActiveFx : function(){
10816 return this.fxQueue && this.fxQueue[0];
10820 * Stops any running effects and clears the element's internal effects queue if it contains
10821 * any additional effects that haven't started yet.
10822 * @return {Roo.Element} The Element
10824 stopFx : function(){
10825 if(this.hasActiveFx()){
10826 var cur = this.fxQueue[0];
10827 if(cur && cur.anim && cur.anim.isAnimated()){
10828 this.fxQueue = [cur]; // clear out others
10829 cur.anim.stop(true);
10836 beforeFx : function(o){
10837 if(this.hasActiveFx() && !o.concurrent){
10848 * Returns true if the element is currently blocking so that no other effect can be queued
10849 * until this effect is finished, else returns false if blocking is not set. This is commonly
10850 * used to ensure that an effect initiated by a user action runs to completion prior to the
10851 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10852 * @return {Boolean} True if blocking, else false
10854 hasFxBlock : function(){
10855 var q = this.fxQueue;
10856 return q && q[0] && q[0].block;
10860 queueFx : function(o, fn){
10864 if(!this.hasFxBlock()){
10865 Roo.applyIf(o, this.fxDefaults);
10867 var run = this.beforeFx(o);
10868 fn.block = o.block;
10869 this.fxQueue.push(fn);
10881 fxWrap : function(pos, o, vis){
10883 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10886 wrapXY = this.getXY();
10888 var div = document.createElement("div");
10889 div.style.visibility = vis;
10890 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10891 wrap.setPositioning(pos);
10892 if(wrap.getStyle("position") == "static"){
10893 wrap.position("relative");
10895 this.clearPositioning('auto');
10897 wrap.dom.appendChild(this.dom);
10899 wrap.setXY(wrapXY);
10906 fxUnwrap : function(wrap, pos, o){
10907 this.clearPositioning();
10908 this.setPositioning(pos);
10910 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10916 getFxRestore : function(){
10917 var st = this.dom.style;
10918 return {pos: this.getPositioning(), width: st.width, height : st.height};
10922 afterFx : function(o){
10924 this.applyStyles(o.afterStyle);
10927 this.addClass(o.afterCls);
10929 if(o.remove === true){
10932 Roo.callback(o.callback, o.scope, [this]);
10934 this.fxQueue.shift();
10940 getFxEl : function(){ // support for composite element fx
10941 return Roo.get(this.dom);
10945 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10946 animType = animType || 'run';
10948 var anim = Roo.lib.Anim[animType](
10950 (opt.duration || defaultDur) || .35,
10951 (opt.easing || defaultEase) || 'easeOut',
10953 Roo.callback(cb, this);
10962 // backwords compat
10963 Roo.Fx.resize = Roo.Fx.scale;
10965 //When included, Roo.Fx is automatically applied to Element so that all basic
10966 //effects are available directly via the Element API
10967 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10969 * Ext JS Library 1.1.1
10970 * Copyright(c) 2006-2007, Ext JS, LLC.
10972 * Originally Released Under LGPL - original licence link has changed is not relivant.
10975 * <script type="text/javascript">
10980 * @class Roo.CompositeElement
10981 * Standard composite class. Creates a Roo.Element for every element in the collection.
10983 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10984 * actions will be performed on all the elements in this collection.</b>
10986 * All methods return <i>this</i> and can be chained.
10988 var els = Roo.select("#some-el div.some-class", true);
10989 // or select directly from an existing element
10990 var el = Roo.get('some-el');
10991 el.select('div.some-class', true);
10993 els.setWidth(100); // all elements become 100 width
10994 els.hide(true); // all elements fade out and hide
10996 els.setWidth(100).hide(true);
10999 Roo.CompositeElement = function(els){
11000 this.elements = [];
11001 this.addElements(els);
11003 Roo.CompositeElement.prototype = {
11005 addElements : function(els){
11009 if(typeof els == "string"){
11010 els = Roo.Element.selectorFunction(els);
11012 var yels = this.elements;
11013 var index = yels.length-1;
11014 for(var i = 0, len = els.length; i < len; i++) {
11015 yels[++index] = Roo.get(els[i]);
11021 * Clears this composite and adds the elements returned by the passed selector.
11022 * @param {String/Array} els A string CSS selector, an array of elements or an element
11023 * @return {CompositeElement} this
11025 fill : function(els){
11026 this.elements = [];
11032 * Filters this composite to only elements that match the passed selector.
11033 * @param {String} selector A string CSS selector
11034 * @param {Boolean} inverse return inverse filter (not matches)
11035 * @return {CompositeElement} this
11037 filter : function(selector, inverse){
11039 inverse = inverse || false;
11040 this.each(function(el){
11041 var match = inverse ? !el.is(selector) : el.is(selector);
11043 els[els.length] = el.dom;
11050 invoke : function(fn, args){
11051 var els = this.elements;
11052 for(var i = 0, len = els.length; i < len; i++) {
11053 Roo.Element.prototype[fn].apply(els[i], args);
11058 * Adds elements to this composite.
11059 * @param {String/Array} els A string CSS selector, an array of elements or an element
11060 * @return {CompositeElement} this
11062 add : function(els){
11063 if(typeof els == "string"){
11064 this.addElements(Roo.Element.selectorFunction(els));
11065 }else if(els.length !== undefined){
11066 this.addElements(els);
11068 this.addElements([els]);
11073 * Calls the passed function passing (el, this, index) for each element in this composite.
11074 * @param {Function} fn The function to call
11075 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11076 * @return {CompositeElement} this
11078 each : function(fn, scope){
11079 var els = this.elements;
11080 for(var i = 0, len = els.length; i < len; i++){
11081 if(fn.call(scope || els[i], els[i], this, i) === false) {
11089 * Returns the Element object at the specified index
11090 * @param {Number} index
11091 * @return {Roo.Element}
11093 item : function(index){
11094 return this.elements[index] || null;
11098 * Returns the first Element
11099 * @return {Roo.Element}
11101 first : function(){
11102 return this.item(0);
11106 * Returns the last Element
11107 * @return {Roo.Element}
11110 return this.item(this.elements.length-1);
11114 * Returns the number of elements in this composite
11117 getCount : function(){
11118 return this.elements.length;
11122 * Returns true if this composite contains the passed element
11125 contains : function(el){
11126 return this.indexOf(el) !== -1;
11130 * Returns true if this composite contains the passed element
11133 indexOf : function(el){
11134 return this.elements.indexOf(Roo.get(el));
11139 * Removes the specified element(s).
11140 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11141 * or an array of any of those.
11142 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11143 * @return {CompositeElement} this
11145 removeElement : function(el, removeDom){
11146 if(el instanceof Array){
11147 for(var i = 0, len = el.length; i < len; i++){
11148 this.removeElement(el[i]);
11152 var index = typeof el == 'number' ? el : this.indexOf(el);
11155 var d = this.elements[index];
11159 d.parentNode.removeChild(d);
11162 this.elements.splice(index, 1);
11168 * Replaces the specified element with the passed element.
11169 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11171 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11172 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11173 * @return {CompositeElement} this
11175 replaceElement : function(el, replacement, domReplace){
11176 var index = typeof el == 'number' ? el : this.indexOf(el);
11179 this.elements[index].replaceWith(replacement);
11181 this.elements.splice(index, 1, Roo.get(replacement))
11188 * Removes all elements.
11190 clear : function(){
11191 this.elements = [];
11195 Roo.CompositeElement.createCall = function(proto, fnName){
11196 if(!proto[fnName]){
11197 proto[fnName] = function(){
11198 return this.invoke(fnName, arguments);
11202 for(var fnName in Roo.Element.prototype){
11203 if(typeof Roo.Element.prototype[fnName] == "function"){
11204 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11210 * Ext JS Library 1.1.1
11211 * Copyright(c) 2006-2007, Ext JS, LLC.
11213 * Originally Released Under LGPL - original licence link has changed is not relivant.
11216 * <script type="text/javascript">
11220 * @class Roo.CompositeElementLite
11221 * @extends Roo.CompositeElement
11222 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11224 var els = Roo.select("#some-el div.some-class");
11225 // or select directly from an existing element
11226 var el = Roo.get('some-el');
11227 el.select('div.some-class');
11229 els.setWidth(100); // all elements become 100 width
11230 els.hide(true); // all elements fade out and hide
11232 els.setWidth(100).hide(true);
11233 </code></pre><br><br>
11234 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11235 * actions will be performed on all the elements in this collection.</b>
11237 Roo.CompositeElementLite = function(els){
11238 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11239 this.el = new Roo.Element.Flyweight();
11241 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11242 addElements : function(els){
11244 if(els instanceof Array){
11245 this.elements = this.elements.concat(els);
11247 var yels = this.elements;
11248 var index = yels.length-1;
11249 for(var i = 0, len = els.length; i < len; i++) {
11250 yels[++index] = els[i];
11256 invoke : function(fn, args){
11257 var els = this.elements;
11259 for(var i = 0, len = els.length; i < len; i++) {
11261 Roo.Element.prototype[fn].apply(el, args);
11266 * Returns a flyweight Element of the dom element object at the specified index
11267 * @param {Number} index
11268 * @return {Roo.Element}
11270 item : function(index){
11271 if(!this.elements[index]){
11274 this.el.dom = this.elements[index];
11278 // fixes scope with flyweight
11279 addListener : function(eventName, handler, scope, opt){
11280 var els = this.elements;
11281 for(var i = 0, len = els.length; i < len; i++) {
11282 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11288 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11289 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11290 * a reference to the dom node, use el.dom.</b>
11291 * @param {Function} fn The function to call
11292 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11293 * @return {CompositeElement} this
11295 each : function(fn, scope){
11296 var els = this.elements;
11298 for(var i = 0, len = els.length; i < len; i++){
11300 if(fn.call(scope || el, el, this, i) === false){
11307 indexOf : function(el){
11308 return this.elements.indexOf(Roo.getDom(el));
11311 replaceElement : function(el, replacement, domReplace){
11312 var index = typeof el == 'number' ? el : this.indexOf(el);
11314 replacement = Roo.getDom(replacement);
11316 var d = this.elements[index];
11317 d.parentNode.insertBefore(replacement, d);
11318 d.parentNode.removeChild(d);
11320 this.elements.splice(index, 1, replacement);
11325 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11329 * Ext JS Library 1.1.1
11330 * Copyright(c) 2006-2007, Ext JS, LLC.
11332 * Originally Released Under LGPL - original licence link has changed is not relivant.
11335 * <script type="text/javascript">
11341 * @class Roo.data.Connection
11342 * @extends Roo.util.Observable
11343 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11344 * either to a configured URL, or to a URL specified at request time.<br><br>
11346 * Requests made by this class are asynchronous, and will return immediately. No data from
11347 * the server will be available to the statement immediately following the {@link #request} call.
11348 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11350 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11351 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11352 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11353 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11354 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11355 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11356 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11357 * standard DOM methods.
11359 * @param {Object} config a configuration object.
11361 Roo.data.Connection = function(config){
11362 Roo.apply(this, config);
11365 * @event beforerequest
11366 * Fires before a network request is made to retrieve a data object.
11367 * @param {Connection} conn This Connection object.
11368 * @param {Object} options The options config object passed to the {@link #request} method.
11370 "beforerequest" : true,
11372 * @event requestcomplete
11373 * Fires if the request was successfully completed.
11374 * @param {Connection} conn This Connection object.
11375 * @param {Object} response The XHR object containing the response data.
11376 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11377 * @param {Object} options The options config object passed to the {@link #request} method.
11379 "requestcomplete" : true,
11381 * @event requestexception
11382 * Fires if an error HTTP status was returned from the server.
11383 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11384 * @param {Connection} conn This Connection object.
11385 * @param {Object} response The XHR object containing the response data.
11386 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11387 * @param {Object} options The options config object passed to the {@link #request} method.
11389 "requestexception" : true
11391 Roo.data.Connection.superclass.constructor.call(this);
11394 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11396 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11399 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11400 * extra parameters to each request made by this object. (defaults to undefined)
11403 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11404 * to each request made by this object. (defaults to undefined)
11407 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11410 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11414 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11420 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11423 disableCaching: true,
11426 * Sends an HTTP request to a remote server.
11427 * @param {Object} options An object which may contain the following properties:<ul>
11428 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11429 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11430 * request, a url encoded string or a function to call to get either.</li>
11431 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11432 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11433 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11434 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11435 * <li>options {Object} The parameter to the request call.</li>
11436 * <li>success {Boolean} True if the request succeeded.</li>
11437 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11439 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11440 * The callback is passed the following parameters:<ul>
11441 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11442 * <li>options {Object} The parameter to the request call.</li>
11444 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11445 * The callback is passed the following parameters:<ul>
11446 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11447 * <li>options {Object} The parameter to the request call.</li>
11449 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11450 * for the callback function. Defaults to the browser window.</li>
11451 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11452 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11453 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11454 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11455 * params for the post data. Any params will be appended to the URL.</li>
11456 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11458 * @return {Number} transactionId
11460 request : function(o){
11461 if(this.fireEvent("beforerequest", this, o) !== false){
11464 if(typeof p == "function"){
11465 p = p.call(o.scope||window, o);
11467 if(typeof p == "object"){
11468 p = Roo.urlEncode(o.params);
11470 if(this.extraParams){
11471 var extras = Roo.urlEncode(this.extraParams);
11472 p = p ? (p + '&' + extras) : extras;
11475 var url = o.url || this.url;
11476 if(typeof url == 'function'){
11477 url = url.call(o.scope||window, o);
11481 var form = Roo.getDom(o.form);
11482 url = url || form.action;
11484 var enctype = form.getAttribute("enctype");
11485 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11486 return this.doFormUpload(o, p, url);
11488 var f = Roo.lib.Ajax.serializeForm(form);
11489 p = p ? (p + '&' + f) : f;
11492 var hs = o.headers;
11493 if(this.defaultHeaders){
11494 hs = Roo.apply(hs || {}, this.defaultHeaders);
11501 success: this.handleResponse,
11502 failure: this.handleFailure,
11504 argument: {options: o},
11505 timeout : o.timeout || this.timeout
11508 var method = o.method||this.method||(p ? "POST" : "GET");
11510 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11511 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11514 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11518 }else if(this.autoAbort !== false){
11522 if((method == 'GET' && p) || o.xmlData){
11523 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11526 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11527 return this.transId;
11529 Roo.callback(o.callback, o.scope, [o, null, null]);
11535 * Determine whether this object has a request outstanding.
11536 * @param {Number} transactionId (Optional) defaults to the last transaction
11537 * @return {Boolean} True if there is an outstanding request.
11539 isLoading : function(transId){
11541 return Roo.lib.Ajax.isCallInProgress(transId);
11543 return this.transId ? true : false;
11548 * Aborts any outstanding request.
11549 * @param {Number} transactionId (Optional) defaults to the last transaction
11551 abort : function(transId){
11552 if(transId || this.isLoading()){
11553 Roo.lib.Ajax.abort(transId || this.transId);
11558 handleResponse : function(response){
11559 this.transId = false;
11560 var options = response.argument.options;
11561 response.argument = options ? options.argument : null;
11562 this.fireEvent("requestcomplete", this, response, options);
11563 Roo.callback(options.success, options.scope, [response, options]);
11564 Roo.callback(options.callback, options.scope, [options, true, response]);
11568 handleFailure : function(response, e){
11569 this.transId = false;
11570 var options = response.argument.options;
11571 response.argument = options ? options.argument : null;
11572 this.fireEvent("requestexception", this, response, options, e);
11573 Roo.callback(options.failure, options.scope, [response, options]);
11574 Roo.callback(options.callback, options.scope, [options, false, response]);
11578 doFormUpload : function(o, ps, url){
11580 var frame = document.createElement('iframe');
11583 frame.className = 'x-hidden';
11585 frame.src = Roo.SSL_SECURE_URL;
11587 document.body.appendChild(frame);
11590 document.frames[id].name = id;
11593 var form = Roo.getDom(o.form);
11595 form.method = 'POST';
11596 form.enctype = form.encoding = 'multipart/form-data';
11602 if(ps){ // add dynamic params
11604 ps = Roo.urlDecode(ps, false);
11606 if(ps.hasOwnProperty(k)){
11607 hd = document.createElement('input');
11608 hd.type = 'hidden';
11611 form.appendChild(hd);
11618 var r = { // bogus response object
11623 r.argument = o ? o.argument : null;
11628 doc = frame.contentWindow.document;
11630 doc = (frame.contentDocument || window.frames[id].document);
11632 if(doc && doc.body){
11633 r.responseText = doc.body.innerHTML;
11635 if(doc && doc.XMLDocument){
11636 r.responseXML = doc.XMLDocument;
11638 r.responseXML = doc;
11645 Roo.EventManager.removeListener(frame, 'load', cb, this);
11647 this.fireEvent("requestcomplete", this, r, o);
11648 Roo.callback(o.success, o.scope, [r, o]);
11649 Roo.callback(o.callback, o.scope, [o, true, r]);
11651 setTimeout(function(){document.body.removeChild(frame);}, 100);
11654 Roo.EventManager.on(frame, 'load', cb, this);
11657 if(hiddens){ // remove dynamic params
11658 for(var i = 0, len = hiddens.length; i < len; i++){
11659 form.removeChild(hiddens[i]);
11666 * Ext JS Library 1.1.1
11667 * Copyright(c) 2006-2007, Ext JS, LLC.
11669 * Originally Released Under LGPL - original licence link has changed is not relivant.
11672 * <script type="text/javascript">
11676 * Global Ajax request class.
11679 * @extends Roo.data.Connection
11682 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11683 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11684 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11685 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11686 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11687 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11688 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11690 Roo.Ajax = new Roo.data.Connection({
11699 * Serialize the passed form into a url encoded string
11701 * @param {String/HTMLElement} form
11704 serializeForm : function(form){
11705 return Roo.lib.Ajax.serializeForm(form);
11709 * Ext JS Library 1.1.1
11710 * Copyright(c) 2006-2007, Ext JS, LLC.
11712 * Originally Released Under LGPL - original licence link has changed is not relivant.
11715 * <script type="text/javascript">
11720 * @class Roo.UpdateManager
11721 * @extends Roo.util.Observable
11722 * Provides AJAX-style update for Element object.<br><br>
11725 * // Get it from a Roo.Element object
11726 * var el = Roo.get("foo");
11727 * var mgr = el.getUpdateManager();
11728 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11730 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11732 * // or directly (returns the same UpdateManager instance)
11733 * var mgr = new Roo.UpdateManager("myElementId");
11734 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11735 * mgr.on("update", myFcnNeedsToKnow);
11737 // short handed call directly from the element object
11738 Roo.get("foo").load({
11742 text: "Loading Foo..."
11746 * Create new UpdateManager directly.
11747 * @param {String/HTMLElement/Roo.Element} el The element to update
11748 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11750 Roo.UpdateManager = function(el, forceNew){
11752 if(!forceNew && el.updateManager){
11753 return el.updateManager;
11756 * The Element object
11757 * @type Roo.Element
11761 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11764 this.defaultUrl = null;
11768 * @event beforeupdate
11769 * Fired before an update is made, return false from your handler and the update is cancelled.
11770 * @param {Roo.Element} el
11771 * @param {String/Object/Function} url
11772 * @param {String/Object} params
11774 "beforeupdate": true,
11777 * Fired after successful update is made.
11778 * @param {Roo.Element} el
11779 * @param {Object} oResponseObject The response Object
11784 * Fired on update failure.
11785 * @param {Roo.Element} el
11786 * @param {Object} oResponseObject The response Object
11790 var d = Roo.UpdateManager.defaults;
11792 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11795 this.sslBlankUrl = d.sslBlankUrl;
11797 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11800 this.disableCaching = d.disableCaching;
11802 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11805 this.indicatorText = d.indicatorText;
11807 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11810 this.showLoadIndicator = d.showLoadIndicator;
11812 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11815 this.timeout = d.timeout;
11818 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11821 this.loadScripts = d.loadScripts;
11824 * Transaction object of current executing transaction
11826 this.transaction = null;
11831 this.autoRefreshProcId = null;
11833 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11836 this.refreshDelegate = this.refresh.createDelegate(this);
11838 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11841 this.updateDelegate = this.update.createDelegate(this);
11843 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11846 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11850 this.successDelegate = this.processSuccess.createDelegate(this);
11854 this.failureDelegate = this.processFailure.createDelegate(this);
11856 if(!this.renderer){
11858 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11860 this.renderer = new Roo.UpdateManager.BasicRenderer();
11863 Roo.UpdateManager.superclass.constructor.call(this);
11866 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11868 * Get the Element this UpdateManager is bound to
11869 * @return {Roo.Element} The element
11871 getEl : function(){
11875 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11876 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11879 url: "your-url.php",<br/>
11880 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11881 callback: yourFunction,<br/>
11882 scope: yourObject, //(optional scope) <br/>
11883 discardUrl: false, <br/>
11884 nocache: false,<br/>
11885 text: "Loading...",<br/>
11887 scripts: false<br/>
11890 * The only required property is url. The optional properties nocache, text and scripts
11891 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11892 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
11893 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11894 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11896 update : function(url, params, callback, discardUrl){
11897 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11898 var method = this.method,
11900 if(typeof url == "object"){ // must be config object
11903 params = params || cfg.params;
11904 callback = callback || cfg.callback;
11905 discardUrl = discardUrl || cfg.discardUrl;
11906 if(callback && cfg.scope){
11907 callback = callback.createDelegate(cfg.scope);
11909 if(typeof cfg.method != "undefined"){method = cfg.method;};
11910 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11911 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11912 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11913 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11915 this.showLoading();
11917 this.defaultUrl = url;
11919 if(typeof url == "function"){
11920 url = url.call(this);
11923 method = method || (params ? "POST" : "GET");
11924 if(method == "GET"){
11925 url = this.prepareUrl(url);
11928 var o = Roo.apply(cfg ||{}, {
11931 success: this.successDelegate,
11932 failure: this.failureDelegate,
11933 callback: undefined,
11934 timeout: (this.timeout*1000),
11935 argument: {"url": url, "form": null, "callback": callback, "params": params}
11937 Roo.log("updated manager called with timeout of " + o.timeout);
11938 this.transaction = Roo.Ajax.request(o);
11943 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11944 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11945 * @param {String/HTMLElement} form The form Id or form element
11946 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11947 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11948 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11950 formUpdate : function(form, url, reset, callback){
11951 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11952 if(typeof url == "function"){
11953 url = url.call(this);
11955 form = Roo.getDom(form);
11956 this.transaction = Roo.Ajax.request({
11959 success: this.successDelegate,
11960 failure: this.failureDelegate,
11961 timeout: (this.timeout*1000),
11962 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11964 this.showLoading.defer(1, this);
11969 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11970 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11972 refresh : function(callback){
11973 if(this.defaultUrl == null){
11976 this.update(this.defaultUrl, null, callback, true);
11980 * Set this element to auto refresh.
11981 * @param {Number} interval How often to update (in seconds).
11982 * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11983 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
11984 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11985 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11987 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11989 this.update(url || this.defaultUrl, params, callback, true);
11991 if(this.autoRefreshProcId){
11992 clearInterval(this.autoRefreshProcId);
11994 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11998 * Stop auto refresh on this element.
12000 stopAutoRefresh : function(){
12001 if(this.autoRefreshProcId){
12002 clearInterval(this.autoRefreshProcId);
12003 delete this.autoRefreshProcId;
12007 isAutoRefreshing : function(){
12008 return this.autoRefreshProcId ? true : false;
12011 * Called to update the element to "Loading" state. Override to perform custom action.
12013 showLoading : function(){
12014 if(this.showLoadIndicator){
12015 this.el.update(this.indicatorText);
12020 * Adds unique parameter to query string if disableCaching = true
12023 prepareUrl : function(url){
12024 if(this.disableCaching){
12025 var append = "_dc=" + (new Date().getTime());
12026 if(url.indexOf("?") !== -1){
12027 url += "&" + append;
12029 url += "?" + append;
12038 processSuccess : function(response){
12039 this.transaction = null;
12040 if(response.argument.form && response.argument.reset){
12041 try{ // put in try/catch since some older FF releases had problems with this
12042 response.argument.form.reset();
12045 if(this.loadScripts){
12046 this.renderer.render(this.el, response, this,
12047 this.updateComplete.createDelegate(this, [response]));
12049 this.renderer.render(this.el, response, this);
12050 this.updateComplete(response);
12054 updateComplete : function(response){
12055 this.fireEvent("update", this.el, response);
12056 if(typeof response.argument.callback == "function"){
12057 response.argument.callback(this.el, true, response);
12064 processFailure : function(response){
12065 this.transaction = null;
12066 this.fireEvent("failure", this.el, response);
12067 if(typeof response.argument.callback == "function"){
12068 response.argument.callback(this.el, false, response);
12073 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12074 * @param {Object} renderer The object implementing the render() method
12076 setRenderer : function(renderer){
12077 this.renderer = renderer;
12080 getRenderer : function(){
12081 return this.renderer;
12085 * Set the defaultUrl used for updates
12086 * @param {String/Function} defaultUrl The url or a function to call to get the url
12088 setDefaultUrl : function(defaultUrl){
12089 this.defaultUrl = defaultUrl;
12093 * Aborts the executing transaction
12095 abort : function(){
12096 if(this.transaction){
12097 Roo.Ajax.abort(this.transaction);
12102 * Returns true if an update is in progress
12103 * @return {Boolean}
12105 isUpdating : function(){
12106 if(this.transaction){
12107 return Roo.Ajax.isLoading(this.transaction);
12114 * @class Roo.UpdateManager.defaults
12115 * @static (not really - but it helps the doc tool)
12116 * The defaults collection enables customizing the default properties of UpdateManager
12118 Roo.UpdateManager.defaults = {
12120 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12126 * True to process scripts by default (Defaults to false).
12129 loadScripts : false,
12132 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12135 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12137 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12140 disableCaching : false,
12142 * Whether to show indicatorText when loading (Defaults to true).
12145 showLoadIndicator : true,
12147 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12150 indicatorText : '<div class="loading-indicator">Loading...</div>'
12154 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12156 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12157 * @param {String/HTMLElement/Roo.Element} el The element to update
12158 * @param {String} url The url
12159 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12160 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12163 * @member Roo.UpdateManager
12165 Roo.UpdateManager.updateElement = function(el, url, params, options){
12166 var um = Roo.get(el, true).getUpdateManager();
12167 Roo.apply(um, options);
12168 um.update(url, params, options ? options.callback : null);
12170 // alias for backwards compat
12171 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12173 * @class Roo.UpdateManager.BasicRenderer
12174 * Default Content renderer. Updates the elements innerHTML with the responseText.
12176 Roo.UpdateManager.BasicRenderer = function(){};
12178 Roo.UpdateManager.BasicRenderer.prototype = {
12180 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12181 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12182 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12183 * @param {Roo.Element} el The element being rendered
12184 * @param {Object} response The YUI Connect response object
12185 * @param {UpdateManager} updateManager The calling update manager
12186 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12188 render : function(el, response, updateManager, callback){
12189 el.update(response.responseText, updateManager.loadScripts, callback);
12195 * (c)) Alan Knowles
12201 * @class Roo.DomTemplate
12202 * @extends Roo.Template
12203 * An effort at a dom based template engine..
12205 * Similar to XTemplate, except it uses dom parsing to create the template..
12207 * Supported features:
12212 {a_variable} - output encoded.
12213 {a_variable.format:("Y-m-d")} - call a method on the variable
12214 {a_variable:raw} - unencoded output
12215 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12216 {a_variable:this.method_on_template(...)} - call a method on the template object.
12221 <div roo-for="a_variable or condition.."></div>
12222 <div roo-if="a_variable or condition"></div>
12223 <div roo-exec="some javascript"></div>
12224 <div roo-name="named_template"></div>
12229 Roo.DomTemplate = function()
12231 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12238 Roo.extend(Roo.DomTemplate, Roo.Template, {
12240 * id counter for sub templates.
12244 * flag to indicate if dom parser is inside a pre,
12245 * it will strip whitespace if not.
12250 * The various sub templates
12258 * basic tag replacing syntax
12261 * // you can fake an object call by doing this
12265 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12266 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12268 iterChild : function (node, method) {
12270 var oldPre = this.inPre;
12271 if (node.tagName == 'PRE') {
12274 for( var i = 0; i < node.childNodes.length; i++) {
12275 method.call(this, node.childNodes[i]);
12277 this.inPre = oldPre;
12283 * compile the template
12285 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12288 compile: function()
12292 // covert the html into DOM...
12296 doc = document.implementation.createHTMLDocument("");
12297 doc.documentElement.innerHTML = this.html ;
12298 div = doc.documentElement;
12300 // old IE... - nasty -- it causes all sorts of issues.. with
12301 // images getting pulled from server..
12302 div = document.createElement('div');
12303 div.innerHTML = this.html;
12305 //doc.documentElement.innerHTML = htmlBody
12311 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12313 var tpls = this.tpls;
12315 // create a top level template from the snippet..
12317 //Roo.log(div.innerHTML);
12324 body : div.innerHTML,
12337 Roo.each(tpls, function(tp){
12338 this.compileTpl(tp);
12339 this.tpls[tp.id] = tp;
12342 this.master = tpls[0];
12348 compileNode : function(node, istop) {
12353 // skip anything not a tag..
12354 if (node.nodeType != 1) {
12355 if (node.nodeType == 3 && !this.inPre) {
12356 // reduce white space..
12357 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12380 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12381 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12382 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12383 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12389 // just itterate children..
12390 this.iterChild(node,this.compileNode);
12393 tpl.uid = this.id++;
12394 tpl.value = node.getAttribute('roo-' + tpl.attr);
12395 node.removeAttribute('roo-'+ tpl.attr);
12396 if (tpl.attr != 'name') {
12397 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12398 node.parentNode.replaceChild(placeholder, node);
12401 var placeholder = document.createElement('span');
12402 placeholder.className = 'roo-tpl-' + tpl.value;
12403 node.parentNode.replaceChild(placeholder, node);
12406 // parent now sees '{domtplXXXX}
12407 this.iterChild(node,this.compileNode);
12409 // we should now have node body...
12410 var div = document.createElement('div');
12411 div.appendChild(node);
12413 // this has the unfortunate side effect of converting tagged attributes
12414 // eg. href="{...}" into %7C...%7D
12415 // this has been fixed by searching for those combo's although it's a bit hacky..
12418 tpl.body = div.innerHTML;
12425 switch (tpl.value) {
12426 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12427 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12428 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12433 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12437 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12441 tpl.id = tpl.value; // replace non characters???
12447 this.tpls.push(tpl);
12457 * Compile a segment of the template into a 'sub-template'
12463 compileTpl : function(tpl)
12465 var fm = Roo.util.Format;
12466 var useF = this.disableFormats !== true;
12468 var sep = Roo.isGecko ? "+\n" : ",\n";
12470 var undef = function(str) {
12471 Roo.debug && Roo.log("Property not found :" + str);
12475 //Roo.log(tpl.body);
12479 var fn = function(m, lbrace, name, format, args)
12482 //Roo.log(arguments);
12483 args = args ? args.replace(/\\'/g,"'") : args;
12484 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12485 if (typeof(format) == 'undefined') {
12486 format = 'htmlEncode';
12488 if (format == 'raw' ) {
12492 if(name.substr(0, 6) == 'domtpl'){
12493 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12496 // build an array of options to determine if value is undefined..
12498 // basically get 'xxxx.yyyy' then do
12499 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12500 // (function () { Roo.log("Property not found"); return ''; })() :
12505 Roo.each(name.split('.'), function(st) {
12506 lookfor += (lookfor.length ? '.': '') + st;
12507 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12510 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12513 if(format && useF){
12515 args = args ? ',' + args : "";
12517 if(format.substr(0, 5) != "this."){
12518 format = "fm." + format + '(';
12520 format = 'this.call("'+ format.substr(5) + '", ';
12524 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12527 if (args && args.length) {
12528 // called with xxyx.yuu:(test,test)
12530 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12532 // raw.. - :raw modifier..
12533 return "'"+ sep + udef_st + name + ")"+sep+"'";
12537 // branched to use + in gecko and [].join() in others
12539 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12540 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12543 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12544 body.push(tpl.body.replace(/(\r\n|\n)/g,
12545 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12546 body.push("'].join('');};};");
12547 body = body.join('');
12550 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12552 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12559 * same as applyTemplate, except it's done to one of the subTemplates
12560 * when using named templates, you can do:
12562 * var str = pl.applySubTemplate('your-name', values);
12565 * @param {Number} id of the template
12566 * @param {Object} values to apply to template
12567 * @param {Object} parent (normaly the instance of this object)
12569 applySubTemplate : function(id, values, parent)
12573 var t = this.tpls[id];
12577 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12578 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12582 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12589 if(t.execCall && t.execCall.call(this, values, parent)){
12593 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12599 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12600 parent = t.target ? values : parent;
12601 if(t.forCall && vs instanceof Array){
12603 for(var i = 0, len = vs.length; i < len; i++){
12605 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12607 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12609 //Roo.log(t.compiled);
12613 return buf.join('');
12616 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12621 return t.compiled.call(this, vs, parent);
12623 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12625 //Roo.log(t.compiled);
12633 applyTemplate : function(values){
12634 return this.master.compiled.call(this, values, {});
12635 //var s = this.subs;
12638 apply : function(){
12639 return this.applyTemplate.apply(this, arguments);
12644 Roo.DomTemplate.from = function(el){
12645 el = Roo.getDom(el);
12646 return new Roo.Domtemplate(el.value || el.innerHTML);
12649 * Ext JS Library 1.1.1
12650 * Copyright(c) 2006-2007, Ext JS, LLC.
12652 * Originally Released Under LGPL - original licence link has changed is not relivant.
12655 * <script type="text/javascript">
12659 * @class Roo.util.DelayedTask
12660 * Provides a convenient method of performing setTimeout where a new
12661 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12662 * You can use this class to buffer
12663 * the keypress events for a certain number of milliseconds, and perform only if they stop
12664 * for that amount of time.
12665 * @constructor The parameters to this constructor serve as defaults and are not required.
12666 * @param {Function} fn (optional) The default function to timeout
12667 * @param {Object} scope (optional) The default scope of that timeout
12668 * @param {Array} args (optional) The default Array of arguments
12670 Roo.util.DelayedTask = function(fn, scope, args){
12671 var id = null, d, t;
12673 var call = function(){
12674 var now = new Date().getTime();
12678 fn.apply(scope, args || []);
12682 * Cancels any pending timeout and queues a new one
12683 * @param {Number} delay The milliseconds to delay
12684 * @param {Function} newFn (optional) Overrides function passed to constructor
12685 * @param {Object} newScope (optional) Overrides scope passed to constructor
12686 * @param {Array} newArgs (optional) Overrides args passed to constructor
12688 this.delay = function(delay, newFn, newScope, newArgs){
12689 if(id && delay != d){
12693 t = new Date().getTime();
12695 scope = newScope || scope;
12696 args = newArgs || args;
12698 id = setInterval(call, d);
12703 * Cancel the last queued timeout
12705 this.cancel = function(){
12713 * Ext JS Library 1.1.1
12714 * Copyright(c) 2006-2007, Ext JS, LLC.
12716 * Originally Released Under LGPL - original licence link has changed is not relivant.
12719 * <script type="text/javascript">
12723 Roo.util.TaskRunner = function(interval){
12724 interval = interval || 10;
12725 var tasks = [], removeQueue = [];
12727 var running = false;
12729 var stopThread = function(){
12735 var startThread = function(){
12738 id = setInterval(runTasks, interval);
12742 var removeTask = function(task){
12743 removeQueue.push(task);
12749 var runTasks = function(){
12750 if(removeQueue.length > 0){
12751 for(var i = 0, len = removeQueue.length; i < len; i++){
12752 tasks.remove(removeQueue[i]);
12755 if(tasks.length < 1){
12760 var now = new Date().getTime();
12761 for(var i = 0, len = tasks.length; i < len; ++i){
12763 var itime = now - t.taskRunTime;
12764 if(t.interval <= itime){
12765 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12766 t.taskRunTime = now;
12767 if(rt === false || t.taskRunCount === t.repeat){
12772 if(t.duration && t.duration <= (now - t.taskStartTime)){
12779 * Queues a new task.
12780 * @param {Object} task
12782 this.start = function(task){
12784 task.taskStartTime = new Date().getTime();
12785 task.taskRunTime = 0;
12786 task.taskRunCount = 0;
12791 this.stop = function(task){
12796 this.stopAll = function(){
12798 for(var i = 0, len = tasks.length; i < len; i++){
12799 if(tasks[i].onStop){
12808 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12810 * Ext JS Library 1.1.1
12811 * Copyright(c) 2006-2007, Ext JS, LLC.
12813 * Originally Released Under LGPL - original licence link has changed is not relivant.
12816 * <script type="text/javascript">
12821 * @class Roo.util.MixedCollection
12822 * @extends Roo.util.Observable
12823 * A Collection class that maintains both numeric indexes and keys and exposes events.
12825 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12826 * collection (defaults to false)
12827 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12828 * and return the key value for that item. This is used when available to look up the key on items that
12829 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12830 * equivalent to providing an implementation for the {@link #getKey} method.
12832 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12840 * Fires when the collection is cleared.
12845 * Fires when an item is added to the collection.
12846 * @param {Number} index The index at which the item was added.
12847 * @param {Object} o The item added.
12848 * @param {String} key The key associated with the added item.
12853 * Fires when an item is replaced in the collection.
12854 * @param {String} key he key associated with the new added.
12855 * @param {Object} old The item being replaced.
12856 * @param {Object} new The new item.
12861 * Fires when an item is removed from the collection.
12862 * @param {Object} o The item being removed.
12863 * @param {String} key (optional) The key associated with the removed item.
12868 this.allowFunctions = allowFunctions === true;
12870 this.getKey = keyFn;
12872 Roo.util.MixedCollection.superclass.constructor.call(this);
12875 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12876 allowFunctions : false,
12879 * Adds an item to the collection.
12880 * @param {String} key The key to associate with the item
12881 * @param {Object} o The item to add.
12882 * @return {Object} The item added.
12884 add : function(key, o){
12885 if(arguments.length == 1){
12887 key = this.getKey(o);
12889 if(typeof key == "undefined" || key === null){
12891 this.items.push(o);
12892 this.keys.push(null);
12894 var old = this.map[key];
12896 return this.replace(key, o);
12899 this.items.push(o);
12901 this.keys.push(key);
12903 this.fireEvent("add", this.length-1, o, key);
12908 * MixedCollection has a generic way to fetch keys if you implement getKey.
12911 var mc = new Roo.util.MixedCollection();
12912 mc.add(someEl.dom.id, someEl);
12913 mc.add(otherEl.dom.id, otherEl);
12917 var mc = new Roo.util.MixedCollection();
12918 mc.getKey = function(el){
12924 // or via the constructor
12925 var mc = new Roo.util.MixedCollection(false, function(el){
12931 * @param o {Object} The item for which to find the key.
12932 * @return {Object} The key for the passed item.
12934 getKey : function(o){
12939 * Replaces an item in the collection.
12940 * @param {String} key The key associated with the item to replace, or the item to replace.
12941 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12942 * @return {Object} The new item.
12944 replace : function(key, o){
12945 if(arguments.length == 1){
12947 key = this.getKey(o);
12949 var old = this.item(key);
12950 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12951 return this.add(key, o);
12953 var index = this.indexOfKey(key);
12954 this.items[index] = o;
12956 this.fireEvent("replace", key, old, o);
12961 * Adds all elements of an Array or an Object to the collection.
12962 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12963 * an Array of values, each of which are added to the collection.
12965 addAll : function(objs){
12966 if(arguments.length > 1 || objs instanceof Array){
12967 var args = arguments.length > 1 ? arguments : objs;
12968 for(var i = 0, len = args.length; i < len; i++){
12972 for(var key in objs){
12973 if(this.allowFunctions || typeof objs[key] != "function"){
12974 this.add(key, objs[key]);
12981 * Executes the specified function once for every item in the collection, passing each
12982 * item as the first and only parameter. returning false from the function will stop the iteration.
12983 * @param {Function} fn The function to execute for each item.
12984 * @param {Object} scope (optional) The scope in which to execute the function.
12986 each : function(fn, scope){
12987 var items = [].concat(this.items); // each safe for removal
12988 for(var i = 0, len = items.length; i < len; i++){
12989 if(fn.call(scope || items[i], items[i], i, len) === false){
12996 * Executes the specified function once for every key in the collection, passing each
12997 * key, and its associated item as the first two parameters.
12998 * @param {Function} fn The function to execute for each item.
12999 * @param {Object} scope (optional) The scope in which to execute the function.
13001 eachKey : function(fn, scope){
13002 for(var i = 0, len = this.keys.length; i < len; i++){
13003 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13008 * Returns the first item in the collection which elicits a true return value from the
13009 * passed selection function.
13010 * @param {Function} fn The selection function to execute for each item.
13011 * @param {Object} scope (optional) The scope in which to execute the function.
13012 * @return {Object} The first item in the collection which returned true from the selection function.
13014 find : function(fn, scope){
13015 for(var i = 0, len = this.items.length; i < len; i++){
13016 if(fn.call(scope || window, this.items[i], this.keys[i])){
13017 return this.items[i];
13024 * Inserts an item at the specified index in the collection.
13025 * @param {Number} index The index to insert the item at.
13026 * @param {String} key The key to associate with the new item, or the item itself.
13027 * @param {Object} o (optional) If the second parameter was a key, the new item.
13028 * @return {Object} The item inserted.
13030 insert : function(index, key, o){
13031 if(arguments.length == 2){
13033 key = this.getKey(o);
13035 if(index >= this.length){
13036 return this.add(key, o);
13039 this.items.splice(index, 0, o);
13040 if(typeof key != "undefined" && key != null){
13043 this.keys.splice(index, 0, key);
13044 this.fireEvent("add", index, o, key);
13049 * Removed an item from the collection.
13050 * @param {Object} o The item to remove.
13051 * @return {Object} The item removed.
13053 remove : function(o){
13054 return this.removeAt(this.indexOf(o));
13058 * Remove an item from a specified index in the collection.
13059 * @param {Number} index The index within the collection of the item to remove.
13061 removeAt : function(index){
13062 if(index < this.length && index >= 0){
13064 var o = this.items[index];
13065 this.items.splice(index, 1);
13066 var key = this.keys[index];
13067 if(typeof key != "undefined"){
13068 delete this.map[key];
13070 this.keys.splice(index, 1);
13071 this.fireEvent("remove", o, key);
13076 * Removed an item associated with the passed key fom the collection.
13077 * @param {String} key The key of the item to remove.
13079 removeKey : function(key){
13080 return this.removeAt(this.indexOfKey(key));
13084 * Returns the number of items in the collection.
13085 * @return {Number} the number of items in the collection.
13087 getCount : function(){
13088 return this.length;
13092 * Returns index within the collection of the passed Object.
13093 * @param {Object} o The item to find the index of.
13094 * @return {Number} index of the item.
13096 indexOf : function(o){
13097 if(!this.items.indexOf){
13098 for(var i = 0, len = this.items.length; i < len; i++){
13099 if(this.items[i] == o) {
13105 return this.items.indexOf(o);
13110 * Returns index within the collection of the passed key.
13111 * @param {String} key The key to find the index of.
13112 * @return {Number} index of the key.
13114 indexOfKey : function(key){
13115 if(!this.keys.indexOf){
13116 for(var i = 0, len = this.keys.length; i < len; i++){
13117 if(this.keys[i] == key) {
13123 return this.keys.indexOf(key);
13128 * Returns the item associated with the passed key OR index. Key has priority over index.
13129 * @param {String/Number} key The key or index of the item.
13130 * @return {Object} The item associated with the passed key.
13132 item : function(key){
13133 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13134 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13138 * Returns the item at the specified index.
13139 * @param {Number} index The index of the item.
13142 itemAt : function(index){
13143 return this.items[index];
13147 * Returns the item associated with the passed key.
13148 * @param {String/Number} key The key of the item.
13149 * @return {Object} The item associated with the passed key.
13151 key : function(key){
13152 return this.map[key];
13156 * Returns true if the collection contains the passed Object as an item.
13157 * @param {Object} o The Object to look for in the collection.
13158 * @return {Boolean} True if the collection contains the Object as an item.
13160 contains : function(o){
13161 return this.indexOf(o) != -1;
13165 * Returns true if the collection contains the passed Object as a key.
13166 * @param {String} key The key to look for in the collection.
13167 * @return {Boolean} True if the collection contains the Object as a key.
13169 containsKey : function(key){
13170 return typeof this.map[key] != "undefined";
13174 * Removes all items from the collection.
13176 clear : function(){
13181 this.fireEvent("clear");
13185 * Returns the first item in the collection.
13186 * @return {Object} the first item in the collection..
13188 first : function(){
13189 return this.items[0];
13193 * Returns the last item in the collection.
13194 * @return {Object} the last item in the collection..
13197 return this.items[this.length-1];
13200 _sort : function(property, dir, fn){
13201 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13202 fn = fn || function(a, b){
13205 var c = [], k = this.keys, items = this.items;
13206 for(var i = 0, len = items.length; i < len; i++){
13207 c[c.length] = {key: k[i], value: items[i], index: i};
13209 c.sort(function(a, b){
13210 var v = fn(a[property], b[property]) * dsc;
13212 v = (a.index < b.index ? -1 : 1);
13216 for(var i = 0, len = c.length; i < len; i++){
13217 items[i] = c[i].value;
13220 this.fireEvent("sort", this);
13224 * Sorts this collection with the passed comparison function
13225 * @param {String} direction (optional) "ASC" or "DESC"
13226 * @param {Function} fn (optional) comparison function
13228 sort : function(dir, fn){
13229 this._sort("value", dir, fn);
13233 * Sorts this collection by keys
13234 * @param {String} direction (optional) "ASC" or "DESC"
13235 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13237 keySort : function(dir, fn){
13238 this._sort("key", dir, fn || function(a, b){
13239 return String(a).toUpperCase()-String(b).toUpperCase();
13244 * Returns a range of items in this collection
13245 * @param {Number} startIndex (optional) defaults to 0
13246 * @param {Number} endIndex (optional) default to the last item
13247 * @return {Array} An array of items
13249 getRange : function(start, end){
13250 var items = this.items;
13251 if(items.length < 1){
13254 start = start || 0;
13255 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13258 for(var i = start; i <= end; i++) {
13259 r[r.length] = items[i];
13262 for(var i = start; i >= end; i--) {
13263 r[r.length] = items[i];
13270 * Filter the <i>objects</i> in this collection by a specific property.
13271 * Returns a new collection that has been filtered.
13272 * @param {String} property A property on your objects
13273 * @param {String/RegExp} value Either string that the property values
13274 * should start with or a RegExp to test against the property
13275 * @return {MixedCollection} The new filtered collection
13277 filter : function(property, value){
13278 if(!value.exec){ // not a regex
13279 value = String(value);
13280 if(value.length == 0){
13281 return this.clone();
13283 value = new RegExp("^" + Roo.escapeRe(value), "i");
13285 return this.filterBy(function(o){
13286 return o && value.test(o[property]);
13291 * Filter by a function. * Returns a new collection that has been filtered.
13292 * The passed function will be called with each
13293 * object in the collection. If the function returns true, the value is included
13294 * otherwise it is filtered.
13295 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13296 * @param {Object} scope (optional) The scope of the function (defaults to this)
13297 * @return {MixedCollection} The new filtered collection
13299 filterBy : function(fn, scope){
13300 var r = new Roo.util.MixedCollection();
13301 r.getKey = this.getKey;
13302 var k = this.keys, it = this.items;
13303 for(var i = 0, len = it.length; i < len; i++){
13304 if(fn.call(scope||this, it[i], k[i])){
13305 r.add(k[i], it[i]);
13312 * Creates a duplicate of this collection
13313 * @return {MixedCollection}
13315 clone : function(){
13316 var r = new Roo.util.MixedCollection();
13317 var k = this.keys, it = this.items;
13318 for(var i = 0, len = it.length; i < len; i++){
13319 r.add(k[i], it[i]);
13321 r.getKey = this.getKey;
13326 * Returns the item associated with the passed key or index.
13328 * @param {String/Number} key The key or index of the item.
13329 * @return {Object} The item associated with the passed key.
13331 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13333 * Ext JS Library 1.1.1
13334 * Copyright(c) 2006-2007, Ext JS, LLC.
13336 * Originally Released Under LGPL - original licence link has changed is not relivant.
13339 * <script type="text/javascript">
13342 * @class Roo.util.JSON
13343 * Modified version of Douglas Crockford"s json.js that doesn"t
13344 * mess with the Object prototype
13345 * http://www.json.org/js.html
13348 Roo.util.JSON = new (function(){
13349 var useHasOwn = {}.hasOwnProperty ? true : false;
13351 // crashes Safari in some instances
13352 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13354 var pad = function(n) {
13355 return n < 10 ? "0" + n : n;
13368 var encodeString = function(s){
13369 if (/["\\\x00-\x1f]/.test(s)) {
13370 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13375 c = b.charCodeAt();
13377 Math.floor(c / 16).toString(16) +
13378 (c % 16).toString(16);
13381 return '"' + s + '"';
13384 var encodeArray = function(o){
13385 var a = ["["], b, i, l = o.length, v;
13386 for (i = 0; i < l; i += 1) {
13388 switch (typeof v) {
13397 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13405 var encodeDate = function(o){
13406 return '"' + o.getFullYear() + "-" +
13407 pad(o.getMonth() + 1) + "-" +
13408 pad(o.getDate()) + "T" +
13409 pad(o.getHours()) + ":" +
13410 pad(o.getMinutes()) + ":" +
13411 pad(o.getSeconds()) + '"';
13415 * Encodes an Object, Array or other value
13416 * @param {Mixed} o The variable to encode
13417 * @return {String} The JSON string
13419 this.encode = function(o)
13421 // should this be extended to fully wrap stringify..
13423 if(typeof o == "undefined" || o === null){
13425 }else if(o instanceof Array){
13426 return encodeArray(o);
13427 }else if(o instanceof Date){
13428 return encodeDate(o);
13429 }else if(typeof o == "string"){
13430 return encodeString(o);
13431 }else if(typeof o == "number"){
13432 return isFinite(o) ? String(o) : "null";
13433 }else if(typeof o == "boolean"){
13436 var a = ["{"], b, i, v;
13438 if(!useHasOwn || o.hasOwnProperty(i)) {
13440 switch (typeof v) {
13449 a.push(this.encode(i), ":",
13450 v === null ? "null" : this.encode(v));
13461 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13462 * @param {String} json The JSON string
13463 * @return {Object} The resulting object
13465 this.decode = function(json){
13467 return /** eval:var:json */ eval("(" + json + ')');
13471 * Shorthand for {@link Roo.util.JSON#encode}
13472 * @member Roo encode
13474 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13476 * Shorthand for {@link Roo.util.JSON#decode}
13477 * @member Roo decode
13479 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13482 * Ext JS Library 1.1.1
13483 * Copyright(c) 2006-2007, Ext JS, LLC.
13485 * Originally Released Under LGPL - original licence link has changed is not relivant.
13488 * <script type="text/javascript">
13492 * @class Roo.util.Format
13493 * Reusable data formatting functions
13496 Roo.util.Format = function(){
13497 var trimRe = /^\s+|\s+$/g;
13500 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13501 * @param {String} value The string to truncate
13502 * @param {Number} length The maximum length to allow before truncating
13503 * @return {String} The converted text
13505 ellipsis : function(value, len){
13506 if(value && value.length > len){
13507 return value.substr(0, len-3)+"...";
13513 * Checks a reference and converts it to empty string if it is undefined
13514 * @param {Mixed} value Reference to check
13515 * @return {Mixed} Empty string if converted, otherwise the original value
13517 undef : function(value){
13518 return typeof value != "undefined" ? value : "";
13522 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13523 * @param {String} value The string to encode
13524 * @return {String} The encoded text
13526 htmlEncode : function(value){
13527 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13531 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13532 * @param {String} value The string to decode
13533 * @return {String} The decoded text
13535 htmlDecode : function(value){
13536 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13540 * Trims any whitespace from either side of a string
13541 * @param {String} value The text to trim
13542 * @return {String} The trimmed text
13544 trim : function(value){
13545 return String(value).replace(trimRe, "");
13549 * Returns a substring from within an original string
13550 * @param {String} value The original text
13551 * @param {Number} start The start index of the substring
13552 * @param {Number} length The length of the substring
13553 * @return {String} The substring
13555 substr : function(value, start, length){
13556 return String(value).substr(start, length);
13560 * Converts a string to all lower case letters
13561 * @param {String} value The text to convert
13562 * @return {String} The converted text
13564 lowercase : function(value){
13565 return String(value).toLowerCase();
13569 * Converts a string to all upper case letters
13570 * @param {String} value The text to convert
13571 * @return {String} The converted text
13573 uppercase : function(value){
13574 return String(value).toUpperCase();
13578 * Converts the first character only of a string to upper case
13579 * @param {String} value The text to convert
13580 * @return {String} The converted text
13582 capitalize : function(value){
13583 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13587 call : function(value, fn){
13588 if(arguments.length > 2){
13589 var args = Array.prototype.slice.call(arguments, 2);
13590 args.unshift(value);
13592 return /** eval:var:value */ eval(fn).apply(window, args);
13594 /** eval:var:value */
13595 return /** eval:var:value */ eval(fn).call(window, value);
13601 * safer version of Math.toFixed..??/
13602 * @param {Number/String} value The numeric value to format
13603 * @param {Number/String} value Decimal places
13604 * @return {String} The formatted currency string
13606 toFixed : function(v, n)
13608 // why not use to fixed - precision is buggered???
13610 return Math.round(v-0);
13612 var fact = Math.pow(10,n+1);
13613 v = (Math.round((v-0)*fact))/fact;
13614 var z = (''+fact).substring(2);
13615 if (v == Math.floor(v)) {
13616 return Math.floor(v) + '.' + z;
13619 // now just padd decimals..
13620 var ps = String(v).split('.');
13621 var fd = (ps[1] + z);
13622 var r = fd.substring(0,n);
13623 var rm = fd.substring(n);
13625 return ps[0] + '.' + r;
13627 r*=1; // turn it into a number;
13629 if (String(r).length != n) {
13632 r = String(r).substring(1); // chop the end off.
13635 return ps[0] + '.' + r;
13640 * Format a number as US currency
13641 * @param {Number/String} value The numeric value to format
13642 * @return {String} The formatted currency string
13644 usMoney : function(v){
13645 return '$' + Roo.util.Format.number(v);
13650 * eventually this should probably emulate php's number_format
13651 * @param {Number/String} value The numeric value to format
13652 * @param {Number} decimals number of decimal places
13653 * @return {String} The formatted currency string
13655 number : function(v,decimals)
13657 // multiply and round.
13658 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13659 var mul = Math.pow(10, decimals);
13660 var zero = String(mul).substring(1);
13661 v = (Math.round((v-0)*mul))/mul;
13663 // if it's '0' number.. then
13665 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13667 var ps = v.split('.');
13671 var r = /(\d+)(\d{3})/;
13673 while (r.test(whole)) {
13674 whole = whole.replace(r, '$1' + ',' + '$2');
13680 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13681 // does not have decimals
13682 (decimals ? ('.' + zero) : '');
13685 return whole + sub ;
13689 * Parse a value into a formatted date using the specified format pattern.
13690 * @param {Mixed} value The value to format
13691 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13692 * @return {String} The formatted date string
13694 date : function(v, format){
13698 if(!(v instanceof Date)){
13699 v = new Date(Date.parse(v));
13701 return v.dateFormat(format || Roo.util.Format.defaults.date);
13705 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13706 * @param {String} format Any valid date format string
13707 * @return {Function} The date formatting function
13709 dateRenderer : function(format){
13710 return function(v){
13711 return Roo.util.Format.date(v, format);
13716 stripTagsRE : /<\/?[^>]+>/gi,
13719 * Strips all HTML tags
13720 * @param {Mixed} value The text from which to strip tags
13721 * @return {String} The stripped text
13723 stripTags : function(v){
13724 return !v ? v : String(v).replace(this.stripTagsRE, "");
13728 Roo.util.Format.defaults = {
13732 * Ext JS Library 1.1.1
13733 * Copyright(c) 2006-2007, Ext JS, LLC.
13735 * Originally Released Under LGPL - original licence link has changed is not relivant.
13738 * <script type="text/javascript">
13745 * @class Roo.MasterTemplate
13746 * @extends Roo.Template
13747 * Provides a template that can have child templates. The syntax is:
13749 var t = new Roo.MasterTemplate(
13750 '<select name="{name}">',
13751 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13754 t.add('options', {value: 'foo', text: 'bar'});
13755 // or you can add multiple child elements in one shot
13756 t.addAll('options', [
13757 {value: 'foo', text: 'bar'},
13758 {value: 'foo2', text: 'bar2'},
13759 {value: 'foo3', text: 'bar3'}
13761 // then append, applying the master template values
13762 t.append('my-form', {name: 'my-select'});
13764 * A name attribute for the child template is not required if you have only one child
13765 * template or you want to refer to them by index.
13767 Roo.MasterTemplate = function(){
13768 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13769 this.originalHtml = this.html;
13771 var m, re = this.subTemplateRe;
13774 while(m = re.exec(this.html)){
13775 var name = m[1], content = m[2];
13780 tpl : new Roo.Template(content)
13783 st[name] = st[subIndex];
13785 st[subIndex].tpl.compile();
13786 st[subIndex].tpl.call = this.call.createDelegate(this);
13789 this.subCount = subIndex;
13792 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13794 * The regular expression used to match sub templates
13798 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13801 * Applies the passed values to a child template.
13802 * @param {String/Number} name (optional) The name or index of the child template
13803 * @param {Array/Object} values The values to be applied to the template
13804 * @return {MasterTemplate} this
13806 add : function(name, values){
13807 if(arguments.length == 1){
13808 values = arguments[0];
13811 var s = this.subs[name];
13812 s.buffer[s.buffer.length] = s.tpl.apply(values);
13817 * Applies all the passed values to a child template.
13818 * @param {String/Number} name (optional) The name or index of the child template
13819 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13820 * @param {Boolean} reset (optional) True to reset the template first
13821 * @return {MasterTemplate} this
13823 fill : function(name, values, reset){
13825 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13833 for(var i = 0, len = values.length; i < len; i++){
13834 this.add(name, values[i]);
13840 * Resets the template for reuse
13841 * @return {MasterTemplate} this
13843 reset : function(){
13845 for(var i = 0; i < this.subCount; i++){
13851 applyTemplate : function(values){
13853 var replaceIndex = -1;
13854 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13855 return s[++replaceIndex].buffer.join("");
13857 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13860 apply : function(){
13861 return this.applyTemplate.apply(this, arguments);
13864 compile : function(){return this;}
13868 * Alias for fill().
13871 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13873 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13874 * var tpl = Roo.MasterTemplate.from('element-id');
13875 * @param {String/HTMLElement} el
13876 * @param {Object} config
13879 Roo.MasterTemplate.from = function(el, config){
13880 el = Roo.getDom(el);
13881 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13884 * Ext JS Library 1.1.1
13885 * Copyright(c) 2006-2007, Ext JS, LLC.
13887 * Originally Released Under LGPL - original licence link has changed is not relivant.
13890 * <script type="text/javascript">
13895 * @class Roo.util.CSS
13896 * Utility class for manipulating CSS rules
13899 Roo.util.CSS = function(){
13901 var doc = document;
13903 var camelRe = /(-[a-z])/gi;
13904 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13908 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13909 * tag and appended to the HEAD of the document.
13910 * @param {String|Object} cssText The text containing the css rules
13911 * @param {String} id An id to add to the stylesheet for later removal
13912 * @return {StyleSheet}
13914 createStyleSheet : function(cssText, id){
13916 var head = doc.getElementsByTagName("head")[0];
13917 var nrules = doc.createElement("style");
13918 nrules.setAttribute("type", "text/css");
13920 nrules.setAttribute("id", id);
13922 if (typeof(cssText) != 'string') {
13923 // support object maps..
13924 // not sure if this a good idea..
13925 // perhaps it should be merged with the general css handling
13926 // and handle js style props.
13927 var cssTextNew = [];
13928 for(var n in cssText) {
13930 for(var k in cssText[n]) {
13931 citems.push( k + ' : ' +cssText[n][k] + ';' );
13933 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13936 cssText = cssTextNew.join("\n");
13942 head.appendChild(nrules);
13943 ss = nrules.styleSheet;
13944 ss.cssText = cssText;
13947 nrules.appendChild(doc.createTextNode(cssText));
13949 nrules.cssText = cssText;
13951 head.appendChild(nrules);
13952 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13954 this.cacheStyleSheet(ss);
13959 * Removes a style or link tag by id
13960 * @param {String} id The id of the tag
13962 removeStyleSheet : function(id){
13963 var existing = doc.getElementById(id);
13965 existing.parentNode.removeChild(existing);
13970 * Dynamically swaps an existing stylesheet reference for a new one
13971 * @param {String} id The id of an existing link tag to remove
13972 * @param {String} url The href of the new stylesheet to include
13974 swapStyleSheet : function(id, url){
13975 this.removeStyleSheet(id);
13976 var ss = doc.createElement("link");
13977 ss.setAttribute("rel", "stylesheet");
13978 ss.setAttribute("type", "text/css");
13979 ss.setAttribute("id", id);
13980 ss.setAttribute("href", url);
13981 doc.getElementsByTagName("head")[0].appendChild(ss);
13985 * Refresh the rule cache if you have dynamically added stylesheets
13986 * @return {Object} An object (hash) of rules indexed by selector
13988 refreshCache : function(){
13989 return this.getRules(true);
13993 cacheStyleSheet : function(stylesheet){
13997 try{// try catch for cross domain access issue
13998 var ssRules = stylesheet.cssRules || stylesheet.rules;
13999 for(var j = ssRules.length-1; j >= 0; --j){
14000 rules[ssRules[j].selectorText] = ssRules[j];
14006 * Gets all css rules for the document
14007 * @param {Boolean} refreshCache true to refresh the internal cache
14008 * @return {Object} An object (hash) of rules indexed by selector
14010 getRules : function(refreshCache){
14011 if(rules == null || refreshCache){
14013 var ds = doc.styleSheets;
14014 for(var i =0, len = ds.length; i < len; i++){
14016 this.cacheStyleSheet(ds[i]);
14024 * Gets an an individual CSS rule by selector(s)
14025 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14026 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14027 * @return {CSSRule} The CSS rule or null if one is not found
14029 getRule : function(selector, refreshCache){
14030 var rs = this.getRules(refreshCache);
14031 if(!(selector instanceof Array)){
14032 return rs[selector];
14034 for(var i = 0; i < selector.length; i++){
14035 if(rs[selector[i]]){
14036 return rs[selector[i]];
14044 * Updates a rule property
14045 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14046 * @param {String} property The css property
14047 * @param {String} value The new value for the property
14048 * @return {Boolean} true If a rule was found and updated
14050 updateRule : function(selector, property, value){
14051 if(!(selector instanceof Array)){
14052 var rule = this.getRule(selector);
14054 rule.style[property.replace(camelRe, camelFn)] = value;
14058 for(var i = 0; i < selector.length; i++){
14059 if(this.updateRule(selector[i], property, value)){
14069 * Ext JS Library 1.1.1
14070 * Copyright(c) 2006-2007, Ext JS, LLC.
14072 * Originally Released Under LGPL - original licence link has changed is not relivant.
14075 * <script type="text/javascript">
14081 * @class Roo.util.ClickRepeater
14082 * @extends Roo.util.Observable
14084 * A wrapper class which can be applied to any element. Fires a "click" event while the
14085 * mouse is pressed. The interval between firings may be specified in the config but
14086 * defaults to 10 milliseconds.
14088 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14090 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14091 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14092 * Similar to an autorepeat key delay.
14093 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14094 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14095 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14096 * "interval" and "delay" are ignored. "immediate" is honored.
14097 * @cfg {Boolean} preventDefault True to prevent the default click event
14098 * @cfg {Boolean} stopDefault True to stop the default click event
14101 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14102 * 2007-02-02 jvs Renamed to ClickRepeater
14103 * 2007-02-03 jvs Modifications for FF Mac and Safari
14106 * @param {String/HTMLElement/Element} el The element to listen on
14107 * @param {Object} config
14109 Roo.util.ClickRepeater = function(el, config)
14111 this.el = Roo.get(el);
14112 this.el.unselectable();
14114 Roo.apply(this, config);
14119 * Fires when the mouse button is depressed.
14120 * @param {Roo.util.ClickRepeater} this
14122 "mousedown" : true,
14125 * Fires on a specified interval during the time the element is pressed.
14126 * @param {Roo.util.ClickRepeater} this
14131 * Fires when the mouse key is released.
14132 * @param {Roo.util.ClickRepeater} this
14137 this.el.on("mousedown", this.handleMouseDown, this);
14138 if(this.preventDefault || this.stopDefault){
14139 this.el.on("click", function(e){
14140 if(this.preventDefault){
14141 e.preventDefault();
14143 if(this.stopDefault){
14149 // allow inline handler
14151 this.on("click", this.handler, this.scope || this);
14154 Roo.util.ClickRepeater.superclass.constructor.call(this);
14157 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14160 preventDefault : true,
14161 stopDefault : false,
14165 handleMouseDown : function(){
14166 clearTimeout(this.timer);
14168 if(this.pressClass){
14169 this.el.addClass(this.pressClass);
14171 this.mousedownTime = new Date();
14173 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14174 this.el.on("mouseout", this.handleMouseOut, this);
14176 this.fireEvent("mousedown", this);
14177 this.fireEvent("click", this);
14179 this.timer = this.click.defer(this.delay || this.interval, this);
14183 click : function(){
14184 this.fireEvent("click", this);
14185 this.timer = this.click.defer(this.getInterval(), this);
14189 getInterval: function(){
14190 if(!this.accelerate){
14191 return this.interval;
14193 var pressTime = this.mousedownTime.getElapsed();
14194 if(pressTime < 500){
14196 }else if(pressTime < 1700){
14198 }else if(pressTime < 2600){
14200 }else if(pressTime < 3500){
14202 }else if(pressTime < 4400){
14204 }else if(pressTime < 5300){
14206 }else if(pressTime < 6200){
14214 handleMouseOut : function(){
14215 clearTimeout(this.timer);
14216 if(this.pressClass){
14217 this.el.removeClass(this.pressClass);
14219 this.el.on("mouseover", this.handleMouseReturn, this);
14223 handleMouseReturn : function(){
14224 this.el.un("mouseover", this.handleMouseReturn);
14225 if(this.pressClass){
14226 this.el.addClass(this.pressClass);
14232 handleMouseUp : function(){
14233 clearTimeout(this.timer);
14234 this.el.un("mouseover", this.handleMouseReturn);
14235 this.el.un("mouseout", this.handleMouseOut);
14236 Roo.get(document).un("mouseup", this.handleMouseUp);
14237 this.el.removeClass(this.pressClass);
14238 this.fireEvent("mouseup", this);
14242 * Ext JS Library 1.1.1
14243 * Copyright(c) 2006-2007, Ext JS, LLC.
14245 * Originally Released Under LGPL - original licence link has changed is not relivant.
14248 * <script type="text/javascript">
14253 * @class Roo.KeyNav
14254 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14255 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14256 * way to implement custom navigation schemes for any UI component.</p>
14257 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14258 * pageUp, pageDown, del, home, end. Usage:</p>
14260 var nav = new Roo.KeyNav("my-element", {
14261 "left" : function(e){
14262 this.moveLeft(e.ctrlKey);
14264 "right" : function(e){
14265 this.moveRight(e.ctrlKey);
14267 "enter" : function(e){
14274 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14275 * @param {Object} config The config
14277 Roo.KeyNav = function(el, config){
14278 this.el = Roo.get(el);
14279 Roo.apply(this, config);
14280 if(!this.disabled){
14281 this.disabled = true;
14286 Roo.KeyNav.prototype = {
14288 * @cfg {Boolean} disabled
14289 * True to disable this KeyNav instance (defaults to false)
14293 * @cfg {String} defaultEventAction
14294 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14295 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14296 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14298 defaultEventAction: "stopEvent",
14300 * @cfg {Boolean} forceKeyDown
14301 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14302 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14303 * handle keydown instead of keypress.
14305 forceKeyDown : false,
14308 prepareEvent : function(e){
14309 var k = e.getKey();
14310 var h = this.keyToHandler[k];
14311 //if(h && this[h]){
14312 // e.stopPropagation();
14314 if(Roo.isSafari && h && k >= 37 && k <= 40){
14320 relay : function(e){
14321 var k = e.getKey();
14322 var h = this.keyToHandler[k];
14324 if(this.doRelay(e, this[h], h) !== true){
14325 e[this.defaultEventAction]();
14331 doRelay : function(e, h, hname){
14332 return h.call(this.scope || this, e);
14335 // possible handlers
14349 // quick lookup hash
14366 * Enable this KeyNav
14368 enable: function(){
14370 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14371 // the EventObject will normalize Safari automatically
14372 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14373 this.el.on("keydown", this.relay, this);
14375 this.el.on("keydown", this.prepareEvent, this);
14376 this.el.on("keypress", this.relay, this);
14378 this.disabled = false;
14383 * Disable this KeyNav
14385 disable: function(){
14386 if(!this.disabled){
14387 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14388 this.el.un("keydown", this.relay);
14390 this.el.un("keydown", this.prepareEvent);
14391 this.el.un("keypress", this.relay);
14393 this.disabled = true;
14398 * Ext JS Library 1.1.1
14399 * Copyright(c) 2006-2007, Ext JS, LLC.
14401 * Originally Released Under LGPL - original licence link has changed is not relivant.
14404 * <script type="text/javascript">
14409 * @class Roo.KeyMap
14410 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14411 * The constructor accepts the same config object as defined by {@link #addBinding}.
14412 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14413 * combination it will call the function with this signature (if the match is a multi-key
14414 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14415 * A KeyMap can also handle a string representation of keys.<br />
14418 // map one key by key code
14419 var map = new Roo.KeyMap("my-element", {
14420 key: 13, // or Roo.EventObject.ENTER
14425 // map multiple keys to one action by string
14426 var map = new Roo.KeyMap("my-element", {
14432 // map multiple keys to multiple actions by strings and array of codes
14433 var map = new Roo.KeyMap("my-element", [
14436 fn: function(){ alert("Return was pressed"); }
14439 fn: function(){ alert('a, b or c was pressed'); }
14444 fn: function(){ alert('Control + shift + tab was pressed.'); }
14448 * <b>Note: A KeyMap starts enabled</b>
14450 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14451 * @param {Object} config The config (see {@link #addBinding})
14452 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14454 Roo.KeyMap = function(el, config, eventName){
14455 this.el = Roo.get(el);
14456 this.eventName = eventName || "keydown";
14457 this.bindings = [];
14459 this.addBinding(config);
14464 Roo.KeyMap.prototype = {
14466 * True to stop the event from bubbling and prevent the default browser action if the
14467 * key was handled by the KeyMap (defaults to false)
14473 * Add a new binding to this KeyMap. The following config object properties are supported:
14475 Property Type Description
14476 ---------- --------------- ----------------------------------------------------------------------
14477 key String/Array A single keycode or an array of keycodes to handle
14478 shift Boolean True to handle key only when shift is pressed (defaults to false)
14479 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14480 alt Boolean True to handle key only when alt is pressed (defaults to false)
14481 fn Function The function to call when KeyMap finds the expected key combination
14482 scope Object The scope of the callback function
14488 var map = new Roo.KeyMap(document, {
14489 key: Roo.EventObject.ENTER,
14494 //Add a new binding to the existing KeyMap later
14502 * @param {Object/Array} config A single KeyMap config or an array of configs
14504 addBinding : function(config){
14505 if(config instanceof Array){
14506 for(var i = 0, len = config.length; i < len; i++){
14507 this.addBinding(config[i]);
14511 var keyCode = config.key,
14512 shift = config.shift,
14513 ctrl = config.ctrl,
14516 scope = config.scope;
14517 if(typeof keyCode == "string"){
14519 var keyString = keyCode.toUpperCase();
14520 for(var j = 0, len = keyString.length; j < len; j++){
14521 ks.push(keyString.charCodeAt(j));
14525 var keyArray = keyCode instanceof Array;
14526 var handler = function(e){
14527 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14528 var k = e.getKey();
14530 for(var i = 0, len = keyCode.length; i < len; i++){
14531 if(keyCode[i] == k){
14532 if(this.stopEvent){
14535 fn.call(scope || window, k, e);
14541 if(this.stopEvent){
14544 fn.call(scope || window, k, e);
14549 this.bindings.push(handler);
14553 * Shorthand for adding a single key listener
14554 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14555 * following options:
14556 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14557 * @param {Function} fn The function to call
14558 * @param {Object} scope (optional) The scope of the function
14560 on : function(key, fn, scope){
14561 var keyCode, shift, ctrl, alt;
14562 if(typeof key == "object" && !(key instanceof Array)){
14581 handleKeyDown : function(e){
14582 if(this.enabled){ //just in case
14583 var b = this.bindings;
14584 for(var i = 0, len = b.length; i < len; i++){
14585 b[i].call(this, e);
14591 * Returns true if this KeyMap is enabled
14592 * @return {Boolean}
14594 isEnabled : function(){
14595 return this.enabled;
14599 * Enables this KeyMap
14601 enable: function(){
14603 this.el.on(this.eventName, this.handleKeyDown, this);
14604 this.enabled = true;
14609 * Disable this KeyMap
14611 disable: function(){
14613 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14614 this.enabled = false;
14619 * Ext JS Library 1.1.1
14620 * Copyright(c) 2006-2007, Ext JS, LLC.
14622 * Originally Released Under LGPL - original licence link has changed is not relivant.
14625 * <script type="text/javascript">
14630 * @class Roo.util.TextMetrics
14631 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14632 * wide, in pixels, a given block of text will be.
14635 Roo.util.TextMetrics = function(){
14639 * Measures the size of the specified text
14640 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14641 * that can affect the size of the rendered text
14642 * @param {String} text The text to measure
14643 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14644 * in order to accurately measure the text height
14645 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14647 measure : function(el, text, fixedWidth){
14649 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14652 shared.setFixedWidth(fixedWidth || 'auto');
14653 return shared.getSize(text);
14657 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14658 * the overhead of multiple calls to initialize the style properties on each measurement.
14659 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14660 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14661 * in order to accurately measure the text height
14662 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14664 createInstance : function(el, fixedWidth){
14665 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14672 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14673 var ml = new Roo.Element(document.createElement('div'));
14674 document.body.appendChild(ml.dom);
14675 ml.position('absolute');
14676 ml.setLeftTop(-1000, -1000);
14680 ml.setWidth(fixedWidth);
14685 * Returns the size of the specified text based on the internal element's style and width properties
14686 * @memberOf Roo.util.TextMetrics.Instance#
14687 * @param {String} text The text to measure
14688 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14690 getSize : function(text){
14692 var s = ml.getSize();
14698 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14699 * that can affect the size of the rendered text
14700 * @memberOf Roo.util.TextMetrics.Instance#
14701 * @param {String/HTMLElement} el The element, dom node or id
14703 bind : function(el){
14705 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14710 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14711 * to set a fixed width in order to accurately measure the text height.
14712 * @memberOf Roo.util.TextMetrics.Instance#
14713 * @param {Number} width The width to set on the element
14715 setFixedWidth : function(width){
14716 ml.setWidth(width);
14720 * Returns the measured width of the specified text
14721 * @memberOf Roo.util.TextMetrics.Instance#
14722 * @param {String} text The text to measure
14723 * @return {Number} width The width in pixels
14725 getWidth : function(text){
14726 ml.dom.style.width = 'auto';
14727 return this.getSize(text).width;
14731 * Returns the measured height of the specified text. For multiline text, be sure to call
14732 * {@link #setFixedWidth} if necessary.
14733 * @memberOf Roo.util.TextMetrics.Instance#
14734 * @param {String} text The text to measure
14735 * @return {Number} height The height in pixels
14737 getHeight : function(text){
14738 return this.getSize(text).height;
14742 instance.bind(bindTo);
14747 // backwards compat
14748 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14750 * Ext JS Library 1.1.1
14751 * Copyright(c) 2006-2007, Ext JS, LLC.
14753 * Originally Released Under LGPL - original licence link has changed is not relivant.
14756 * <script type="text/javascript">
14760 * @class Roo.state.Provider
14761 * Abstract base class for state provider implementations. This class provides methods
14762 * for encoding and decoding <b>typed</b> variables including dates and defines the
14763 * Provider interface.
14765 Roo.state.Provider = function(){
14767 * @event statechange
14768 * Fires when a state change occurs.
14769 * @param {Provider} this This state provider
14770 * @param {String} key The state key which was changed
14771 * @param {String} value The encoded value for the state
14774 "statechange": true
14777 Roo.state.Provider.superclass.constructor.call(this);
14779 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14781 * Returns the current value for a key
14782 * @param {String} name The key name
14783 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14784 * @return {Mixed} The state data
14786 get : function(name, defaultValue){
14787 return typeof this.state[name] == "undefined" ?
14788 defaultValue : this.state[name];
14792 * Clears a value from the state
14793 * @param {String} name The key name
14795 clear : function(name){
14796 delete this.state[name];
14797 this.fireEvent("statechange", this, name, null);
14801 * Sets the value for a key
14802 * @param {String} name The key name
14803 * @param {Mixed} value The value to set
14805 set : function(name, value){
14806 this.state[name] = value;
14807 this.fireEvent("statechange", this, name, value);
14811 * Decodes a string previously encoded with {@link #encodeValue}.
14812 * @param {String} value The value to decode
14813 * @return {Mixed} The decoded value
14815 decodeValue : function(cookie){
14816 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14817 var matches = re.exec(unescape(cookie));
14818 if(!matches || !matches[1]) {
14819 return; // non state cookie
14821 var type = matches[1];
14822 var v = matches[2];
14825 return parseFloat(v);
14827 return new Date(Date.parse(v));
14832 var values = v.split("^");
14833 for(var i = 0, len = values.length; i < len; i++){
14834 all.push(this.decodeValue(values[i]));
14839 var values = v.split("^");
14840 for(var i = 0, len = values.length; i < len; i++){
14841 var kv = values[i].split("=");
14842 all[kv[0]] = this.decodeValue(kv[1]);
14851 * Encodes a value including type information. Decode with {@link #decodeValue}.
14852 * @param {Mixed} value The value to encode
14853 * @return {String} The encoded value
14855 encodeValue : function(v){
14857 if(typeof v == "number"){
14859 }else if(typeof v == "boolean"){
14860 enc = "b:" + (v ? "1" : "0");
14861 }else if(v instanceof Date){
14862 enc = "d:" + v.toGMTString();
14863 }else if(v instanceof Array){
14865 for(var i = 0, len = v.length; i < len; i++){
14866 flat += this.encodeValue(v[i]);
14872 }else if(typeof v == "object"){
14875 if(typeof v[key] != "function"){
14876 flat += key + "=" + this.encodeValue(v[key]) + "^";
14879 enc = "o:" + flat.substring(0, flat.length-1);
14883 return escape(enc);
14889 * Ext JS Library 1.1.1
14890 * Copyright(c) 2006-2007, Ext JS, LLC.
14892 * Originally Released Under LGPL - original licence link has changed is not relivant.
14895 * <script type="text/javascript">
14898 * @class Roo.state.Manager
14899 * This is the global state manager. By default all components that are "state aware" check this class
14900 * for state information if you don't pass them a custom state provider. In order for this class
14901 * to be useful, it must be initialized with a provider when your application initializes.
14903 // in your initialization function
14905 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14907 // supposed you have a {@link Roo.BorderLayout}
14908 var layout = new Roo.BorderLayout(...);
14909 layout.restoreState();
14910 // or a {Roo.BasicDialog}
14911 var dialog = new Roo.BasicDialog(...);
14912 dialog.restoreState();
14916 Roo.state.Manager = function(){
14917 var provider = new Roo.state.Provider();
14921 * Configures the default state provider for your application
14922 * @param {Provider} stateProvider The state provider to set
14924 setProvider : function(stateProvider){
14925 provider = stateProvider;
14929 * Returns the current value for a key
14930 * @param {String} name The key name
14931 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14932 * @return {Mixed} The state data
14934 get : function(key, defaultValue){
14935 return provider.get(key, defaultValue);
14939 * Sets the value for a key
14940 * @param {String} name The key name
14941 * @param {Mixed} value The state data
14943 set : function(key, value){
14944 provider.set(key, value);
14948 * Clears a value from the state
14949 * @param {String} name The key name
14951 clear : function(key){
14952 provider.clear(key);
14956 * Gets the currently configured state provider
14957 * @return {Provider} The state provider
14959 getProvider : function(){
14966 * Ext JS Library 1.1.1
14967 * Copyright(c) 2006-2007, Ext JS, LLC.
14969 * Originally Released Under LGPL - original licence link has changed is not relivant.
14972 * <script type="text/javascript">
14975 * @class Roo.state.CookieProvider
14976 * @extends Roo.state.Provider
14977 * The default Provider implementation which saves state via cookies.
14980 var cp = new Roo.state.CookieProvider({
14982 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14983 domain: "roojs.com"
14985 Roo.state.Manager.setProvider(cp);
14987 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14988 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14989 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14990 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14991 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14992 * domain the page is running on including the 'www' like 'www.roojs.com')
14993 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14995 * Create a new CookieProvider
14996 * @param {Object} config The configuration object
14998 Roo.state.CookieProvider = function(config){
14999 Roo.state.CookieProvider.superclass.constructor.call(this);
15001 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15002 this.domain = null;
15003 this.secure = false;
15004 Roo.apply(this, config);
15005 this.state = this.readCookies();
15008 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15010 set : function(name, value){
15011 if(typeof value == "undefined" || value === null){
15015 this.setCookie(name, value);
15016 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15020 clear : function(name){
15021 this.clearCookie(name);
15022 Roo.state.CookieProvider.superclass.clear.call(this, name);
15026 readCookies : function(){
15028 var c = document.cookie + ";";
15029 var re = /\s?(.*?)=(.*?);/g;
15031 while((matches = re.exec(c)) != null){
15032 var name = matches[1];
15033 var value = matches[2];
15034 if(name && name.substring(0,3) == "ys-"){
15035 cookies[name.substr(3)] = this.decodeValue(value);
15042 setCookie : function(name, value){
15043 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15044 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15045 ((this.path == null) ? "" : ("; path=" + this.path)) +
15046 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15047 ((this.secure == true) ? "; secure" : "");
15051 clearCookie : function(name){
15052 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15053 ((this.path == null) ? "" : ("; path=" + this.path)) +
15054 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15055 ((this.secure == true) ? "; secure" : "");
15059 * Ext JS Library 1.1.1
15060 * Copyright(c) 2006-2007, Ext JS, LLC.
15062 * Originally Released Under LGPL - original licence link has changed is not relivant.
15065 * <script type="text/javascript">
15070 * @class Roo.ComponentMgr
15071 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15074 Roo.ComponentMgr = function(){
15075 var all = new Roo.util.MixedCollection();
15079 * Registers a component.
15080 * @param {Roo.Component} c The component
15082 register : function(c){
15087 * Unregisters a component.
15088 * @param {Roo.Component} c The component
15090 unregister : function(c){
15095 * Returns a component by id
15096 * @param {String} id The component id
15098 get : function(id){
15099 return all.get(id);
15103 * Registers a function that will be called when a specified component is added to ComponentMgr
15104 * @param {String} id The component id
15105 * @param {Funtction} fn The callback function
15106 * @param {Object} scope The scope of the callback
15108 onAvailable : function(id, fn, scope){
15109 all.on("add", function(index, o){
15111 fn.call(scope || o, o);
15112 all.un("add", fn, scope);
15119 * Ext JS Library 1.1.1
15120 * Copyright(c) 2006-2007, Ext JS, LLC.
15122 * Originally Released Under LGPL - original licence link has changed is not relivant.
15125 * <script type="text/javascript">
15129 * @class Roo.Component
15130 * @extends Roo.util.Observable
15131 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15132 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15133 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15134 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15135 * All visual components (widgets) that require rendering into a layout should subclass Component.
15137 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15138 * element and its id used as the component id. If a string is passed, it is assumed to be the id of an existing element
15139 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15141 Roo.Component = function(config){
15142 config = config || {};
15143 if(config.tagName || config.dom || typeof config == "string"){ // element object
15144 config = {el: config, id: config.id || config};
15146 this.initialConfig = config;
15148 Roo.apply(this, config);
15152 * Fires after the component is disabled.
15153 * @param {Roo.Component} this
15158 * Fires after the component is enabled.
15159 * @param {Roo.Component} this
15163 * @event beforeshow
15164 * Fires before the component is shown. Return false to stop the show.
15165 * @param {Roo.Component} this
15170 * Fires after the component is shown.
15171 * @param {Roo.Component} this
15175 * @event beforehide
15176 * Fires before the component is hidden. Return false to stop the hide.
15177 * @param {Roo.Component} this
15182 * Fires after the component is hidden.
15183 * @param {Roo.Component} this
15187 * @event beforerender
15188 * Fires before the component is rendered. Return false to stop the render.
15189 * @param {Roo.Component} this
15191 beforerender : true,
15194 * Fires after the component is rendered.
15195 * @param {Roo.Component} this
15199 * @event beforedestroy
15200 * Fires before the component is destroyed. Return false to stop the destroy.
15201 * @param {Roo.Component} this
15203 beforedestroy : true,
15206 * Fires after the component is destroyed.
15207 * @param {Roo.Component} this
15212 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15214 Roo.ComponentMgr.register(this);
15215 Roo.Component.superclass.constructor.call(this);
15216 this.initComponent();
15217 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15218 this.render(this.renderTo);
15219 delete this.renderTo;
15224 Roo.Component.AUTO_ID = 1000;
15226 Roo.extend(Roo.Component, Roo.util.Observable, {
15228 * @scope Roo.Component.prototype
15230 * true if this component is hidden. Read-only.
15235 * true if this component is disabled. Read-only.
15240 * true if this component has been rendered. Read-only.
15244 /** @cfg {String} disableClass
15245 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15247 disabledClass : "x-item-disabled",
15248 /** @cfg {Boolean} allowDomMove
15249 * Whether the component can move the Dom node when rendering (defaults to true).
15251 allowDomMove : true,
15252 /** @cfg {String} hideMode (display|visibility)
15253 * How this component should hidden. Supported values are
15254 * "visibility" (css visibility), "offsets" (negative offset position) and
15255 * "display" (css display) - defaults to "display".
15257 hideMode: 'display',
15260 ctype : "Roo.Component",
15263 * @cfg {String} actionMode
15264 * which property holds the element that used for hide() / show() / disable() / enable()
15270 getActionEl : function(){
15271 return this[this.actionMode];
15274 initComponent : Roo.emptyFn,
15276 * If this is a lazy rendering component, render it to its container element.
15277 * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
15279 render : function(container, position){
15280 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15281 if(!container && this.el){
15282 this.el = Roo.get(this.el);
15283 container = this.el.dom.parentNode;
15284 this.allowDomMove = false;
15286 this.container = Roo.get(container);
15287 this.rendered = true;
15288 if(position !== undefined){
15289 if(typeof position == 'number'){
15290 position = this.container.dom.childNodes[position];
15292 position = Roo.getDom(position);
15295 this.onRender(this.container, position || null);
15297 this.el.addClass(this.cls);
15301 this.el.applyStyles(this.style);
15304 this.fireEvent("render", this);
15305 this.afterRender(this.container);
15317 // default function is not really useful
15318 onRender : function(ct, position){
15320 this.el = Roo.get(this.el);
15321 if(this.allowDomMove !== false){
15322 ct.dom.insertBefore(this.el.dom, position);
15328 getAutoCreate : function(){
15329 var cfg = typeof this.autoCreate == "object" ?
15330 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15331 if(this.id && !cfg.id){
15338 afterRender : Roo.emptyFn,
15341 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15342 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15344 destroy : function(){
15345 if(this.fireEvent("beforedestroy", this) !== false){
15346 this.purgeListeners();
15347 this.beforeDestroy();
15349 this.el.removeAllListeners();
15351 if(this.actionMode == "container"){
15352 this.container.remove();
15356 Roo.ComponentMgr.unregister(this);
15357 this.fireEvent("destroy", this);
15362 beforeDestroy : function(){
15367 onDestroy : function(){
15372 * Returns the underlying {@link Roo.Element}.
15373 * @return {Roo.Element} The element
15375 getEl : function(){
15380 * Returns the id of this component.
15383 getId : function(){
15388 * Try to focus this component.
15389 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15390 * @return {Roo.Component} this
15392 focus : function(selectText){
15395 if(selectText === true){
15396 this.el.dom.select();
15411 * Disable this component.
15412 * @return {Roo.Component} this
15414 disable : function(){
15418 this.disabled = true;
15419 this.fireEvent("disable", this);
15424 onDisable : function(){
15425 this.getActionEl().addClass(this.disabledClass);
15426 this.el.dom.disabled = true;
15430 * Enable this component.
15431 * @return {Roo.Component} this
15433 enable : function(){
15437 this.disabled = false;
15438 this.fireEvent("enable", this);
15443 onEnable : function(){
15444 this.getActionEl().removeClass(this.disabledClass);
15445 this.el.dom.disabled = false;
15449 * Convenience function for setting disabled/enabled by boolean.
15450 * @param {Boolean} disabled
15452 setDisabled : function(disabled){
15453 this[disabled ? "disable" : "enable"]();
15457 * Show this component.
15458 * @return {Roo.Component} this
15461 if(this.fireEvent("beforeshow", this) !== false){
15462 this.hidden = false;
15466 this.fireEvent("show", this);
15472 onShow : function(){
15473 var ae = this.getActionEl();
15474 if(this.hideMode == 'visibility'){
15475 ae.dom.style.visibility = "visible";
15476 }else if(this.hideMode == 'offsets'){
15477 ae.removeClass('x-hidden');
15479 ae.dom.style.display = "";
15484 * Hide this component.
15485 * @return {Roo.Component} this
15488 if(this.fireEvent("beforehide", this) !== false){
15489 this.hidden = true;
15493 this.fireEvent("hide", this);
15499 onHide : function(){
15500 var ae = this.getActionEl();
15501 if(this.hideMode == 'visibility'){
15502 ae.dom.style.visibility = "hidden";
15503 }else if(this.hideMode == 'offsets'){
15504 ae.addClass('x-hidden');
15506 ae.dom.style.display = "none";
15511 * Convenience function to hide or show this component by boolean.
15512 * @param {Boolean} visible True to show, false to hide
15513 * @return {Roo.Component} this
15515 setVisible: function(visible){
15525 * Returns true if this component is visible.
15527 isVisible : function(){
15528 return this.getActionEl().isVisible();
15531 cloneConfig : function(overrides){
15532 overrides = overrides || {};
15533 var id = overrides.id || Roo.id();
15534 var cfg = Roo.applyIf(overrides, this.initialConfig);
15535 cfg.id = id; // prevent dup id
15536 return new this.constructor(cfg);
15540 * Ext JS Library 1.1.1
15541 * Copyright(c) 2006-2007, Ext JS, LLC.
15543 * Originally Released Under LGPL - original licence link has changed is not relivant.
15546 * <script type="text/javascript">
15550 * @class Roo.BoxComponent
15551 * @extends Roo.Component
15552 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15553 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15554 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15555 * layout containers.
15557 * @param {Roo.Element/String/Object} config The configuration options.
15559 Roo.BoxComponent = function(config){
15560 Roo.Component.call(this, config);
15564 * Fires after the component is resized.
15565 * @param {Roo.Component} this
15566 * @param {Number} adjWidth The box-adjusted width that was set
15567 * @param {Number} adjHeight The box-adjusted height that was set
15568 * @param {Number} rawWidth The width that was originally specified
15569 * @param {Number} rawHeight The height that was originally specified
15574 * Fires after the component is moved.
15575 * @param {Roo.Component} this
15576 * @param {Number} x The new x position
15577 * @param {Number} y The new y position
15583 Roo.extend(Roo.BoxComponent, Roo.Component, {
15584 // private, set in afterRender to signify that the component has been rendered
15586 // private, used to defer height settings to subclasses
15587 deferHeight: false,
15588 /** @cfg {Number} width
15589 * width (optional) size of component
15591 /** @cfg {Number} height
15592 * height (optional) size of component
15596 * Sets the width and height of the component. This method fires the resize event. This method can accept
15597 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15598 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15599 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15600 * @return {Roo.BoxComponent} this
15602 setSize : function(w, h){
15603 // support for standard size objects
15604 if(typeof w == 'object'){
15609 if(!this.boxReady){
15615 // prevent recalcs when not needed
15616 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15619 this.lastSize = {width: w, height: h};
15621 var adj = this.adjustSize(w, h);
15622 var aw = adj.width, ah = adj.height;
15623 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15624 var rz = this.getResizeEl();
15625 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15626 rz.setSize(aw, ah);
15627 }else if(!this.deferHeight && ah !== undefined){
15629 }else if(aw !== undefined){
15632 this.onResize(aw, ah, w, h);
15633 this.fireEvent('resize', this, aw, ah, w, h);
15639 * Gets the current size of the component's underlying element.
15640 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15642 getSize : function(){
15643 return this.el.getSize();
15647 * Gets the current XY position of the component's underlying element.
15648 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15649 * @return {Array} The XY position of the element (e.g., [100, 200])
15651 getPosition : function(local){
15652 if(local === true){
15653 return [this.el.getLeft(true), this.el.getTop(true)];
15655 return this.xy || this.el.getXY();
15659 * Gets the current box measurements of the component's underlying element.
15660 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15661 * @returns {Object} box An object in the format {x, y, width, height}
15663 getBox : function(local){
15664 var s = this.el.getSize();
15666 s.x = this.el.getLeft(true);
15667 s.y = this.el.getTop(true);
15669 var xy = this.xy || this.el.getXY();
15677 * Sets the current box measurements of the component's underlying element.
15678 * @param {Object} box An object in the format {x, y, width, height}
15679 * @returns {Roo.BoxComponent} this
15681 updateBox : function(box){
15682 this.setSize(box.width, box.height);
15683 this.setPagePosition(box.x, box.y);
15688 getResizeEl : function(){
15689 return this.resizeEl || this.el;
15693 getPositionEl : function(){
15694 return this.positionEl || this.el;
15698 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15699 * This method fires the move event.
15700 * @param {Number} left The new left
15701 * @param {Number} top The new top
15702 * @returns {Roo.BoxComponent} this
15704 setPosition : function(x, y){
15707 if(!this.boxReady){
15710 var adj = this.adjustPosition(x, y);
15711 var ax = adj.x, ay = adj.y;
15713 var el = this.getPositionEl();
15714 if(ax !== undefined || ay !== undefined){
15715 if(ax !== undefined && ay !== undefined){
15716 el.setLeftTop(ax, ay);
15717 }else if(ax !== undefined){
15719 }else if(ay !== undefined){
15722 this.onPosition(ax, ay);
15723 this.fireEvent('move', this, ax, ay);
15729 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15730 * This method fires the move event.
15731 * @param {Number} x The new x position
15732 * @param {Number} y The new y position
15733 * @returns {Roo.BoxComponent} this
15735 setPagePosition : function(x, y){
15738 if(!this.boxReady){
15741 if(x === undefined || y === undefined){ // cannot translate undefined points
15744 var p = this.el.translatePoints(x, y);
15745 this.setPosition(p.left, p.top);
15750 onRender : function(ct, position){
15751 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15753 this.resizeEl = Roo.get(this.resizeEl);
15755 if(this.positionEl){
15756 this.positionEl = Roo.get(this.positionEl);
15761 afterRender : function(){
15762 Roo.BoxComponent.superclass.afterRender.call(this);
15763 this.boxReady = true;
15764 this.setSize(this.width, this.height);
15765 if(this.x || this.y){
15766 this.setPosition(this.x, this.y);
15768 if(this.pageX || this.pageY){
15769 this.setPagePosition(this.pageX, this.pageY);
15774 * Force the component's size to recalculate based on the underlying element's current height and width.
15775 * @returns {Roo.BoxComponent} this
15777 syncSize : function(){
15778 delete this.lastSize;
15779 this.setSize(this.el.getWidth(), this.el.getHeight());
15784 * Called after the component is resized, this method is empty by default but can be implemented by any
15785 * subclass that needs to perform custom logic after a resize occurs.
15786 * @param {Number} adjWidth The box-adjusted width that was set
15787 * @param {Number} adjHeight The box-adjusted height that was set
15788 * @param {Number} rawWidth The width that was originally specified
15789 * @param {Number} rawHeight The height that was originally specified
15791 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15796 * Called after the component is moved, this method is empty by default but can be implemented by any
15797 * subclass that needs to perform custom logic after a move occurs.
15798 * @param {Number} x The new x position
15799 * @param {Number} y The new y position
15801 onPosition : function(x, y){
15806 adjustSize : function(w, h){
15807 if(this.autoWidth){
15810 if(this.autoHeight){
15813 return {width : w, height: h};
15817 adjustPosition : function(x, y){
15818 return {x : x, y: y};
15821 * Original code for Roojs - LGPL
15822 * <script type="text/javascript">
15826 * @class Roo.XComponent
15827 * A delayed Element creator...
15828 * Or a way to group chunks of interface together.
15829 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15830 * used in conjunction with XComponent.build() it will create an instance of each element,
15831 * then call addxtype() to build the User interface.
15833 * Mypart.xyx = new Roo.XComponent({
15835 parent : 'Mypart.xyz', // empty == document.element.!!
15839 disabled : function() {}
15841 tree : function() { // return an tree of xtype declared components
15845 xtype : 'NestedLayoutPanel',
15852 * It can be used to build a big heiracy, with parent etc.
15853 * or you can just use this to render a single compoent to a dom element
15854 * MYPART.render(Roo.Element | String(id) | dom_element )
15861 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15862 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15864 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15866 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15867 * - if mulitple topModules exist, the last one is defined as the top module.
15871 * When the top level or multiple modules are to embedded into a existing HTML page,
15872 * the parent element can container '#id' of the element where the module will be drawn.
15876 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15877 * it relies more on a include mechanism, where sub modules are included into an outer page.
15878 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15880 * Bootstrap Roo Included elements
15882 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15883 * hence confusing the component builder as it thinks there are multiple top level elements.
15887 * @extends Roo.util.Observable
15889 * @param cfg {Object} configuration of component
15892 Roo.XComponent = function(cfg) {
15893 Roo.apply(this, cfg);
15897 * Fires when this the componnt is built
15898 * @param {Roo.XComponent} c the component
15903 this.region = this.region || 'center'; // default..
15904 Roo.XComponent.register(this);
15905 this.modules = false;
15906 this.el = false; // where the layout goes..
15910 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15913 * The created element (with Roo.factory())
15914 * @type {Roo.Layout}
15920 * for BC - use el in new code
15921 * @type {Roo.Layout}
15927 * for BC - use el in new code
15928 * @type {Roo.Layout}
15933 * @cfg {Function|boolean} disabled
15934 * If this module is disabled by some rule, return true from the funtion
15939 * @cfg {String} parent
15940 * Name of parent element which it get xtype added to..
15945 * @cfg {String} order
15946 * Used to set the order in which elements are created (usefull for multiple tabs)
15951 * @cfg {String} name
15952 * String to display while loading.
15956 * @cfg {String} region
15957 * Region to render component to (defaults to center)
15962 * @cfg {Array} items
15963 * A single item array - the first element is the root of the tree..
15964 * It's done this way to stay compatible with the Xtype system...
15970 * The method that retuns the tree of parts that make up this compoennt
15977 * render element to dom or tree
15978 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15981 render : function(el)
15985 var hp = this.parent ? 1 : 0;
15986 Roo.debug && Roo.log(this);
15988 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15989 // if parent is a '#.....' string, then let's use that..
15990 var ename = this.parent.substr(1);
15991 this.parent = false;
15992 Roo.debug && Roo.log(ename);
15994 case 'bootstrap-body' :
15995 if (typeof(Roo.bootstrap.Body) != 'undefined') {
15996 this.parent = { el : new Roo.bootstrap.Body() };
15997 Roo.debug && Roo.log("setting el to doc body");
16000 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16004 this.parent = { el : true};
16007 el = Roo.get(ename);
16012 if (!el && !this.parent) {
16013 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16017 Roo.debug && Roo.log("EL:");
16018 Roo.debug && Roo.log(el);
16019 Roo.debug && Roo.log("this.parent.el:");
16020 Roo.debug && Roo.log(this.parent.el);
16022 var tree = this._tree ? this._tree() : this.tree();
16024 // altertive root elements ??? - we need a better way to indicate these.
16025 var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16026 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16028 if (!this.parent && is_alt) {
16029 //el = Roo.get(document.body);
16030 this.parent = { el : true };
16035 if (!this.parent) {
16037 Roo.debug && Roo.log("no parent - creating one");
16039 el = el ? Roo.get(el) : false;
16041 // it's a top level one..
16043 el : new Roo.BorderLayout(el || document.body, {
16049 tabPosition: 'top',
16050 //resizeTabs: true,
16051 alwaysShowTabs: el && hp? false : true,
16052 hideTabs: el || !hp ? true : false,
16059 if (!this.parent.el) {
16060 // probably an old style ctor, which has been disabled.
16064 // The 'tree' method is '_tree now'
16066 tree.region = tree.region || this.region;
16068 if (this.parent.el === true) {
16069 // bootstrap... - body..
16070 this.parent.el = Roo.factory(tree);
16073 this.el = this.parent.el.addxtype(tree);
16074 this.fireEvent('built', this);
16076 this.panel = this.el;
16077 this.layout = this.panel.layout;
16078 this.parentLayout = this.parent.layout || false;
16084 Roo.apply(Roo.XComponent, {
16086 * @property hideProgress
16087 * true to disable the building progress bar.. usefull on single page renders.
16090 hideProgress : false,
16092 * @property buildCompleted
16093 * True when the builder has completed building the interface.
16096 buildCompleted : false,
16099 * @property topModule
16100 * the upper most module - uses document.element as it's constructor.
16107 * @property modules
16108 * array of modules to be created by registration system.
16109 * @type {Array} of Roo.XComponent
16114 * @property elmodules
16115 * array of modules to be created by which use #ID
16116 * @type {Array} of Roo.XComponent
16122 * @property build_from_html
16123 * Build elements from html - used by bootstrap HTML stuff
16124 * - this is cleared after build is completed
16125 * @type {boolean} true (default false)
16128 build_from_html : false,
16131 * Register components to be built later.
16133 * This solves the following issues
16134 * - Building is not done on page load, but after an authentication process has occured.
16135 * - Interface elements are registered on page load
16136 * - Parent Interface elements may not be loaded before child, so this handles that..
16143 module : 'Pman.Tab.projectMgr',
16145 parent : 'Pman.layout',
16146 disabled : false, // or use a function..
16149 * * @param {Object} details about module
16151 register : function(obj) {
16153 Roo.XComponent.event.fireEvent('register', obj);
16154 switch(typeof(obj.disabled) ) {
16160 if ( obj.disabled() ) {
16166 if (obj.disabled) {
16172 this.modules.push(obj);
16176 * convert a string to an object..
16177 * eg. 'AAA.BBB' -> finds AAA.BBB
16181 toObject : function(str)
16183 if (!str || typeof(str) == 'object') {
16186 if (str.substring(0,1) == '#') {
16190 var ar = str.split('.');
16195 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16197 throw "Module not found : " + str;
16201 throw "Module not found : " + str;
16203 Roo.each(ar, function(e) {
16204 if (typeof(o[e]) == 'undefined') {
16205 throw "Module not found : " + str;
16216 * move modules into their correct place in the tree..
16219 preBuild : function ()
16222 Roo.each(this.modules , function (obj)
16224 Roo.XComponent.event.fireEvent('beforebuild', obj);
16226 var opar = obj.parent;
16228 obj.parent = this.toObject(opar);
16230 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16235 Roo.debug && Roo.log("GOT top level module");
16236 Roo.debug && Roo.log(obj);
16237 obj.modules = new Roo.util.MixedCollection(false,
16238 function(o) { return o.order + '' }
16240 this.topModule = obj;
16243 // parent is a string (usually a dom element name..)
16244 if (typeof(obj.parent) == 'string') {
16245 this.elmodules.push(obj);
16248 if (obj.parent.constructor != Roo.XComponent) {
16249 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16251 if (!obj.parent.modules) {
16252 obj.parent.modules = new Roo.util.MixedCollection(false,
16253 function(o) { return o.order + '' }
16256 if (obj.parent.disabled) {
16257 obj.disabled = true;
16259 obj.parent.modules.add(obj);
16264 * make a list of modules to build.
16265 * @return {Array} list of modules.
16268 buildOrder : function()
16271 var cmp = function(a,b) {
16272 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16274 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16275 throw "No top level modules to build";
16278 // make a flat list in order of modules to build.
16279 var mods = this.topModule ? [ this.topModule ] : [];
16282 // elmodules (is a list of DOM based modules )
16283 Roo.each(this.elmodules, function(e) {
16285 if (!this.topModule &&
16286 typeof(e.parent) == 'string' &&
16287 e.parent.substring(0,1) == '#' &&
16288 Roo.get(e.parent.substr(1))
16291 _this.topModule = e;
16297 // add modules to their parents..
16298 var addMod = function(m) {
16299 Roo.debug && Roo.log("build Order: add: " + m.name);
16302 if (m.modules && !m.disabled) {
16303 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16304 m.modules.keySort('ASC', cmp );
16305 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16307 m.modules.each(addMod);
16309 Roo.debug && Roo.log("build Order: no child modules");
16311 // not sure if this is used any more..
16313 m.finalize.name = m.name + " (clean up) ";
16314 mods.push(m.finalize);
16318 if (this.topModule && this.topModule.modules) {
16319 this.topModule.modules.keySort('ASC', cmp );
16320 this.topModule.modules.each(addMod);
16326 * Build the registered modules.
16327 * @param {Object} parent element.
16328 * @param {Function} optional method to call after module has been added.
16332 build : function(opts)
16335 if (typeof(opts) != 'undefined') {
16336 Roo.apply(this,opts);
16340 var mods = this.buildOrder();
16342 //this.allmods = mods;
16343 //Roo.debug && Roo.log(mods);
16345 if (!mods.length) { // should not happen
16346 throw "NO modules!!!";
16350 var msg = "Building Interface...";
16351 // flash it up as modal - so we store the mask!?
16352 if (!this.hideProgress && Roo.MessageBox) {
16353 Roo.MessageBox.show({ title: 'loading' });
16354 Roo.MessageBox.show({
16355 title: "Please wait...",
16364 var total = mods.length;
16367 var progressRun = function() {
16368 if (!mods.length) {
16369 Roo.debug && Roo.log('hide?');
16370 if (!this.hideProgress && Roo.MessageBox) {
16371 Roo.MessageBox.hide();
16373 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16375 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16381 var m = mods.shift();
16384 Roo.debug && Roo.log(m);
16385 // not sure if this is supported any more.. - modules that are are just function
16386 if (typeof(m) == 'function') {
16388 return progressRun.defer(10, _this);
16392 msg = "Building Interface " + (total - mods.length) +
16394 (m.name ? (' - ' + m.name) : '');
16395 Roo.debug && Roo.log(msg);
16396 if (!this.hideProgress && Roo.MessageBox) {
16397 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16401 // is the module disabled?
16402 var disabled = (typeof(m.disabled) == 'function') ?
16403 m.disabled.call(m.module.disabled) : m.disabled;
16407 return progressRun(); // we do not update the display!
16415 // it's 10 on top level, and 1 on others??? why...
16416 return progressRun.defer(10, _this);
16419 progressRun.defer(1, _this);
16433 * wrapper for event.on - aliased later..
16434 * Typically use to register a event handler for register:
16436 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16445 Roo.XComponent.event = new Roo.util.Observable({
16449 * Fires when an Component is registered,
16450 * set the disable property on the Component to stop registration.
16451 * @param {Roo.XComponent} c the component being registerd.
16456 * @event beforebuild
16457 * Fires before each Component is built
16458 * can be used to apply permissions.
16459 * @param {Roo.XComponent} c the component being registerd.
16462 'beforebuild' : true,
16464 * @event buildcomplete
16465 * Fires on the top level element when all elements have been built
16466 * @param {Roo.XComponent} the top level component.
16468 'buildcomplete' : true
16473 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16476 * Ext JS Library 1.1.1
16477 * Copyright(c) 2006-2007, Ext JS, LLC.
16479 * Originally Released Under LGPL - original licence link has changed is not relivant.
16482 * <script type="text/javascript">
16488 * These classes are derivatives of the similarly named classes in the YUI Library.
16489 * The original license:
16490 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16491 * Code licensed under the BSD License:
16492 * http://developer.yahoo.net/yui/license.txt
16497 var Event=Roo.EventManager;
16498 var Dom=Roo.lib.Dom;
16501 * @class Roo.dd.DragDrop
16502 * @extends Roo.util.Observable
16503 * Defines the interface and base operation of items that that can be
16504 * dragged or can be drop targets. It was designed to be extended, overriding
16505 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16506 * Up to three html elements can be associated with a DragDrop instance:
16508 * <li>linked element: the element that is passed into the constructor.
16509 * This is the element which defines the boundaries for interaction with
16510 * other DragDrop objects.</li>
16511 * <li>handle element(s): The drag operation only occurs if the element that
16512 * was clicked matches a handle element. By default this is the linked
16513 * element, but there are times that you will want only a portion of the
16514 * linked element to initiate the drag operation, and the setHandleElId()
16515 * method provides a way to define this.</li>
16516 * <li>drag element: this represents the element that would be moved along
16517 * with the cursor during a drag operation. By default, this is the linked
16518 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16519 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16522 * This class should not be instantiated until the onload event to ensure that
16523 * the associated elements are available.
16524 * The following would define a DragDrop obj that would interact with any
16525 * other DragDrop obj in the "group1" group:
16527 * dd = new Roo.dd.DragDrop("div1", "group1");
16529 * Since none of the event handlers have been implemented, nothing would
16530 * actually happen if you were to run the code above. Normally you would
16531 * override this class or one of the default implementations, but you can
16532 * also override the methods you want on an instance of the class...
16534 * dd.onDragDrop = function(e, id) {
16535 * alert("dd was dropped on " + id);
16539 * @param {String} id of the element that is linked to this instance
16540 * @param {String} sGroup the group of related DragDrop objects
16541 * @param {object} config an object containing configurable attributes
16542 * Valid properties for DragDrop:
16543 * padding, isTarget, maintainOffset, primaryButtonOnly
16545 Roo.dd.DragDrop = function(id, sGroup, config) {
16547 this.init(id, sGroup, config);
16552 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16555 * The id of the element associated with this object. This is what we
16556 * refer to as the "linked element" because the size and position of
16557 * this element is used to determine when the drag and drop objects have
16565 * Configuration attributes passed into the constructor
16572 * The id of the element that will be dragged. By default this is same
16573 * as the linked element , but could be changed to another element. Ex:
16575 * @property dragElId
16582 * the id of the element that initiates the drag operation. By default
16583 * this is the linked element, but could be changed to be a child of this
16584 * element. This lets us do things like only starting the drag when the
16585 * header element within the linked html element is clicked.
16586 * @property handleElId
16593 * An associative array of HTML tags that will be ignored if clicked.
16594 * @property invalidHandleTypes
16595 * @type {string: string}
16597 invalidHandleTypes: null,
16600 * An associative array of ids for elements that will be ignored if clicked
16601 * @property invalidHandleIds
16602 * @type {string: string}
16604 invalidHandleIds: null,
16607 * An indexted array of css class names for elements that will be ignored
16609 * @property invalidHandleClasses
16612 invalidHandleClasses: null,
16615 * The linked element's absolute X position at the time the drag was
16617 * @property startPageX
16624 * The linked element's absolute X position at the time the drag was
16626 * @property startPageY
16633 * The group defines a logical collection of DragDrop objects that are
16634 * related. Instances only get events when interacting with other
16635 * DragDrop object in the same group. This lets us define multiple
16636 * groups using a single DragDrop subclass if we want.
16638 * @type {string: string}
16643 * Individual drag/drop instances can be locked. This will prevent
16644 * onmousedown start drag.
16652 * Lock this instance
16655 lock: function() { this.locked = true; },
16658 * Unlock this instace
16661 unlock: function() { this.locked = false; },
16664 * By default, all insances can be a drop target. This can be disabled by
16665 * setting isTarget to false.
16672 * The padding configured for this drag and drop object for calculating
16673 * the drop zone intersection with this object.
16680 * Cached reference to the linked element
16681 * @property _domRef
16687 * Internal typeof flag
16688 * @property __ygDragDrop
16691 __ygDragDrop: true,
16694 * Set to true when horizontal contraints are applied
16695 * @property constrainX
16702 * Set to true when vertical contraints are applied
16703 * @property constrainY
16710 * The left constraint
16718 * The right constraint
16726 * The up constraint
16735 * The down constraint
16743 * Maintain offsets when we resetconstraints. Set to true when you want
16744 * the position of the element relative to its parent to stay the same
16745 * when the page changes
16747 * @property maintainOffset
16750 maintainOffset: false,
16753 * Array of pixel locations the element will snap to if we specified a
16754 * horizontal graduation/interval. This array is generated automatically
16755 * when you define a tick interval.
16762 * Array of pixel locations the element will snap to if we specified a
16763 * vertical graduation/interval. This array is generated automatically
16764 * when you define a tick interval.
16771 * By default the drag and drop instance will only respond to the primary
16772 * button click (left button for a right-handed mouse). Set to true to
16773 * allow drag and drop to start with any mouse click that is propogated
16775 * @property primaryButtonOnly
16778 primaryButtonOnly: true,
16781 * The availabe property is false until the linked dom element is accessible.
16782 * @property available
16788 * By default, drags can only be initiated if the mousedown occurs in the
16789 * region the linked element is. This is done in part to work around a
16790 * bug in some browsers that mis-report the mousedown if the previous
16791 * mouseup happened outside of the window. This property is set to true
16792 * if outer handles are defined.
16794 * @property hasOuterHandles
16798 hasOuterHandles: false,
16801 * Code that executes immediately before the startDrag event
16802 * @method b4StartDrag
16805 b4StartDrag: function(x, y) { },
16808 * Abstract method called after a drag/drop object is clicked
16809 * and the drag or mousedown time thresholds have beeen met.
16810 * @method startDrag
16811 * @param {int} X click location
16812 * @param {int} Y click location
16814 startDrag: function(x, y) { /* override this */ },
16817 * Code that executes immediately before the onDrag event
16821 b4Drag: function(e) { },
16824 * Abstract method called during the onMouseMove event while dragging an
16827 * @param {Event} e the mousemove event
16829 onDrag: function(e) { /* override this */ },
16832 * Abstract method called when this element fist begins hovering over
16833 * another DragDrop obj
16834 * @method onDragEnter
16835 * @param {Event} e the mousemove event
16836 * @param {String|DragDrop[]} id In POINT mode, the element
16837 * id this is hovering over. In INTERSECT mode, an array of one or more
16838 * dragdrop items being hovered over.
16840 onDragEnter: function(e, id) { /* override this */ },
16843 * Code that executes immediately before the onDragOver event
16844 * @method b4DragOver
16847 b4DragOver: function(e) { },
16850 * Abstract method called when this element is hovering over another
16852 * @method onDragOver
16853 * @param {Event} e the mousemove event
16854 * @param {String|DragDrop[]} id In POINT mode, the element
16855 * id this is hovering over. In INTERSECT mode, an array of dd items
16856 * being hovered over.
16858 onDragOver: function(e, id) { /* override this */ },
16861 * Code that executes immediately before the onDragOut event
16862 * @method b4DragOut
16865 b4DragOut: function(e) { },
16868 * Abstract method called when we are no longer hovering over an element
16869 * @method onDragOut
16870 * @param {Event} e the mousemove event
16871 * @param {String|DragDrop[]} id In POINT mode, the element
16872 * id this was hovering over. In INTERSECT mode, an array of dd items
16873 * that the mouse is no longer over.
16875 onDragOut: function(e, id) { /* override this */ },
16878 * Code that executes immediately before the onDragDrop event
16879 * @method b4DragDrop
16882 b4DragDrop: function(e) { },
16885 * Abstract method called when this item is dropped on another DragDrop
16887 * @method onDragDrop
16888 * @param {Event} e the mouseup event
16889 * @param {String|DragDrop[]} id In POINT mode, the element
16890 * id this was dropped on. In INTERSECT mode, an array of dd items this
16893 onDragDrop: function(e, id) { /* override this */ },
16896 * Abstract method called when this item is dropped on an area with no
16898 * @method onInvalidDrop
16899 * @param {Event} e the mouseup event
16901 onInvalidDrop: function(e) { /* override this */ },
16904 * Code that executes immediately before the endDrag event
16905 * @method b4EndDrag
16908 b4EndDrag: function(e) { },
16911 * Fired when we are done dragging the object
16913 * @param {Event} e the mouseup event
16915 endDrag: function(e) { /* override this */ },
16918 * Code executed immediately before the onMouseDown event
16919 * @method b4MouseDown
16920 * @param {Event} e the mousedown event
16923 b4MouseDown: function(e) { },
16926 * Event handler that fires when a drag/drop obj gets a mousedown
16927 * @method onMouseDown
16928 * @param {Event} e the mousedown event
16930 onMouseDown: function(e) { /* override this */ },
16933 * Event handler that fires when a drag/drop obj gets a mouseup
16934 * @method onMouseUp
16935 * @param {Event} e the mouseup event
16937 onMouseUp: function(e) { /* override this */ },
16940 * Override the onAvailable method to do what is needed after the initial
16941 * position was determined.
16942 * @method onAvailable
16944 onAvailable: function () {
16948 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16951 defaultPadding : {left:0, right:0, top:0, bottom:0},
16954 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16958 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16959 { dragElId: "existingProxyDiv" });
16960 dd.startDrag = function(){
16961 this.constrainTo("parent-id");
16964 * Or you can initalize it using the {@link Roo.Element} object:
16966 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16967 startDrag : function(){
16968 this.constrainTo("parent-id");
16972 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16973 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16974 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16975 * an object containing the sides to pad. For example: {right:10, bottom:10}
16976 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16978 constrainTo : function(constrainTo, pad, inContent){
16979 if(typeof pad == "number"){
16980 pad = {left: pad, right:pad, top:pad, bottom:pad};
16982 pad = pad || this.defaultPadding;
16983 var b = Roo.get(this.getEl()).getBox();
16984 var ce = Roo.get(constrainTo);
16985 var s = ce.getScroll();
16986 var c, cd = ce.dom;
16987 if(cd == document.body){
16988 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16991 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16995 var topSpace = b.y - c.y;
16996 var leftSpace = b.x - c.x;
16998 this.resetConstraints();
16999 this.setXConstraint(leftSpace - (pad.left||0), // left
17000 c.width - leftSpace - b.width - (pad.right||0) //right
17002 this.setYConstraint(topSpace - (pad.top||0), //top
17003 c.height - topSpace - b.height - (pad.bottom||0) //bottom
17008 * Returns a reference to the linked element
17010 * @return {HTMLElement} the html element
17012 getEl: function() {
17013 if (!this._domRef) {
17014 this._domRef = Roo.getDom(this.id);
17017 return this._domRef;
17021 * Returns a reference to the actual element to drag. By default this is
17022 * the same as the html element, but it can be assigned to another
17023 * element. An example of this can be found in Roo.dd.DDProxy
17024 * @method getDragEl
17025 * @return {HTMLElement} the html element
17027 getDragEl: function() {
17028 return Roo.getDom(this.dragElId);
17032 * Sets up the DragDrop object. Must be called in the constructor of any
17033 * Roo.dd.DragDrop subclass
17035 * @param id the id of the linked element
17036 * @param {String} sGroup the group of related items
17037 * @param {object} config configuration attributes
17039 init: function(id, sGroup, config) {
17040 this.initTarget(id, sGroup, config);
17041 if (!Roo.isTouch) {
17042 Event.on(this.id, "mousedown", this.handleMouseDown, this);
17044 Event.on(this.id, "touchstart", this.handleMouseDown, this);
17045 // Event.on(this.id, "selectstart", Event.preventDefault);
17049 * Initializes Targeting functionality only... the object does not
17050 * get a mousedown handler.
17051 * @method initTarget
17052 * @param id the id of the linked element
17053 * @param {String} sGroup the group of related items
17054 * @param {object} config configuration attributes
17056 initTarget: function(id, sGroup, config) {
17058 // configuration attributes
17059 this.config = config || {};
17061 // create a local reference to the drag and drop manager
17062 this.DDM = Roo.dd.DDM;
17063 // initialize the groups array
17066 // assume that we have an element reference instead of an id if the
17067 // parameter is not a string
17068 if (typeof id !== "string") {
17075 // add to an interaction group
17076 this.addToGroup((sGroup) ? sGroup : "default");
17078 // We don't want to register this as the handle with the manager
17079 // so we just set the id rather than calling the setter.
17080 this.handleElId = id;
17082 // the linked element is the element that gets dragged by default
17083 this.setDragElId(id);
17085 // by default, clicked anchors will not start drag operations.
17086 this.invalidHandleTypes = { A: "A" };
17087 this.invalidHandleIds = {};
17088 this.invalidHandleClasses = [];
17090 this.applyConfig();
17092 this.handleOnAvailable();
17096 * Applies the configuration parameters that were passed into the constructor.
17097 * This is supposed to happen at each level through the inheritance chain. So
17098 * a DDProxy implentation will execute apply config on DDProxy, DD, and
17099 * DragDrop in order to get all of the parameters that are available in
17101 * @method applyConfig
17103 applyConfig: function() {
17105 // configurable properties:
17106 // padding, isTarget, maintainOffset, primaryButtonOnly
17107 this.padding = this.config.padding || [0, 0, 0, 0];
17108 this.isTarget = (this.config.isTarget !== false);
17109 this.maintainOffset = (this.config.maintainOffset);
17110 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
17115 * Executed when the linked element is available
17116 * @method handleOnAvailable
17119 handleOnAvailable: function() {
17120 this.available = true;
17121 this.resetConstraints();
17122 this.onAvailable();
17126 * Configures the padding for the target zone in px. Effectively expands
17127 * (or reduces) the virtual object size for targeting calculations.
17128 * Supports css-style shorthand; if only one parameter is passed, all sides
17129 * will have that padding, and if only two are passed, the top and bottom
17130 * will have the first param, the left and right the second.
17131 * @method setPadding
17132 * @param {int} iTop Top pad
17133 * @param {int} iRight Right pad
17134 * @param {int} iBot Bot pad
17135 * @param {int} iLeft Left pad
17137 setPadding: function(iTop, iRight, iBot, iLeft) {
17138 // this.padding = [iLeft, iRight, iTop, iBot];
17139 if (!iRight && 0 !== iRight) {
17140 this.padding = [iTop, iTop, iTop, iTop];
17141 } else if (!iBot && 0 !== iBot) {
17142 this.padding = [iTop, iRight, iTop, iRight];
17144 this.padding = [iTop, iRight, iBot, iLeft];
17149 * Stores the initial placement of the linked element.
17150 * @method setInitialPosition
17151 * @param {int} diffX the X offset, default 0
17152 * @param {int} diffY the Y offset, default 0
17154 setInitPosition: function(diffX, diffY) {
17155 var el = this.getEl();
17157 if (!this.DDM.verifyEl(el)) {
17161 var dx = diffX || 0;
17162 var dy = diffY || 0;
17164 var p = Dom.getXY( el );
17166 this.initPageX = p[0] - dx;
17167 this.initPageY = p[1] - dy;
17169 this.lastPageX = p[0];
17170 this.lastPageY = p[1];
17173 this.setStartPosition(p);
17177 * Sets the start position of the element. This is set when the obj
17178 * is initialized, the reset when a drag is started.
17179 * @method setStartPosition
17180 * @param pos current position (from previous lookup)
17183 setStartPosition: function(pos) {
17184 var p = pos || Dom.getXY( this.getEl() );
17185 this.deltaSetXY = null;
17187 this.startPageX = p[0];
17188 this.startPageY = p[1];
17192 * Add this instance to a group of related drag/drop objects. All
17193 * instances belong to at least one group, and can belong to as many
17194 * groups as needed.
17195 * @method addToGroup
17196 * @param sGroup {string} the name of the group
17198 addToGroup: function(sGroup) {
17199 this.groups[sGroup] = true;
17200 this.DDM.regDragDrop(this, sGroup);
17204 * Remove's this instance from the supplied interaction group
17205 * @method removeFromGroup
17206 * @param {string} sGroup The group to drop
17208 removeFromGroup: function(sGroup) {
17209 if (this.groups[sGroup]) {
17210 delete this.groups[sGroup];
17213 this.DDM.removeDDFromGroup(this, sGroup);
17217 * Allows you to specify that an element other than the linked element
17218 * will be moved with the cursor during a drag
17219 * @method setDragElId
17220 * @param id {string} the id of the element that will be used to initiate the drag
17222 setDragElId: function(id) {
17223 this.dragElId = id;
17227 * Allows you to specify a child of the linked element that should be
17228 * used to initiate the drag operation. An example of this would be if
17229 * you have a content div with text and links. Clicking anywhere in the
17230 * content area would normally start the drag operation. Use this method
17231 * to specify that an element inside of the content div is the element
17232 * that starts the drag operation.
17233 * @method setHandleElId
17234 * @param id {string} the id of the element that will be used to
17235 * initiate the drag.
17237 setHandleElId: function(id) {
17238 if (typeof id !== "string") {
17241 this.handleElId = id;
17242 this.DDM.regHandle(this.id, id);
17246 * Allows you to set an element outside of the linked element as a drag
17248 * @method setOuterHandleElId
17249 * @param id the id of the element that will be used to initiate the drag
17251 setOuterHandleElId: function(id) {
17252 if (typeof id !== "string") {
17255 Event.on(id, "mousedown",
17256 this.handleMouseDown, this);
17257 this.setHandleElId(id);
17259 this.hasOuterHandles = true;
17263 * Remove all drag and drop hooks for this element
17266 unreg: function() {
17267 Event.un(this.id, "mousedown",
17268 this.handleMouseDown);
17269 Event.un(this.id, "touchstart",
17270 this.handleMouseDown);
17271 this._domRef = null;
17272 this.DDM._remove(this);
17275 destroy : function(){
17280 * Returns true if this instance is locked, or the drag drop mgr is locked
17281 * (meaning that all drag/drop is disabled on the page.)
17283 * @return {boolean} true if this obj or all drag/drop is locked, else
17286 isLocked: function() {
17287 return (this.DDM.isLocked() || this.locked);
17291 * Fired when this object is clicked
17292 * @method handleMouseDown
17294 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17297 handleMouseDown: function(e, oDD){
17299 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17300 //Roo.log('not touch/ button !=0');
17303 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17304 return; // double touch..
17308 if (this.isLocked()) {
17309 //Roo.log('locked');
17313 this.DDM.refreshCache(this.groups);
17314 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17315 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17316 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17317 //Roo.log('no outer handes or not over target');
17320 // Roo.log('check validator');
17321 if (this.clickValidator(e)) {
17322 // Roo.log('validate success');
17323 // set the initial element position
17324 this.setStartPosition();
17327 this.b4MouseDown(e);
17328 this.onMouseDown(e);
17330 this.DDM.handleMouseDown(e, this);
17332 this.DDM.stopEvent(e);
17340 clickValidator: function(e) {
17341 var target = e.getTarget();
17342 return ( this.isValidHandleChild(target) &&
17343 (this.id == this.handleElId ||
17344 this.DDM.handleWasClicked(target, this.id)) );
17348 * Allows you to specify a tag name that should not start a drag operation
17349 * when clicked. This is designed to facilitate embedding links within a
17350 * drag handle that do something other than start the drag.
17351 * @method addInvalidHandleType
17352 * @param {string} tagName the type of element to exclude
17354 addInvalidHandleType: function(tagName) {
17355 var type = tagName.toUpperCase();
17356 this.invalidHandleTypes[type] = type;
17360 * Lets you to specify an element id for a child of a drag handle
17361 * that should not initiate a drag
17362 * @method addInvalidHandleId
17363 * @param {string} id the element id of the element you wish to ignore
17365 addInvalidHandleId: function(id) {
17366 if (typeof id !== "string") {
17369 this.invalidHandleIds[id] = id;
17373 * Lets you specify a css class of elements that will not initiate a drag
17374 * @method addInvalidHandleClass
17375 * @param {string} cssClass the class of the elements you wish to ignore
17377 addInvalidHandleClass: function(cssClass) {
17378 this.invalidHandleClasses.push(cssClass);
17382 * Unsets an excluded tag name set by addInvalidHandleType
17383 * @method removeInvalidHandleType
17384 * @param {string} tagName the type of element to unexclude
17386 removeInvalidHandleType: function(tagName) {
17387 var type = tagName.toUpperCase();
17388 // this.invalidHandleTypes[type] = null;
17389 delete this.invalidHandleTypes[type];
17393 * Unsets an invalid handle id
17394 * @method removeInvalidHandleId
17395 * @param {string} id the id of the element to re-enable
17397 removeInvalidHandleId: function(id) {
17398 if (typeof id !== "string") {
17401 delete this.invalidHandleIds[id];
17405 * Unsets an invalid css class
17406 * @method removeInvalidHandleClass
17407 * @param {string} cssClass the class of the element(s) you wish to
17410 removeInvalidHandleClass: function(cssClass) {
17411 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17412 if (this.invalidHandleClasses[i] == cssClass) {
17413 delete this.invalidHandleClasses[i];
17419 * Checks the tag exclusion list to see if this click should be ignored
17420 * @method isValidHandleChild
17421 * @param {HTMLElement} node the HTMLElement to evaluate
17422 * @return {boolean} true if this is a valid tag type, false if not
17424 isValidHandleChild: function(node) {
17427 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17430 nodeName = node.nodeName.toUpperCase();
17432 nodeName = node.nodeName;
17434 valid = valid && !this.invalidHandleTypes[nodeName];
17435 valid = valid && !this.invalidHandleIds[node.id];
17437 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17438 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17447 * Create the array of horizontal tick marks if an interval was specified
17448 * in setXConstraint().
17449 * @method setXTicks
17452 setXTicks: function(iStartX, iTickSize) {
17454 this.xTickSize = iTickSize;
17458 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17460 this.xTicks[this.xTicks.length] = i;
17465 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17467 this.xTicks[this.xTicks.length] = i;
17472 this.xTicks.sort(this.DDM.numericSort) ;
17476 * Create the array of vertical tick marks if an interval was specified in
17477 * setYConstraint().
17478 * @method setYTicks
17481 setYTicks: function(iStartY, iTickSize) {
17483 this.yTickSize = iTickSize;
17487 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17489 this.yTicks[this.yTicks.length] = i;
17494 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17496 this.yTicks[this.yTicks.length] = i;
17501 this.yTicks.sort(this.DDM.numericSort) ;
17505 * By default, the element can be dragged any place on the screen. Use
17506 * this method to limit the horizontal travel of the element. Pass in
17507 * 0,0 for the parameters if you want to lock the drag to the y axis.
17508 * @method setXConstraint
17509 * @param {int} iLeft the number of pixels the element can move to the left
17510 * @param {int} iRight the number of pixels the element can move to the
17512 * @param {int} iTickSize optional parameter for specifying that the
17514 * should move iTickSize pixels at a time.
17516 setXConstraint: function(iLeft, iRight, iTickSize) {
17517 this.leftConstraint = iLeft;
17518 this.rightConstraint = iRight;
17520 this.minX = this.initPageX - iLeft;
17521 this.maxX = this.initPageX + iRight;
17522 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17524 this.constrainX = true;
17528 * Clears any constraints applied to this instance. Also clears ticks
17529 * since they can't exist independent of a constraint at this time.
17530 * @method clearConstraints
17532 clearConstraints: function() {
17533 this.constrainX = false;
17534 this.constrainY = false;
17539 * Clears any tick interval defined for this instance
17540 * @method clearTicks
17542 clearTicks: function() {
17543 this.xTicks = null;
17544 this.yTicks = null;
17545 this.xTickSize = 0;
17546 this.yTickSize = 0;
17550 * By default, the element can be dragged any place on the screen. Set
17551 * this to limit the vertical travel of the element. Pass in 0,0 for the
17552 * parameters if you want to lock the drag to the x axis.
17553 * @method setYConstraint
17554 * @param {int} iUp the number of pixels the element can move up
17555 * @param {int} iDown the number of pixels the element can move down
17556 * @param {int} iTickSize optional parameter for specifying that the
17557 * element should move iTickSize pixels at a time.
17559 setYConstraint: function(iUp, iDown, iTickSize) {
17560 this.topConstraint = iUp;
17561 this.bottomConstraint = iDown;
17563 this.minY = this.initPageY - iUp;
17564 this.maxY = this.initPageY + iDown;
17565 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17567 this.constrainY = true;
17572 * resetConstraints must be called if you manually reposition a dd element.
17573 * @method resetConstraints
17574 * @param {boolean} maintainOffset
17576 resetConstraints: function() {
17579 // Maintain offsets if necessary
17580 if (this.initPageX || this.initPageX === 0) {
17581 // figure out how much this thing has moved
17582 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17583 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17585 this.setInitPosition(dx, dy);
17587 // This is the first time we have detected the element's position
17589 this.setInitPosition();
17592 if (this.constrainX) {
17593 this.setXConstraint( this.leftConstraint,
17594 this.rightConstraint,
17598 if (this.constrainY) {
17599 this.setYConstraint( this.topConstraint,
17600 this.bottomConstraint,
17606 * Normally the drag element is moved pixel by pixel, but we can specify
17607 * that it move a number of pixels at a time. This method resolves the
17608 * location when we have it set up like this.
17610 * @param {int} val where we want to place the object
17611 * @param {int[]} tickArray sorted array of valid points
17612 * @return {int} the closest tick
17615 getTick: function(val, tickArray) {
17618 // If tick interval is not defined, it is effectively 1 pixel,
17619 // so we return the value passed to us.
17621 } else if (tickArray[0] >= val) {
17622 // The value is lower than the first tick, so we return the first
17624 return tickArray[0];
17626 for (var i=0, len=tickArray.length; i<len; ++i) {
17628 if (tickArray[next] && tickArray[next] >= val) {
17629 var diff1 = val - tickArray[i];
17630 var diff2 = tickArray[next] - val;
17631 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17635 // The value is larger than the last tick, so we return the last
17637 return tickArray[tickArray.length - 1];
17644 * @return {string} string representation of the dd obj
17646 toString: function() {
17647 return ("DragDrop " + this.id);
17655 * Ext JS Library 1.1.1
17656 * Copyright(c) 2006-2007, Ext JS, LLC.
17658 * Originally Released Under LGPL - original licence link has changed is not relivant.
17661 * <script type="text/javascript">
17666 * The drag and drop utility provides a framework for building drag and drop
17667 * applications. In addition to enabling drag and drop for specific elements,
17668 * the drag and drop elements are tracked by the manager class, and the
17669 * interactions between the various elements are tracked during the drag and
17670 * the implementing code is notified about these important moments.
17673 // Only load the library once. Rewriting the manager class would orphan
17674 // existing drag and drop instances.
17675 if (!Roo.dd.DragDropMgr) {
17678 * @class Roo.dd.DragDropMgr
17679 * DragDropMgr is a singleton that tracks the element interaction for
17680 * all DragDrop items in the window. Generally, you will not call
17681 * this class directly, but it does have helper methods that could
17682 * be useful in your DragDrop implementations.
17685 Roo.dd.DragDropMgr = function() {
17687 var Event = Roo.EventManager;
17692 * Two dimensional Array of registered DragDrop objects. The first
17693 * dimension is the DragDrop item group, the second the DragDrop
17696 * @type {string: string}
17703 * Array of element ids defined as drag handles. Used to determine
17704 * if the element that generated the mousedown event is actually the
17705 * handle and not the html element itself.
17706 * @property handleIds
17707 * @type {string: string}
17714 * the DragDrop object that is currently being dragged
17715 * @property dragCurrent
17723 * the DragDrop object(s) that are being hovered over
17724 * @property dragOvers
17732 * the X distance between the cursor and the object being dragged
17741 * the Y distance between the cursor and the object being dragged
17750 * Flag to determine if we should prevent the default behavior of the
17751 * events we define. By default this is true, but this can be set to
17752 * false if you need the default behavior (not recommended)
17753 * @property preventDefault
17757 preventDefault: true,
17760 * Flag to determine if we should stop the propagation of the events
17761 * we generate. This is true by default but you may want to set it to
17762 * false if the html element contains other features that require the
17764 * @property stopPropagation
17768 stopPropagation: true,
17771 * Internal flag that is set to true when drag and drop has been
17773 * @property initialized
17780 * All drag and drop can be disabled.
17788 * Called the first time an element is registered.
17794 this.initialized = true;
17798 * In point mode, drag and drop interaction is defined by the
17799 * location of the cursor during the drag/drop
17807 * In intersect mode, drag and drop interactio nis defined by the
17808 * overlap of two or more drag and drop objects.
17809 * @property INTERSECT
17816 * The current drag and drop mode. Default: POINT
17824 * Runs method on all drag and drop objects
17825 * @method _execOnAll
17829 _execOnAll: function(sMethod, args) {
17830 for (var i in this.ids) {
17831 for (var j in this.ids[i]) {
17832 var oDD = this.ids[i][j];
17833 if (! this.isTypeOfDD(oDD)) {
17836 oDD[sMethod].apply(oDD, args);
17842 * Drag and drop initialization. Sets up the global event handlers
17847 _onLoad: function() {
17851 if (!Roo.isTouch) {
17852 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17853 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17855 Event.on(document, "touchend", this.handleMouseUp, this, true);
17856 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17858 Event.on(window, "unload", this._onUnload, this, true);
17859 Event.on(window, "resize", this._onResize, this, true);
17860 // Event.on(window, "mouseout", this._test);
17865 * Reset constraints on all drag and drop objs
17866 * @method _onResize
17870 _onResize: function(e) {
17871 this._execOnAll("resetConstraints", []);
17875 * Lock all drag and drop functionality
17879 lock: function() { this.locked = true; },
17882 * Unlock all drag and drop functionality
17886 unlock: function() { this.locked = false; },
17889 * Is drag and drop locked?
17891 * @return {boolean} True if drag and drop is locked, false otherwise.
17894 isLocked: function() { return this.locked; },
17897 * Location cache that is set for all drag drop objects when a drag is
17898 * initiated, cleared when the drag is finished.
17899 * @property locationCache
17906 * Set useCache to false if you want to force object the lookup of each
17907 * drag and drop linked element constantly during a drag.
17908 * @property useCache
17915 * The number of pixels that the mouse needs to move after the
17916 * mousedown before the drag is initiated. Default=3;
17917 * @property clickPixelThresh
17921 clickPixelThresh: 3,
17924 * The number of milliseconds after the mousedown event to initiate the
17925 * drag if we don't get a mouseup event. Default=1000
17926 * @property clickTimeThresh
17930 clickTimeThresh: 350,
17933 * Flag that indicates that either the drag pixel threshold or the
17934 * mousdown time threshold has been met
17935 * @property dragThreshMet
17940 dragThreshMet: false,
17943 * Timeout used for the click time threshold
17944 * @property clickTimeout
17949 clickTimeout: null,
17952 * The X position of the mousedown event stored for later use when a
17953 * drag threshold is met.
17962 * The Y position of the mousedown event stored for later use when a
17963 * drag threshold is met.
17972 * Each DragDrop instance must be registered with the DragDropMgr.
17973 * This is executed in DragDrop.init()
17974 * @method regDragDrop
17975 * @param {DragDrop} oDD the DragDrop object to register
17976 * @param {String} sGroup the name of the group this element belongs to
17979 regDragDrop: function(oDD, sGroup) {
17980 if (!this.initialized) { this.init(); }
17982 if (!this.ids[sGroup]) {
17983 this.ids[sGroup] = {};
17985 this.ids[sGroup][oDD.id] = oDD;
17989 * Removes the supplied dd instance from the supplied group. Executed
17990 * by DragDrop.removeFromGroup, so don't call this function directly.
17991 * @method removeDDFromGroup
17995 removeDDFromGroup: function(oDD, sGroup) {
17996 if (!this.ids[sGroup]) {
17997 this.ids[sGroup] = {};
18000 var obj = this.ids[sGroup];
18001 if (obj && obj[oDD.id]) {
18002 delete obj[oDD.id];
18007 * Unregisters a drag and drop item. This is executed in
18008 * DragDrop.unreg, use that method instead of calling this directly.
18013 _remove: function(oDD) {
18014 for (var g in oDD.groups) {
18015 if (g && this.ids[g][oDD.id]) {
18016 delete this.ids[g][oDD.id];
18019 delete this.handleIds[oDD.id];
18023 * Each DragDrop handle element must be registered. This is done
18024 * automatically when executing DragDrop.setHandleElId()
18025 * @method regHandle
18026 * @param {String} sDDId the DragDrop id this element is a handle for
18027 * @param {String} sHandleId the id of the element that is the drag
18031 regHandle: function(sDDId, sHandleId) {
18032 if (!this.handleIds[sDDId]) {
18033 this.handleIds[sDDId] = {};
18035 this.handleIds[sDDId][sHandleId] = sHandleId;
18039 * Utility function to determine if a given element has been
18040 * registered as a drag drop item.
18041 * @method isDragDrop
18042 * @param {String} id the element id to check
18043 * @return {boolean} true if this element is a DragDrop item,
18047 isDragDrop: function(id) {
18048 return ( this.getDDById(id) ) ? true : false;
18052 * Returns the drag and drop instances that are in all groups the
18053 * passed in instance belongs to.
18054 * @method getRelated
18055 * @param {DragDrop} p_oDD the obj to get related data for
18056 * @param {boolean} bTargetsOnly if true, only return targetable objs
18057 * @return {DragDrop[]} the related instances
18060 getRelated: function(p_oDD, bTargetsOnly) {
18062 for (var i in p_oDD.groups) {
18063 for (j in this.ids[i]) {
18064 var dd = this.ids[i][j];
18065 if (! this.isTypeOfDD(dd)) {
18068 if (!bTargetsOnly || dd.isTarget) {
18069 oDDs[oDDs.length] = dd;
18078 * Returns true if the specified dd target is a legal target for
18079 * the specifice drag obj
18080 * @method isLegalTarget
18081 * @param {DragDrop} the drag obj
18082 * @param {DragDrop} the target
18083 * @return {boolean} true if the target is a legal target for the
18087 isLegalTarget: function (oDD, oTargetDD) {
18088 var targets = this.getRelated(oDD, true);
18089 for (var i=0, len=targets.length;i<len;++i) {
18090 if (targets[i].id == oTargetDD.id) {
18099 * My goal is to be able to transparently determine if an object is
18100 * typeof DragDrop, and the exact subclass of DragDrop. typeof
18101 * returns "object", oDD.constructor.toString() always returns
18102 * "DragDrop" and not the name of the subclass. So for now it just
18103 * evaluates a well-known variable in DragDrop.
18104 * @method isTypeOfDD
18105 * @param {Object} the object to evaluate
18106 * @return {boolean} true if typeof oDD = DragDrop
18109 isTypeOfDD: function (oDD) {
18110 return (oDD && oDD.__ygDragDrop);
18114 * Utility function to determine if a given element has been
18115 * registered as a drag drop handle for the given Drag Drop object.
18117 * @param {String} id the element id to check
18118 * @return {boolean} true if this element is a DragDrop handle, false
18122 isHandle: function(sDDId, sHandleId) {
18123 return ( this.handleIds[sDDId] &&
18124 this.handleIds[sDDId][sHandleId] );
18128 * Returns the DragDrop instance for a given id
18129 * @method getDDById
18130 * @param {String} id the id of the DragDrop object
18131 * @return {DragDrop} the drag drop object, null if it is not found
18134 getDDById: function(id) {
18135 for (var i in this.ids) {
18136 if (this.ids[i][id]) {
18137 return this.ids[i][id];
18144 * Fired after a registered DragDrop object gets the mousedown event.
18145 * Sets up the events required to track the object being dragged
18146 * @method handleMouseDown
18147 * @param {Event} e the event
18148 * @param oDD the DragDrop object being dragged
18152 handleMouseDown: function(e, oDD) {
18154 Roo.QuickTips.disable();
18156 this.currentTarget = e.getTarget();
18158 this.dragCurrent = oDD;
18160 var el = oDD.getEl();
18162 // track start position
18163 this.startX = e.getPageX();
18164 this.startY = e.getPageY();
18166 this.deltaX = this.startX - el.offsetLeft;
18167 this.deltaY = this.startY - el.offsetTop;
18169 this.dragThreshMet = false;
18171 this.clickTimeout = setTimeout(
18173 var DDM = Roo.dd.DDM;
18174 DDM.startDrag(DDM.startX, DDM.startY);
18176 this.clickTimeThresh );
18180 * Fired when either the drag pixel threshol or the mousedown hold
18181 * time threshold has been met.
18182 * @method startDrag
18183 * @param x {int} the X position of the original mousedown
18184 * @param y {int} the Y position of the original mousedown
18187 startDrag: function(x, y) {
18188 clearTimeout(this.clickTimeout);
18189 if (this.dragCurrent) {
18190 this.dragCurrent.b4StartDrag(x, y);
18191 this.dragCurrent.startDrag(x, y);
18193 this.dragThreshMet = true;
18197 * Internal function to handle the mouseup event. Will be invoked
18198 * from the context of the document.
18199 * @method handleMouseUp
18200 * @param {Event} e the event
18204 handleMouseUp: function(e) {
18207 Roo.QuickTips.enable();
18209 if (! this.dragCurrent) {
18213 clearTimeout(this.clickTimeout);
18215 if (this.dragThreshMet) {
18216 this.fireEvents(e, true);
18226 * Utility to stop event propagation and event default, if these
18227 * features are turned on.
18228 * @method stopEvent
18229 * @param {Event} e the event as returned by this.getEvent()
18232 stopEvent: function(e){
18233 if(this.stopPropagation) {
18234 e.stopPropagation();
18237 if (this.preventDefault) {
18238 e.preventDefault();
18243 * Internal function to clean up event handlers after the drag
18244 * operation is complete
18246 * @param {Event} e the event
18250 stopDrag: function(e) {
18251 // Fire the drag end event for the item that was dragged
18252 if (this.dragCurrent) {
18253 if (this.dragThreshMet) {
18254 this.dragCurrent.b4EndDrag(e);
18255 this.dragCurrent.endDrag(e);
18258 this.dragCurrent.onMouseUp(e);
18261 this.dragCurrent = null;
18262 this.dragOvers = {};
18266 * Internal function to handle the mousemove event. Will be invoked
18267 * from the context of the html element.
18269 * @TODO figure out what we can do about mouse events lost when the
18270 * user drags objects beyond the window boundary. Currently we can
18271 * detect this in internet explorer by verifying that the mouse is
18272 * down during the mousemove event. Firefox doesn't give us the
18273 * button state on the mousemove event.
18274 * @method handleMouseMove
18275 * @param {Event} e the event
18279 handleMouseMove: function(e) {
18280 if (! this.dragCurrent) {
18284 // var button = e.which || e.button;
18286 // check for IE mouseup outside of page boundary
18287 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18289 return this.handleMouseUp(e);
18292 if (!this.dragThreshMet) {
18293 var diffX = Math.abs(this.startX - e.getPageX());
18294 var diffY = Math.abs(this.startY - e.getPageY());
18295 if (diffX > this.clickPixelThresh ||
18296 diffY > this.clickPixelThresh) {
18297 this.startDrag(this.startX, this.startY);
18301 if (this.dragThreshMet) {
18302 this.dragCurrent.b4Drag(e);
18303 this.dragCurrent.onDrag(e);
18304 if(!this.dragCurrent.moveOnly){
18305 this.fireEvents(e, false);
18315 * Iterates over all of the DragDrop elements to find ones we are
18316 * hovering over or dropping on
18317 * @method fireEvents
18318 * @param {Event} e the event
18319 * @param {boolean} isDrop is this a drop op or a mouseover op?
18323 fireEvents: function(e, isDrop) {
18324 var dc = this.dragCurrent;
18326 // If the user did the mouse up outside of the window, we could
18327 // get here even though we have ended the drag.
18328 if (!dc || dc.isLocked()) {
18332 var pt = e.getPoint();
18334 // cache the previous dragOver array
18340 var enterEvts = [];
18342 // Check to see if the object(s) we were hovering over is no longer
18343 // being hovered over so we can fire the onDragOut event
18344 for (var i in this.dragOvers) {
18346 var ddo = this.dragOvers[i];
18348 if (! this.isTypeOfDD(ddo)) {
18352 if (! this.isOverTarget(pt, ddo, this.mode)) {
18353 outEvts.push( ddo );
18356 oldOvers[i] = true;
18357 delete this.dragOvers[i];
18360 for (var sGroup in dc.groups) {
18362 if ("string" != typeof sGroup) {
18366 for (i in this.ids[sGroup]) {
18367 var oDD = this.ids[sGroup][i];
18368 if (! this.isTypeOfDD(oDD)) {
18372 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18373 if (this.isOverTarget(pt, oDD, this.mode)) {
18374 // look for drop interactions
18376 dropEvts.push( oDD );
18377 // look for drag enter and drag over interactions
18380 // initial drag over: dragEnter fires
18381 if (!oldOvers[oDD.id]) {
18382 enterEvts.push( oDD );
18383 // subsequent drag overs: dragOver fires
18385 overEvts.push( oDD );
18388 this.dragOvers[oDD.id] = oDD;
18396 if (outEvts.length) {
18397 dc.b4DragOut(e, outEvts);
18398 dc.onDragOut(e, outEvts);
18401 if (enterEvts.length) {
18402 dc.onDragEnter(e, enterEvts);
18405 if (overEvts.length) {
18406 dc.b4DragOver(e, overEvts);
18407 dc.onDragOver(e, overEvts);
18410 if (dropEvts.length) {
18411 dc.b4DragDrop(e, dropEvts);
18412 dc.onDragDrop(e, dropEvts);
18416 // fire dragout events
18418 for (i=0, len=outEvts.length; i<len; ++i) {
18419 dc.b4DragOut(e, outEvts[i].id);
18420 dc.onDragOut(e, outEvts[i].id);
18423 // fire enter events
18424 for (i=0,len=enterEvts.length; i<len; ++i) {
18425 // dc.b4DragEnter(e, oDD.id);
18426 dc.onDragEnter(e, enterEvts[i].id);
18429 // fire over events
18430 for (i=0,len=overEvts.length; i<len; ++i) {
18431 dc.b4DragOver(e, overEvts[i].id);
18432 dc.onDragOver(e, overEvts[i].id);
18435 // fire drop events
18436 for (i=0, len=dropEvts.length; i<len; ++i) {
18437 dc.b4DragDrop(e, dropEvts[i].id);
18438 dc.onDragDrop(e, dropEvts[i].id);
18443 // notify about a drop that did not find a target
18444 if (isDrop && !dropEvts.length) {
18445 dc.onInvalidDrop(e);
18451 * Helper function for getting the best match from the list of drag
18452 * and drop objects returned by the drag and drop events when we are
18453 * in INTERSECT mode. It returns either the first object that the
18454 * cursor is over, or the object that has the greatest overlap with
18455 * the dragged element.
18456 * @method getBestMatch
18457 * @param {DragDrop[]} dds The array of drag and drop objects
18459 * @return {DragDrop} The best single match
18462 getBestMatch: function(dds) {
18464 // Return null if the input is not what we expect
18465 //if (!dds || !dds.length || dds.length == 0) {
18467 // If there is only one item, it wins
18468 //} else if (dds.length == 1) {
18470 var len = dds.length;
18475 // Loop through the targeted items
18476 for (var i=0; i<len; ++i) {
18478 // If the cursor is over the object, it wins. If the
18479 // cursor is over multiple matches, the first one we come
18481 if (dd.cursorIsOver) {
18484 // Otherwise the object with the most overlap wins
18487 winner.overlap.getArea() < dd.overlap.getArea()) {
18498 * Refreshes the cache of the top-left and bottom-right points of the
18499 * drag and drop objects in the specified group(s). This is in the
18500 * format that is stored in the drag and drop instance, so typical
18503 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18507 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18509 * @TODO this really should be an indexed array. Alternatively this
18510 * method could accept both.
18511 * @method refreshCache
18512 * @param {Object} groups an associative array of groups to refresh
18515 refreshCache: function(groups) {
18516 for (var sGroup in groups) {
18517 if ("string" != typeof sGroup) {
18520 for (var i in this.ids[sGroup]) {
18521 var oDD = this.ids[sGroup][i];
18523 if (this.isTypeOfDD(oDD)) {
18524 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18525 var loc = this.getLocation(oDD);
18527 this.locationCache[oDD.id] = loc;
18529 delete this.locationCache[oDD.id];
18530 // this will unregister the drag and drop object if
18531 // the element is not in a usable state
18540 * This checks to make sure an element exists and is in the DOM. The
18541 * main purpose is to handle cases where innerHTML is used to remove
18542 * drag and drop objects from the DOM. IE provides an 'unspecified
18543 * error' when trying to access the offsetParent of such an element
18545 * @param {HTMLElement} el the element to check
18546 * @return {boolean} true if the element looks usable
18549 verifyEl: function(el) {
18554 parent = el.offsetParent;
18557 parent = el.offsetParent;
18568 * Returns a Region object containing the drag and drop element's position
18569 * and size, including the padding configured for it
18570 * @method getLocation
18571 * @param {DragDrop} oDD the drag and drop object to get the
18573 * @return {Roo.lib.Region} a Region object representing the total area
18574 * the element occupies, including any padding
18575 * the instance is configured for.
18578 getLocation: function(oDD) {
18579 if (! this.isTypeOfDD(oDD)) {
18583 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18586 pos= Roo.lib.Dom.getXY(el);
18594 x2 = x1 + el.offsetWidth;
18596 y2 = y1 + el.offsetHeight;
18598 t = y1 - oDD.padding[0];
18599 r = x2 + oDD.padding[1];
18600 b = y2 + oDD.padding[2];
18601 l = x1 - oDD.padding[3];
18603 return new Roo.lib.Region( t, r, b, l );
18607 * Checks the cursor location to see if it over the target
18608 * @method isOverTarget
18609 * @param {Roo.lib.Point} pt The point to evaluate
18610 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18611 * @return {boolean} true if the mouse is over the target
18615 isOverTarget: function(pt, oTarget, intersect) {
18616 // use cache if available
18617 var loc = this.locationCache[oTarget.id];
18618 if (!loc || !this.useCache) {
18619 loc = this.getLocation(oTarget);
18620 this.locationCache[oTarget.id] = loc;
18628 oTarget.cursorIsOver = loc.contains( pt );
18630 // DragDrop is using this as a sanity check for the initial mousedown
18631 // in this case we are done. In POINT mode, if the drag obj has no
18632 // contraints, we are also done. Otherwise we need to evaluate the
18633 // location of the target as related to the actual location of the
18634 // dragged element.
18635 var dc = this.dragCurrent;
18636 if (!dc || !dc.getTargetCoord ||
18637 (!intersect && !dc.constrainX && !dc.constrainY)) {
18638 return oTarget.cursorIsOver;
18641 oTarget.overlap = null;
18643 // Get the current location of the drag element, this is the
18644 // location of the mouse event less the delta that represents
18645 // where the original mousedown happened on the element. We
18646 // need to consider constraints and ticks as well.
18647 var pos = dc.getTargetCoord(pt.x, pt.y);
18649 var el = dc.getDragEl();
18650 var curRegion = new Roo.lib.Region( pos.y,
18651 pos.x + el.offsetWidth,
18652 pos.y + el.offsetHeight,
18655 var overlap = curRegion.intersect(loc);
18658 oTarget.overlap = overlap;
18659 return (intersect) ? true : oTarget.cursorIsOver;
18666 * unload event handler
18667 * @method _onUnload
18671 _onUnload: function(e, me) {
18672 Roo.dd.DragDropMgr.unregAll();
18676 * Cleans up the drag and drop events and objects.
18681 unregAll: function() {
18683 if (this.dragCurrent) {
18685 this.dragCurrent = null;
18688 this._execOnAll("unreg", []);
18690 for (i in this.elementCache) {
18691 delete this.elementCache[i];
18694 this.elementCache = {};
18699 * A cache of DOM elements
18700 * @property elementCache
18707 * Get the wrapper for the DOM element specified
18708 * @method getElWrapper
18709 * @param {String} id the id of the element to get
18710 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18712 * @deprecated This wrapper isn't that useful
18715 getElWrapper: function(id) {
18716 var oWrapper = this.elementCache[id];
18717 if (!oWrapper || !oWrapper.el) {
18718 oWrapper = this.elementCache[id] =
18719 new this.ElementWrapper(Roo.getDom(id));
18725 * Returns the actual DOM element
18726 * @method getElement
18727 * @param {String} id the id of the elment to get
18728 * @return {Object} The element
18729 * @deprecated use Roo.getDom instead
18732 getElement: function(id) {
18733 return Roo.getDom(id);
18737 * Returns the style property for the DOM element (i.e.,
18738 * document.getElById(id).style)
18740 * @param {String} id the id of the elment to get
18741 * @return {Object} The style property of the element
18742 * @deprecated use Roo.getDom instead
18745 getCss: function(id) {
18746 var el = Roo.getDom(id);
18747 return (el) ? el.style : null;
18751 * Inner class for cached elements
18752 * @class DragDropMgr.ElementWrapper
18757 ElementWrapper: function(el) {
18762 this.el = el || null;
18767 this.id = this.el && el.id;
18769 * A reference to the style property
18772 this.css = this.el && el.style;
18776 * Returns the X position of an html element
18778 * @param el the element for which to get the position
18779 * @return {int} the X coordinate
18781 * @deprecated use Roo.lib.Dom.getX instead
18784 getPosX: function(el) {
18785 return Roo.lib.Dom.getX(el);
18789 * Returns the Y position of an html element
18791 * @param el the element for which to get the position
18792 * @return {int} the Y coordinate
18793 * @deprecated use Roo.lib.Dom.getY instead
18796 getPosY: function(el) {
18797 return Roo.lib.Dom.getY(el);
18801 * Swap two nodes. In IE, we use the native method, for others we
18802 * emulate the IE behavior
18804 * @param n1 the first node to swap
18805 * @param n2 the other node to swap
18808 swapNode: function(n1, n2) {
18812 var p = n2.parentNode;
18813 var s = n2.nextSibling;
18816 p.insertBefore(n1, n2);
18817 } else if (n2 == n1.nextSibling) {
18818 p.insertBefore(n2, n1);
18820 n1.parentNode.replaceChild(n2, n1);
18821 p.insertBefore(n1, s);
18827 * Returns the current scroll position
18828 * @method getScroll
18832 getScroll: function () {
18833 var t, l, dde=document.documentElement, db=document.body;
18834 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18836 l = dde.scrollLeft;
18843 return { top: t, left: l };
18847 * Returns the specified element style property
18849 * @param {HTMLElement} el the element
18850 * @param {string} styleProp the style property
18851 * @return {string} The value of the style property
18852 * @deprecated use Roo.lib.Dom.getStyle
18855 getStyle: function(el, styleProp) {
18856 return Roo.fly(el).getStyle(styleProp);
18860 * Gets the scrollTop
18861 * @method getScrollTop
18862 * @return {int} the document's scrollTop
18865 getScrollTop: function () { return this.getScroll().top; },
18868 * Gets the scrollLeft
18869 * @method getScrollLeft
18870 * @return {int} the document's scrollTop
18873 getScrollLeft: function () { return this.getScroll().left; },
18876 * Sets the x/y position of an element to the location of the
18879 * @param {HTMLElement} moveEl The element to move
18880 * @param {HTMLElement} targetEl The position reference element
18883 moveToEl: function (moveEl, targetEl) {
18884 var aCoord = Roo.lib.Dom.getXY(targetEl);
18885 Roo.lib.Dom.setXY(moveEl, aCoord);
18889 * Numeric array sort function
18890 * @method numericSort
18893 numericSort: function(a, b) { return (a - b); },
18897 * @property _timeoutCount
18904 * Trying to make the load order less important. Without this we get
18905 * an error if this file is loaded before the Event Utility.
18906 * @method _addListeners
18910 _addListeners: function() {
18911 var DDM = Roo.dd.DDM;
18912 if ( Roo.lib.Event && document ) {
18915 if (DDM._timeoutCount > 2000) {
18917 setTimeout(DDM._addListeners, 10);
18918 if (document && document.body) {
18919 DDM._timeoutCount += 1;
18926 * Recursively searches the immediate parent and all child nodes for
18927 * the handle element in order to determine wheter or not it was
18929 * @method handleWasClicked
18930 * @param node the html element to inspect
18933 handleWasClicked: function(node, id) {
18934 if (this.isHandle(id, node.id)) {
18937 // check to see if this is a text node child of the one we want
18938 var p = node.parentNode;
18941 if (this.isHandle(id, p.id)) {
18956 // shorter alias, save a few bytes
18957 Roo.dd.DDM = Roo.dd.DragDropMgr;
18958 Roo.dd.DDM._addListeners();
18962 * Ext JS Library 1.1.1
18963 * Copyright(c) 2006-2007, Ext JS, LLC.
18965 * Originally Released Under LGPL - original licence link has changed is not relivant.
18968 * <script type="text/javascript">
18973 * A DragDrop implementation where the linked element follows the
18974 * mouse cursor during a drag.
18975 * @extends Roo.dd.DragDrop
18977 * @param {String} id the id of the linked element
18978 * @param {String} sGroup the group of related DragDrop items
18979 * @param {object} config an object containing configurable attributes
18980 * Valid properties for DD:
18983 Roo.dd.DD = function(id, sGroup, config) {
18985 this.init(id, sGroup, config);
18989 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18992 * When set to true, the utility automatically tries to scroll the browser
18993 * window wehn a drag and drop element is dragged near the viewport boundary.
18994 * Defaults to true.
19001 * Sets the pointer offset to the distance between the linked element's top
19002 * left corner and the location the element was clicked
19003 * @method autoOffset
19004 * @param {int} iPageX the X coordinate of the click
19005 * @param {int} iPageY the Y coordinate of the click
19007 autoOffset: function(iPageX, iPageY) {
19008 var x = iPageX - this.startPageX;
19009 var y = iPageY - this.startPageY;
19010 this.setDelta(x, y);
19014 * Sets the pointer offset. You can call this directly to force the
19015 * offset to be in a particular location (e.g., pass in 0,0 to set it
19016 * to the center of the object)
19018 * @param {int} iDeltaX the distance from the left
19019 * @param {int} iDeltaY the distance from the top
19021 setDelta: function(iDeltaX, iDeltaY) {
19022 this.deltaX = iDeltaX;
19023 this.deltaY = iDeltaY;
19027 * Sets the drag element to the location of the mousedown or click event,
19028 * maintaining the cursor location relative to the location on the element
19029 * that was clicked. Override this if you want to place the element in a
19030 * location other than where the cursor is.
19031 * @method setDragElPos
19032 * @param {int} iPageX the X coordinate of the mousedown or drag event
19033 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19035 setDragElPos: function(iPageX, iPageY) {
19036 // the first time we do this, we are going to check to make sure
19037 // the element has css positioning
19039 var el = this.getDragEl();
19040 this.alignElWithMouse(el, iPageX, iPageY);
19044 * Sets the element to the location of the mousedown or click event,
19045 * maintaining the cursor location relative to the location on the element
19046 * that was clicked. Override this if you want to place the element in a
19047 * location other than where the cursor is.
19048 * @method alignElWithMouse
19049 * @param {HTMLElement} el the element to move
19050 * @param {int} iPageX the X coordinate of the mousedown or drag event
19051 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19053 alignElWithMouse: function(el, iPageX, iPageY) {
19054 var oCoord = this.getTargetCoord(iPageX, iPageY);
19055 var fly = el.dom ? el : Roo.fly(el);
19056 if (!this.deltaSetXY) {
19057 var aCoord = [oCoord.x, oCoord.y];
19059 var newLeft = fly.getLeft(true);
19060 var newTop = fly.getTop(true);
19061 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
19063 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
19066 this.cachePosition(oCoord.x, oCoord.y);
19067 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
19072 * Saves the most recent position so that we can reset the constraints and
19073 * tick marks on-demand. We need to know this so that we can calculate the
19074 * number of pixels the element is offset from its original position.
19075 * @method cachePosition
19076 * @param iPageX the current x position (optional, this just makes it so we
19077 * don't have to look it up again)
19078 * @param iPageY the current y position (optional, this just makes it so we
19079 * don't have to look it up again)
19081 cachePosition: function(iPageX, iPageY) {
19083 this.lastPageX = iPageX;
19084 this.lastPageY = iPageY;
19086 var aCoord = Roo.lib.Dom.getXY(this.getEl());
19087 this.lastPageX = aCoord[0];
19088 this.lastPageY = aCoord[1];
19093 * Auto-scroll the window if the dragged object has been moved beyond the
19094 * visible window boundary.
19095 * @method autoScroll
19096 * @param {int} x the drag element's x position
19097 * @param {int} y the drag element's y position
19098 * @param {int} h the height of the drag element
19099 * @param {int} w the width of the drag element
19102 autoScroll: function(x, y, h, w) {
19105 // The client height
19106 var clientH = Roo.lib.Dom.getViewWidth();
19108 // The client width
19109 var clientW = Roo.lib.Dom.getViewHeight();
19111 // The amt scrolled down
19112 var st = this.DDM.getScrollTop();
19114 // The amt scrolled right
19115 var sl = this.DDM.getScrollLeft();
19117 // Location of the bottom of the element
19120 // Location of the right of the element
19123 // The distance from the cursor to the bottom of the visible area,
19124 // adjusted so that we don't scroll if the cursor is beyond the
19125 // element drag constraints
19126 var toBot = (clientH + st - y - this.deltaY);
19128 // The distance from the cursor to the right of the visible area
19129 var toRight = (clientW + sl - x - this.deltaX);
19132 // How close to the edge the cursor must be before we scroll
19133 // var thresh = (document.all) ? 100 : 40;
19136 // How many pixels to scroll per autoscroll op. This helps to reduce
19137 // clunky scrolling. IE is more sensitive about this ... it needs this
19138 // value to be higher.
19139 var scrAmt = (document.all) ? 80 : 30;
19141 // Scroll down if we are near the bottom of the visible page and the
19142 // obj extends below the crease
19143 if ( bot > clientH && toBot < thresh ) {
19144 window.scrollTo(sl, st + scrAmt);
19147 // Scroll up if the window is scrolled down and the top of the object
19148 // goes above the top border
19149 if ( y < st && st > 0 && y - st < thresh ) {
19150 window.scrollTo(sl, st - scrAmt);
19153 // Scroll right if the obj is beyond the right border and the cursor is
19154 // near the border.
19155 if ( right > clientW && toRight < thresh ) {
19156 window.scrollTo(sl + scrAmt, st);
19159 // Scroll left if the window has been scrolled to the right and the obj
19160 // extends past the left border
19161 if ( x < sl && sl > 0 && x - sl < thresh ) {
19162 window.scrollTo(sl - scrAmt, st);
19168 * Finds the location the element should be placed if we want to move
19169 * it to where the mouse location less the click offset would place us.
19170 * @method getTargetCoord
19171 * @param {int} iPageX the X coordinate of the click
19172 * @param {int} iPageY the Y coordinate of the click
19173 * @return an object that contains the coordinates (Object.x and Object.y)
19176 getTargetCoord: function(iPageX, iPageY) {
19179 var x = iPageX - this.deltaX;
19180 var y = iPageY - this.deltaY;
19182 if (this.constrainX) {
19183 if (x < this.minX) { x = this.minX; }
19184 if (x > this.maxX) { x = this.maxX; }
19187 if (this.constrainY) {
19188 if (y < this.minY) { y = this.minY; }
19189 if (y > this.maxY) { y = this.maxY; }
19192 x = this.getTick(x, this.xTicks);
19193 y = this.getTick(y, this.yTicks);
19200 * Sets up config options specific to this class. Overrides
19201 * Roo.dd.DragDrop, but all versions of this method through the
19202 * inheritance chain are called
19204 applyConfig: function() {
19205 Roo.dd.DD.superclass.applyConfig.call(this);
19206 this.scroll = (this.config.scroll !== false);
19210 * Event that fires prior to the onMouseDown event. Overrides
19213 b4MouseDown: function(e) {
19214 // this.resetConstraints();
19215 this.autoOffset(e.getPageX(),
19220 * Event that fires prior to the onDrag event. Overrides
19223 b4Drag: function(e) {
19224 this.setDragElPos(e.getPageX(),
19228 toString: function() {
19229 return ("DD " + this.id);
19232 //////////////////////////////////////////////////////////////////////////
19233 // Debugging ygDragDrop events that can be overridden
19234 //////////////////////////////////////////////////////////////////////////
19236 startDrag: function(x, y) {
19239 onDrag: function(e) {
19242 onDragEnter: function(e, id) {
19245 onDragOver: function(e, id) {
19248 onDragOut: function(e, id) {
19251 onDragDrop: function(e, id) {
19254 endDrag: function(e) {
19261 * Ext JS Library 1.1.1
19262 * Copyright(c) 2006-2007, Ext JS, LLC.
19264 * Originally Released Under LGPL - original licence link has changed is not relivant.
19267 * <script type="text/javascript">
19271 * @class Roo.dd.DDProxy
19272 * A DragDrop implementation that inserts an empty, bordered div into
19273 * the document that follows the cursor during drag operations. At the time of
19274 * the click, the frame div is resized to the dimensions of the linked html
19275 * element, and moved to the exact location of the linked element.
19277 * References to the "frame" element refer to the single proxy element that
19278 * was created to be dragged in place of all DDProxy elements on the
19281 * @extends Roo.dd.DD
19283 * @param {String} id the id of the linked html element
19284 * @param {String} sGroup the group of related DragDrop objects
19285 * @param {object} config an object containing configurable attributes
19286 * Valid properties for DDProxy in addition to those in DragDrop:
19287 * resizeFrame, centerFrame, dragElId
19289 Roo.dd.DDProxy = function(id, sGroup, config) {
19291 this.init(id, sGroup, config);
19297 * The default drag frame div id
19298 * @property Roo.dd.DDProxy.dragElId
19302 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19304 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19307 * By default we resize the drag frame to be the same size as the element
19308 * we want to drag (this is to get the frame effect). We can turn it off
19309 * if we want a different behavior.
19310 * @property resizeFrame
19316 * By default the frame is positioned exactly where the drag element is, so
19317 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19318 * you do not have constraints on the obj is to have the drag frame centered
19319 * around the cursor. Set centerFrame to true for this effect.
19320 * @property centerFrame
19323 centerFrame: false,
19326 * Creates the proxy element if it does not yet exist
19327 * @method createFrame
19329 createFrame: function() {
19331 var body = document.body;
19333 if (!body || !body.firstChild) {
19334 setTimeout( function() { self.createFrame(); }, 50 );
19338 var div = this.getDragEl();
19341 div = document.createElement("div");
19342 div.id = this.dragElId;
19345 s.position = "absolute";
19346 s.visibility = "hidden";
19348 s.border = "2px solid #aaa";
19351 // appendChild can blow up IE if invoked prior to the window load event
19352 // while rendering a table. It is possible there are other scenarios
19353 // that would cause this to happen as well.
19354 body.insertBefore(div, body.firstChild);
19359 * Initialization for the drag frame element. Must be called in the
19360 * constructor of all subclasses
19361 * @method initFrame
19363 initFrame: function() {
19364 this.createFrame();
19367 applyConfig: function() {
19368 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19370 this.resizeFrame = (this.config.resizeFrame !== false);
19371 this.centerFrame = (this.config.centerFrame);
19372 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19376 * Resizes the drag frame to the dimensions of the clicked object, positions
19377 * it over the object, and finally displays it
19378 * @method showFrame
19379 * @param {int} iPageX X click position
19380 * @param {int} iPageY Y click position
19383 showFrame: function(iPageX, iPageY) {
19384 var el = this.getEl();
19385 var dragEl = this.getDragEl();
19386 var s = dragEl.style;
19388 this._resizeProxy();
19390 if (this.centerFrame) {
19391 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19392 Math.round(parseInt(s.height, 10)/2) );
19395 this.setDragElPos(iPageX, iPageY);
19397 Roo.fly(dragEl).show();
19401 * The proxy is automatically resized to the dimensions of the linked
19402 * element when a drag is initiated, unless resizeFrame is set to false
19403 * @method _resizeProxy
19406 _resizeProxy: function() {
19407 if (this.resizeFrame) {
19408 var el = this.getEl();
19409 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19413 // overrides Roo.dd.DragDrop
19414 b4MouseDown: function(e) {
19415 var x = e.getPageX();
19416 var y = e.getPageY();
19417 this.autoOffset(x, y);
19418 this.setDragElPos(x, y);
19421 // overrides Roo.dd.DragDrop
19422 b4StartDrag: function(x, y) {
19423 // show the drag frame
19424 this.showFrame(x, y);
19427 // overrides Roo.dd.DragDrop
19428 b4EndDrag: function(e) {
19429 Roo.fly(this.getDragEl()).hide();
19432 // overrides Roo.dd.DragDrop
19433 // By default we try to move the element to the last location of the frame.
19434 // This is so that the default behavior mirrors that of Roo.dd.DD.
19435 endDrag: function(e) {
19437 var lel = this.getEl();
19438 var del = this.getDragEl();
19440 // Show the drag frame briefly so we can get its position
19441 del.style.visibility = "";
19444 // Hide the linked element before the move to get around a Safari
19446 lel.style.visibility = "hidden";
19447 Roo.dd.DDM.moveToEl(lel, del);
19448 del.style.visibility = "hidden";
19449 lel.style.visibility = "";
19454 beforeMove : function(){
19458 afterDrag : function(){
19462 toString: function() {
19463 return ("DDProxy " + this.id);
19469 * Ext JS Library 1.1.1
19470 * Copyright(c) 2006-2007, Ext JS, LLC.
19472 * Originally Released Under LGPL - original licence link has changed is not relivant.
19475 * <script type="text/javascript">
19479 * @class Roo.dd.DDTarget
19480 * A DragDrop implementation that does not move, but can be a drop
19481 * target. You would get the same result by simply omitting implementation
19482 * for the event callbacks, but this way we reduce the processing cost of the
19483 * event listener and the callbacks.
19484 * @extends Roo.dd.DragDrop
19486 * @param {String} id the id of the element that is a drop target
19487 * @param {String} sGroup the group of related DragDrop objects
19488 * @param {object} config an object containing configurable attributes
19489 * Valid properties for DDTarget in addition to those in
19493 Roo.dd.DDTarget = function(id, sGroup, config) {
19495 this.initTarget(id, sGroup, config);
19497 if (config.listeners || config.events) {
19498 Roo.dd.DragDrop.superclass.constructor.call(this, {
19499 listeners : config.listeners || {},
19500 events : config.events || {}
19505 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19506 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19507 toString: function() {
19508 return ("DDTarget " + this.id);
19513 * Ext JS Library 1.1.1
19514 * Copyright(c) 2006-2007, Ext JS, LLC.
19516 * Originally Released Under LGPL - original licence link has changed is not relivant.
19519 * <script type="text/javascript">
19524 * @class Roo.dd.ScrollManager
19525 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19526 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19529 Roo.dd.ScrollManager = function(){
19530 var ddm = Roo.dd.DragDropMgr;
19537 var onStop = function(e){
19542 var triggerRefresh = function(){
19543 if(ddm.dragCurrent){
19544 ddm.refreshCache(ddm.dragCurrent.groups);
19548 var doScroll = function(){
19549 if(ddm.dragCurrent){
19550 var dds = Roo.dd.ScrollManager;
19552 if(proc.el.scroll(proc.dir, dds.increment)){
19556 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19561 var clearProc = function(){
19563 clearInterval(proc.id);
19570 var startProc = function(el, dir){
19571 Roo.log('scroll startproc');
19575 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19578 var onFire = function(e, isDrop){
19580 if(isDrop || !ddm.dragCurrent){ return; }
19581 var dds = Roo.dd.ScrollManager;
19582 if(!dragEl || dragEl != ddm.dragCurrent){
19583 dragEl = ddm.dragCurrent;
19584 // refresh regions on drag start
19585 dds.refreshCache();
19588 var xy = Roo.lib.Event.getXY(e);
19589 var pt = new Roo.lib.Point(xy[0], xy[1]);
19590 for(var id in els){
19591 var el = els[id], r = el._region;
19592 if(r && r.contains(pt) && el.isScrollable()){
19593 if(r.bottom - pt.y <= dds.thresh){
19595 startProc(el, "down");
19598 }else if(r.right - pt.x <= dds.thresh){
19600 startProc(el, "left");
19603 }else if(pt.y - r.top <= dds.thresh){
19605 startProc(el, "up");
19608 }else if(pt.x - r.left <= dds.thresh){
19610 startProc(el, "right");
19619 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19620 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19624 * Registers new overflow element(s) to auto scroll
19625 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19627 register : function(el){
19628 if(el instanceof Array){
19629 for(var i = 0, len = el.length; i < len; i++) {
19630 this.register(el[i]);
19636 Roo.dd.ScrollManager.els = els;
19640 * Unregisters overflow element(s) so they are no longer scrolled
19641 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19643 unregister : function(el){
19644 if(el instanceof Array){
19645 for(var i = 0, len = el.length; i < len; i++) {
19646 this.unregister(el[i]);
19655 * The number of pixels from the edge of a container the pointer needs to be to
19656 * trigger scrolling (defaults to 25)
19662 * The number of pixels to scroll in each scroll increment (defaults to 50)
19668 * The frequency of scrolls in milliseconds (defaults to 500)
19674 * True to animate the scroll (defaults to true)
19680 * The animation duration in seconds -
19681 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19687 * Manually trigger a cache refresh.
19689 refreshCache : function(){
19690 for(var id in els){
19691 if(typeof els[id] == 'object'){ // for people extending the object prototype
19692 els[id]._region = els[id].getRegion();
19699 * Ext JS Library 1.1.1
19700 * Copyright(c) 2006-2007, Ext JS, LLC.
19702 * Originally Released Under LGPL - original licence link has changed is not relivant.
19705 * <script type="text/javascript">
19710 * @class Roo.dd.Registry
19711 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19712 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19715 Roo.dd.Registry = function(){
19718 var autoIdSeed = 0;
19720 var getId = function(el, autogen){
19721 if(typeof el == "string"){
19725 if(!id && autogen !== false){
19726 id = "roodd-" + (++autoIdSeed);
19734 * Register a drag drop element
19735 * @param {String|HTMLElement} element The id or DOM node to register
19736 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19737 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19738 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19739 * populated in the data object (if applicable):
19741 Value Description<br />
19742 --------- ------------------------------------------<br />
19743 handles Array of DOM nodes that trigger dragging<br />
19744 for the element being registered<br />
19745 isHandle True if the element passed in triggers<br />
19746 dragging itself, else false
19749 register : function(el, data){
19751 if(typeof el == "string"){
19752 el = document.getElementById(el);
19755 elements[getId(el)] = data;
19756 if(data.isHandle !== false){
19757 handles[data.ddel.id] = data;
19760 var hs = data.handles;
19761 for(var i = 0, len = hs.length; i < len; i++){
19762 handles[getId(hs[i])] = data;
19768 * Unregister a drag drop element
19769 * @param {String|HTMLElement} element The id or DOM node to unregister
19771 unregister : function(el){
19772 var id = getId(el, false);
19773 var data = elements[id];
19775 delete elements[id];
19777 var hs = data.handles;
19778 for(var i = 0, len = hs.length; i < len; i++){
19779 delete handles[getId(hs[i], false)];
19786 * Returns the handle registered for a DOM Node by id
19787 * @param {String|HTMLElement} id The DOM node or id to look up
19788 * @return {Object} handle The custom handle data
19790 getHandle : function(id){
19791 if(typeof id != "string"){ // must be element?
19794 return handles[id];
19798 * Returns the handle that is registered for the DOM node that is the target of the event
19799 * @param {Event} e The event
19800 * @return {Object} handle The custom handle data
19802 getHandleFromEvent : function(e){
19803 var t = Roo.lib.Event.getTarget(e);
19804 return t ? handles[t.id] : null;
19808 * Returns a custom data object that is registered for a DOM node by id
19809 * @param {String|HTMLElement} id The DOM node or id to look up
19810 * @return {Object} data The custom data
19812 getTarget : function(id){
19813 if(typeof id != "string"){ // must be element?
19816 return elements[id];
19820 * Returns a custom data object that is registered for the DOM node that is the target of the event
19821 * @param {Event} e The event
19822 * @return {Object} data The custom data
19824 getTargetFromEvent : function(e){
19825 var t = Roo.lib.Event.getTarget(e);
19826 return t ? elements[t.id] || handles[t.id] : null;
19831 * Ext JS Library 1.1.1
19832 * Copyright(c) 2006-2007, Ext JS, LLC.
19834 * Originally Released Under LGPL - original licence link has changed is not relivant.
19837 * <script type="text/javascript">
19842 * @class Roo.dd.StatusProxy
19843 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19844 * default drag proxy used by all Roo.dd components.
19846 * @param {Object} config
19848 Roo.dd.StatusProxy = function(config){
19849 Roo.apply(this, config);
19850 this.id = this.id || Roo.id();
19851 this.el = new Roo.Layer({
19853 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19854 {tag: "div", cls: "x-dd-drop-icon"},
19855 {tag: "div", cls: "x-dd-drag-ghost"}
19858 shadow: !config || config.shadow !== false
19860 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19861 this.dropStatus = this.dropNotAllowed;
19864 Roo.dd.StatusProxy.prototype = {
19866 * @cfg {String} dropAllowed
19867 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19869 dropAllowed : "x-dd-drop-ok",
19871 * @cfg {String} dropNotAllowed
19872 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19874 dropNotAllowed : "x-dd-drop-nodrop",
19877 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19878 * over the current target element.
19879 * @param {String} cssClass The css class for the new drop status indicator image
19881 setStatus : function(cssClass){
19882 cssClass = cssClass || this.dropNotAllowed;
19883 if(this.dropStatus != cssClass){
19884 this.el.replaceClass(this.dropStatus, cssClass);
19885 this.dropStatus = cssClass;
19890 * Resets the status indicator to the default dropNotAllowed value
19891 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19893 reset : function(clearGhost){
19894 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19895 this.dropStatus = this.dropNotAllowed;
19897 this.ghost.update("");
19902 * Updates the contents of the ghost element
19903 * @param {String} html The html that will replace the current innerHTML of the ghost element
19905 update : function(html){
19906 if(typeof html == "string"){
19907 this.ghost.update(html);
19909 this.ghost.update("");
19910 html.style.margin = "0";
19911 this.ghost.dom.appendChild(html);
19913 // ensure float = none set?? cant remember why though.
19914 var el = this.ghost.dom.firstChild;
19916 Roo.fly(el).setStyle('float', 'none');
19921 * Returns the underlying proxy {@link Roo.Layer}
19922 * @return {Roo.Layer} el
19924 getEl : function(){
19929 * Returns the ghost element
19930 * @return {Roo.Element} el
19932 getGhost : function(){
19938 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19940 hide : function(clear){
19948 * Stops the repair animation if it's currently running
19951 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19957 * Displays this proxy
19964 * Force the Layer to sync its shadow and shim positions to the element
19971 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19972 * invalid drop operation by the item being dragged.
19973 * @param {Array} xy The XY position of the element ([x, y])
19974 * @param {Function} callback The function to call after the repair is complete
19975 * @param {Object} scope The scope in which to execute the callback
19977 repair : function(xy, callback, scope){
19978 this.callback = callback;
19979 this.scope = scope;
19980 if(xy && this.animRepair !== false){
19981 this.el.addClass("x-dd-drag-repair");
19982 this.el.hideUnders(true);
19983 this.anim = this.el.shift({
19984 duration: this.repairDuration || .5,
19988 callback: this.afterRepair,
19992 this.afterRepair();
19997 afterRepair : function(){
19999 if(typeof this.callback == "function"){
20000 this.callback.call(this.scope || this);
20002 this.callback = null;
20007 * Ext JS Library 1.1.1
20008 * Copyright(c) 2006-2007, Ext JS, LLC.
20010 * Originally Released Under LGPL - original licence link has changed is not relivant.
20013 * <script type="text/javascript">
20017 * @class Roo.dd.DragSource
20018 * @extends Roo.dd.DDProxy
20019 * A simple class that provides the basic implementation needed to make any element draggable.
20021 * @param {String/HTMLElement/Element} el The container element
20022 * @param {Object} config
20024 Roo.dd.DragSource = function(el, config){
20025 this.el = Roo.get(el);
20026 this.dragData = {};
20028 Roo.apply(this, config);
20031 this.proxy = new Roo.dd.StatusProxy();
20034 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
20035 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
20037 this.dragging = false;
20040 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
20042 * @cfg {String} dropAllowed
20043 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20045 dropAllowed : "x-dd-drop-ok",
20047 * @cfg {String} dropNotAllowed
20048 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20050 dropNotAllowed : "x-dd-drop-nodrop",
20053 * Returns the data object associated with this drag source
20054 * @return {Object} data An object containing arbitrary data
20056 getDragData : function(e){
20057 return this.dragData;
20061 onDragEnter : function(e, id){
20062 var target = Roo.dd.DragDropMgr.getDDById(id);
20063 this.cachedTarget = target;
20064 if(this.beforeDragEnter(target, e, id) !== false){
20065 if(target.isNotifyTarget){
20066 var status = target.notifyEnter(this, e, this.dragData);
20067 this.proxy.setStatus(status);
20069 this.proxy.setStatus(this.dropAllowed);
20072 if(this.afterDragEnter){
20074 * An empty function by default, but provided so that you can perform a custom action
20075 * when the dragged item enters the drop target by providing an implementation.
20076 * @param {Roo.dd.DragDrop} target The drop target
20077 * @param {Event} e The event object
20078 * @param {String} id The id of the dragged element
20079 * @method afterDragEnter
20081 this.afterDragEnter(target, e, id);
20087 * An empty function by default, but provided so that you can perform a custom action
20088 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
20089 * @param {Roo.dd.DragDrop} target The drop target
20090 * @param {Event} e The event object
20091 * @param {String} id The id of the dragged element
20092 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20094 beforeDragEnter : function(target, e, id){
20099 alignElWithMouse: function() {
20100 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
20105 onDragOver : function(e, id){
20106 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20107 if(this.beforeDragOver(target, e, id) !== false){
20108 if(target.isNotifyTarget){
20109 var status = target.notifyOver(this, e, this.dragData);
20110 this.proxy.setStatus(status);
20113 if(this.afterDragOver){
20115 * An empty function by default, but provided so that you can perform a custom action
20116 * while the dragged item is over the drop target by providing an implementation.
20117 * @param {Roo.dd.DragDrop} target The drop target
20118 * @param {Event} e The event object
20119 * @param {String} id The id of the dragged element
20120 * @method afterDragOver
20122 this.afterDragOver(target, e, id);
20128 * An empty function by default, but provided so that you can perform a custom action
20129 * while the dragged item is over the drop target and optionally cancel the onDragOver.
20130 * @param {Roo.dd.DragDrop} target The drop target
20131 * @param {Event} e The event object
20132 * @param {String} id The id of the dragged element
20133 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20135 beforeDragOver : function(target, e, id){
20140 onDragOut : function(e, id){
20141 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20142 if(this.beforeDragOut(target, e, id) !== false){
20143 if(target.isNotifyTarget){
20144 target.notifyOut(this, e, this.dragData);
20146 this.proxy.reset();
20147 if(this.afterDragOut){
20149 * An empty function by default, but provided so that you can perform a custom action
20150 * after the dragged item is dragged out of the target without dropping.
20151 * @param {Roo.dd.DragDrop} target The drop target
20152 * @param {Event} e The event object
20153 * @param {String} id The id of the dragged element
20154 * @method afterDragOut
20156 this.afterDragOut(target, e, id);
20159 this.cachedTarget = null;
20163 * An empty function by default, but provided so that you can perform a custom action before the dragged
20164 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20165 * @param {Roo.dd.DragDrop} target The drop target
20166 * @param {Event} e The event object
20167 * @param {String} id The id of the dragged element
20168 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20170 beforeDragOut : function(target, e, id){
20175 onDragDrop : function(e, id){
20176 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20177 if(this.beforeDragDrop(target, e, id) !== false){
20178 if(target.isNotifyTarget){
20179 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20180 this.onValidDrop(target, e, id);
20182 this.onInvalidDrop(target, e, id);
20185 this.onValidDrop(target, e, id);
20188 if(this.afterDragDrop){
20190 * An empty function by default, but provided so that you can perform a custom action
20191 * after a valid drag drop has occurred by providing an implementation.
20192 * @param {Roo.dd.DragDrop} target The drop target
20193 * @param {Event} e The event object
20194 * @param {String} id The id of the dropped element
20195 * @method afterDragDrop
20197 this.afterDragDrop(target, e, id);
20200 delete this.cachedTarget;
20204 * An empty function by default, but provided so that you can perform a custom action before the dragged
20205 * item is dropped onto the target and optionally cancel the onDragDrop.
20206 * @param {Roo.dd.DragDrop} target The drop target
20207 * @param {Event} e The event object
20208 * @param {String} id The id of the dragged element
20209 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20211 beforeDragDrop : function(target, e, id){
20216 onValidDrop : function(target, e, id){
20218 if(this.afterValidDrop){
20220 * An empty function by default, but provided so that you can perform a custom action
20221 * after a valid drop has occurred by providing an implementation.
20222 * @param {Object} target The target DD
20223 * @param {Event} e The event object
20224 * @param {String} id The id of the dropped element
20225 * @method afterInvalidDrop
20227 this.afterValidDrop(target, e, id);
20232 getRepairXY : function(e, data){
20233 return this.el.getXY();
20237 onInvalidDrop : function(target, e, id){
20238 this.beforeInvalidDrop(target, e, id);
20239 if(this.cachedTarget){
20240 if(this.cachedTarget.isNotifyTarget){
20241 this.cachedTarget.notifyOut(this, e, this.dragData);
20243 this.cacheTarget = null;
20245 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20247 if(this.afterInvalidDrop){
20249 * An empty function by default, but provided so that you can perform a custom action
20250 * after an invalid drop has occurred by providing an implementation.
20251 * @param {Event} e The event object
20252 * @param {String} id The id of the dropped element
20253 * @method afterInvalidDrop
20255 this.afterInvalidDrop(e, id);
20260 afterRepair : function(){
20262 this.el.highlight(this.hlColor || "c3daf9");
20264 this.dragging = false;
20268 * An empty function by default, but provided so that you can perform a custom action after an invalid
20269 * drop has occurred.
20270 * @param {Roo.dd.DragDrop} target The drop target
20271 * @param {Event} e The event object
20272 * @param {String} id The id of the dragged element
20273 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20275 beforeInvalidDrop : function(target, e, id){
20280 handleMouseDown : function(e){
20281 if(this.dragging) {
20284 var data = this.getDragData(e);
20285 if(data && this.onBeforeDrag(data, e) !== false){
20286 this.dragData = data;
20288 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20293 * An empty function by default, but provided so that you can perform a custom action before the initial
20294 * drag event begins and optionally cancel it.
20295 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20296 * @param {Event} e The event object
20297 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20299 onBeforeDrag : function(data, e){
20304 * An empty function by default, but provided so that you can perform a custom action once the initial
20305 * drag event has begun. The drag cannot be canceled from this function.
20306 * @param {Number} x The x position of the click on the dragged object
20307 * @param {Number} y The y position of the click on the dragged object
20309 onStartDrag : Roo.emptyFn,
20311 // private - YUI override
20312 startDrag : function(x, y){
20313 this.proxy.reset();
20314 this.dragging = true;
20315 this.proxy.update("");
20316 this.onInitDrag(x, y);
20321 onInitDrag : function(x, y){
20322 var clone = this.el.dom.cloneNode(true);
20323 clone.id = Roo.id(); // prevent duplicate ids
20324 this.proxy.update(clone);
20325 this.onStartDrag(x, y);
20330 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20331 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20333 getProxy : function(){
20338 * Hides the drag source's {@link Roo.dd.StatusProxy}
20340 hideProxy : function(){
20342 this.proxy.reset(true);
20343 this.dragging = false;
20347 triggerCacheRefresh : function(){
20348 Roo.dd.DDM.refreshCache(this.groups);
20351 // private - override to prevent hiding
20352 b4EndDrag: function(e) {
20355 // private - override to prevent moving
20356 endDrag : function(e){
20357 this.onEndDrag(this.dragData, e);
20361 onEndDrag : function(data, e){
20364 // private - pin to cursor
20365 autoOffset : function(x, y) {
20366 this.setDelta(-12, -20);
20370 * Ext JS Library 1.1.1
20371 * Copyright(c) 2006-2007, Ext JS, LLC.
20373 * Originally Released Under LGPL - original licence link has changed is not relivant.
20376 * <script type="text/javascript">
20381 * @class Roo.dd.DropTarget
20382 * @extends Roo.dd.DDTarget
20383 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20384 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20386 * @param {String/HTMLElement/Element} el The container element
20387 * @param {Object} config
20389 Roo.dd.DropTarget = function(el, config){
20390 this.el = Roo.get(el);
20392 var listeners = false; ;
20393 if (config && config.listeners) {
20394 listeners= config.listeners;
20395 delete config.listeners;
20397 Roo.apply(this, config);
20399 if(this.containerScroll){
20400 Roo.dd.ScrollManager.register(this.el);
20404 * @scope Roo.dd.DropTarget
20409 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20410 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20411 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20413 * IMPORTANT : it should set this.overClass and this.dropAllowed
20415 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20416 * @param {Event} e The event
20417 * @param {Object} data An object containing arbitrary data supplied by the drag source
20423 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20424 * This method will be called on every mouse movement while the drag source is over the drop target.
20425 * This default implementation simply returns the dropAllowed config value.
20427 * IMPORTANT : it should set this.dropAllowed
20429 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20430 * @param {Event} e The event
20431 * @param {Object} data An object containing arbitrary data supplied by the drag source
20437 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20438 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20439 * overClass (if any) from the drop element.
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 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20450 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20451 * implementation that does something to process the drop event and returns true so that the drag source's
20452 * repair action does not run.
20454 * IMPORTANT : it should set this.success
20456 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20457 * @param {Event} e The event
20458 * @param {Object} data An object containing arbitrary data supplied by the drag source
20464 Roo.dd.DropTarget.superclass.constructor.call( this,
20466 this.ddGroup || this.group,
20469 listeners : listeners || {}
20477 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20479 * @cfg {String} overClass
20480 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20483 * @cfg {String} ddGroup
20484 * The drag drop group to handle drop events for
20488 * @cfg {String} dropAllowed
20489 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20491 dropAllowed : "x-dd-drop-ok",
20493 * @cfg {String} dropNotAllowed
20494 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20496 dropNotAllowed : "x-dd-drop-nodrop",
20498 * @cfg {boolean} success
20499 * set this after drop listener..
20503 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20504 * if the drop point is valid for over/enter..
20511 isNotifyTarget : true,
20516 notifyEnter : function(dd, e, data)
20519 this.fireEvent('enter', dd, e, data);
20520 if(this.overClass){
20521 this.el.addClass(this.overClass);
20523 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20524 this.valid ? this.dropAllowed : this.dropNotAllowed
20531 notifyOver : function(dd, e, data)
20534 this.fireEvent('over', dd, e, data);
20535 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20536 this.valid ? this.dropAllowed : this.dropNotAllowed
20543 notifyOut : function(dd, e, data)
20545 this.fireEvent('out', dd, e, data);
20546 if(this.overClass){
20547 this.el.removeClass(this.overClass);
20554 notifyDrop : function(dd, e, data)
20556 this.success = false;
20557 this.fireEvent('drop', dd, e, data);
20558 return this.success;
20562 * Ext JS Library 1.1.1
20563 * Copyright(c) 2006-2007, Ext JS, LLC.
20565 * Originally Released Under LGPL - original licence link has changed is not relivant.
20568 * <script type="text/javascript">
20573 * @class Roo.dd.DragZone
20574 * @extends Roo.dd.DragSource
20575 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20576 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20578 * @param {String/HTMLElement/Element} el The container element
20579 * @param {Object} config
20581 Roo.dd.DragZone = function(el, config){
20582 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20583 if(this.containerScroll){
20584 Roo.dd.ScrollManager.register(this.el);
20588 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20590 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20591 * for auto scrolling during drag operations.
20594 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20595 * method after a failed drop (defaults to "c3daf9" - light blue)
20599 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20600 * for a valid target to drag based on the mouse down. Override this method
20601 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20602 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20603 * @param {EventObject} e The mouse down event
20604 * @return {Object} The dragData
20606 getDragData : function(e){
20607 return Roo.dd.Registry.getHandleFromEvent(e);
20611 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20612 * this.dragData.ddel
20613 * @param {Number} x The x position of the click on the dragged object
20614 * @param {Number} y The y position of the click on the dragged object
20615 * @return {Boolean} true to continue the drag, false to cancel
20617 onInitDrag : function(x, y){
20618 this.proxy.update(this.dragData.ddel.cloneNode(true));
20619 this.onStartDrag(x, y);
20624 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20626 afterRepair : function(){
20628 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20630 this.dragging = false;
20634 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20635 * the XY of this.dragData.ddel
20636 * @param {EventObject} e The mouse up event
20637 * @return {Array} The xy location (e.g. [100, 200])
20639 getRepairXY : function(e){
20640 return Roo.Element.fly(this.dragData.ddel).getXY();
20644 * Ext JS Library 1.1.1
20645 * Copyright(c) 2006-2007, Ext JS, LLC.
20647 * Originally Released Under LGPL - original licence link has changed is not relivant.
20650 * <script type="text/javascript">
20653 * @class Roo.dd.DropZone
20654 * @extends Roo.dd.DropTarget
20655 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20656 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20658 * @param {String/HTMLElement/Element} el The container element
20659 * @param {Object} config
20661 Roo.dd.DropZone = function(el, config){
20662 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20665 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20667 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20668 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20669 * provide your own custom lookup.
20670 * @param {Event} e The event
20671 * @return {Object} data The custom data
20673 getTargetFromEvent : function(e){
20674 return Roo.dd.Registry.getTargetFromEvent(e);
20678 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20679 * that it has registered. This method has no default implementation and should be overridden to provide
20680 * node-specific processing if necessary.
20681 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20682 * {@link #getTargetFromEvent} for this node)
20683 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20684 * @param {Event} e The event
20685 * @param {Object} data An object containing arbitrary data supplied by the drag source
20687 onNodeEnter : function(n, dd, e, data){
20692 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20693 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20694 * overridden to provide the proper feedback.
20695 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20696 * {@link #getTargetFromEvent} for this node)
20697 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20698 * @param {Event} e The event
20699 * @param {Object} data An object containing arbitrary data supplied by the drag source
20700 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20701 * underlying {@link Roo.dd.StatusProxy} can be updated
20703 onNodeOver : function(n, dd, e, data){
20704 return this.dropAllowed;
20708 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20709 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20710 * node-specific processing if necessary.
20711 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20712 * {@link #getTargetFromEvent} for this node)
20713 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20714 * @param {Event} e The event
20715 * @param {Object} data An object containing arbitrary data supplied by the drag source
20717 onNodeOut : function(n, dd, e, data){
20722 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20723 * the drop node. The default implementation returns false, so it should be overridden to provide the
20724 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20725 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20726 * {@link #getTargetFromEvent} for this node)
20727 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20728 * @param {Event} e The event
20729 * @param {Object} data An object containing arbitrary data supplied by the drag source
20730 * @return {Boolean} True if the drop was valid, else false
20732 onNodeDrop : function(n, dd, e, data){
20737 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20738 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20739 * it should be overridden to provide the proper feedback if necessary.
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 {String} status The CSS class that communicates the drop status back to the source so that the
20744 * underlying {@link Roo.dd.StatusProxy} can be updated
20746 onContainerOver : function(dd, e, data){
20747 return this.dropNotAllowed;
20751 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20752 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20753 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20754 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20755 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20756 * @param {Event} e The event
20757 * @param {Object} data An object containing arbitrary data supplied by the drag source
20758 * @return {Boolean} True if the drop was valid, else false
20760 onContainerDrop : function(dd, e, data){
20765 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20766 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20767 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20768 * you should override this method and provide a custom implementation.
20769 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20770 * @param {Event} e The event
20771 * @param {Object} data An object containing arbitrary data supplied by the drag source
20772 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20773 * underlying {@link Roo.dd.StatusProxy} can be updated
20775 notifyEnter : function(dd, e, data){
20776 return this.dropNotAllowed;
20780 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20781 * This method will be called on every mouse movement while the drag source is over the drop zone.
20782 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20783 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20784 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20785 * registered node, it will call {@link #onContainerOver}.
20786 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20787 * @param {Event} e The event
20788 * @param {Object} data An object containing arbitrary data supplied by the drag source
20789 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20790 * underlying {@link Roo.dd.StatusProxy} can be updated
20792 notifyOver : function(dd, e, data){
20793 var n = this.getTargetFromEvent(e);
20794 if(!n){ // not over valid drop target
20795 if(this.lastOverNode){
20796 this.onNodeOut(this.lastOverNode, dd, e, data);
20797 this.lastOverNode = null;
20799 return this.onContainerOver(dd, e, data);
20801 if(this.lastOverNode != n){
20802 if(this.lastOverNode){
20803 this.onNodeOut(this.lastOverNode, dd, e, data);
20805 this.onNodeEnter(n, dd, e, data);
20806 this.lastOverNode = n;
20808 return this.onNodeOver(n, dd, e, data);
20812 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20813 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20814 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20815 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20816 * @param {Event} e The event
20817 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20819 notifyOut : function(dd, e, data){
20820 if(this.lastOverNode){
20821 this.onNodeOut(this.lastOverNode, dd, e, data);
20822 this.lastOverNode = null;
20827 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20828 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20829 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20830 * otherwise it will call {@link #onContainerDrop}.
20831 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20832 * @param {Event} e The event
20833 * @param {Object} data An object containing arbitrary data supplied by the drag source
20834 * @return {Boolean} True if the drop was valid, else false
20836 notifyDrop : function(dd, e, data){
20837 if(this.lastOverNode){
20838 this.onNodeOut(this.lastOverNode, dd, e, data);
20839 this.lastOverNode = null;
20841 var n = this.getTargetFromEvent(e);
20843 this.onNodeDrop(n, dd, e, data) :
20844 this.onContainerDrop(dd, e, data);
20848 triggerCacheRefresh : function(){
20849 Roo.dd.DDM.refreshCache(this.groups);
20853 * Ext JS Library 1.1.1
20854 * Copyright(c) 2006-2007, Ext JS, LLC.
20856 * Originally Released Under LGPL - original licence link has changed is not relivant.
20859 * <script type="text/javascript">
20864 * @class Roo.data.SortTypes
20866 * Defines the default sorting (casting?) comparison functions used when sorting data.
20868 Roo.data.SortTypes = {
20870 * Default sort that does nothing
20871 * @param {Mixed} s The value being converted
20872 * @return {Mixed} The comparison value
20874 none : function(s){
20879 * The regular expression used to strip tags
20883 stripTagsRE : /<\/?[^>]+>/gi,
20886 * Strips all HTML tags to sort on text only
20887 * @param {Mixed} s The value being converted
20888 * @return {String} The comparison value
20890 asText : function(s){
20891 return String(s).replace(this.stripTagsRE, "");
20895 * Strips all HTML tags to sort on text only - Case insensitive
20896 * @param {Mixed} s The value being converted
20897 * @return {String} The comparison value
20899 asUCText : function(s){
20900 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20904 * Case insensitive string
20905 * @param {Mixed} s The value being converted
20906 * @return {String} The comparison value
20908 asUCString : function(s) {
20909 return String(s).toUpperCase();
20914 * @param {Mixed} s The value being converted
20915 * @return {Number} The comparison value
20917 asDate : function(s) {
20921 if(s instanceof Date){
20922 return s.getTime();
20924 return Date.parse(String(s));
20929 * @param {Mixed} s The value being converted
20930 * @return {Float} The comparison value
20932 asFloat : function(s) {
20933 var val = parseFloat(String(s).replace(/,/g, ""));
20942 * @param {Mixed} s The value being converted
20943 * @return {Number} The comparison value
20945 asInt : function(s) {
20946 var val = parseInt(String(s).replace(/,/g, ""));
20954 * Ext JS Library 1.1.1
20955 * Copyright(c) 2006-2007, Ext JS, LLC.
20957 * Originally Released Under LGPL - original licence link has changed is not relivant.
20960 * <script type="text/javascript">
20964 * @class Roo.data.Record
20965 * Instances of this class encapsulate both record <em>definition</em> information, and record
20966 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20967 * to access Records cached in an {@link Roo.data.Store} object.<br>
20969 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20970 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20973 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20975 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20976 * {@link #create}. The parameters are the same.
20977 * @param {Array} data An associative Array of data values keyed by the field name.
20978 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20979 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20980 * not specified an integer id is generated.
20982 Roo.data.Record = function(data, id){
20983 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20988 * Generate a constructor for a specific record layout.
20989 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20990 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20991 * Each field definition object may contain the following properties: <ul>
20992 * <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,
20993 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20994 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20995 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20996 * is being used, then this is a string containing the javascript expression to reference the data relative to
20997 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20998 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20999 * this may be omitted.</p></li>
21000 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
21001 * <ul><li>auto (Default, implies no conversion)</li>
21006 * <li>date</li></ul></p></li>
21007 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
21008 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
21009 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
21010 * by the Reader into an object that will be stored in the Record. It is passed the
21011 * following parameters:<ul>
21012 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
21014 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
21016 * <br>usage:<br><pre><code>
21017 var TopicRecord = Roo.data.Record.create(
21018 {name: 'title', mapping: 'topic_title'},
21019 {name: 'author', mapping: 'username'},
21020 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
21021 {name: 'lastPost', mapping: 'post_time', type: 'date'},
21022 {name: 'lastPoster', mapping: 'user2'},
21023 {name: 'excerpt', mapping: 'post_text'}
21026 var myNewRecord = new TopicRecord({
21027 title: 'Do my job please',
21030 lastPost: new Date(),
21031 lastPoster: 'Animal',
21032 excerpt: 'No way dude!'
21034 myStore.add(myNewRecord);
21039 Roo.data.Record.create = function(o){
21040 var f = function(){
21041 f.superclass.constructor.apply(this, arguments);
21043 Roo.extend(f, Roo.data.Record);
21044 var p = f.prototype;
21045 p.fields = new Roo.util.MixedCollection(false, function(field){
21048 for(var i = 0, len = o.length; i < len; i++){
21049 p.fields.add(new Roo.data.Field(o[i]));
21051 f.getField = function(name){
21052 return p.fields.get(name);
21057 Roo.data.Record.AUTO_ID = 1000;
21058 Roo.data.Record.EDIT = 'edit';
21059 Roo.data.Record.REJECT = 'reject';
21060 Roo.data.Record.COMMIT = 'commit';
21062 Roo.data.Record.prototype = {
21064 * Readonly flag - true if this record has been modified.
21073 join : function(store){
21074 this.store = store;
21078 * Set the named field to the specified value.
21079 * @param {String} name The name of the field to set.
21080 * @param {Object} value The value to set the field to.
21082 set : function(name, value){
21083 if(this.data[name] == value){
21087 if(!this.modified){
21088 this.modified = {};
21090 if(typeof this.modified[name] == 'undefined'){
21091 this.modified[name] = this.data[name];
21093 this.data[name] = value;
21094 if(!this.editing && this.store){
21095 this.store.afterEdit(this);
21100 * Get the value of the named field.
21101 * @param {String} name The name of the field to get the value of.
21102 * @return {Object} The value of the field.
21104 get : function(name){
21105 return this.data[name];
21109 beginEdit : function(){
21110 this.editing = true;
21111 this.modified = {};
21115 cancelEdit : function(){
21116 this.editing = false;
21117 delete this.modified;
21121 endEdit : function(){
21122 this.editing = false;
21123 if(this.dirty && this.store){
21124 this.store.afterEdit(this);
21129 * Usually called by the {@link Roo.data.Store} which owns the Record.
21130 * Rejects all changes made to the Record since either creation, or the last commit operation.
21131 * Modified fields are reverted to their original values.
21133 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21134 * of reject operations.
21136 reject : function(){
21137 var m = this.modified;
21139 if(typeof m[n] != "function"){
21140 this.data[n] = m[n];
21143 this.dirty = false;
21144 delete this.modified;
21145 this.editing = false;
21147 this.store.afterReject(this);
21152 * Usually called by the {@link Roo.data.Store} which owns the Record.
21153 * Commits all changes made to the Record since either creation, or the last commit operation.
21155 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21156 * of commit operations.
21158 commit : function(){
21159 this.dirty = false;
21160 delete this.modified;
21161 this.editing = false;
21163 this.store.afterCommit(this);
21168 hasError : function(){
21169 return this.error != null;
21173 clearError : function(){
21178 * Creates a copy of this record.
21179 * @param {String} id (optional) A new record id if you don't want to use this record's id
21182 copy : function(newId) {
21183 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21187 * Ext JS Library 1.1.1
21188 * Copyright(c) 2006-2007, Ext JS, LLC.
21190 * Originally Released Under LGPL - original licence link has changed is not relivant.
21193 * <script type="text/javascript">
21199 * @class Roo.data.Store
21200 * @extends Roo.util.Observable
21201 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21202 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21204 * 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
21205 * has no knowledge of the format of the data returned by the Proxy.<br>
21207 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21208 * instances from the data object. These records are cached and made available through accessor functions.
21210 * Creates a new Store.
21211 * @param {Object} config A config object containing the objects needed for the Store to access data,
21212 * and read the data into Records.
21214 Roo.data.Store = function(config){
21215 this.data = new Roo.util.MixedCollection(false);
21216 this.data.getKey = function(o){
21219 this.baseParams = {};
21221 this.paramNames = {
21226 "multisort" : "_multisort"
21229 if(config && config.data){
21230 this.inlineData = config.data;
21231 delete config.data;
21234 Roo.apply(this, config);
21236 if(this.reader){ // reader passed
21237 this.reader = Roo.factory(this.reader, Roo.data);
21238 this.reader.xmodule = this.xmodule || false;
21239 if(!this.recordType){
21240 this.recordType = this.reader.recordType;
21242 if(this.reader.onMetaChange){
21243 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21247 if(this.recordType){
21248 this.fields = this.recordType.prototype.fields;
21250 this.modified = [];
21254 * @event datachanged
21255 * Fires when the data cache has changed, and a widget which is using this Store
21256 * as a Record cache should refresh its view.
21257 * @param {Store} this
21259 datachanged : true,
21261 * @event metachange
21262 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21263 * @param {Store} this
21264 * @param {Object} meta The JSON metadata
21269 * Fires when Records have been added to the Store
21270 * @param {Store} this
21271 * @param {Roo.data.Record[]} records The array of Records added
21272 * @param {Number} index The index at which the record(s) were added
21277 * Fires when a Record has been removed from the Store
21278 * @param {Store} this
21279 * @param {Roo.data.Record} record The Record that was removed
21280 * @param {Number} index The index at which the record was removed
21285 * Fires when a Record has been updated
21286 * @param {Store} this
21287 * @param {Roo.data.Record} record The Record that was updated
21288 * @param {String} operation The update operation being performed. Value may be one of:
21290 Roo.data.Record.EDIT
21291 Roo.data.Record.REJECT
21292 Roo.data.Record.COMMIT
21298 * Fires when the data cache has been cleared.
21299 * @param {Store} this
21303 * @event beforeload
21304 * Fires before a request is made for a new data object. If the beforeload handler returns false
21305 * the load action will be canceled.
21306 * @param {Store} this
21307 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21311 * @event beforeloadadd
21312 * Fires after a new set of Records has been loaded.
21313 * @param {Store} this
21314 * @param {Roo.data.Record[]} records The Records that were loaded
21315 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21317 beforeloadadd : true,
21320 * Fires after a new set of Records has been loaded, before they are added to the store.
21321 * @param {Store} this
21322 * @param {Roo.data.Record[]} records The Records that were loaded
21323 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21324 * @params {Object} return from reader
21328 * @event loadexception
21329 * Fires if an exception occurs in the Proxy during loading.
21330 * Called with the signature of the Proxy's "loadexception" event.
21331 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21334 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21335 * @param {Object} load options
21336 * @param {Object} jsonData from your request (normally this contains the Exception)
21338 loadexception : true
21342 this.proxy = Roo.factory(this.proxy, Roo.data);
21343 this.proxy.xmodule = this.xmodule || false;
21344 this.relayEvents(this.proxy, ["loadexception"]);
21346 this.sortToggle = {};
21347 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21349 Roo.data.Store.superclass.constructor.call(this);
21351 if(this.inlineData){
21352 this.loadData(this.inlineData);
21353 delete this.inlineData;
21357 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21359 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21360 * without a remote query - used by combo/forms at present.
21364 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21367 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21370 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21371 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21374 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21375 * on any HTTP request
21378 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21381 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21385 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21386 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21388 remoteSort : false,
21391 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21392 * loaded or when a record is removed. (defaults to false).
21394 pruneModifiedRecords : false,
21397 lastOptions : null,
21400 * Add Records to the Store and fires the add event.
21401 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21403 add : function(records){
21404 records = [].concat(records);
21405 for(var i = 0, len = records.length; i < len; i++){
21406 records[i].join(this);
21408 var index = this.data.length;
21409 this.data.addAll(records);
21410 this.fireEvent("add", this, records, index);
21414 * Remove a Record from the Store and fires the remove event.
21415 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21417 remove : function(record){
21418 var index = this.data.indexOf(record);
21419 this.data.removeAt(index);
21420 if(this.pruneModifiedRecords){
21421 this.modified.remove(record);
21423 this.fireEvent("remove", this, record, index);
21427 * Remove all Records from the Store and fires the clear event.
21429 removeAll : function(){
21431 if(this.pruneModifiedRecords){
21432 this.modified = [];
21434 this.fireEvent("clear", this);
21438 * Inserts Records to the Store at the given index and fires the add event.
21439 * @param {Number} index The start index at which to insert the passed Records.
21440 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21442 insert : function(index, records){
21443 records = [].concat(records);
21444 for(var i = 0, len = records.length; i < len; i++){
21445 this.data.insert(index, records[i]);
21446 records[i].join(this);
21448 this.fireEvent("add", this, records, index);
21452 * Get the index within the cache of the passed Record.
21453 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21454 * @return {Number} The index of the passed Record. Returns -1 if not found.
21456 indexOf : function(record){
21457 return this.data.indexOf(record);
21461 * Get the index within the cache of the Record with the passed id.
21462 * @param {String} id The id of the Record to find.
21463 * @return {Number} The index of the Record. Returns -1 if not found.
21465 indexOfId : function(id){
21466 return this.data.indexOfKey(id);
21470 * Get the Record with the specified id.
21471 * @param {String} id The id of the Record to find.
21472 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21474 getById : function(id){
21475 return this.data.key(id);
21479 * Get the Record at the specified index.
21480 * @param {Number} index The index of the Record to find.
21481 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21483 getAt : function(index){
21484 return this.data.itemAt(index);
21488 * Returns a range of Records between specified indices.
21489 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21490 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21491 * @return {Roo.data.Record[]} An array of Records
21493 getRange : function(start, end){
21494 return this.data.getRange(start, end);
21498 storeOptions : function(o){
21499 o = Roo.apply({}, o);
21502 this.lastOptions = o;
21506 * Loads the Record cache from the configured Proxy using the configured Reader.
21508 * If using remote paging, then the first load call must specify the <em>start</em>
21509 * and <em>limit</em> properties in the options.params property to establish the initial
21510 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21512 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21513 * and this call will return before the new data has been loaded. Perform any post-processing
21514 * in a callback function, or in a "load" event handler.</strong>
21516 * @param {Object} options An object containing properties which control loading options:<ul>
21517 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21518 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21519 * passed the following arguments:<ul>
21520 * <li>r : Roo.data.Record[]</li>
21521 * <li>options: Options object from the load call</li>
21522 * <li>success: Boolean success indicator</li></ul></li>
21523 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21524 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21527 load : function(options){
21528 options = options || {};
21529 if(this.fireEvent("beforeload", this, options) !== false){
21530 this.storeOptions(options);
21531 var p = Roo.apply(options.params || {}, this.baseParams);
21532 // if meta was not loaded from remote source.. try requesting it.
21533 if (!this.reader.metaFromRemote) {
21534 p._requestMeta = 1;
21536 if(this.sortInfo && this.remoteSort){
21537 var pn = this.paramNames;
21538 p[pn["sort"]] = this.sortInfo.field;
21539 p[pn["dir"]] = this.sortInfo.direction;
21541 if (this.multiSort) {
21542 var pn = this.paramNames;
21543 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21546 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21551 * Reloads the Record cache from the configured Proxy using the configured Reader and
21552 * the options from the last load operation performed.
21553 * @param {Object} options (optional) An object containing properties which may override the options
21554 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21555 * the most recently used options are reused).
21557 reload : function(options){
21558 this.load(Roo.applyIf(options||{}, this.lastOptions));
21562 // Called as a callback by the Reader during a load operation.
21563 loadRecords : function(o, options, success){
21564 if(!o || success === false){
21565 if(success !== false){
21566 this.fireEvent("load", this, [], options, o);
21568 if(options.callback){
21569 options.callback.call(options.scope || this, [], options, false);
21573 // if data returned failure - throw an exception.
21574 if (o.success === false) {
21575 // show a message if no listener is registered.
21576 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21577 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21579 // loadmask wil be hooked into this..
21580 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21583 var r = o.records, t = o.totalRecords || r.length;
21585 this.fireEvent("beforeloadadd", this, r, options, o);
21587 if(!options || options.add !== true){
21588 if(this.pruneModifiedRecords){
21589 this.modified = [];
21591 for(var i = 0, len = r.length; i < len; i++){
21595 this.data = this.snapshot;
21596 delete this.snapshot;
21599 this.data.addAll(r);
21600 this.totalLength = t;
21602 this.fireEvent("datachanged", this);
21604 this.totalLength = Math.max(t, this.data.length+r.length);
21607 this.fireEvent("load", this, r, options, o);
21608 if(options.callback){
21609 options.callback.call(options.scope || this, r, options, true);
21615 * Loads data from a passed data block. A Reader which understands the format of the data
21616 * must have been configured in the constructor.
21617 * @param {Object} data The data block from which to read the Records. The format of the data expected
21618 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21619 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21621 loadData : function(o, append){
21622 var r = this.reader.readRecords(o);
21623 this.loadRecords(r, {add: append}, true);
21627 * Gets the number of cached records.
21629 * <em>If using paging, this may not be the total size of the dataset. If the data object
21630 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21631 * the data set size</em>
21633 getCount : function(){
21634 return this.data.length || 0;
21638 * Gets the total number of records in the dataset as returned by the server.
21640 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21641 * the dataset size</em>
21643 getTotalCount : function(){
21644 return this.totalLength || 0;
21648 * Returns the sort state of the Store as an object with two properties:
21650 field {String} The name of the field by which the Records are sorted
21651 direction {String} The sort order, "ASC" or "DESC"
21654 getSortState : function(){
21655 return this.sortInfo;
21659 applySort : function(){
21660 if(this.sortInfo && !this.remoteSort){
21661 var s = this.sortInfo, f = s.field;
21662 var st = this.fields.get(f).sortType;
21663 var fn = function(r1, r2){
21664 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21665 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21667 this.data.sort(s.direction, fn);
21668 if(this.snapshot && this.snapshot != this.data){
21669 this.snapshot.sort(s.direction, fn);
21675 * Sets the default sort column and order to be used by the next load operation.
21676 * @param {String} fieldName The name of the field to sort by.
21677 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21679 setDefaultSort : function(field, dir){
21680 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21684 * Sort the Records.
21685 * If remote sorting is used, the sort is performed on the server, and the cache is
21686 * reloaded. If local sorting is used, the cache is sorted internally.
21687 * @param {String} fieldName The name of the field to sort by.
21688 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21690 sort : function(fieldName, dir){
21691 var f = this.fields.get(fieldName);
21693 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21695 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21696 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21701 this.sortToggle[f.name] = dir;
21702 this.sortInfo = {field: f.name, direction: dir};
21703 if(!this.remoteSort){
21705 this.fireEvent("datachanged", this);
21707 this.load(this.lastOptions);
21712 * Calls the specified function for each of the Records in the cache.
21713 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21714 * Returning <em>false</em> aborts and exits the iteration.
21715 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21717 each : function(fn, scope){
21718 this.data.each(fn, scope);
21722 * Gets all records modified since the last commit. Modified records are persisted across load operations
21723 * (e.g., during paging).
21724 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21726 getModifiedRecords : function(){
21727 return this.modified;
21731 createFilterFn : function(property, value, anyMatch){
21732 if(!value.exec){ // not a regex
21733 value = String(value);
21734 if(value.length == 0){
21737 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21739 return function(r){
21740 return value.test(r.data[property]);
21745 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21746 * @param {String} property A field on your records
21747 * @param {Number} start The record index to start at (defaults to 0)
21748 * @param {Number} end The last record index to include (defaults to length - 1)
21749 * @return {Number} The sum
21751 sum : function(property, start, end){
21752 var rs = this.data.items, v = 0;
21753 start = start || 0;
21754 end = (end || end === 0) ? end : rs.length-1;
21756 for(var i = start; i <= end; i++){
21757 v += (rs[i].data[property] || 0);
21763 * Filter the records by a specified property.
21764 * @param {String} field A field on your records
21765 * @param {String/RegExp} value Either a string that the field
21766 * should start with or a RegExp to test against the field
21767 * @param {Boolean} anyMatch True to match any part not just the beginning
21769 filter : function(property, value, anyMatch){
21770 var fn = this.createFilterFn(property, value, anyMatch);
21771 return fn ? this.filterBy(fn) : this.clearFilter();
21775 * Filter by a function. The specified function will be called with each
21776 * record in this data source. If the function returns true the record is included,
21777 * otherwise it is filtered.
21778 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21779 * @param {Object} scope (optional) The scope of the function (defaults to this)
21781 filterBy : function(fn, scope){
21782 this.snapshot = this.snapshot || this.data;
21783 this.data = this.queryBy(fn, scope||this);
21784 this.fireEvent("datachanged", this);
21788 * Query the records by a specified property.
21789 * @param {String} field A field on your records
21790 * @param {String/RegExp} value Either a string that the field
21791 * should start with or a RegExp to test against the field
21792 * @param {Boolean} anyMatch True to match any part not just the beginning
21793 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21795 query : function(property, value, anyMatch){
21796 var fn = this.createFilterFn(property, value, anyMatch);
21797 return fn ? this.queryBy(fn) : this.data.clone();
21801 * Query by a function. The specified function will be called with each
21802 * record in this data source. If the function returns true the record is included
21804 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21805 * @param {Object} scope (optional) The scope of the function (defaults to this)
21806 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21808 queryBy : function(fn, scope){
21809 var data = this.snapshot || this.data;
21810 return data.filterBy(fn, scope||this);
21814 * Collects unique values for a particular dataIndex from this store.
21815 * @param {String} dataIndex The property to collect
21816 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21817 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21818 * @return {Array} An array of the unique values
21820 collect : function(dataIndex, allowNull, bypassFilter){
21821 var d = (bypassFilter === true && this.snapshot) ?
21822 this.snapshot.items : this.data.items;
21823 var v, sv, r = [], l = {};
21824 for(var i = 0, len = d.length; i < len; i++){
21825 v = d[i].data[dataIndex];
21827 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21836 * Revert to a view of the Record cache with no filtering applied.
21837 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21839 clearFilter : function(suppressEvent){
21840 if(this.snapshot && this.snapshot != this.data){
21841 this.data = this.snapshot;
21842 delete this.snapshot;
21843 if(suppressEvent !== true){
21844 this.fireEvent("datachanged", this);
21850 afterEdit : function(record){
21851 if(this.modified.indexOf(record) == -1){
21852 this.modified.push(record);
21854 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21858 afterReject : function(record){
21859 this.modified.remove(record);
21860 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21864 afterCommit : function(record){
21865 this.modified.remove(record);
21866 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21870 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21871 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21873 commitChanges : function(){
21874 var m = this.modified.slice(0);
21875 this.modified = [];
21876 for(var i = 0, len = m.length; i < len; i++){
21882 * Cancel outstanding changes on all changed records.
21884 rejectChanges : function(){
21885 var m = this.modified.slice(0);
21886 this.modified = [];
21887 for(var i = 0, len = m.length; i < len; i++){
21892 onMetaChange : function(meta, rtype, o){
21893 this.recordType = rtype;
21894 this.fields = rtype.prototype.fields;
21895 delete this.snapshot;
21896 this.sortInfo = meta.sortInfo || this.sortInfo;
21897 this.modified = [];
21898 this.fireEvent('metachange', this, this.reader.meta);
21901 moveIndex : function(data, type)
21903 var index = this.indexOf(data);
21905 var newIndex = index + type;
21909 this.insert(newIndex, data);
21914 * Ext JS Library 1.1.1
21915 * Copyright(c) 2006-2007, Ext JS, LLC.
21917 * Originally Released Under LGPL - original licence link has changed is not relivant.
21920 * <script type="text/javascript">
21924 * @class Roo.data.SimpleStore
21925 * @extends Roo.data.Store
21926 * Small helper class to make creating Stores from Array data easier.
21927 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21928 * @cfg {Array} fields An array of field definition objects, or field name strings.
21929 * @cfg {Array} data The multi-dimensional array of data
21931 * @param {Object} config
21933 Roo.data.SimpleStore = function(config){
21934 Roo.data.SimpleStore.superclass.constructor.call(this, {
21936 reader: new Roo.data.ArrayReader({
21939 Roo.data.Record.create(config.fields)
21941 proxy : new Roo.data.MemoryProxy(config.data)
21945 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21947 * Ext JS Library 1.1.1
21948 * Copyright(c) 2006-2007, Ext JS, LLC.
21950 * Originally Released Under LGPL - original licence link has changed is not relivant.
21953 * <script type="text/javascript">
21958 * @extends Roo.data.Store
21959 * @class Roo.data.JsonStore
21960 * Small helper class to make creating Stores for JSON data easier. <br/>
21962 var store = new Roo.data.JsonStore({
21963 url: 'get-images.php',
21965 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21968 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21969 * JsonReader and HttpProxy (unless inline data is provided).</b>
21970 * @cfg {Array} fields An array of field definition objects, or field name strings.
21972 * @param {Object} config
21974 Roo.data.JsonStore = function(c){
21975 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21976 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21977 reader: new Roo.data.JsonReader(c, c.fields)
21980 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21982 * Ext JS Library 1.1.1
21983 * Copyright(c) 2006-2007, Ext JS, LLC.
21985 * Originally Released Under LGPL - original licence link has changed is not relivant.
21988 * <script type="text/javascript">
21992 Roo.data.Field = function(config){
21993 if(typeof config == "string"){
21994 config = {name: config};
21996 Roo.apply(this, config);
21999 this.type = "auto";
22002 var st = Roo.data.SortTypes;
22003 // named sortTypes are supported, here we look them up
22004 if(typeof this.sortType == "string"){
22005 this.sortType = st[this.sortType];
22008 // set default sortType for strings and dates
22009 if(!this.sortType){
22012 this.sortType = st.asUCString;
22015 this.sortType = st.asDate;
22018 this.sortType = st.none;
22023 var stripRe = /[\$,%]/g;
22025 // prebuilt conversion function for this field, instead of
22026 // switching every time we're reading a value
22028 var cv, dateFormat = this.dateFormat;
22033 cv = function(v){ return v; };
22036 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
22040 return v !== undefined && v !== null && v !== '' ?
22041 parseInt(String(v).replace(stripRe, ""), 10) : '';
22046 return v !== undefined && v !== null && v !== '' ?
22047 parseFloat(String(v).replace(stripRe, ""), 10) : '';
22052 cv = function(v){ return v === true || v === "true" || v == 1; };
22059 if(v instanceof Date){
22063 if(dateFormat == "timestamp"){
22064 return new Date(v*1000);
22066 return Date.parseDate(v, dateFormat);
22068 var parsed = Date.parse(v);
22069 return parsed ? new Date(parsed) : null;
22078 Roo.data.Field.prototype = {
22086 * Ext JS Library 1.1.1
22087 * Copyright(c) 2006-2007, Ext JS, LLC.
22089 * Originally Released Under LGPL - original licence link has changed is not relivant.
22092 * <script type="text/javascript">
22095 // Base class for reading structured data from a data source. This class is intended to be
22096 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
22099 * @class Roo.data.DataReader
22100 * Base class for reading structured data from a data source. This class is intended to be
22101 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
22104 Roo.data.DataReader = function(meta, recordType){
22108 this.recordType = recordType instanceof Array ?
22109 Roo.data.Record.create(recordType) : recordType;
22112 Roo.data.DataReader.prototype = {
22114 * Create an empty record
22115 * @param {Object} data (optional) - overlay some values
22116 * @return {Roo.data.Record} record created.
22118 newRow : function(d) {
22120 this.recordType.prototype.fields.each(function(c) {
22122 case 'int' : da[c.name] = 0; break;
22123 case 'date' : da[c.name] = new Date(); break;
22124 case 'float' : da[c.name] = 0.0; break;
22125 case 'boolean' : da[c.name] = false; break;
22126 default : da[c.name] = ""; break;
22130 return new this.recordType(Roo.apply(da, d));
22135 * Ext JS Library 1.1.1
22136 * Copyright(c) 2006-2007, Ext JS, LLC.
22138 * Originally Released Under LGPL - original licence link has changed is not relivant.
22141 * <script type="text/javascript">
22145 * @class Roo.data.DataProxy
22146 * @extends Roo.data.Observable
22147 * This class is an abstract base class for implementations which provide retrieval of
22148 * unformatted data objects.<br>
22150 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
22151 * (of the appropriate type which knows how to parse the data object) to provide a block of
22152 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
22154 * Custom implementations must implement the load method as described in
22155 * {@link Roo.data.HttpProxy#load}.
22157 Roo.data.DataProxy = function(){
22160 * @event beforeload
22161 * Fires before a network request is made to retrieve a data object.
22162 * @param {Object} This DataProxy object.
22163 * @param {Object} params The params parameter to the load function.
22168 * Fires before the load method's callback is called.
22169 * @param {Object} This DataProxy object.
22170 * @param {Object} o The data object.
22171 * @param {Object} arg The callback argument object passed to the load function.
22175 * @event loadexception
22176 * Fires if an Exception occurs during data retrieval.
22177 * @param {Object} This DataProxy object.
22178 * @param {Object} o The data object.
22179 * @param {Object} arg The callback argument object passed to the load function.
22180 * @param {Object} e The Exception.
22182 loadexception : true
22184 Roo.data.DataProxy.superclass.constructor.call(this);
22187 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22190 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22194 * Ext JS Library 1.1.1
22195 * Copyright(c) 2006-2007, Ext JS, LLC.
22197 * Originally Released Under LGPL - original licence link has changed is not relivant.
22200 * <script type="text/javascript">
22203 * @class Roo.data.MemoryProxy
22204 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22205 * to the Reader when its load method is called.
22207 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22209 Roo.data.MemoryProxy = function(data){
22213 Roo.data.MemoryProxy.superclass.constructor.call(this);
22217 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22219 * Load data from the requested source (in this case an in-memory
22220 * data object passed to the constructor), read the data object into
22221 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22222 * process that block using the passed callback.
22223 * @param {Object} params This parameter is not used by the MemoryProxy class.
22224 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22225 * object into a block of Roo.data.Records.
22226 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22227 * The function must be passed <ul>
22228 * <li>The Record block object</li>
22229 * <li>The "arg" argument from the load function</li>
22230 * <li>A boolean success indicator</li>
22232 * @param {Object} scope The scope in which to call the callback
22233 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22235 load : function(params, reader, callback, scope, arg){
22236 params = params || {};
22239 result = reader.readRecords(this.data);
22241 this.fireEvent("loadexception", this, arg, null, e);
22242 callback.call(scope, null, arg, false);
22245 callback.call(scope, result, arg, true);
22249 update : function(params, records){
22254 * Ext JS Library 1.1.1
22255 * Copyright(c) 2006-2007, Ext JS, LLC.
22257 * Originally Released Under LGPL - original licence link has changed is not relivant.
22260 * <script type="text/javascript">
22263 * @class Roo.data.HttpProxy
22264 * @extends Roo.data.DataProxy
22265 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22266 * configured to reference a certain URL.<br><br>
22268 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22269 * from which the running page was served.<br><br>
22271 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22273 * Be aware that to enable the browser to parse an XML document, the server must set
22274 * the Content-Type header in the HTTP response to "text/xml".
22276 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22277 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22278 * will be used to make the request.
22280 Roo.data.HttpProxy = function(conn){
22281 Roo.data.HttpProxy.superclass.constructor.call(this);
22282 // is conn a conn config or a real conn?
22284 this.useAjax = !conn || !conn.events;
22288 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22289 // thse are take from connection...
22292 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22295 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22296 * extra parameters to each request made by this object. (defaults to undefined)
22299 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22300 * to each request made by this object. (defaults to undefined)
22303 * @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)
22306 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22309 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22315 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22319 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22320 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22321 * a finer-grained basis than the DataProxy events.
22323 getConnection : function(){
22324 return this.useAjax ? Roo.Ajax : this.conn;
22328 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22329 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22330 * process that block using the passed callback.
22331 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22332 * for the request to the remote server.
22333 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22334 * object into a block of Roo.data.Records.
22335 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22336 * The function must be passed <ul>
22337 * <li>The Record block object</li>
22338 * <li>The "arg" argument from the load function</li>
22339 * <li>A boolean success indicator</li>
22341 * @param {Object} scope The scope in which to call the callback
22342 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22344 load : function(params, reader, callback, scope, arg){
22345 if(this.fireEvent("beforeload", this, params) !== false){
22347 params : params || {},
22349 callback : callback,
22354 callback : this.loadResponse,
22358 Roo.applyIf(o, this.conn);
22359 if(this.activeRequest){
22360 Roo.Ajax.abort(this.activeRequest);
22362 this.activeRequest = Roo.Ajax.request(o);
22364 this.conn.request(o);
22367 callback.call(scope||this, null, arg, false);
22372 loadResponse : function(o, success, response){
22373 delete this.activeRequest;
22375 this.fireEvent("loadexception", this, o, response);
22376 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22381 result = o.reader.read(response);
22383 this.fireEvent("loadexception", this, o, response, e);
22384 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22388 this.fireEvent("load", this, o, o.request.arg);
22389 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22393 update : function(dataSet){
22398 updateResponse : function(dataSet){
22403 * Ext JS Library 1.1.1
22404 * Copyright(c) 2006-2007, Ext JS, LLC.
22406 * Originally Released Under LGPL - original licence link has changed is not relivant.
22409 * <script type="text/javascript">
22413 * @class Roo.data.ScriptTagProxy
22414 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22415 * other than the originating domain of the running page.<br><br>
22417 * <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
22418 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22420 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22421 * source code that is used as the source inside a <script> tag.<br><br>
22423 * In order for the browser to process the returned data, the server must wrap the data object
22424 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22425 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22426 * depending on whether the callback name was passed:
22429 boolean scriptTag = false;
22430 String cb = request.getParameter("callback");
22433 response.setContentType("text/javascript");
22435 response.setContentType("application/x-json");
22437 Writer out = response.getWriter();
22439 out.write(cb + "(");
22441 out.print(dataBlock.toJsonString());
22448 * @param {Object} config A configuration object.
22450 Roo.data.ScriptTagProxy = function(config){
22451 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22452 Roo.apply(this, config);
22453 this.head = document.getElementsByTagName("head")[0];
22456 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22458 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22460 * @cfg {String} url The URL from which to request the data object.
22463 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22467 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22468 * the server the name of the callback function set up by the load call to process the returned data object.
22469 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22470 * javascript output which calls this named function passing the data object as its only parameter.
22472 callbackParam : "callback",
22474 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22475 * name to the request.
22480 * Load data from the configured URL, read the data object into
22481 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22482 * process that block using the passed callback.
22483 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22484 * for the request to the remote server.
22485 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22486 * object into a block of Roo.data.Records.
22487 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22488 * The function must be passed <ul>
22489 * <li>The Record block object</li>
22490 * <li>The "arg" argument from the load function</li>
22491 * <li>A boolean success indicator</li>
22493 * @param {Object} scope The scope in which to call the callback
22494 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22496 load : function(params, reader, callback, scope, arg){
22497 if(this.fireEvent("beforeload", this, params) !== false){
22499 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22501 var url = this.url;
22502 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22504 url += "&_dc=" + (new Date().getTime());
22506 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22509 cb : "stcCallback"+transId,
22510 scriptId : "stcScript"+transId,
22514 callback : callback,
22520 window[trans.cb] = function(o){
22521 conn.handleResponse(o, trans);
22524 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22526 if(this.autoAbort !== false){
22530 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22532 var script = document.createElement("script");
22533 script.setAttribute("src", url);
22534 script.setAttribute("type", "text/javascript");
22535 script.setAttribute("id", trans.scriptId);
22536 this.head.appendChild(script);
22538 this.trans = trans;
22540 callback.call(scope||this, null, arg, false);
22545 isLoading : function(){
22546 return this.trans ? true : false;
22550 * Abort the current server request.
22552 abort : function(){
22553 if(this.isLoading()){
22554 this.destroyTrans(this.trans);
22559 destroyTrans : function(trans, isLoaded){
22560 this.head.removeChild(document.getElementById(trans.scriptId));
22561 clearTimeout(trans.timeoutId);
22563 window[trans.cb] = undefined;
22565 delete window[trans.cb];
22568 // if hasn't been loaded, wait for load to remove it to prevent script error
22569 window[trans.cb] = function(){
22570 window[trans.cb] = undefined;
22572 delete window[trans.cb];
22579 handleResponse : function(o, trans){
22580 this.trans = false;
22581 this.destroyTrans(trans, true);
22584 result = trans.reader.readRecords(o);
22586 this.fireEvent("loadexception", this, o, trans.arg, e);
22587 trans.callback.call(trans.scope||window, null, trans.arg, false);
22590 this.fireEvent("load", this, o, trans.arg);
22591 trans.callback.call(trans.scope||window, result, trans.arg, true);
22595 handleFailure : function(trans){
22596 this.trans = false;
22597 this.destroyTrans(trans, false);
22598 this.fireEvent("loadexception", this, null, trans.arg);
22599 trans.callback.call(trans.scope||window, null, trans.arg, false);
22603 * Ext JS Library 1.1.1
22604 * Copyright(c) 2006-2007, Ext JS, LLC.
22606 * Originally Released Under LGPL - original licence link has changed is not relivant.
22609 * <script type="text/javascript">
22613 * @class Roo.data.JsonReader
22614 * @extends Roo.data.DataReader
22615 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22616 * based on mappings in a provided Roo.data.Record constructor.
22618 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22619 * in the reply previously.
22624 var RecordDef = Roo.data.Record.create([
22625 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22626 {name: 'occupation'} // This field will use "occupation" as the mapping.
22628 var myReader = new Roo.data.JsonReader({
22629 totalProperty: "results", // The property which contains the total dataset size (optional)
22630 root: "rows", // The property which contains an Array of row objects
22631 id: "id" // The property within each row object that provides an ID for the record (optional)
22635 * This would consume a JSON file like this:
22637 { 'results': 2, 'rows': [
22638 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22639 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22642 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22643 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22644 * paged from the remote server.
22645 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22646 * @cfg {String} root name of the property which contains the Array of row objects.
22647 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22648 * @cfg {Array} fields Array of field definition objects
22650 * Create a new JsonReader
22651 * @param {Object} meta Metadata configuration options
22652 * @param {Object} recordType Either an Array of field definition objects,
22653 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22655 Roo.data.JsonReader = function(meta, recordType){
22658 // set some defaults:
22659 Roo.applyIf(meta, {
22660 totalProperty: 'total',
22661 successProperty : 'success',
22666 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22668 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22671 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22672 * Used by Store query builder to append _requestMeta to params.
22675 metaFromRemote : false,
22677 * This method is only used by a DataProxy which has retrieved data from a remote server.
22678 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22679 * @return {Object} data A data block which is used by an Roo.data.Store object as
22680 * a cache of Roo.data.Records.
22682 read : function(response){
22683 var json = response.responseText;
22685 var o = /* eval:var:o */ eval("("+json+")");
22687 throw {message: "JsonReader.read: Json object not found"};
22693 this.metaFromRemote = true;
22694 this.meta = o.metaData;
22695 this.recordType = Roo.data.Record.create(o.metaData.fields);
22696 this.onMetaChange(this.meta, this.recordType, o);
22698 return this.readRecords(o);
22701 // private function a store will implement
22702 onMetaChange : function(meta, recordType, o){
22709 simpleAccess: function(obj, subsc) {
22716 getJsonAccessor: function(){
22718 return function(expr) {
22720 return(re.test(expr))
22721 ? new Function("obj", "return obj." + expr)
22726 return Roo.emptyFn;
22731 * Create a data block containing Roo.data.Records from an XML document.
22732 * @param {Object} o An object which contains an Array of row objects in the property specified
22733 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22734 * which contains the total size of the dataset.
22735 * @return {Object} data A data block which is used by an Roo.data.Store object as
22736 * a cache of Roo.data.Records.
22738 readRecords : function(o){
22740 * After any data loads, the raw JSON data is available for further custom processing.
22744 var s = this.meta, Record = this.recordType,
22745 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
22747 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22749 if(s.totalProperty) {
22750 this.getTotal = this.getJsonAccessor(s.totalProperty);
22752 if(s.successProperty) {
22753 this.getSuccess = this.getJsonAccessor(s.successProperty);
22755 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22757 var g = this.getJsonAccessor(s.id);
22758 this.getId = function(rec) {
22760 return (r === undefined || r === "") ? null : r;
22763 this.getId = function(){return null;};
22766 for(var jj = 0; jj < fl; jj++){
22768 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22769 this.ef[jj] = this.getJsonAccessor(map);
22773 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22774 if(s.totalProperty){
22775 var vt = parseInt(this.getTotal(o), 10);
22780 if(s.successProperty){
22781 var vs = this.getSuccess(o);
22782 if(vs === false || vs === 'false'){
22787 for(var i = 0; i < c; i++){
22790 var id = this.getId(n);
22791 for(var j = 0; j < fl; j++){
22793 var v = this.ef[j](n);
22795 Roo.log('missing convert for ' + f.name);
22799 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22801 var record = new Record(values, id);
22803 records[i] = record;
22809 totalRecords : totalRecords
22814 * Ext JS Library 1.1.1
22815 * Copyright(c) 2006-2007, Ext JS, LLC.
22817 * Originally Released Under LGPL - original licence link has changed is not relivant.
22820 * <script type="text/javascript">
22824 * @class Roo.data.XmlReader
22825 * @extends Roo.data.DataReader
22826 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22827 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22829 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22830 * header in the HTTP response must be set to "text/xml".</em>
22834 var RecordDef = Roo.data.Record.create([
22835 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22836 {name: 'occupation'} // This field will use "occupation" as the mapping.
22838 var myReader = new Roo.data.XmlReader({
22839 totalRecords: "results", // The element which contains the total dataset size (optional)
22840 record: "row", // The repeated element which contains row information
22841 id: "id" // The element within the row that provides an ID for the record (optional)
22845 * This would consume an XML file like this:
22849 <results>2</results>
22852 <name>Bill</name>
22853 <occupation>Gardener</occupation>
22857 <name>Ben</name>
22858 <occupation>Horticulturalist</occupation>
22862 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22863 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22864 * paged from the remote server.
22865 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22866 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22867 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22868 * a record identifier value.
22870 * Create a new XmlReader
22871 * @param {Object} meta Metadata configuration options
22872 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22873 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22874 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22876 Roo.data.XmlReader = function(meta, recordType){
22878 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22880 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22882 * This method is only used by a DataProxy which has retrieved data from a remote server.
22883 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22884 * to contain a method called 'responseXML' that returns an XML document object.
22885 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22886 * a cache of Roo.data.Records.
22888 read : function(response){
22889 var doc = response.responseXML;
22891 throw {message: "XmlReader.read: XML Document not available"};
22893 return this.readRecords(doc);
22897 * Create a data block containing Roo.data.Records from an XML document.
22898 * @param {Object} doc A parsed XML document.
22899 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22900 * a cache of Roo.data.Records.
22902 readRecords : function(doc){
22904 * After any data loads/reads, the raw XML Document is available for further custom processing.
22905 * @type XMLDocument
22907 this.xmlData = doc;
22908 var root = doc.documentElement || doc;
22909 var q = Roo.DomQuery;
22910 var recordType = this.recordType, fields = recordType.prototype.fields;
22911 var sid = this.meta.id;
22912 var totalRecords = 0, success = true;
22913 if(this.meta.totalRecords){
22914 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22917 if(this.meta.success){
22918 var sv = q.selectValue(this.meta.success, root, true);
22919 success = sv !== false && sv !== 'false';
22922 var ns = q.select(this.meta.record, root);
22923 for(var i = 0, len = ns.length; i < len; i++) {
22926 var id = sid ? q.selectValue(sid, n) : undefined;
22927 for(var j = 0, jlen = fields.length; j < jlen; j++){
22928 var f = fields.items[j];
22929 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22931 values[f.name] = v;
22933 var record = new recordType(values, id);
22935 records[records.length] = record;
22941 totalRecords : totalRecords || records.length
22946 * Ext JS Library 1.1.1
22947 * Copyright(c) 2006-2007, Ext JS, LLC.
22949 * Originally Released Under LGPL - original licence link has changed is not relivant.
22952 * <script type="text/javascript">
22956 * @class Roo.data.ArrayReader
22957 * @extends Roo.data.DataReader
22958 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22959 * Each element of that Array represents a row of data fields. The
22960 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22961 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22965 var RecordDef = Roo.data.Record.create([
22966 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22967 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22969 var myReader = new Roo.data.ArrayReader({
22970 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22974 * This would consume an Array like this:
22976 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22978 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22980 * Create a new JsonReader
22981 * @param {Object} meta Metadata configuration options.
22982 * @param {Object} recordType Either an Array of field definition objects
22983 * as specified to {@link Roo.data.Record#create},
22984 * or an {@link Roo.data.Record} object
22985 * created using {@link Roo.data.Record#create}.
22987 Roo.data.ArrayReader = function(meta, recordType){
22988 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22991 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22993 * Create a data block containing Roo.data.Records from an XML document.
22994 * @param {Object} o An Array of row objects which represents the dataset.
22995 * @return {Object} data A data block which is used by an Roo.data.Store object as
22996 * a cache of Roo.data.Records.
22998 readRecords : function(o){
22999 var sid = this.meta ? this.meta.id : null;
23000 var recordType = this.recordType, fields = recordType.prototype.fields;
23003 for(var i = 0; i < root.length; i++){
23006 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
23007 for(var j = 0, jlen = fields.length; j < jlen; j++){
23008 var f = fields.items[j];
23009 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
23010 var v = n[k] !== undefined ? n[k] : f.defaultValue;
23012 values[f.name] = v;
23014 var record = new recordType(values, id);
23016 records[records.length] = record;
23020 totalRecords : records.length
23025 * Ext JS Library 1.1.1
23026 * Copyright(c) 2006-2007, Ext JS, LLC.
23028 * Originally Released Under LGPL - original licence link has changed is not relivant.
23031 * <script type="text/javascript">
23036 * @class Roo.data.Tree
23037 * @extends Roo.util.Observable
23038 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
23039 * in the tree have most standard DOM functionality.
23041 * @param {Node} root (optional) The root node
23043 Roo.data.Tree = function(root){
23044 this.nodeHash = {};
23046 * The root node for this tree
23051 this.setRootNode(root);
23056 * Fires when a new child node is appended to a node in this tree.
23057 * @param {Tree} tree The owner tree
23058 * @param {Node} parent The parent node
23059 * @param {Node} node The newly appended node
23060 * @param {Number} index The index of the newly appended node
23065 * Fires when a child node is removed from a node in this tree.
23066 * @param {Tree} tree The owner tree
23067 * @param {Node} parent The parent node
23068 * @param {Node} node The child node removed
23073 * Fires when a node is moved to a new location in the tree
23074 * @param {Tree} tree The owner tree
23075 * @param {Node} node The node moved
23076 * @param {Node} oldParent The old parent of this node
23077 * @param {Node} newParent The new parent of this node
23078 * @param {Number} index The index it was moved to
23083 * Fires when a new child node is inserted in a node in this tree.
23084 * @param {Tree} tree The owner tree
23085 * @param {Node} parent The parent node
23086 * @param {Node} node The child node inserted
23087 * @param {Node} refNode The child node the node was inserted before
23091 * @event beforeappend
23092 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
23093 * @param {Tree} tree The owner tree
23094 * @param {Node} parent The parent node
23095 * @param {Node} node The child node to be appended
23097 "beforeappend" : true,
23099 * @event beforeremove
23100 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
23101 * @param {Tree} tree The owner tree
23102 * @param {Node} parent The parent node
23103 * @param {Node} node The child node to be removed
23105 "beforeremove" : true,
23107 * @event beforemove
23108 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
23109 * @param {Tree} tree The owner tree
23110 * @param {Node} node The node being moved
23111 * @param {Node} oldParent The parent of the node
23112 * @param {Node} newParent The new parent the node is moving to
23113 * @param {Number} index The index it is being moved to
23115 "beforemove" : true,
23117 * @event beforeinsert
23118 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
23119 * @param {Tree} tree The owner tree
23120 * @param {Node} parent The parent node
23121 * @param {Node} node The child node to be inserted
23122 * @param {Node} refNode The child node the node is being inserted before
23124 "beforeinsert" : true
23127 Roo.data.Tree.superclass.constructor.call(this);
23130 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
23131 pathSeparator: "/",
23133 proxyNodeEvent : function(){
23134 return this.fireEvent.apply(this, arguments);
23138 * Returns the root node for this tree.
23141 getRootNode : function(){
23146 * Sets the root node for this tree.
23147 * @param {Node} node
23150 setRootNode : function(node){
23152 node.ownerTree = this;
23153 node.isRoot = true;
23154 this.registerNode(node);
23159 * Gets a node in this tree by its id.
23160 * @param {String} id
23163 getNodeById : function(id){
23164 return this.nodeHash[id];
23167 registerNode : function(node){
23168 this.nodeHash[node.id] = node;
23171 unregisterNode : function(node){
23172 delete this.nodeHash[node.id];
23175 toString : function(){
23176 return "[Tree"+(this.id?" "+this.id:"")+"]";
23181 * @class Roo.data.Node
23182 * @extends Roo.util.Observable
23183 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23184 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23186 * @param {Object} attributes The attributes/config for the node
23188 Roo.data.Node = function(attributes){
23190 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23193 this.attributes = attributes || {};
23194 this.leaf = this.attributes.leaf;
23196 * The node id. @type String
23198 this.id = this.attributes.id;
23200 this.id = Roo.id(null, "ynode-");
23201 this.attributes.id = this.id;
23206 * All child nodes of this node. @type Array
23208 this.childNodes = [];
23209 if(!this.childNodes.indexOf){ // indexOf is a must
23210 this.childNodes.indexOf = function(o){
23211 for(var i = 0, len = this.length; i < len; i++){
23220 * The parent node for this node. @type Node
23222 this.parentNode = null;
23224 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23226 this.firstChild = null;
23228 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23230 this.lastChild = null;
23232 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23234 this.previousSibling = null;
23236 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23238 this.nextSibling = null;
23243 * Fires when a new child node is appended
23244 * @param {Tree} tree The owner tree
23245 * @param {Node} this This node
23246 * @param {Node} node The newly appended node
23247 * @param {Number} index The index of the newly appended node
23252 * Fires when a child node is removed
23253 * @param {Tree} tree The owner tree
23254 * @param {Node} this This node
23255 * @param {Node} node The removed node
23260 * Fires when this node is moved to a new location in the tree
23261 * @param {Tree} tree The owner tree
23262 * @param {Node} this This node
23263 * @param {Node} oldParent The old parent of this node
23264 * @param {Node} newParent The new parent of this node
23265 * @param {Number} index The index it was moved to
23270 * Fires when a new child node is inserted.
23271 * @param {Tree} tree The owner tree
23272 * @param {Node} this This node
23273 * @param {Node} node The child node inserted
23274 * @param {Node} refNode The child node the node was inserted before
23278 * @event beforeappend
23279 * Fires before a new child is appended, return false to cancel the append.
23280 * @param {Tree} tree The owner tree
23281 * @param {Node} this This node
23282 * @param {Node} node The child node to be appended
23284 "beforeappend" : true,
23286 * @event beforeremove
23287 * Fires before a child is removed, return false to cancel the remove.
23288 * @param {Tree} tree The owner tree
23289 * @param {Node} this This node
23290 * @param {Node} node The child node to be removed
23292 "beforeremove" : true,
23294 * @event beforemove
23295 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23296 * @param {Tree} tree The owner tree
23297 * @param {Node} this This node
23298 * @param {Node} oldParent The parent of this node
23299 * @param {Node} newParent The new parent this node is moving to
23300 * @param {Number} index The index it is being moved to
23302 "beforemove" : true,
23304 * @event beforeinsert
23305 * Fires before a new child is inserted, return false to cancel the insert.
23306 * @param {Tree} tree The owner tree
23307 * @param {Node} this This node
23308 * @param {Node} node The child node to be inserted
23309 * @param {Node} refNode The child node the node is being inserted before
23311 "beforeinsert" : true
23313 this.listeners = this.attributes.listeners;
23314 Roo.data.Node.superclass.constructor.call(this);
23317 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23318 fireEvent : function(evtName){
23319 // first do standard event for this node
23320 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23323 // then bubble it up to the tree if the event wasn't cancelled
23324 var ot = this.getOwnerTree();
23326 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23334 * Returns true if this node is a leaf
23335 * @return {Boolean}
23337 isLeaf : function(){
23338 return this.leaf === true;
23342 setFirstChild : function(node){
23343 this.firstChild = node;
23347 setLastChild : function(node){
23348 this.lastChild = node;
23353 * Returns true if this node is the last child of its parent
23354 * @return {Boolean}
23356 isLast : function(){
23357 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23361 * Returns true if this node is the first child of its parent
23362 * @return {Boolean}
23364 isFirst : function(){
23365 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23368 hasChildNodes : function(){
23369 return !this.isLeaf() && this.childNodes.length > 0;
23373 * Insert node(s) as the last child node of this node.
23374 * @param {Node/Array} node The node or Array of nodes to append
23375 * @return {Node} The appended node if single append, or null if an array was passed
23377 appendChild : function(node){
23379 if(node instanceof Array){
23381 }else if(arguments.length > 1){
23384 // if passed an array or multiple args do them one by one
23386 for(var i = 0, len = multi.length; i < len; i++) {
23387 this.appendChild(multi[i]);
23390 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23393 var index = this.childNodes.length;
23394 var oldParent = node.parentNode;
23395 // it's a move, make sure we move it cleanly
23397 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23400 oldParent.removeChild(node);
23402 index = this.childNodes.length;
23404 this.setFirstChild(node);
23406 this.childNodes.push(node);
23407 node.parentNode = this;
23408 var ps = this.childNodes[index-1];
23410 node.previousSibling = ps;
23411 ps.nextSibling = node;
23413 node.previousSibling = null;
23415 node.nextSibling = null;
23416 this.setLastChild(node);
23417 node.setOwnerTree(this.getOwnerTree());
23418 this.fireEvent("append", this.ownerTree, this, node, index);
23420 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23427 * Removes a child node from this node.
23428 * @param {Node} node The node to remove
23429 * @return {Node} The removed node
23431 removeChild : function(node){
23432 var index = this.childNodes.indexOf(node);
23436 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23440 // remove it from childNodes collection
23441 this.childNodes.splice(index, 1);
23444 if(node.previousSibling){
23445 node.previousSibling.nextSibling = node.nextSibling;
23447 if(node.nextSibling){
23448 node.nextSibling.previousSibling = node.previousSibling;
23451 // update child refs
23452 if(this.firstChild == node){
23453 this.setFirstChild(node.nextSibling);
23455 if(this.lastChild == node){
23456 this.setLastChild(node.previousSibling);
23459 node.setOwnerTree(null);
23460 // clear any references from the node
23461 node.parentNode = null;
23462 node.previousSibling = null;
23463 node.nextSibling = null;
23464 this.fireEvent("remove", this.ownerTree, this, node);
23469 * Inserts the first node before the second node in this nodes childNodes collection.
23470 * @param {Node} node The node to insert
23471 * @param {Node} refNode The node to insert before (if null the node is appended)
23472 * @return {Node} The inserted node
23474 insertBefore : function(node, refNode){
23475 if(!refNode){ // like standard Dom, refNode can be null for append
23476 return this.appendChild(node);
23479 if(node == refNode){
23483 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23486 var index = this.childNodes.indexOf(refNode);
23487 var oldParent = node.parentNode;
23488 var refIndex = index;
23490 // when moving internally, indexes will change after remove
23491 if(oldParent == this && this.childNodes.indexOf(node) < index){
23495 // it's a move, make sure we move it cleanly
23497 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23500 oldParent.removeChild(node);
23503 this.setFirstChild(node);
23505 this.childNodes.splice(refIndex, 0, node);
23506 node.parentNode = this;
23507 var ps = this.childNodes[refIndex-1];
23509 node.previousSibling = ps;
23510 ps.nextSibling = node;
23512 node.previousSibling = null;
23514 node.nextSibling = refNode;
23515 refNode.previousSibling = node;
23516 node.setOwnerTree(this.getOwnerTree());
23517 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23519 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23525 * Returns the child node at the specified index.
23526 * @param {Number} index
23529 item : function(index){
23530 return this.childNodes[index];
23534 * Replaces one child node in this node with another.
23535 * @param {Node} newChild The replacement node
23536 * @param {Node} oldChild The node to replace
23537 * @return {Node} The replaced node
23539 replaceChild : function(newChild, oldChild){
23540 this.insertBefore(newChild, oldChild);
23541 this.removeChild(oldChild);
23546 * Returns the index of a child node
23547 * @param {Node} node
23548 * @return {Number} The index of the node or -1 if it was not found
23550 indexOf : function(child){
23551 return this.childNodes.indexOf(child);
23555 * Returns the tree this node is in.
23558 getOwnerTree : function(){
23559 // if it doesn't have one, look for one
23560 if(!this.ownerTree){
23564 this.ownerTree = p.ownerTree;
23570 return this.ownerTree;
23574 * Returns depth of this node (the root node has a depth of 0)
23577 getDepth : function(){
23580 while(p.parentNode){
23588 setOwnerTree : function(tree){
23589 // if it's move, we need to update everyone
23590 if(tree != this.ownerTree){
23591 if(this.ownerTree){
23592 this.ownerTree.unregisterNode(this);
23594 this.ownerTree = tree;
23595 var cs = this.childNodes;
23596 for(var i = 0, len = cs.length; i < len; i++) {
23597 cs[i].setOwnerTree(tree);
23600 tree.registerNode(this);
23606 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23607 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23608 * @return {String} The path
23610 getPath : function(attr){
23611 attr = attr || "id";
23612 var p = this.parentNode;
23613 var b = [this.attributes[attr]];
23615 b.unshift(p.attributes[attr]);
23618 var sep = this.getOwnerTree().pathSeparator;
23619 return sep + b.join(sep);
23623 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23624 * function call will be the scope provided or the current node. The arguments to the function
23625 * will be the args provided or the current node. If the function returns false at any point,
23626 * the bubble is stopped.
23627 * @param {Function} fn The function to call
23628 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23629 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23631 bubble : function(fn, scope, args){
23634 if(fn.call(scope || p, args || p) === false){
23642 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23643 * function call will be the scope provided or the current node. The arguments to the function
23644 * will be the args provided or the current node. If the function returns false at any point,
23645 * the cascade is stopped on that branch.
23646 * @param {Function} fn The function to call
23647 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23648 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23650 cascade : function(fn, scope, args){
23651 if(fn.call(scope || this, args || this) !== false){
23652 var cs = this.childNodes;
23653 for(var i = 0, len = cs.length; i < len; i++) {
23654 cs[i].cascade(fn, scope, args);
23660 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23661 * function call will be the scope provided or the current node. The arguments to the function
23662 * will be the args provided or the current node. If the function returns false at any point,
23663 * the iteration stops.
23664 * @param {Function} fn The function to call
23665 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23666 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23668 eachChild : function(fn, scope, args){
23669 var cs = this.childNodes;
23670 for(var i = 0, len = cs.length; i < len; i++) {
23671 if(fn.call(scope || this, args || cs[i]) === false){
23678 * Finds the first child that has the attribute with the specified value.
23679 * @param {String} attribute The attribute name
23680 * @param {Mixed} value The value to search for
23681 * @return {Node} The found child or null if none was found
23683 findChild : function(attribute, value){
23684 var cs = this.childNodes;
23685 for(var i = 0, len = cs.length; i < len; i++) {
23686 if(cs[i].attributes[attribute] == value){
23694 * Finds the first child by a custom function. The child matches if the function passed
23696 * @param {Function} fn
23697 * @param {Object} scope (optional)
23698 * @return {Node} The found child or null if none was found
23700 findChildBy : function(fn, scope){
23701 var cs = this.childNodes;
23702 for(var i = 0, len = cs.length; i < len; i++) {
23703 if(fn.call(scope||cs[i], cs[i]) === true){
23711 * Sorts this nodes children using the supplied sort function
23712 * @param {Function} fn
23713 * @param {Object} scope (optional)
23715 sort : function(fn, scope){
23716 var cs = this.childNodes;
23717 var len = cs.length;
23719 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23721 for(var i = 0; i < len; i++){
23723 n.previousSibling = cs[i-1];
23724 n.nextSibling = cs[i+1];
23726 this.setFirstChild(n);
23729 this.setLastChild(n);
23736 * Returns true if this node is an ancestor (at any point) of the passed node.
23737 * @param {Node} node
23738 * @return {Boolean}
23740 contains : function(node){
23741 return node.isAncestor(this);
23745 * Returns true if the passed node is an ancestor (at any point) of this node.
23746 * @param {Node} node
23747 * @return {Boolean}
23749 isAncestor : function(node){
23750 var p = this.parentNode;
23760 toString : function(){
23761 return "[Node"+(this.id?" "+this.id:"")+"]";
23765 * Ext JS Library 1.1.1
23766 * Copyright(c) 2006-2007, Ext JS, LLC.
23768 * Originally Released Under LGPL - original licence link has changed is not relivant.
23771 * <script type="text/javascript">
23776 * @extends Roo.Element
23777 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23778 * automatic maintaining of shadow/shim positions.
23779 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23780 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23781 * you can pass a string with a CSS class name. False turns off the shadow.
23782 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23783 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23784 * @cfg {String} cls CSS class to add to the element
23785 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23786 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23788 * @param {Object} config An object with config options.
23789 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23792 Roo.Layer = function(config, existingEl){
23793 config = config || {};
23794 var dh = Roo.DomHelper;
23795 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23797 this.dom = Roo.getDom(existingEl);
23800 var o = config.dh || {tag: "div", cls: "x-layer"};
23801 this.dom = dh.append(pel, o);
23804 this.addClass(config.cls);
23806 this.constrain = config.constrain !== false;
23807 this.visibilityMode = Roo.Element.VISIBILITY;
23809 this.id = this.dom.id = config.id;
23811 this.id = Roo.id(this.dom);
23813 this.zindex = config.zindex || this.getZIndex();
23814 this.position("absolute", this.zindex);
23816 this.shadowOffset = config.shadowOffset || 4;
23817 this.shadow = new Roo.Shadow({
23818 offset : this.shadowOffset,
23819 mode : config.shadow
23822 this.shadowOffset = 0;
23824 this.useShim = config.shim !== false && Roo.useShims;
23825 this.useDisplay = config.useDisplay;
23829 var supr = Roo.Element.prototype;
23831 // shims are shared among layer to keep from having 100 iframes
23834 Roo.extend(Roo.Layer, Roo.Element, {
23836 getZIndex : function(){
23837 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23840 getShim : function(){
23847 var shim = shims.shift();
23849 shim = this.createShim();
23850 shim.enableDisplayMode('block');
23851 shim.dom.style.display = 'none';
23852 shim.dom.style.visibility = 'visible';
23854 var pn = this.dom.parentNode;
23855 if(shim.dom.parentNode != pn){
23856 pn.insertBefore(shim.dom, this.dom);
23858 shim.setStyle('z-index', this.getZIndex()-2);
23863 hideShim : function(){
23865 this.shim.setDisplayed(false);
23866 shims.push(this.shim);
23871 disableShadow : function(){
23873 this.shadowDisabled = true;
23874 this.shadow.hide();
23875 this.lastShadowOffset = this.shadowOffset;
23876 this.shadowOffset = 0;
23880 enableShadow : function(show){
23882 this.shadowDisabled = false;
23883 this.shadowOffset = this.lastShadowOffset;
23884 delete this.lastShadowOffset;
23892 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23893 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23894 sync : function(doShow){
23895 var sw = this.shadow;
23896 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23897 var sh = this.getShim();
23899 var w = this.getWidth(),
23900 h = this.getHeight();
23902 var l = this.getLeft(true),
23903 t = this.getTop(true);
23905 if(sw && !this.shadowDisabled){
23906 if(doShow && !sw.isVisible()){
23909 sw.realign(l, t, w, h);
23915 // fit the shim behind the shadow, so it is shimmed too
23916 var a = sw.adjusts, s = sh.dom.style;
23917 s.left = (Math.min(l, l+a.l))+"px";
23918 s.top = (Math.min(t, t+a.t))+"px";
23919 s.width = (w+a.w)+"px";
23920 s.height = (h+a.h)+"px";
23927 sh.setLeftTop(l, t);
23934 destroy : function(){
23937 this.shadow.hide();
23939 this.removeAllListeners();
23940 var pn = this.dom.parentNode;
23942 pn.removeChild(this.dom);
23944 Roo.Element.uncache(this.id);
23947 remove : function(){
23952 beginUpdate : function(){
23953 this.updating = true;
23957 endUpdate : function(){
23958 this.updating = false;
23963 hideUnders : function(negOffset){
23965 this.shadow.hide();
23971 constrainXY : function(){
23972 if(this.constrain){
23973 var vw = Roo.lib.Dom.getViewWidth(),
23974 vh = Roo.lib.Dom.getViewHeight();
23975 var s = Roo.get(document).getScroll();
23977 var xy = this.getXY();
23978 var x = xy[0], y = xy[1];
23979 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23980 // only move it if it needs it
23982 // first validate right/bottom
23983 if((x + w) > vw+s.left){
23984 x = vw - w - this.shadowOffset;
23987 if((y + h) > vh+s.top){
23988 y = vh - h - this.shadowOffset;
23991 // then make sure top/left isn't negative
24002 var ay = this.avoidY;
24003 if(y <= ay && (y+h) >= ay){
24009 supr.setXY.call(this, xy);
24015 isVisible : function(){
24016 return this.visible;
24020 showAction : function(){
24021 this.visible = true; // track visibility to prevent getStyle calls
24022 if(this.useDisplay === true){
24023 this.setDisplayed("");
24024 }else if(this.lastXY){
24025 supr.setXY.call(this, this.lastXY);
24026 }else if(this.lastLT){
24027 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
24032 hideAction : function(){
24033 this.visible = false;
24034 if(this.useDisplay === true){
24035 this.setDisplayed(false);
24037 this.setLeftTop(-10000,-10000);
24041 // overridden Element method
24042 setVisible : function(v, a, d, c, e){
24047 var cb = function(){
24052 }.createDelegate(this);
24053 supr.setVisible.call(this, true, true, d, cb, e);
24056 this.hideUnders(true);
24065 }.createDelegate(this);
24067 supr.setVisible.call(this, v, a, d, cb, e);
24076 storeXY : function(xy){
24077 delete this.lastLT;
24081 storeLeftTop : function(left, top){
24082 delete this.lastXY;
24083 this.lastLT = [left, top];
24087 beforeFx : function(){
24088 this.beforeAction();
24089 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
24093 afterFx : function(){
24094 Roo.Layer.superclass.afterFx.apply(this, arguments);
24095 this.sync(this.isVisible());
24099 beforeAction : function(){
24100 if(!this.updating && this.shadow){
24101 this.shadow.hide();
24105 // overridden Element method
24106 setLeft : function(left){
24107 this.storeLeftTop(left, this.getTop(true));
24108 supr.setLeft.apply(this, arguments);
24112 setTop : function(top){
24113 this.storeLeftTop(this.getLeft(true), top);
24114 supr.setTop.apply(this, arguments);
24118 setLeftTop : function(left, top){
24119 this.storeLeftTop(left, top);
24120 supr.setLeftTop.apply(this, arguments);
24124 setXY : function(xy, a, d, c, e){
24126 this.beforeAction();
24128 var cb = this.createCB(c);
24129 supr.setXY.call(this, xy, a, d, cb, e);
24136 createCB : function(c){
24147 // overridden Element method
24148 setX : function(x, a, d, c, e){
24149 this.setXY([x, this.getY()], a, d, c, e);
24152 // overridden Element method
24153 setY : function(y, a, d, c, e){
24154 this.setXY([this.getX(), y], a, d, c, e);
24157 // overridden Element method
24158 setSize : function(w, h, a, d, c, e){
24159 this.beforeAction();
24160 var cb = this.createCB(c);
24161 supr.setSize.call(this, w, h, a, d, cb, e);
24167 // overridden Element method
24168 setWidth : function(w, a, d, c, e){
24169 this.beforeAction();
24170 var cb = this.createCB(c);
24171 supr.setWidth.call(this, w, a, d, cb, e);
24177 // overridden Element method
24178 setHeight : function(h, a, d, c, e){
24179 this.beforeAction();
24180 var cb = this.createCB(c);
24181 supr.setHeight.call(this, h, a, d, cb, e);
24187 // overridden Element method
24188 setBounds : function(x, y, w, h, a, d, c, e){
24189 this.beforeAction();
24190 var cb = this.createCB(c);
24192 this.storeXY([x, y]);
24193 supr.setXY.call(this, [x, y]);
24194 supr.setSize.call(this, w, h, a, d, cb, e);
24197 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24203 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24204 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24205 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24206 * @param {Number} zindex The new z-index to set
24207 * @return {this} The Layer
24209 setZIndex : function(zindex){
24210 this.zindex = zindex;
24211 this.setStyle("z-index", zindex + 2);
24213 this.shadow.setZIndex(zindex + 1);
24216 this.shim.setStyle("z-index", zindex);
24222 * Ext JS Library 1.1.1
24223 * Copyright(c) 2006-2007, Ext JS, LLC.
24225 * Originally Released Under LGPL - original licence link has changed is not relivant.
24228 * <script type="text/javascript">
24233 * @class Roo.Shadow
24234 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24235 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24236 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24238 * Create a new Shadow
24239 * @param {Object} config The config object
24241 Roo.Shadow = function(config){
24242 Roo.apply(this, config);
24243 if(typeof this.mode != "string"){
24244 this.mode = this.defaultMode;
24246 var o = this.offset, a = {h: 0};
24247 var rad = Math.floor(this.offset/2);
24248 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24254 a.l -= this.offset + rad;
24255 a.t -= this.offset + rad;
24266 a.l -= (this.offset - rad);
24267 a.t -= this.offset + rad;
24269 a.w -= (this.offset - rad)*2;
24280 a.l -= (this.offset - rad);
24281 a.t -= (this.offset - rad);
24283 a.w -= (this.offset + rad + 1);
24284 a.h -= (this.offset + rad);
24293 Roo.Shadow.prototype = {
24295 * @cfg {String} mode
24296 * The shadow display mode. Supports the following options:<br />
24297 * sides: Shadow displays on both sides and bottom only<br />
24298 * frame: Shadow displays equally on all four sides<br />
24299 * drop: Traditional bottom-right drop shadow (default)
24302 * @cfg {String} offset
24303 * The number of pixels to offset the shadow from the element (defaults to 4)
24308 defaultMode: "drop",
24311 * Displays the shadow under the target element
24312 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24314 show : function(target){
24315 target = Roo.get(target);
24317 this.el = Roo.Shadow.Pool.pull();
24318 if(this.el.dom.nextSibling != target.dom){
24319 this.el.insertBefore(target);
24322 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24324 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24327 target.getLeft(true),
24328 target.getTop(true),
24332 this.el.dom.style.display = "block";
24336 * Returns true if the shadow is visible, else false
24338 isVisible : function(){
24339 return this.el ? true : false;
24343 * Direct alignment when values are already available. Show must be called at least once before
24344 * calling this method to ensure it is initialized.
24345 * @param {Number} left The target element left position
24346 * @param {Number} top The target element top position
24347 * @param {Number} width The target element width
24348 * @param {Number} height The target element height
24350 realign : function(l, t, w, h){
24354 var a = this.adjusts, d = this.el.dom, s = d.style;
24356 s.left = (l+a.l)+"px";
24357 s.top = (t+a.t)+"px";
24358 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24360 if(s.width != sws || s.height != shs){
24364 var cn = d.childNodes;
24365 var sww = Math.max(0, (sw-12))+"px";
24366 cn[0].childNodes[1].style.width = sww;
24367 cn[1].childNodes[1].style.width = sww;
24368 cn[2].childNodes[1].style.width = sww;
24369 cn[1].style.height = Math.max(0, (sh-12))+"px";
24375 * Hides this shadow
24379 this.el.dom.style.display = "none";
24380 Roo.Shadow.Pool.push(this.el);
24386 * Adjust the z-index of this shadow
24387 * @param {Number} zindex The new z-index
24389 setZIndex : function(z){
24392 this.el.setStyle("z-index", z);
24397 // Private utility class that manages the internal Shadow cache
24398 Roo.Shadow.Pool = function(){
24400 var markup = Roo.isIE ?
24401 '<div class="x-ie-shadow"></div>' :
24402 '<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>';
24405 var sh = p.shift();
24407 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24408 sh.autoBoxAdjust = false;
24413 push : function(sh){
24419 * Ext JS Library 1.1.1
24420 * Copyright(c) 2006-2007, Ext JS, LLC.
24422 * Originally Released Under LGPL - original licence link has changed is not relivant.
24425 * <script type="text/javascript">
24430 * @class Roo.SplitBar
24431 * @extends Roo.util.Observable
24432 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24436 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24437 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24438 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24439 split.minSize = 100;
24440 split.maxSize = 600;
24441 split.animate = true;
24442 split.on('moved', splitterMoved);
24445 * Create a new SplitBar
24446 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24447 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24448 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24449 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24450 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24451 position of the SplitBar).
24453 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24456 this.el = Roo.get(dragElement, true);
24457 this.el.dom.unselectable = "on";
24459 this.resizingEl = Roo.get(resizingElement, true);
24463 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24464 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24467 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24470 * The minimum size of the resizing element. (Defaults to 0)
24476 * The maximum size of the resizing element. (Defaults to 2000)
24479 this.maxSize = 2000;
24482 * Whether to animate the transition to the new size
24485 this.animate = false;
24488 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24491 this.useShim = false;
24496 if(!existingProxy){
24498 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24500 this.proxy = Roo.get(existingProxy).dom;
24503 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24506 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24509 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24512 this.dragSpecs = {};
24515 * @private The adapter to use to positon and resize elements
24517 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24518 this.adapter.init(this);
24520 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24522 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24523 this.el.addClass("x-splitbar-h");
24526 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24527 this.el.addClass("x-splitbar-v");
24533 * Fires when the splitter is moved (alias for {@link #event-moved})
24534 * @param {Roo.SplitBar} this
24535 * @param {Number} newSize the new width or height
24540 * Fires when the splitter is moved
24541 * @param {Roo.SplitBar} this
24542 * @param {Number} newSize the new width or height
24546 * @event beforeresize
24547 * Fires before the splitter is dragged
24548 * @param {Roo.SplitBar} this
24550 "beforeresize" : true,
24552 "beforeapply" : true
24555 Roo.util.Observable.call(this);
24558 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24559 onStartProxyDrag : function(x, y){
24560 this.fireEvent("beforeresize", this);
24562 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24564 o.enableDisplayMode("block");
24565 // all splitbars share the same overlay
24566 Roo.SplitBar.prototype.overlay = o;
24568 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24569 this.overlay.show();
24570 Roo.get(this.proxy).setDisplayed("block");
24571 var size = this.adapter.getElementSize(this);
24572 this.activeMinSize = this.getMinimumSize();;
24573 this.activeMaxSize = this.getMaximumSize();;
24574 var c1 = size - this.activeMinSize;
24575 var c2 = Math.max(this.activeMaxSize - size, 0);
24576 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24577 this.dd.resetConstraints();
24578 this.dd.setXConstraint(
24579 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24580 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24582 this.dd.setYConstraint(0, 0);
24584 this.dd.resetConstraints();
24585 this.dd.setXConstraint(0, 0);
24586 this.dd.setYConstraint(
24587 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24588 this.placement == Roo.SplitBar.TOP ? c2 : c1
24591 this.dragSpecs.startSize = size;
24592 this.dragSpecs.startPoint = [x, y];
24593 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24597 * @private Called after the drag operation by the DDProxy
24599 onEndProxyDrag : function(e){
24600 Roo.get(this.proxy).setDisplayed(false);
24601 var endPoint = Roo.lib.Event.getXY(e);
24603 this.overlay.hide();
24606 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24607 newSize = this.dragSpecs.startSize +
24608 (this.placement == Roo.SplitBar.LEFT ?
24609 endPoint[0] - this.dragSpecs.startPoint[0] :
24610 this.dragSpecs.startPoint[0] - endPoint[0]
24613 newSize = this.dragSpecs.startSize +
24614 (this.placement == Roo.SplitBar.TOP ?
24615 endPoint[1] - this.dragSpecs.startPoint[1] :
24616 this.dragSpecs.startPoint[1] - endPoint[1]
24619 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24620 if(newSize != this.dragSpecs.startSize){
24621 if(this.fireEvent('beforeapply', this, newSize) !== false){
24622 this.adapter.setElementSize(this, newSize);
24623 this.fireEvent("moved", this, newSize);
24624 this.fireEvent("resize", this, newSize);
24630 * Get the adapter this SplitBar uses
24631 * @return The adapter object
24633 getAdapter : function(){
24634 return this.adapter;
24638 * Set the adapter this SplitBar uses
24639 * @param {Object} adapter A SplitBar adapter object
24641 setAdapter : function(adapter){
24642 this.adapter = adapter;
24643 this.adapter.init(this);
24647 * Gets the minimum size for the resizing element
24648 * @return {Number} The minimum size
24650 getMinimumSize : function(){
24651 return this.minSize;
24655 * Sets the minimum size for the resizing element
24656 * @param {Number} minSize The minimum size
24658 setMinimumSize : function(minSize){
24659 this.minSize = minSize;
24663 * Gets the maximum size for the resizing element
24664 * @return {Number} The maximum size
24666 getMaximumSize : function(){
24667 return this.maxSize;
24671 * Sets the maximum size for the resizing element
24672 * @param {Number} maxSize The maximum size
24674 setMaximumSize : function(maxSize){
24675 this.maxSize = maxSize;
24679 * Sets the initialize size for the resizing element
24680 * @param {Number} size The initial size
24682 setCurrentSize : function(size){
24683 var oldAnimate = this.animate;
24684 this.animate = false;
24685 this.adapter.setElementSize(this, size);
24686 this.animate = oldAnimate;
24690 * Destroy this splitbar.
24691 * @param {Boolean} removeEl True to remove the element
24693 destroy : function(removeEl){
24695 this.shim.remove();
24698 this.proxy.parentNode.removeChild(this.proxy);
24706 * @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.
24708 Roo.SplitBar.createProxy = function(dir){
24709 var proxy = new Roo.Element(document.createElement("div"));
24710 proxy.unselectable();
24711 var cls = 'x-splitbar-proxy';
24712 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24713 document.body.appendChild(proxy.dom);
24718 * @class Roo.SplitBar.BasicLayoutAdapter
24719 * Default Adapter. It assumes the splitter and resizing element are not positioned
24720 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24722 Roo.SplitBar.BasicLayoutAdapter = function(){
24725 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24726 // do nothing for now
24727 init : function(s){
24731 * Called before drag operations to get the current size of the resizing element.
24732 * @param {Roo.SplitBar} s The SplitBar using this adapter
24734 getElementSize : function(s){
24735 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24736 return s.resizingEl.getWidth();
24738 return s.resizingEl.getHeight();
24743 * Called after drag operations to set the size of the resizing element.
24744 * @param {Roo.SplitBar} s The SplitBar using this adapter
24745 * @param {Number} newSize The new size to set
24746 * @param {Function} onComplete A function to be invoked when resizing is complete
24748 setElementSize : function(s, newSize, onComplete){
24749 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24751 s.resizingEl.setWidth(newSize);
24753 onComplete(s, newSize);
24756 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24761 s.resizingEl.setHeight(newSize);
24763 onComplete(s, newSize);
24766 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24773 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24774 * @extends Roo.SplitBar.BasicLayoutAdapter
24775 * Adapter that moves the splitter element to align with the resized sizing element.
24776 * Used with an absolute positioned SplitBar.
24777 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24778 * document.body, make sure you assign an id to the body element.
24780 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24781 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24782 this.container = Roo.get(container);
24785 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24786 init : function(s){
24787 this.basic.init(s);
24790 getElementSize : function(s){
24791 return this.basic.getElementSize(s);
24794 setElementSize : function(s, newSize, onComplete){
24795 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24798 moveSplitter : function(s){
24799 var yes = Roo.SplitBar;
24800 switch(s.placement){
24802 s.el.setX(s.resizingEl.getRight());
24805 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24808 s.el.setY(s.resizingEl.getBottom());
24811 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24818 * Orientation constant - Create a vertical SplitBar
24822 Roo.SplitBar.VERTICAL = 1;
24825 * Orientation constant - Create a horizontal SplitBar
24829 Roo.SplitBar.HORIZONTAL = 2;
24832 * Placement constant - The resizing element is to the left of the splitter element
24836 Roo.SplitBar.LEFT = 1;
24839 * Placement constant - The resizing element is to the right of the splitter element
24843 Roo.SplitBar.RIGHT = 2;
24846 * Placement constant - The resizing element is positioned above the splitter element
24850 Roo.SplitBar.TOP = 3;
24853 * Placement constant - The resizing element is positioned under splitter element
24857 Roo.SplitBar.BOTTOM = 4;
24860 * Ext JS Library 1.1.1
24861 * Copyright(c) 2006-2007, Ext JS, LLC.
24863 * Originally Released Under LGPL - original licence link has changed is not relivant.
24866 * <script type="text/javascript">
24871 * @extends Roo.util.Observable
24872 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24873 * This class also supports single and multi selection modes. <br>
24874 * Create a data model bound view:
24876 var store = new Roo.data.Store(...);
24878 var view = new Roo.View({
24880 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24882 singleSelect: true,
24883 selectedClass: "ydataview-selected",
24887 // listen for node click?
24888 view.on("click", function(vw, index, node, e){
24889 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24893 dataModel.load("foobar.xml");
24895 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24897 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24898 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24900 * Note: old style constructor is still suported (container, template, config)
24903 * Create a new View
24904 * @param {Object} config The config object
24907 Roo.View = function(config, depreciated_tpl, depreciated_config){
24909 this.parent = false;
24911 if (typeof(depreciated_tpl) == 'undefined') {
24912 // new way.. - universal constructor.
24913 Roo.apply(this, config);
24914 this.el = Roo.get(this.el);
24917 this.el = Roo.get(config);
24918 this.tpl = depreciated_tpl;
24919 Roo.apply(this, depreciated_config);
24921 this.wrapEl = this.el.wrap().wrap();
24922 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24925 if(typeof(this.tpl) == "string"){
24926 this.tpl = new Roo.Template(this.tpl);
24928 // support xtype ctors..
24929 this.tpl = new Roo.factory(this.tpl, Roo);
24933 this.tpl.compile();
24938 * @event beforeclick
24939 * Fires before a click is processed. Returns false to cancel the default action.
24940 * @param {Roo.View} this
24941 * @param {Number} index The index of the target node
24942 * @param {HTMLElement} node The target node
24943 * @param {Roo.EventObject} e The raw event object
24945 "beforeclick" : true,
24948 * Fires when a template node is clicked.
24949 * @param {Roo.View} this
24950 * @param {Number} index The index of the target node
24951 * @param {HTMLElement} node The target node
24952 * @param {Roo.EventObject} e The raw event object
24957 * Fires when a template node is double clicked.
24958 * @param {Roo.View} this
24959 * @param {Number} index The index of the target node
24960 * @param {HTMLElement} node The target node
24961 * @param {Roo.EventObject} e The raw event object
24965 * @event contextmenu
24966 * Fires when a template node is right clicked.
24967 * @param {Roo.View} this
24968 * @param {Number} index The index of the target node
24969 * @param {HTMLElement} node The target node
24970 * @param {Roo.EventObject} e The raw event object
24972 "contextmenu" : true,
24974 * @event selectionchange
24975 * Fires when the selected nodes change.
24976 * @param {Roo.View} this
24977 * @param {Array} selections Array of the selected nodes
24979 "selectionchange" : true,
24982 * @event beforeselect
24983 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24984 * @param {Roo.View} this
24985 * @param {HTMLElement} node The node to be selected
24986 * @param {Array} selections Array of currently selected nodes
24988 "beforeselect" : true,
24990 * @event preparedata
24991 * Fires on every row to render, to allow you to change the data.
24992 * @param {Roo.View} this
24993 * @param {Object} data to be rendered (change this)
24995 "preparedata" : true
25003 "click": this.onClick,
25004 "dblclick": this.onDblClick,
25005 "contextmenu": this.onContextMenu,
25009 this.selections = [];
25011 this.cmp = new Roo.CompositeElementLite([]);
25013 this.store = Roo.factory(this.store, Roo.data);
25014 this.setStore(this.store, true);
25017 if ( this.footer && this.footer.xtype) {
25019 var fctr = this.wrapEl.appendChild(document.createElement("div"));
25021 this.footer.dataSource = this.store;
25022 this.footer.container = fctr;
25023 this.footer = Roo.factory(this.footer, Roo);
25024 fctr.insertFirst(this.el);
25026 // this is a bit insane - as the paging toolbar seems to detach the el..
25027 // dom.parentNode.parentNode.parentNode
25028 // they get detached?
25032 Roo.View.superclass.constructor.call(this);
25037 Roo.extend(Roo.View, Roo.util.Observable, {
25040 * @cfg {Roo.data.Store} store Data store to load data from.
25045 * @cfg {String|Roo.Element} el The container element.
25050 * @cfg {String|Roo.Template} tpl The template used by this View
25054 * @cfg {String} dataName the named area of the template to use as the data area
25055 * Works with domtemplates roo-name="name"
25059 * @cfg {String} selectedClass The css class to add to selected nodes
25061 selectedClass : "x-view-selected",
25063 * @cfg {String} emptyText The empty text to show when nothing is loaded.
25068 * @cfg {String} text to display on mask (default Loading)
25072 * @cfg {Boolean} multiSelect Allow multiple selection
25074 multiSelect : false,
25076 * @cfg {Boolean} singleSelect Allow single selection
25078 singleSelect: false,
25081 * @cfg {Boolean} toggleSelect - selecting
25083 toggleSelect : false,
25086 * @cfg {Boolean} tickable - selecting
25091 * Returns the element this view is bound to.
25092 * @return {Roo.Element}
25094 getEl : function(){
25095 return this.wrapEl;
25101 * Refreshes the view. - called by datachanged on the store. - do not call directly.
25103 refresh : function(){
25104 //Roo.log('refresh');
25107 // if we are using something like 'domtemplate', then
25108 // the what gets used is:
25109 // t.applySubtemplate(NAME, data, wrapping data..)
25110 // the outer template then get' applied with
25111 // the store 'extra data'
25112 // and the body get's added to the
25113 // roo-name="data" node?
25114 // <span class='roo-tpl-{name}'></span> ?????
25118 this.clearSelections();
25119 this.el.update("");
25121 var records = this.store.getRange();
25122 if(records.length < 1) {
25124 // is this valid?? = should it render a template??
25126 this.el.update(this.emptyText);
25130 if (this.dataName) {
25131 this.el.update(t.apply(this.store.meta)); //????
25132 el = this.el.child('.roo-tpl-' + this.dataName);
25135 for(var i = 0, len = records.length; i < len; i++){
25136 var data = this.prepareData(records[i].data, i, records[i]);
25137 this.fireEvent("preparedata", this, data, i, records[i]);
25139 var d = Roo.apply({}, data);
25142 Roo.apply(d, {'roo-id' : Roo.id()});
25146 Roo.each(this.parent.item, function(item){
25147 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
25150 Roo.apply(d, {'roo-data-checked' : 'checked'});
25154 html[html.length] = Roo.util.Format.trim(
25156 t.applySubtemplate(this.dataName, d, this.store.meta) :
25163 el.update(html.join(""));
25164 this.nodes = el.dom.childNodes;
25165 this.updateIndexes(0);
25170 * Function to override to reformat the data that is sent to
25171 * the template for each node.
25172 * DEPRICATED - use the preparedata event handler.
25173 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25174 * a JSON object for an UpdateManager bound view).
25176 prepareData : function(data, index, record)
25178 this.fireEvent("preparedata", this, data, index, record);
25182 onUpdate : function(ds, record){
25183 // Roo.log('on update');
25184 this.clearSelections();
25185 var index = this.store.indexOf(record);
25186 var n = this.nodes[index];
25187 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25188 n.parentNode.removeChild(n);
25189 this.updateIndexes(index, index);
25195 onAdd : function(ds, records, index)
25197 //Roo.log(['on Add', ds, records, index] );
25198 this.clearSelections();
25199 if(this.nodes.length == 0){
25203 var n = this.nodes[index];
25204 for(var i = 0, len = records.length; i < len; i++){
25205 var d = this.prepareData(records[i].data, i, records[i]);
25207 this.tpl.insertBefore(n, d);
25210 this.tpl.append(this.el, d);
25213 this.updateIndexes(index);
25216 onRemove : function(ds, record, index){
25217 // Roo.log('onRemove');
25218 this.clearSelections();
25219 var el = this.dataName ?
25220 this.el.child('.roo-tpl-' + this.dataName) :
25223 el.dom.removeChild(this.nodes[index]);
25224 this.updateIndexes(index);
25228 * Refresh an individual node.
25229 * @param {Number} index
25231 refreshNode : function(index){
25232 this.onUpdate(this.store, this.store.getAt(index));
25235 updateIndexes : function(startIndex, endIndex){
25236 var ns = this.nodes;
25237 startIndex = startIndex || 0;
25238 endIndex = endIndex || ns.length - 1;
25239 for(var i = startIndex; i <= endIndex; i++){
25240 ns[i].nodeIndex = i;
25245 * Changes the data store this view uses and refresh the view.
25246 * @param {Store} store
25248 setStore : function(store, initial){
25249 if(!initial && this.store){
25250 this.store.un("datachanged", this.refresh);
25251 this.store.un("add", this.onAdd);
25252 this.store.un("remove", this.onRemove);
25253 this.store.un("update", this.onUpdate);
25254 this.store.un("clear", this.refresh);
25255 this.store.un("beforeload", this.onBeforeLoad);
25256 this.store.un("load", this.onLoad);
25257 this.store.un("loadexception", this.onLoad);
25261 store.on("datachanged", this.refresh, this);
25262 store.on("add", this.onAdd, this);
25263 store.on("remove", this.onRemove, this);
25264 store.on("update", this.onUpdate, this);
25265 store.on("clear", this.refresh, this);
25266 store.on("beforeload", this.onBeforeLoad, this);
25267 store.on("load", this.onLoad, this);
25268 store.on("loadexception", this.onLoad, this);
25276 * onbeforeLoad - masks the loading area.
25279 onBeforeLoad : function(store,opts)
25281 //Roo.log('onBeforeLoad');
25283 this.el.update("");
25285 this.el.mask(this.mask ? this.mask : "Loading" );
25287 onLoad : function ()
25294 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25295 * @param {HTMLElement} node
25296 * @return {HTMLElement} The template node
25298 findItemFromChild : function(node){
25299 var el = this.dataName ?
25300 this.el.child('.roo-tpl-' + this.dataName,true) :
25303 if(!node || node.parentNode == el){
25306 var p = node.parentNode;
25307 while(p && p != el){
25308 if(p.parentNode == el){
25317 onClick : function(e){
25318 var item = this.findItemFromChild(e.getTarget());
25320 var index = this.indexOf(item);
25321 if(this.onItemClick(item, index, e) !== false){
25322 this.fireEvent("click", this, index, item, e);
25325 this.clearSelections();
25330 onContextMenu : function(e){
25331 var item = this.findItemFromChild(e.getTarget());
25333 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25338 onDblClick : function(e){
25339 var item = this.findItemFromChild(e.getTarget());
25341 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25345 onItemClick : function(item, index, e)
25347 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25350 if (this.toggleSelect) {
25351 var m = this.isSelected(item) ? 'unselect' : 'select';
25354 _t[m](item, true, false);
25357 if(this.multiSelect || this.singleSelect){
25358 if(this.multiSelect && e.shiftKey && this.lastSelection){
25359 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25361 this.select(item, this.multiSelect && e.ctrlKey);
25362 this.lastSelection = item;
25365 if(!this.tickable){
25366 e.preventDefault();
25374 * Get the number of selected nodes.
25377 getSelectionCount : function(){
25378 return this.selections.length;
25382 * Get the currently selected nodes.
25383 * @return {Array} An array of HTMLElements
25385 getSelectedNodes : function(){
25386 return this.selections;
25390 * Get the indexes of the selected nodes.
25393 getSelectedIndexes : function(){
25394 var indexes = [], s = this.selections;
25395 for(var i = 0, len = s.length; i < len; i++){
25396 indexes.push(s[i].nodeIndex);
25402 * Clear all selections
25403 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25405 clearSelections : function(suppressEvent){
25406 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25407 this.cmp.elements = this.selections;
25408 this.cmp.removeClass(this.selectedClass);
25409 this.selections = [];
25410 if(!suppressEvent){
25411 this.fireEvent("selectionchange", this, this.selections);
25417 * Returns true if the passed node is selected
25418 * @param {HTMLElement/Number} node The node or node index
25419 * @return {Boolean}
25421 isSelected : function(node){
25422 var s = this.selections;
25426 node = this.getNode(node);
25427 return s.indexOf(node) !== -1;
25432 * @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
25433 * @param {Boolean} keepExisting (optional) true to keep existing selections
25434 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25436 select : function(nodeInfo, keepExisting, suppressEvent){
25437 if(nodeInfo instanceof Array){
25439 this.clearSelections(true);
25441 for(var i = 0, len = nodeInfo.length; i < len; i++){
25442 this.select(nodeInfo[i], true, true);
25446 var node = this.getNode(nodeInfo);
25447 if(!node || this.isSelected(node)){
25448 return; // already selected.
25451 this.clearSelections(true);
25454 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25455 Roo.fly(node).addClass(this.selectedClass);
25456 this.selections.push(node);
25457 if(!suppressEvent){
25458 this.fireEvent("selectionchange", this, this.selections);
25466 * @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
25467 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25468 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25470 unselect : function(nodeInfo, keepExisting, suppressEvent)
25472 if(nodeInfo instanceof Array){
25473 Roo.each(this.selections, function(s) {
25474 this.unselect(s, nodeInfo);
25478 var node = this.getNode(nodeInfo);
25479 if(!node || !this.isSelected(node)){
25480 //Roo.log("not selected");
25481 return; // not selected.
25485 Roo.each(this.selections, function(s) {
25487 Roo.fly(node).removeClass(this.selectedClass);
25494 this.selections= ns;
25495 this.fireEvent("selectionchange", this, this.selections);
25499 * Gets a template node.
25500 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25501 * @return {HTMLElement} The node or null if it wasn't found
25503 getNode : function(nodeInfo){
25504 if(typeof nodeInfo == "string"){
25505 return document.getElementById(nodeInfo);
25506 }else if(typeof nodeInfo == "number"){
25507 return this.nodes[nodeInfo];
25513 * Gets a range template nodes.
25514 * @param {Number} startIndex
25515 * @param {Number} endIndex
25516 * @return {Array} An array of nodes
25518 getNodes : function(start, end){
25519 var ns = this.nodes;
25520 start = start || 0;
25521 end = typeof end == "undefined" ? ns.length - 1 : end;
25524 for(var i = start; i <= end; i++){
25528 for(var i = start; i >= end; i--){
25536 * Finds the index of the passed node
25537 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25538 * @return {Number} The index of the node or -1
25540 indexOf : function(node){
25541 node = this.getNode(node);
25542 if(typeof node.nodeIndex == "number"){
25543 return node.nodeIndex;
25545 var ns = this.nodes;
25546 for(var i = 0, len = ns.length; i < len; i++){
25556 * Ext JS Library 1.1.1
25557 * Copyright(c) 2006-2007, Ext JS, LLC.
25559 * Originally Released Under LGPL - original licence link has changed is not relivant.
25562 * <script type="text/javascript">
25566 * @class Roo.JsonView
25567 * @extends Roo.View
25568 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25570 var view = new Roo.JsonView({
25571 container: "my-element",
25572 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25577 // listen for node click?
25578 view.on("click", function(vw, index, node, e){
25579 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25582 // direct load of JSON data
25583 view.load("foobar.php");
25585 // Example from my blog list
25586 var tpl = new Roo.Template(
25587 '<div class="entry">' +
25588 '<a class="entry-title" href="{link}">{title}</a>' +
25589 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25590 "</div><hr />"
25593 var moreView = new Roo.JsonView({
25594 container : "entry-list",
25598 moreView.on("beforerender", this.sortEntries, this);
25600 url: "/blog/get-posts.php",
25601 params: "allposts=true",
25602 text: "Loading Blog Entries..."
25606 * Note: old code is supported with arguments : (container, template, config)
25610 * Create a new JsonView
25612 * @param {Object} config The config object
25615 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25618 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25620 var um = this.el.getUpdateManager();
25621 um.setRenderer(this);
25622 um.on("update", this.onLoad, this);
25623 um.on("failure", this.onLoadException, this);
25626 * @event beforerender
25627 * Fires before rendering of the downloaded JSON data.
25628 * @param {Roo.JsonView} this
25629 * @param {Object} data The JSON data loaded
25633 * Fires when data is loaded.
25634 * @param {Roo.JsonView} this
25635 * @param {Object} data The JSON data loaded
25636 * @param {Object} response The raw Connect response object
25639 * @event loadexception
25640 * Fires when loading fails.
25641 * @param {Roo.JsonView} this
25642 * @param {Object} response The raw Connect response object
25645 'beforerender' : true,
25647 'loadexception' : true
25650 Roo.extend(Roo.JsonView, Roo.View, {
25652 * @type {String} The root property in the loaded JSON object that contains the data
25657 * Refreshes the view.
25659 refresh : function(){
25660 this.clearSelections();
25661 this.el.update("");
25663 var o = this.jsonData;
25664 if(o && o.length > 0){
25665 for(var i = 0, len = o.length; i < len; i++){
25666 var data = this.prepareData(o[i], i, o);
25667 html[html.length] = this.tpl.apply(data);
25670 html.push(this.emptyText);
25672 this.el.update(html.join(""));
25673 this.nodes = this.el.dom.childNodes;
25674 this.updateIndexes(0);
25678 * 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.
25679 * @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:
25682 url: "your-url.php",
25683 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25684 callback: yourFunction,
25685 scope: yourObject, //(optional scope)
25688 text: "Loading...",
25693 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25694 * 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.
25695 * @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}
25696 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25697 * @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.
25700 var um = this.el.getUpdateManager();
25701 um.update.apply(um, arguments);
25704 render : function(el, response){
25705 this.clearSelections();
25706 this.el.update("");
25709 o = Roo.util.JSON.decode(response.responseText);
25712 o = o[this.jsonRoot];
25717 * The current JSON data or null
25720 this.beforeRender();
25725 * Get the number of records in the current JSON dataset
25728 getCount : function(){
25729 return this.jsonData ? this.jsonData.length : 0;
25733 * Returns the JSON object for the specified node(s)
25734 * @param {HTMLElement/Array} node The node or an array of nodes
25735 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25736 * you get the JSON object for the node
25738 getNodeData : function(node){
25739 if(node instanceof Array){
25741 for(var i = 0, len = node.length; i < len; i++){
25742 data.push(this.getNodeData(node[i]));
25746 return this.jsonData[this.indexOf(node)] || null;
25749 beforeRender : function(){
25750 this.snapshot = this.jsonData;
25752 this.sort.apply(this, this.sortInfo);
25754 this.fireEvent("beforerender", this, this.jsonData);
25757 onLoad : function(el, o){
25758 this.fireEvent("load", this, this.jsonData, o);
25761 onLoadException : function(el, o){
25762 this.fireEvent("loadexception", this, o);
25766 * Filter the data by a specific property.
25767 * @param {String} property A property on your JSON objects
25768 * @param {String/RegExp} value Either string that the property values
25769 * should start with, or a RegExp to test against the property
25771 filter : function(property, value){
25774 var ss = this.snapshot;
25775 if(typeof value == "string"){
25776 var vlen = value.length;
25778 this.clearFilter();
25781 value = value.toLowerCase();
25782 for(var i = 0, len = ss.length; i < len; i++){
25784 if(o[property].substr(0, vlen).toLowerCase() == value){
25788 } else if(value.exec){ // regex?
25789 for(var i = 0, len = ss.length; i < len; i++){
25791 if(value.test(o[property])){
25798 this.jsonData = data;
25804 * Filter by a function. The passed function will be called with each
25805 * object in the current dataset. If the function returns true the value is kept,
25806 * otherwise it is filtered.
25807 * @param {Function} fn
25808 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25810 filterBy : function(fn, scope){
25813 var ss = this.snapshot;
25814 for(var i = 0, len = ss.length; i < len; i++){
25816 if(fn.call(scope || this, o)){
25820 this.jsonData = data;
25826 * Clears the current filter.
25828 clearFilter : function(){
25829 if(this.snapshot && this.jsonData != this.snapshot){
25830 this.jsonData = this.snapshot;
25837 * Sorts the data for this view and refreshes it.
25838 * @param {String} property A property on your JSON objects to sort on
25839 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25840 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25842 sort : function(property, dir, sortType){
25843 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25846 var dsc = dir && dir.toLowerCase() == "desc";
25847 var f = function(o1, o2){
25848 var v1 = sortType ? sortType(o1[p]) : o1[p];
25849 var v2 = sortType ? sortType(o2[p]) : o2[p];
25852 return dsc ? +1 : -1;
25853 } else if(v1 > v2){
25854 return dsc ? -1 : +1;
25859 this.jsonData.sort(f);
25861 if(this.jsonData != this.snapshot){
25862 this.snapshot.sort(f);
25868 * Ext JS Library 1.1.1
25869 * Copyright(c) 2006-2007, Ext JS, LLC.
25871 * Originally Released Under LGPL - original licence link has changed is not relivant.
25874 * <script type="text/javascript">
25879 * @class Roo.ColorPalette
25880 * @extends Roo.Component
25881 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25882 * Here's an example of typical usage:
25884 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25885 cp.render('my-div');
25887 cp.on('select', function(palette, selColor){
25888 // do something with selColor
25892 * Create a new ColorPalette
25893 * @param {Object} config The config object
25895 Roo.ColorPalette = function(config){
25896 Roo.ColorPalette.superclass.constructor.call(this, config);
25900 * Fires when a color is selected
25901 * @param {ColorPalette} this
25902 * @param {String} color The 6-digit color hex code (without the # symbol)
25908 this.on("select", this.handler, this.scope, true);
25911 Roo.extend(Roo.ColorPalette, Roo.Component, {
25913 * @cfg {String} itemCls
25914 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25916 itemCls : "x-color-palette",
25918 * @cfg {String} value
25919 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25920 * the hex codes are case-sensitive.
25923 clickEvent:'click',
25925 ctype: "Roo.ColorPalette",
25928 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25930 allowReselect : false,
25933 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25934 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25935 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25936 * of colors with the width setting until the box is symmetrical.</p>
25937 * <p>You can override individual colors if needed:</p>
25939 var cp = new Roo.ColorPalette();
25940 cp.colors[0] = "FF0000"; // change the first box to red
25943 Or you can provide a custom array of your own for complete control:
25945 var cp = new Roo.ColorPalette();
25946 cp.colors = ["000000", "993300", "333300"];
25951 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25952 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25953 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25954 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25955 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25959 onRender : function(container, position){
25960 var t = new Roo.MasterTemplate(
25961 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25963 var c = this.colors;
25964 for(var i = 0, len = c.length; i < len; i++){
25967 var el = document.createElement("div");
25968 el.className = this.itemCls;
25970 container.dom.insertBefore(el, position);
25971 this.el = Roo.get(el);
25972 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25973 if(this.clickEvent != 'click'){
25974 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25979 afterRender : function(){
25980 Roo.ColorPalette.superclass.afterRender.call(this);
25982 var s = this.value;
25989 handleClick : function(e, t){
25990 e.preventDefault();
25991 if(!this.disabled){
25992 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25993 this.select(c.toUpperCase());
25998 * Selects the specified color in the palette (fires the select event)
25999 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
26001 select : function(color){
26002 color = color.replace("#", "");
26003 if(color != this.value || this.allowReselect){
26006 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
26008 el.child("a.color-"+color).addClass("x-color-palette-sel");
26009 this.value = color;
26010 this.fireEvent("select", this, color);
26015 * Ext JS Library 1.1.1
26016 * Copyright(c) 2006-2007, Ext JS, LLC.
26018 * Originally Released Under LGPL - original licence link has changed is not relivant.
26021 * <script type="text/javascript">
26025 * @class Roo.DatePicker
26026 * @extends Roo.Component
26027 * Simple date picker class.
26029 * Create a new DatePicker
26030 * @param {Object} config The config object
26032 Roo.DatePicker = function(config){
26033 Roo.DatePicker.superclass.constructor.call(this, config);
26035 this.value = config && config.value ?
26036 config.value.clearTime() : new Date().clearTime();
26041 * Fires when a date is selected
26042 * @param {DatePicker} this
26043 * @param {Date} date The selected date
26047 * @event monthchange
26048 * Fires when the displayed month changes
26049 * @param {DatePicker} this
26050 * @param {Date} date The selected month
26052 'monthchange': true
26056 this.on("select", this.handler, this.scope || this);
26058 // build the disabledDatesRE
26059 if(!this.disabledDatesRE && this.disabledDates){
26060 var dd = this.disabledDates;
26062 for(var i = 0; i < dd.length; i++){
26064 if(i != dd.length-1) {
26068 this.disabledDatesRE = new RegExp(re + ")");
26072 Roo.extend(Roo.DatePicker, Roo.Component, {
26074 * @cfg {String} todayText
26075 * The text to display on the button that selects the current date (defaults to "Today")
26077 todayText : "Today",
26079 * @cfg {String} okText
26080 * The text to display on the ok button
26082 okText : " OK ", //   to give the user extra clicking room
26084 * @cfg {String} cancelText
26085 * The text to display on the cancel button
26087 cancelText : "Cancel",
26089 * @cfg {String} todayTip
26090 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
26092 todayTip : "{0} (Spacebar)",
26094 * @cfg {Date} minDate
26095 * Minimum allowable date (JavaScript date object, defaults to null)
26099 * @cfg {Date} maxDate
26100 * Maximum allowable date (JavaScript date object, defaults to null)
26104 * @cfg {String} minText
26105 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
26107 minText : "This date is before the minimum date",
26109 * @cfg {String} maxText
26110 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
26112 maxText : "This date is after the maximum date",
26114 * @cfg {String} format
26115 * The default date format string which can be overriden for localization support. The format must be
26116 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
26120 * @cfg {Array} disabledDays
26121 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
26123 disabledDays : null,
26125 * @cfg {String} disabledDaysText
26126 * The tooltip to display when the date falls on a disabled day (defaults to "")
26128 disabledDaysText : "",
26130 * @cfg {RegExp} disabledDatesRE
26131 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
26133 disabledDatesRE : null,
26135 * @cfg {String} disabledDatesText
26136 * The tooltip text to display when the date falls on a disabled date (defaults to "")
26138 disabledDatesText : "",
26140 * @cfg {Boolean} constrainToViewport
26141 * True to constrain the date picker to the viewport (defaults to true)
26143 constrainToViewport : true,
26145 * @cfg {Array} monthNames
26146 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
26148 monthNames : Date.monthNames,
26150 * @cfg {Array} dayNames
26151 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
26153 dayNames : Date.dayNames,
26155 * @cfg {String} nextText
26156 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
26158 nextText: 'Next Month (Control+Right)',
26160 * @cfg {String} prevText
26161 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
26163 prevText: 'Previous Month (Control+Left)',
26165 * @cfg {String} monthYearText
26166 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
26168 monthYearText: 'Choose a month (Control+Up/Down to move years)',
26170 * @cfg {Number} startDay
26171 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
26175 * @cfg {Bool} showClear
26176 * Show a clear button (usefull for date form elements that can be blank.)
26182 * Sets the value of the date field
26183 * @param {Date} value The date to set
26185 setValue : function(value){
26186 var old = this.value;
26188 if (typeof(value) == 'string') {
26190 value = Date.parseDate(value, this.format);
26193 value = new Date();
26196 this.value = value.clearTime(true);
26198 this.update(this.value);
26203 * Gets the current selected value of the date field
26204 * @return {Date} The selected date
26206 getValue : function(){
26211 focus : function(){
26213 this.update(this.activeDate);
26218 onRender : function(container, position){
26221 '<table cellspacing="0">',
26222 '<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>',
26223 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26224 var dn = this.dayNames;
26225 for(var i = 0; i < 7; i++){
26226 var d = this.startDay+i;
26230 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26232 m[m.length] = "</tr></thead><tbody><tr>";
26233 for(var i = 0; i < 42; i++) {
26234 if(i % 7 == 0 && i != 0){
26235 m[m.length] = "</tr><tr>";
26237 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26239 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26240 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26242 var el = document.createElement("div");
26243 el.className = "x-date-picker";
26244 el.innerHTML = m.join("");
26246 container.dom.insertBefore(el, position);
26248 this.el = Roo.get(el);
26249 this.eventEl = Roo.get(el.firstChild);
26251 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26252 handler: this.showPrevMonth,
26254 preventDefault:true,
26258 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26259 handler: this.showNextMonth,
26261 preventDefault:true,
26265 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26267 this.monthPicker = this.el.down('div.x-date-mp');
26268 this.monthPicker.enableDisplayMode('block');
26270 var kn = new Roo.KeyNav(this.eventEl, {
26271 "left" : function(e){
26273 this.showPrevMonth() :
26274 this.update(this.activeDate.add("d", -1));
26277 "right" : function(e){
26279 this.showNextMonth() :
26280 this.update(this.activeDate.add("d", 1));
26283 "up" : function(e){
26285 this.showNextYear() :
26286 this.update(this.activeDate.add("d", -7));
26289 "down" : function(e){
26291 this.showPrevYear() :
26292 this.update(this.activeDate.add("d", 7));
26295 "pageUp" : function(e){
26296 this.showNextMonth();
26299 "pageDown" : function(e){
26300 this.showPrevMonth();
26303 "enter" : function(e){
26304 e.stopPropagation();
26311 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26313 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26315 this.el.unselectable();
26317 this.cells = this.el.select("table.x-date-inner tbody td");
26318 this.textNodes = this.el.query("table.x-date-inner tbody span");
26320 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26322 tooltip: this.monthYearText
26325 this.mbtn.on('click', this.showMonthPicker, this);
26326 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26329 var today = (new Date()).dateFormat(this.format);
26331 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26332 if (this.showClear) {
26333 baseTb.add( new Roo.Toolbar.Fill());
26336 text: String.format(this.todayText, today),
26337 tooltip: String.format(this.todayTip, today),
26338 handler: this.selectToday,
26342 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26345 if (this.showClear) {
26347 baseTb.add( new Roo.Toolbar.Fill());
26350 cls: 'x-btn-icon x-btn-clear',
26351 handler: function() {
26353 this.fireEvent("select", this, '');
26363 this.update(this.value);
26366 createMonthPicker : function(){
26367 if(!this.monthPicker.dom.firstChild){
26368 var buf = ['<table border="0" cellspacing="0">'];
26369 for(var i = 0; i < 6; i++){
26371 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26372 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26374 '<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>' :
26375 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26379 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26381 '</button><button type="button" class="x-date-mp-cancel">',
26383 '</button></td></tr>',
26386 this.monthPicker.update(buf.join(''));
26387 this.monthPicker.on('click', this.onMonthClick, this);
26388 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26390 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26391 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26393 this.mpMonths.each(function(m, a, i){
26396 m.dom.xmonth = 5 + Math.round(i * .5);
26398 m.dom.xmonth = Math.round((i-1) * .5);
26404 showMonthPicker : function(){
26405 this.createMonthPicker();
26406 var size = this.el.getSize();
26407 this.monthPicker.setSize(size);
26408 this.monthPicker.child('table').setSize(size);
26410 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26411 this.updateMPMonth(this.mpSelMonth);
26412 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26413 this.updateMPYear(this.mpSelYear);
26415 this.monthPicker.slideIn('t', {duration:.2});
26418 updateMPYear : function(y){
26420 var ys = this.mpYears.elements;
26421 for(var i = 1; i <= 10; i++){
26422 var td = ys[i-1], y2;
26424 y2 = y + Math.round(i * .5);
26425 td.firstChild.innerHTML = y2;
26428 y2 = y - (5-Math.round(i * .5));
26429 td.firstChild.innerHTML = y2;
26432 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26436 updateMPMonth : function(sm){
26437 this.mpMonths.each(function(m, a, i){
26438 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26442 selectMPMonth: function(m){
26446 onMonthClick : function(e, t){
26448 var el = new Roo.Element(t), pn;
26449 if(el.is('button.x-date-mp-cancel')){
26450 this.hideMonthPicker();
26452 else if(el.is('button.x-date-mp-ok')){
26453 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26454 this.hideMonthPicker();
26456 else if(pn = el.up('td.x-date-mp-month', 2)){
26457 this.mpMonths.removeClass('x-date-mp-sel');
26458 pn.addClass('x-date-mp-sel');
26459 this.mpSelMonth = pn.dom.xmonth;
26461 else if(pn = el.up('td.x-date-mp-year', 2)){
26462 this.mpYears.removeClass('x-date-mp-sel');
26463 pn.addClass('x-date-mp-sel');
26464 this.mpSelYear = pn.dom.xyear;
26466 else if(el.is('a.x-date-mp-prev')){
26467 this.updateMPYear(this.mpyear-10);
26469 else if(el.is('a.x-date-mp-next')){
26470 this.updateMPYear(this.mpyear+10);
26474 onMonthDblClick : function(e, t){
26476 var el = new Roo.Element(t), pn;
26477 if(pn = el.up('td.x-date-mp-month', 2)){
26478 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26479 this.hideMonthPicker();
26481 else if(pn = el.up('td.x-date-mp-year', 2)){
26482 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26483 this.hideMonthPicker();
26487 hideMonthPicker : function(disableAnim){
26488 if(this.monthPicker){
26489 if(disableAnim === true){
26490 this.monthPicker.hide();
26492 this.monthPicker.slideOut('t', {duration:.2});
26498 showPrevMonth : function(e){
26499 this.update(this.activeDate.add("mo", -1));
26503 showNextMonth : function(e){
26504 this.update(this.activeDate.add("mo", 1));
26508 showPrevYear : function(){
26509 this.update(this.activeDate.add("y", -1));
26513 showNextYear : function(){
26514 this.update(this.activeDate.add("y", 1));
26518 handleMouseWheel : function(e){
26519 var delta = e.getWheelDelta();
26521 this.showPrevMonth();
26523 } else if(delta < 0){
26524 this.showNextMonth();
26530 handleDateClick : function(e, t){
26532 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26533 this.setValue(new Date(t.dateValue));
26534 this.fireEvent("select", this, this.value);
26539 selectToday : function(){
26540 this.setValue(new Date().clearTime());
26541 this.fireEvent("select", this, this.value);
26545 update : function(date)
26547 var vd = this.activeDate;
26548 this.activeDate = date;
26550 var t = date.getTime();
26551 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26552 this.cells.removeClass("x-date-selected");
26553 this.cells.each(function(c){
26554 if(c.dom.firstChild.dateValue == t){
26555 c.addClass("x-date-selected");
26556 setTimeout(function(){
26557 try{c.dom.firstChild.focus();}catch(e){}
26566 var days = date.getDaysInMonth();
26567 var firstOfMonth = date.getFirstDateOfMonth();
26568 var startingPos = firstOfMonth.getDay()-this.startDay;
26570 if(startingPos <= this.startDay){
26574 var pm = date.add("mo", -1);
26575 var prevStart = pm.getDaysInMonth()-startingPos;
26577 var cells = this.cells.elements;
26578 var textEls = this.textNodes;
26579 days += startingPos;
26581 // convert everything to numbers so it's fast
26582 var day = 86400000;
26583 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26584 var today = new Date().clearTime().getTime();
26585 var sel = date.clearTime().getTime();
26586 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26587 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26588 var ddMatch = this.disabledDatesRE;
26589 var ddText = this.disabledDatesText;
26590 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26591 var ddaysText = this.disabledDaysText;
26592 var format = this.format;
26594 var setCellClass = function(cal, cell){
26596 var t = d.getTime();
26597 cell.firstChild.dateValue = t;
26599 cell.className += " x-date-today";
26600 cell.title = cal.todayText;
26603 cell.className += " x-date-selected";
26604 setTimeout(function(){
26605 try{cell.firstChild.focus();}catch(e){}
26610 cell.className = " x-date-disabled";
26611 cell.title = cal.minText;
26615 cell.className = " x-date-disabled";
26616 cell.title = cal.maxText;
26620 if(ddays.indexOf(d.getDay()) != -1){
26621 cell.title = ddaysText;
26622 cell.className = " x-date-disabled";
26625 if(ddMatch && format){
26626 var fvalue = d.dateFormat(format);
26627 if(ddMatch.test(fvalue)){
26628 cell.title = ddText.replace("%0", fvalue);
26629 cell.className = " x-date-disabled";
26635 for(; i < startingPos; i++) {
26636 textEls[i].innerHTML = (++prevStart);
26637 d.setDate(d.getDate()+1);
26638 cells[i].className = "x-date-prevday";
26639 setCellClass(this, cells[i]);
26641 for(; i < days; i++){
26642 intDay = i - startingPos + 1;
26643 textEls[i].innerHTML = (intDay);
26644 d.setDate(d.getDate()+1);
26645 cells[i].className = "x-date-active";
26646 setCellClass(this, cells[i]);
26649 for(; i < 42; i++) {
26650 textEls[i].innerHTML = (++extraDays);
26651 d.setDate(d.getDate()+1);
26652 cells[i].className = "x-date-nextday";
26653 setCellClass(this, cells[i]);
26656 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26657 this.fireEvent('monthchange', this, date);
26659 if(!this.internalRender){
26660 var main = this.el.dom.firstChild;
26661 var w = main.offsetWidth;
26662 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26663 Roo.fly(main).setWidth(w);
26664 this.internalRender = true;
26665 // opera does not respect the auto grow header center column
26666 // then, after it gets a width opera refuses to recalculate
26667 // without a second pass
26668 if(Roo.isOpera && !this.secondPass){
26669 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26670 this.secondPass = true;
26671 this.update.defer(10, this, [date]);
26679 * Ext JS Library 1.1.1
26680 * Copyright(c) 2006-2007, Ext JS, LLC.
26682 * Originally Released Under LGPL - original licence link has changed is not relivant.
26685 * <script type="text/javascript">
26688 * @class Roo.TabPanel
26689 * @extends Roo.util.Observable
26690 * A lightweight tab container.
26694 // basic tabs 1, built from existing content
26695 var tabs = new Roo.TabPanel("tabs1");
26696 tabs.addTab("script", "View Script");
26697 tabs.addTab("markup", "View Markup");
26698 tabs.activate("script");
26700 // more advanced tabs, built from javascript
26701 var jtabs = new Roo.TabPanel("jtabs");
26702 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26704 // set up the UpdateManager
26705 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26706 var updater = tab2.getUpdateManager();
26707 updater.setDefaultUrl("ajax1.htm");
26708 tab2.on('activate', updater.refresh, updater, true);
26710 // Use setUrl for Ajax loading
26711 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26712 tab3.setUrl("ajax2.htm", null, true);
26715 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26718 jtabs.activate("jtabs-1");
26721 * Create a new TabPanel.
26722 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26723 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26725 Roo.TabPanel = function(container, config){
26727 * The container element for this TabPanel.
26728 * @type Roo.Element
26730 this.el = Roo.get(container, true);
26732 if(typeof config == "boolean"){
26733 this.tabPosition = config ? "bottom" : "top";
26735 Roo.apply(this, config);
26738 if(this.tabPosition == "bottom"){
26739 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26740 this.el.addClass("x-tabs-bottom");
26742 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26743 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26744 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26746 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26748 if(this.tabPosition != "bottom"){
26749 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26750 * @type Roo.Element
26752 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26753 this.el.addClass("x-tabs-top");
26757 this.bodyEl.setStyle("position", "relative");
26759 this.active = null;
26760 this.activateDelegate = this.activate.createDelegate(this);
26765 * Fires when the active tab changes
26766 * @param {Roo.TabPanel} this
26767 * @param {Roo.TabPanelItem} activePanel The new active tab
26771 * @event beforetabchange
26772 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26773 * @param {Roo.TabPanel} this
26774 * @param {Object} e Set cancel to true on this object to cancel the tab change
26775 * @param {Roo.TabPanelItem} tab The tab being changed to
26777 "beforetabchange" : true
26780 Roo.EventManager.onWindowResize(this.onResize, this);
26781 this.cpad = this.el.getPadding("lr");
26782 this.hiddenCount = 0;
26785 // toolbar on the tabbar support...
26786 if (this.toolbar) {
26787 var tcfg = this.toolbar;
26788 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26789 this.toolbar = new Roo.Toolbar(tcfg);
26790 if (Roo.isSafari) {
26791 var tbl = tcfg.container.child('table', true);
26792 tbl.setAttribute('width', '100%');
26799 Roo.TabPanel.superclass.constructor.call(this);
26802 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26804 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26806 tabPosition : "top",
26808 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26810 currentTabWidth : 0,
26812 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26816 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26820 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26822 preferredTabWidth : 175,
26824 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26826 resizeTabs : false,
26828 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26830 monitorResize : true,
26832 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26837 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26838 * @param {String} id The id of the div to use <b>or create</b>
26839 * @param {String} text The text for the tab
26840 * @param {String} content (optional) Content to put in the TabPanelItem body
26841 * @param {Boolean} closable (optional) True to create a close icon on the tab
26842 * @return {Roo.TabPanelItem} The created TabPanelItem
26844 addTab : function(id, text, content, closable){
26845 var item = new Roo.TabPanelItem(this, id, text, closable);
26846 this.addTabItem(item);
26848 item.setContent(content);
26854 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26855 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26856 * @return {Roo.TabPanelItem}
26858 getTab : function(id){
26859 return this.items[id];
26863 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26864 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26866 hideTab : function(id){
26867 var t = this.items[id];
26870 this.hiddenCount++;
26871 this.autoSizeTabs();
26876 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26877 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26879 unhideTab : function(id){
26880 var t = this.items[id];
26882 t.setHidden(false);
26883 this.hiddenCount--;
26884 this.autoSizeTabs();
26889 * Adds an existing {@link Roo.TabPanelItem}.
26890 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26892 addTabItem : function(item){
26893 this.items[item.id] = item;
26894 this.items.push(item);
26895 if(this.resizeTabs){
26896 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26897 this.autoSizeTabs();
26904 * Removes a {@link Roo.TabPanelItem}.
26905 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26907 removeTab : function(id){
26908 var items = this.items;
26909 var tab = items[id];
26910 if(!tab) { return; }
26911 var index = items.indexOf(tab);
26912 if(this.active == tab && items.length > 1){
26913 var newTab = this.getNextAvailable(index);
26918 this.stripEl.dom.removeChild(tab.pnode.dom);
26919 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26920 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26922 items.splice(index, 1);
26923 delete this.items[tab.id];
26924 tab.fireEvent("close", tab);
26925 tab.purgeListeners();
26926 this.autoSizeTabs();
26929 getNextAvailable : function(start){
26930 var items = this.items;
26932 // look for a next tab that will slide over to
26933 // replace the one being removed
26934 while(index < items.length){
26935 var item = items[++index];
26936 if(item && !item.isHidden()){
26940 // if one isn't found select the previous tab (on the left)
26943 var item = items[--index];
26944 if(item && !item.isHidden()){
26952 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26953 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26955 disableTab : function(id){
26956 var tab = this.items[id];
26957 if(tab && this.active != tab){
26963 * Enables a {@link Roo.TabPanelItem} that is disabled.
26964 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26966 enableTab : function(id){
26967 var tab = this.items[id];
26972 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26973 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26974 * @return {Roo.TabPanelItem} The TabPanelItem.
26976 activate : function(id){
26977 var tab = this.items[id];
26981 if(tab == this.active || tab.disabled){
26985 this.fireEvent("beforetabchange", this, e, tab);
26986 if(e.cancel !== true && !tab.disabled){
26988 this.active.hide();
26990 this.active = this.items[id];
26991 this.active.show();
26992 this.fireEvent("tabchange", this, this.active);
26998 * Gets the active {@link Roo.TabPanelItem}.
26999 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
27001 getActiveTab : function(){
27002 return this.active;
27006 * Updates the tab body element to fit the height of the container element
27007 * for overflow scrolling
27008 * @param {Number} targetHeight (optional) Override the starting height from the elements height
27010 syncHeight : function(targetHeight){
27011 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
27012 var bm = this.bodyEl.getMargins();
27013 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
27014 this.bodyEl.setHeight(newHeight);
27018 onResize : function(){
27019 if(this.monitorResize){
27020 this.autoSizeTabs();
27025 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
27027 beginUpdate : function(){
27028 this.updating = true;
27032 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
27034 endUpdate : function(){
27035 this.updating = false;
27036 this.autoSizeTabs();
27040 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
27042 autoSizeTabs : function(){
27043 var count = this.items.length;
27044 var vcount = count - this.hiddenCount;
27045 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
27048 var w = Math.max(this.el.getWidth() - this.cpad, 10);
27049 var availWidth = Math.floor(w / vcount);
27050 var b = this.stripBody;
27051 if(b.getWidth() > w){
27052 var tabs = this.items;
27053 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
27054 if(availWidth < this.minTabWidth){
27055 /*if(!this.sleft){ // incomplete scrolling code
27056 this.createScrollButtons();
27059 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
27062 if(this.currentTabWidth < this.preferredTabWidth){
27063 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
27069 * Returns the number of tabs in this TabPanel.
27072 getCount : function(){
27073 return this.items.length;
27077 * Resizes all the tabs to the passed width
27078 * @param {Number} The new width
27080 setTabWidth : function(width){
27081 this.currentTabWidth = width;
27082 for(var i = 0, len = this.items.length; i < len; i++) {
27083 if(!this.items[i].isHidden()) {
27084 this.items[i].setWidth(width);
27090 * Destroys this TabPanel
27091 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
27093 destroy : function(removeEl){
27094 Roo.EventManager.removeResizeListener(this.onResize, this);
27095 for(var i = 0, len = this.items.length; i < len; i++){
27096 this.items[i].purgeListeners();
27098 if(removeEl === true){
27099 this.el.update("");
27106 * @class Roo.TabPanelItem
27107 * @extends Roo.util.Observable
27108 * Represents an individual item (tab plus body) in a TabPanel.
27109 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
27110 * @param {String} id The id of this TabPanelItem
27111 * @param {String} text The text for the tab of this TabPanelItem
27112 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
27114 Roo.TabPanelItem = function(tabPanel, id, text, closable){
27116 * The {@link Roo.TabPanel} this TabPanelItem belongs to
27117 * @type Roo.TabPanel
27119 this.tabPanel = tabPanel;
27121 * The id for this TabPanelItem
27126 this.disabled = false;
27130 this.loaded = false;
27131 this.closable = closable;
27134 * The body element for this TabPanelItem.
27135 * @type Roo.Element
27137 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
27138 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
27139 this.bodyEl.setStyle("display", "block");
27140 this.bodyEl.setStyle("zoom", "1");
27143 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
27145 this.el = Roo.get(els.el, true);
27146 this.inner = Roo.get(els.inner, true);
27147 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
27148 this.pnode = Roo.get(els.el.parentNode, true);
27149 this.el.on("mousedown", this.onTabMouseDown, this);
27150 this.el.on("click", this.onTabClick, this);
27153 var c = Roo.get(els.close, true);
27154 c.dom.title = this.closeText;
27155 c.addClassOnOver("close-over");
27156 c.on("click", this.closeClick, this);
27162 * Fires when this tab becomes the active tab.
27163 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27164 * @param {Roo.TabPanelItem} this
27168 * @event beforeclose
27169 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
27170 * @param {Roo.TabPanelItem} this
27171 * @param {Object} e Set cancel to true on this object to cancel the close.
27173 "beforeclose": true,
27176 * Fires when this tab is closed.
27177 * @param {Roo.TabPanelItem} this
27181 * @event deactivate
27182 * Fires when this tab is no longer the active tab.
27183 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27184 * @param {Roo.TabPanelItem} this
27186 "deactivate" : true
27188 this.hidden = false;
27190 Roo.TabPanelItem.superclass.constructor.call(this);
27193 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27194 purgeListeners : function(){
27195 Roo.util.Observable.prototype.purgeListeners.call(this);
27196 this.el.removeAllListeners();
27199 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27202 this.pnode.addClass("on");
27205 this.tabPanel.stripWrap.repaint();
27207 this.fireEvent("activate", this.tabPanel, this);
27211 * Returns true if this tab is the active tab.
27212 * @return {Boolean}
27214 isActive : function(){
27215 return this.tabPanel.getActiveTab() == this;
27219 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27222 this.pnode.removeClass("on");
27224 this.fireEvent("deactivate", this.tabPanel, this);
27227 hideAction : function(){
27228 this.bodyEl.hide();
27229 this.bodyEl.setStyle("position", "absolute");
27230 this.bodyEl.setLeft("-20000px");
27231 this.bodyEl.setTop("-20000px");
27234 showAction : function(){
27235 this.bodyEl.setStyle("position", "relative");
27236 this.bodyEl.setTop("");
27237 this.bodyEl.setLeft("");
27238 this.bodyEl.show();
27242 * Set the tooltip for the tab.
27243 * @param {String} tooltip The tab's tooltip
27245 setTooltip : function(text){
27246 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27247 this.textEl.dom.qtip = text;
27248 this.textEl.dom.removeAttribute('title');
27250 this.textEl.dom.title = text;
27254 onTabClick : function(e){
27255 e.preventDefault();
27256 this.tabPanel.activate(this.id);
27259 onTabMouseDown : function(e){
27260 e.preventDefault();
27261 this.tabPanel.activate(this.id);
27264 getWidth : function(){
27265 return this.inner.getWidth();
27268 setWidth : function(width){
27269 var iwidth = width - this.pnode.getPadding("lr");
27270 this.inner.setWidth(iwidth);
27271 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27272 this.pnode.setWidth(width);
27276 * Show or hide the tab
27277 * @param {Boolean} hidden True to hide or false to show.
27279 setHidden : function(hidden){
27280 this.hidden = hidden;
27281 this.pnode.setStyle("display", hidden ? "none" : "");
27285 * Returns true if this tab is "hidden"
27286 * @return {Boolean}
27288 isHidden : function(){
27289 return this.hidden;
27293 * Returns the text for this tab
27296 getText : function(){
27300 autoSize : function(){
27301 //this.el.beginMeasure();
27302 this.textEl.setWidth(1);
27304 * #2804 [new] Tabs in Roojs
27305 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
27307 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
27308 //this.el.endMeasure();
27312 * Sets the text for the tab (Note: this also sets the tooltip text)
27313 * @param {String} text The tab's text and tooltip
27315 setText : function(text){
27317 this.textEl.update(text);
27318 this.setTooltip(text);
27319 if(!this.tabPanel.resizeTabs){
27324 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27326 activate : function(){
27327 this.tabPanel.activate(this.id);
27331 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27333 disable : function(){
27334 if(this.tabPanel.active != this){
27335 this.disabled = true;
27336 this.pnode.addClass("disabled");
27341 * Enables this TabPanelItem if it was previously disabled.
27343 enable : function(){
27344 this.disabled = false;
27345 this.pnode.removeClass("disabled");
27349 * Sets the content for this TabPanelItem.
27350 * @param {String} content The content
27351 * @param {Boolean} loadScripts true to look for and load scripts
27353 setContent : function(content, loadScripts){
27354 this.bodyEl.update(content, loadScripts);
27358 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27359 * @return {Roo.UpdateManager} The UpdateManager
27361 getUpdateManager : function(){
27362 return this.bodyEl.getUpdateManager();
27366 * Set a URL to be used to load the content for this TabPanelItem.
27367 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27368 * @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)
27369 * @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)
27370 * @return {Roo.UpdateManager} The UpdateManager
27372 setUrl : function(url, params, loadOnce){
27373 if(this.refreshDelegate){
27374 this.un('activate', this.refreshDelegate);
27376 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27377 this.on("activate", this.refreshDelegate);
27378 return this.bodyEl.getUpdateManager();
27382 _handleRefresh : function(url, params, loadOnce){
27383 if(!loadOnce || !this.loaded){
27384 var updater = this.bodyEl.getUpdateManager();
27385 updater.update(url, params, this._setLoaded.createDelegate(this));
27390 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27391 * Will fail silently if the setUrl method has not been called.
27392 * This does not activate the panel, just updates its content.
27394 refresh : function(){
27395 if(this.refreshDelegate){
27396 this.loaded = false;
27397 this.refreshDelegate();
27402 _setLoaded : function(){
27403 this.loaded = true;
27407 closeClick : function(e){
27410 this.fireEvent("beforeclose", this, o);
27411 if(o.cancel !== true){
27412 this.tabPanel.removeTab(this.id);
27416 * The text displayed in the tooltip for the close icon.
27419 closeText : "Close this tab"
27423 Roo.TabPanel.prototype.createStrip = function(container){
27424 var strip = document.createElement("div");
27425 strip.className = "x-tabs-wrap";
27426 container.appendChild(strip);
27430 Roo.TabPanel.prototype.createStripList = function(strip){
27431 // div wrapper for retard IE
27432 // returns the "tr" element.
27433 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27434 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27435 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27436 return strip.firstChild.firstChild.firstChild.firstChild;
27439 Roo.TabPanel.prototype.createBody = function(container){
27440 var body = document.createElement("div");
27441 Roo.id(body, "tab-body");
27442 Roo.fly(body).addClass("x-tabs-body");
27443 container.appendChild(body);
27447 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27448 var body = Roo.getDom(id);
27450 body = document.createElement("div");
27453 Roo.fly(body).addClass("x-tabs-item-body");
27454 bodyEl.insertBefore(body, bodyEl.firstChild);
27458 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27459 var td = document.createElement("td");
27460 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27461 //stripEl.appendChild(td);
27463 td.className = "x-tabs-closable";
27464 if(!this.closeTpl){
27465 this.closeTpl = new Roo.Template(
27466 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27467 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27468 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27471 var el = this.closeTpl.overwrite(td, {"text": text});
27472 var close = el.getElementsByTagName("div")[0];
27473 var inner = el.getElementsByTagName("em")[0];
27474 return {"el": el, "close": close, "inner": inner};
27477 this.tabTpl = new Roo.Template(
27478 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27479 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27482 var el = this.tabTpl.overwrite(td, {"text": text});
27483 var inner = el.getElementsByTagName("em")[0];
27484 return {"el": el, "inner": inner};
27488 * Ext JS Library 1.1.1
27489 * Copyright(c) 2006-2007, Ext JS, LLC.
27491 * Originally Released Under LGPL - original licence link has changed is not relivant.
27494 * <script type="text/javascript">
27498 * @class Roo.Button
27499 * @extends Roo.util.Observable
27500 * Simple Button class
27501 * @cfg {String} text The button text
27502 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27503 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27504 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27505 * @cfg {Object} scope The scope of the handler
27506 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27507 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27508 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27509 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27510 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27511 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27512 applies if enableToggle = true)
27513 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27514 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27515 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27517 * Create a new button
27518 * @param {Object} config The config object
27520 Roo.Button = function(renderTo, config)
27524 renderTo = config.renderTo || false;
27527 Roo.apply(this, config);
27531 * Fires when this button is clicked
27532 * @param {Button} this
27533 * @param {EventObject} e The click event
27538 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27539 * @param {Button} this
27540 * @param {Boolean} pressed
27545 * Fires when the mouse hovers over the button
27546 * @param {Button} this
27547 * @param {Event} e The event object
27549 'mouseover' : true,
27552 * Fires when the mouse exits the button
27553 * @param {Button} this
27554 * @param {Event} e The event object
27559 * Fires when the button is rendered
27560 * @param {Button} this
27565 this.menu = Roo.menu.MenuMgr.get(this.menu);
27567 // register listeners first!! - so render can be captured..
27568 Roo.util.Observable.call(this);
27570 this.render(renderTo);
27576 Roo.extend(Roo.Button, Roo.util.Observable, {
27582 * Read-only. True if this button is hidden
27587 * Read-only. True if this button is disabled
27592 * Read-only. True if this button is pressed (only if enableToggle = true)
27598 * @cfg {Number} tabIndex
27599 * The DOM tabIndex for this button (defaults to undefined)
27601 tabIndex : undefined,
27604 * @cfg {Boolean} enableToggle
27605 * True to enable pressed/not pressed toggling (defaults to false)
27607 enableToggle: false,
27609 * @cfg {Mixed} menu
27610 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27614 * @cfg {String} menuAlign
27615 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27617 menuAlign : "tl-bl?",
27620 * @cfg {String} iconCls
27621 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27623 iconCls : undefined,
27625 * @cfg {String} type
27626 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27631 menuClassTarget: 'tr',
27634 * @cfg {String} clickEvent
27635 * The type of event to map to the button's event handler (defaults to 'click')
27637 clickEvent : 'click',
27640 * @cfg {Boolean} handleMouseEvents
27641 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27643 handleMouseEvents : true,
27646 * @cfg {String} tooltipType
27647 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27649 tooltipType : 'qtip',
27652 * @cfg {String} cls
27653 * A CSS class to apply to the button's main element.
27657 * @cfg {Roo.Template} template (Optional)
27658 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27659 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27660 * require code modifications if required elements (e.g. a button) aren't present.
27664 render : function(renderTo){
27666 if(this.hideParent){
27667 this.parentEl = Roo.get(renderTo);
27669 if(!this.dhconfig){
27670 if(!this.template){
27671 if(!Roo.Button.buttonTemplate){
27672 // hideous table template
27673 Roo.Button.buttonTemplate = new Roo.Template(
27674 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27675 '<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>',
27676 "</tr></tbody></table>");
27678 this.template = Roo.Button.buttonTemplate;
27680 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27681 var btnEl = btn.child("button:first");
27682 btnEl.on('focus', this.onFocus, this);
27683 btnEl.on('blur', this.onBlur, this);
27685 btn.addClass(this.cls);
27688 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27691 btnEl.addClass(this.iconCls);
27693 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27696 if(this.tabIndex !== undefined){
27697 btnEl.dom.tabIndex = this.tabIndex;
27700 if(typeof this.tooltip == 'object'){
27701 Roo.QuickTips.tips(Roo.apply({
27705 btnEl.dom[this.tooltipType] = this.tooltip;
27709 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27713 this.el.dom.id = this.el.id = this.id;
27716 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27717 this.menu.on("show", this.onMenuShow, this);
27718 this.menu.on("hide", this.onMenuHide, this);
27720 btn.addClass("x-btn");
27721 if(Roo.isIE && !Roo.isIE7){
27722 this.autoWidth.defer(1, this);
27726 if(this.handleMouseEvents){
27727 btn.on("mouseover", this.onMouseOver, this);
27728 btn.on("mouseout", this.onMouseOut, this);
27729 btn.on("mousedown", this.onMouseDown, this);
27731 btn.on(this.clickEvent, this.onClick, this);
27732 //btn.on("mouseup", this.onMouseUp, this);
27739 Roo.ButtonToggleMgr.register(this);
27741 this.el.addClass("x-btn-pressed");
27744 var repeater = new Roo.util.ClickRepeater(btn,
27745 typeof this.repeat == "object" ? this.repeat : {}
27747 repeater.on("click", this.onClick, this);
27750 this.fireEvent('render', this);
27754 * Returns the button's underlying element
27755 * @return {Roo.Element} The element
27757 getEl : function(){
27762 * Destroys this Button and removes any listeners.
27764 destroy : function(){
27765 Roo.ButtonToggleMgr.unregister(this);
27766 this.el.removeAllListeners();
27767 this.purgeListeners();
27772 autoWidth : function(){
27774 this.el.setWidth("auto");
27775 if(Roo.isIE7 && Roo.isStrict){
27776 var ib = this.el.child('button');
27777 if(ib && ib.getWidth() > 20){
27779 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27784 this.el.beginMeasure();
27786 if(this.el.getWidth() < this.minWidth){
27787 this.el.setWidth(this.minWidth);
27790 this.el.endMeasure();
27797 * Assigns this button's click handler
27798 * @param {Function} handler The function to call when the button is clicked
27799 * @param {Object} scope (optional) Scope for the function passed in
27801 setHandler : function(handler, scope){
27802 this.handler = handler;
27803 this.scope = scope;
27807 * Sets this button's text
27808 * @param {String} text The button text
27810 setText : function(text){
27813 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27819 * Gets the text for this button
27820 * @return {String} The button text
27822 getText : function(){
27830 this.hidden = false;
27832 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27840 this.hidden = true;
27842 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27847 * Convenience function for boolean show/hide
27848 * @param {Boolean} visible True to show, false to hide
27850 setVisible: function(visible){
27859 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27860 * @param {Boolean} state (optional) Force a particular state
27862 toggle : function(state){
27863 state = state === undefined ? !this.pressed : state;
27864 if(state != this.pressed){
27866 this.el.addClass("x-btn-pressed");
27867 this.pressed = true;
27868 this.fireEvent("toggle", this, true);
27870 this.el.removeClass("x-btn-pressed");
27871 this.pressed = false;
27872 this.fireEvent("toggle", this, false);
27874 if(this.toggleHandler){
27875 this.toggleHandler.call(this.scope || this, this, state);
27883 focus : function(){
27884 this.el.child('button:first').focus();
27888 * Disable this button
27890 disable : function(){
27892 this.el.addClass("x-btn-disabled");
27894 this.disabled = true;
27898 * Enable this button
27900 enable : function(){
27902 this.el.removeClass("x-btn-disabled");
27904 this.disabled = false;
27908 * Convenience function for boolean enable/disable
27909 * @param {Boolean} enabled True to enable, false to disable
27911 setDisabled : function(v){
27912 this[v !== true ? "enable" : "disable"]();
27916 onClick : function(e)
27919 e.preventDefault();
27924 if(!this.disabled){
27925 if(this.enableToggle){
27928 if(this.menu && !this.menu.isVisible()){
27929 this.menu.show(this.el, this.menuAlign);
27931 this.fireEvent("click", this, e);
27933 this.el.removeClass("x-btn-over");
27934 this.handler.call(this.scope || this, this, e);
27939 onMouseOver : function(e){
27940 if(!this.disabled){
27941 this.el.addClass("x-btn-over");
27942 this.fireEvent('mouseover', this, e);
27946 onMouseOut : function(e){
27947 if(!e.within(this.el, true)){
27948 this.el.removeClass("x-btn-over");
27949 this.fireEvent('mouseout', this, e);
27953 onFocus : function(e){
27954 if(!this.disabled){
27955 this.el.addClass("x-btn-focus");
27959 onBlur : function(e){
27960 this.el.removeClass("x-btn-focus");
27963 onMouseDown : function(e){
27964 if(!this.disabled && e.button == 0){
27965 this.el.addClass("x-btn-click");
27966 Roo.get(document).on('mouseup', this.onMouseUp, this);
27970 onMouseUp : function(e){
27972 this.el.removeClass("x-btn-click");
27973 Roo.get(document).un('mouseup', this.onMouseUp, this);
27977 onMenuShow : function(e){
27978 this.el.addClass("x-btn-menu-active");
27981 onMenuHide : function(e){
27982 this.el.removeClass("x-btn-menu-active");
27986 // Private utility class used by Button
27987 Roo.ButtonToggleMgr = function(){
27990 function toggleGroup(btn, state){
27992 var g = groups[btn.toggleGroup];
27993 for(var i = 0, l = g.length; i < l; i++){
27995 g[i].toggle(false);
28002 register : function(btn){
28003 if(!btn.toggleGroup){
28006 var g = groups[btn.toggleGroup];
28008 g = groups[btn.toggleGroup] = [];
28011 btn.on("toggle", toggleGroup);
28014 unregister : function(btn){
28015 if(!btn.toggleGroup){
28018 var g = groups[btn.toggleGroup];
28021 btn.un("toggle", toggleGroup);
28027 * Ext JS Library 1.1.1
28028 * Copyright(c) 2006-2007, Ext JS, LLC.
28030 * Originally Released Under LGPL - original licence link has changed is not relivant.
28033 * <script type="text/javascript">
28037 * @class Roo.SplitButton
28038 * @extends Roo.Button
28039 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
28040 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
28041 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
28042 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
28043 * @cfg {String} arrowTooltip The title attribute of the arrow
28045 * Create a new menu button
28046 * @param {String/HTMLElement/Element} renderTo The element to append the button to
28047 * @param {Object} config The config object
28049 Roo.SplitButton = function(renderTo, config){
28050 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
28052 * @event arrowclick
28053 * Fires when this button's arrow is clicked
28054 * @param {SplitButton} this
28055 * @param {EventObject} e The click event
28057 this.addEvents({"arrowclick":true});
28060 Roo.extend(Roo.SplitButton, Roo.Button, {
28061 render : function(renderTo){
28062 // this is one sweet looking template!
28063 var tpl = new Roo.Template(
28064 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
28065 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
28066 '<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>',
28067 "</tbody></table></td><td>",
28068 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
28069 '<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>',
28070 "</tbody></table></td></tr></table>"
28072 var btn = tpl.append(renderTo, [this.text, this.type], true);
28073 var btnEl = btn.child("button");
28075 btn.addClass(this.cls);
28078 btnEl.setStyle('background-image', 'url(' +this.icon +')');
28081 btnEl.addClass(this.iconCls);
28083 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
28087 if(this.handleMouseEvents){
28088 btn.on("mouseover", this.onMouseOver, this);
28089 btn.on("mouseout", this.onMouseOut, this);
28090 btn.on("mousedown", this.onMouseDown, this);
28091 btn.on("mouseup", this.onMouseUp, this);
28093 btn.on(this.clickEvent, this.onClick, this);
28095 if(typeof this.tooltip == 'object'){
28096 Roo.QuickTips.tips(Roo.apply({
28100 btnEl.dom[this.tooltipType] = this.tooltip;
28103 if(this.arrowTooltip){
28104 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
28113 this.el.addClass("x-btn-pressed");
28115 if(Roo.isIE && !Roo.isIE7){
28116 this.autoWidth.defer(1, this);
28121 this.menu.on("show", this.onMenuShow, this);
28122 this.menu.on("hide", this.onMenuHide, this);
28124 this.fireEvent('render', this);
28128 autoWidth : function(){
28130 var tbl = this.el.child("table:first");
28131 var tbl2 = this.el.child("table:last");
28132 this.el.setWidth("auto");
28133 tbl.setWidth("auto");
28134 if(Roo.isIE7 && Roo.isStrict){
28135 var ib = this.el.child('button:first');
28136 if(ib && ib.getWidth() > 20){
28138 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
28143 this.el.beginMeasure();
28145 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
28146 tbl.setWidth(this.minWidth-tbl2.getWidth());
28149 this.el.endMeasure();
28152 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
28156 * Sets this button's click handler
28157 * @param {Function} handler The function to call when the button is clicked
28158 * @param {Object} scope (optional) Scope for the function passed above
28160 setHandler : function(handler, scope){
28161 this.handler = handler;
28162 this.scope = scope;
28166 * Sets this button's arrow click handler
28167 * @param {Function} handler The function to call when the arrow is clicked
28168 * @param {Object} scope (optional) Scope for the function passed above
28170 setArrowHandler : function(handler, scope){
28171 this.arrowHandler = handler;
28172 this.scope = scope;
28178 focus : function(){
28180 this.el.child("button:first").focus();
28185 onClick : function(e){
28186 e.preventDefault();
28187 if(!this.disabled){
28188 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28189 if(this.menu && !this.menu.isVisible()){
28190 this.menu.show(this.el, this.menuAlign);
28192 this.fireEvent("arrowclick", this, e);
28193 if(this.arrowHandler){
28194 this.arrowHandler.call(this.scope || this, this, e);
28197 this.fireEvent("click", this, e);
28199 this.handler.call(this.scope || this, this, e);
28205 onMouseDown : function(e){
28206 if(!this.disabled){
28207 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28211 onMouseUp : function(e){
28212 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28217 // backwards compat
28218 Roo.MenuButton = Roo.SplitButton;/*
28220 * Ext JS Library 1.1.1
28221 * Copyright(c) 2006-2007, Ext JS, LLC.
28223 * Originally Released Under LGPL - original licence link has changed is not relivant.
28226 * <script type="text/javascript">
28230 * @class Roo.Toolbar
28231 * Basic Toolbar class.
28233 * Creates a new Toolbar
28234 * @param {Object} container The config object
28236 Roo.Toolbar = function(container, buttons, config)
28238 /// old consturctor format still supported..
28239 if(container instanceof Array){ // omit the container for later rendering
28240 buttons = container;
28244 if (typeof(container) == 'object' && container.xtype) {
28245 config = container;
28246 container = config.container;
28247 buttons = config.buttons || []; // not really - use items!!
28250 if (config && config.items) {
28251 xitems = config.items;
28252 delete config.items;
28254 Roo.apply(this, config);
28255 this.buttons = buttons;
28258 this.render(container);
28260 this.xitems = xitems;
28261 Roo.each(xitems, function(b) {
28267 Roo.Toolbar.prototype = {
28269 * @cfg {Array} items
28270 * array of button configs or elements to add (will be converted to a MixedCollection)
28274 * @cfg {String/HTMLElement/Element} container
28275 * The id or element that will contain the toolbar
28278 render : function(ct){
28279 this.el = Roo.get(ct);
28281 this.el.addClass(this.cls);
28283 // using a table allows for vertical alignment
28284 // 100% width is needed by Safari...
28285 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28286 this.tr = this.el.child("tr", true);
28288 this.items = new Roo.util.MixedCollection(false, function(o){
28289 return o.id || ("item" + (++autoId));
28292 this.add.apply(this, this.buttons);
28293 delete this.buttons;
28298 * Adds element(s) to the toolbar -- this function takes a variable number of
28299 * arguments of mixed type and adds them to the toolbar.
28300 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28302 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28303 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28304 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28305 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28306 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28307 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28308 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28309 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28310 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28312 * @param {Mixed} arg2
28313 * @param {Mixed} etc.
28316 var a = arguments, l = a.length;
28317 for(var i = 0; i < l; i++){
28322 _add : function(el) {
28325 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28328 if (el.applyTo){ // some kind of form field
28329 return this.addField(el);
28331 if (el.render){ // some kind of Toolbar.Item
28332 return this.addItem(el);
28334 if (typeof el == "string"){ // string
28335 if(el == "separator" || el == "-"){
28336 return this.addSeparator();
28339 return this.addSpacer();
28342 return this.addFill();
28344 return this.addText(el);
28347 if(el.tagName){ // element
28348 return this.addElement(el);
28350 if(typeof el == "object"){ // must be button config?
28351 return this.addButton(el);
28353 // and now what?!?!
28359 * Add an Xtype element
28360 * @param {Object} xtype Xtype Object
28361 * @return {Object} created Object
28363 addxtype : function(e){
28364 return this.add(e);
28368 * Returns the Element for this toolbar.
28369 * @return {Roo.Element}
28371 getEl : function(){
28377 * @return {Roo.Toolbar.Item} The separator item
28379 addSeparator : function(){
28380 return this.addItem(new Roo.Toolbar.Separator());
28384 * Adds a spacer element
28385 * @return {Roo.Toolbar.Spacer} The spacer item
28387 addSpacer : function(){
28388 return this.addItem(new Roo.Toolbar.Spacer());
28392 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28393 * @return {Roo.Toolbar.Fill} The fill item
28395 addFill : function(){
28396 return this.addItem(new Roo.Toolbar.Fill());
28400 * Adds any standard HTML element to the toolbar
28401 * @param {String/HTMLElement/Element} el The element or id of the element to add
28402 * @return {Roo.Toolbar.Item} The element's item
28404 addElement : function(el){
28405 return this.addItem(new Roo.Toolbar.Item(el));
28408 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28409 * @type Roo.util.MixedCollection
28414 * Adds any Toolbar.Item or subclass
28415 * @param {Roo.Toolbar.Item} item
28416 * @return {Roo.Toolbar.Item} The item
28418 addItem : function(item){
28419 var td = this.nextBlock();
28421 this.items.add(item);
28426 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28427 * @param {Object/Array} config A button config or array of configs
28428 * @return {Roo.Toolbar.Button/Array}
28430 addButton : function(config){
28431 if(config instanceof Array){
28433 for(var i = 0, len = config.length; i < len; i++) {
28434 buttons.push(this.addButton(config[i]));
28439 if(!(config instanceof Roo.Toolbar.Button)){
28441 new Roo.Toolbar.SplitButton(config) :
28442 new Roo.Toolbar.Button(config);
28444 var td = this.nextBlock();
28451 * Adds text to the toolbar
28452 * @param {String} text The text to add
28453 * @return {Roo.Toolbar.Item} The element's item
28455 addText : function(text){
28456 return this.addItem(new Roo.Toolbar.TextItem(text));
28460 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28461 * @param {Number} index The index where the item is to be inserted
28462 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28463 * @return {Roo.Toolbar.Button/Item}
28465 insertButton : function(index, item){
28466 if(item instanceof Array){
28468 for(var i = 0, len = item.length; i < len; i++) {
28469 buttons.push(this.insertButton(index + i, item[i]));
28473 if (!(item instanceof Roo.Toolbar.Button)){
28474 item = new Roo.Toolbar.Button(item);
28476 var td = document.createElement("td");
28477 this.tr.insertBefore(td, this.tr.childNodes[index]);
28479 this.items.insert(index, item);
28484 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28485 * @param {Object} config
28486 * @return {Roo.Toolbar.Item} The element's item
28488 addDom : function(config, returnEl){
28489 var td = this.nextBlock();
28490 Roo.DomHelper.overwrite(td, config);
28491 var ti = new Roo.Toolbar.Item(td.firstChild);
28493 this.items.add(ti);
28498 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28499 * @type Roo.util.MixedCollection
28504 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28505 * Note: the field should not have been rendered yet. For a field that has already been
28506 * rendered, use {@link #addElement}.
28507 * @param {Roo.form.Field} field
28508 * @return {Roo.ToolbarItem}
28512 addField : function(field) {
28513 if (!this.fields) {
28515 this.fields = new Roo.util.MixedCollection(false, function(o){
28516 return o.id || ("item" + (++autoId));
28521 var td = this.nextBlock();
28523 var ti = new Roo.Toolbar.Item(td.firstChild);
28525 this.items.add(ti);
28526 this.fields.add(field);
28537 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28538 this.el.child('div').hide();
28546 this.el.child('div').show();
28550 nextBlock : function(){
28551 var td = document.createElement("td");
28552 this.tr.appendChild(td);
28557 destroy : function(){
28558 if(this.items){ // rendered?
28559 Roo.destroy.apply(Roo, this.items.items);
28561 if(this.fields){ // rendered?
28562 Roo.destroy.apply(Roo, this.fields.items);
28564 Roo.Element.uncache(this.el, this.tr);
28569 * @class Roo.Toolbar.Item
28570 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28572 * Creates a new Item
28573 * @param {HTMLElement} el
28575 Roo.Toolbar.Item = function(el){
28577 if (typeof (el.xtype) != 'undefined') {
28582 this.el = Roo.getDom(el);
28583 this.id = Roo.id(this.el);
28584 this.hidden = false;
28589 * Fires when the button is rendered
28590 * @param {Button} this
28594 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
28596 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
28597 //Roo.Toolbar.Item.prototype = {
28600 * Get this item's HTML Element
28601 * @return {HTMLElement}
28603 getEl : function(){
28608 render : function(td){
28611 td.appendChild(this.el);
28613 this.fireEvent('render', this);
28617 * Removes and destroys this item.
28619 destroy : function(){
28620 this.td.parentNode.removeChild(this.td);
28627 this.hidden = false;
28628 this.td.style.display = "";
28635 this.hidden = true;
28636 this.td.style.display = "none";
28640 * Convenience function for boolean show/hide.
28641 * @param {Boolean} visible true to show/false to hide
28643 setVisible: function(visible){
28652 * Try to focus this item.
28654 focus : function(){
28655 Roo.fly(this.el).focus();
28659 * Disables this item.
28661 disable : function(){
28662 Roo.fly(this.td).addClass("x-item-disabled");
28663 this.disabled = true;
28664 this.el.disabled = true;
28668 * Enables this item.
28670 enable : function(){
28671 Roo.fly(this.td).removeClass("x-item-disabled");
28672 this.disabled = false;
28673 this.el.disabled = false;
28679 * @class Roo.Toolbar.Separator
28680 * @extends Roo.Toolbar.Item
28681 * A simple toolbar separator class
28683 * Creates a new Separator
28685 Roo.Toolbar.Separator = function(cfg){
28687 var s = document.createElement("span");
28688 s.className = "ytb-sep";
28693 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
28695 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28696 enable:Roo.emptyFn,
28697 disable:Roo.emptyFn,
28702 * @class Roo.Toolbar.Spacer
28703 * @extends Roo.Toolbar.Item
28704 * A simple element that adds extra horizontal space to a toolbar.
28706 * Creates a new Spacer
28708 Roo.Toolbar.Spacer = function(cfg){
28709 var s = document.createElement("div");
28710 s.className = "ytb-spacer";
28714 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
28716 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28717 enable:Roo.emptyFn,
28718 disable:Roo.emptyFn,
28723 * @class Roo.Toolbar.Fill
28724 * @extends Roo.Toolbar.Spacer
28725 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28727 * Creates a new Spacer
28729 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28731 render : function(td){
28732 td.style.width = '100%';
28733 Roo.Toolbar.Fill.superclass.render.call(this, td);
28738 * @class Roo.Toolbar.TextItem
28739 * @extends Roo.Toolbar.Item
28740 * A simple class that renders text directly into a toolbar.
28742 * Creates a new TextItem
28743 * @param {String} text
28745 Roo.Toolbar.TextItem = function(cfg){
28746 var text = cfg || "";
28747 if (typeof(cfg) == 'object') {
28748 text = cfg.text || "";
28752 var s = document.createElement("span");
28753 s.className = "ytb-text";
28754 s.innerHTML = text;
28759 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
28761 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28764 enable:Roo.emptyFn,
28765 disable:Roo.emptyFn,
28770 * @class Roo.Toolbar.Button
28771 * @extends Roo.Button
28772 * A button that renders into a toolbar.
28774 * Creates a new Button
28775 * @param {Object} config A standard {@link Roo.Button} config object
28777 Roo.Toolbar.Button = function(config){
28778 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28780 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28781 render : function(td){
28783 Roo.Toolbar.Button.superclass.render.call(this, td);
28787 * Removes and destroys this button
28789 destroy : function(){
28790 Roo.Toolbar.Button.superclass.destroy.call(this);
28791 this.td.parentNode.removeChild(this.td);
28795 * Shows this button
28798 this.hidden = false;
28799 this.td.style.display = "";
28803 * Hides this button
28806 this.hidden = true;
28807 this.td.style.display = "none";
28811 * Disables this item
28813 disable : function(){
28814 Roo.fly(this.td).addClass("x-item-disabled");
28815 this.disabled = true;
28819 * Enables this item
28821 enable : function(){
28822 Roo.fly(this.td).removeClass("x-item-disabled");
28823 this.disabled = false;
28826 // backwards compat
28827 Roo.ToolbarButton = Roo.Toolbar.Button;
28830 * @class Roo.Toolbar.SplitButton
28831 * @extends Roo.SplitButton
28832 * A menu button that renders into a toolbar.
28834 * Creates a new SplitButton
28835 * @param {Object} config A standard {@link Roo.SplitButton} config object
28837 Roo.Toolbar.SplitButton = function(config){
28838 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28840 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28841 render : function(td){
28843 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28847 * Removes and destroys this button
28849 destroy : function(){
28850 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28851 this.td.parentNode.removeChild(this.td);
28855 * Shows this button
28858 this.hidden = false;
28859 this.td.style.display = "";
28863 * Hides this button
28866 this.hidden = true;
28867 this.td.style.display = "none";
28871 // backwards compat
28872 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28874 * Ext JS Library 1.1.1
28875 * Copyright(c) 2006-2007, Ext JS, LLC.
28877 * Originally Released Under LGPL - original licence link has changed is not relivant.
28880 * <script type="text/javascript">
28884 * @class Roo.PagingToolbar
28885 * @extends Roo.Toolbar
28886 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28888 * Create a new PagingToolbar
28889 * @param {Object} config The config object
28891 Roo.PagingToolbar = function(el, ds, config)
28893 // old args format still supported... - xtype is prefered..
28894 if (typeof(el) == 'object' && el.xtype) {
28895 // created from xtype...
28897 ds = el.dataSource;
28898 el = config.container;
28901 if (config.items) {
28902 items = config.items;
28906 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28909 this.renderButtons(this.el);
28912 // supprot items array.
28914 Roo.each(items, function(e) {
28915 this.add(Roo.factory(e));
28920 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28922 * @cfg {Roo.data.Store} dataSource
28923 * The underlying data store providing the paged data
28926 * @cfg {String/HTMLElement/Element} container
28927 * container The id or element that will contain the toolbar
28930 * @cfg {Boolean} displayInfo
28931 * True to display the displayMsg (defaults to false)
28934 * @cfg {Number} pageSize
28935 * The number of records to display per page (defaults to 20)
28939 * @cfg {String} displayMsg
28940 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28942 displayMsg : 'Displaying {0} - {1} of {2}',
28944 * @cfg {String} emptyMsg
28945 * The message to display when no records are found (defaults to "No data to display")
28947 emptyMsg : 'No data to display',
28949 * Customizable piece of the default paging text (defaults to "Page")
28952 beforePageText : "Page",
28954 * Customizable piece of the default paging text (defaults to "of %0")
28957 afterPageText : "of {0}",
28959 * Customizable piece of the default paging text (defaults to "First Page")
28962 firstText : "First Page",
28964 * Customizable piece of the default paging text (defaults to "Previous Page")
28967 prevText : "Previous Page",
28969 * Customizable piece of the default paging text (defaults to "Next Page")
28972 nextText : "Next Page",
28974 * Customizable piece of the default paging text (defaults to "Last Page")
28977 lastText : "Last Page",
28979 * Customizable piece of the default paging text (defaults to "Refresh")
28982 refreshText : "Refresh",
28985 renderButtons : function(el){
28986 Roo.PagingToolbar.superclass.render.call(this, el);
28987 this.first = this.addButton({
28988 tooltip: this.firstText,
28989 cls: "x-btn-icon x-grid-page-first",
28991 handler: this.onClick.createDelegate(this, ["first"])
28993 this.prev = this.addButton({
28994 tooltip: this.prevText,
28995 cls: "x-btn-icon x-grid-page-prev",
28997 handler: this.onClick.createDelegate(this, ["prev"])
28999 //this.addSeparator();
29000 this.add(this.beforePageText);
29001 this.field = Roo.get(this.addDom({
29006 cls: "x-grid-page-number"
29008 this.field.on("keydown", this.onPagingKeydown, this);
29009 this.field.on("focus", function(){this.dom.select();});
29010 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
29011 this.field.setHeight(18);
29012 //this.addSeparator();
29013 this.next = this.addButton({
29014 tooltip: this.nextText,
29015 cls: "x-btn-icon x-grid-page-next",
29017 handler: this.onClick.createDelegate(this, ["next"])
29019 this.last = this.addButton({
29020 tooltip: this.lastText,
29021 cls: "x-btn-icon x-grid-page-last",
29023 handler: this.onClick.createDelegate(this, ["last"])
29025 //this.addSeparator();
29026 this.loading = this.addButton({
29027 tooltip: this.refreshText,
29028 cls: "x-btn-icon x-grid-loading",
29029 handler: this.onClick.createDelegate(this, ["refresh"])
29032 if(this.displayInfo){
29033 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
29038 updateInfo : function(){
29039 if(this.displayEl){
29040 var count = this.ds.getCount();
29041 var msg = count == 0 ?
29045 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
29047 this.displayEl.update(msg);
29052 onLoad : function(ds, r, o){
29053 this.cursor = o.params ? o.params.start : 0;
29054 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
29056 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
29057 this.field.dom.value = ap;
29058 this.first.setDisabled(ap == 1);
29059 this.prev.setDisabled(ap == 1);
29060 this.next.setDisabled(ap == ps);
29061 this.last.setDisabled(ap == ps);
29062 this.loading.enable();
29067 getPageData : function(){
29068 var total = this.ds.getTotalCount();
29071 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
29072 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
29077 onLoadError : function(){
29078 this.loading.enable();
29082 onPagingKeydown : function(e){
29083 var k = e.getKey();
29084 var d = this.getPageData();
29086 var v = this.field.dom.value, pageNum;
29087 if(!v || isNaN(pageNum = parseInt(v, 10))){
29088 this.field.dom.value = d.activePage;
29091 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
29092 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29095 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))
29097 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
29098 this.field.dom.value = pageNum;
29099 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
29102 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29104 var v = this.field.dom.value, pageNum;
29105 var increment = (e.shiftKey) ? 10 : 1;
29106 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
29109 if(!v || isNaN(pageNum = parseInt(v, 10))) {
29110 this.field.dom.value = d.activePage;
29113 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
29115 this.field.dom.value = parseInt(v, 10) + increment;
29116 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
29117 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29124 beforeLoad : function(){
29126 this.loading.disable();
29131 onClick : function(which){
29135 ds.load({params:{start: 0, limit: this.pageSize}});
29138 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
29141 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
29144 var total = ds.getTotalCount();
29145 var extra = total % this.pageSize;
29146 var lastStart = extra ? (total - extra) : total-this.pageSize;
29147 ds.load({params:{start: lastStart, limit: this.pageSize}});
29150 ds.load({params:{start: this.cursor, limit: this.pageSize}});
29156 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
29157 * @param {Roo.data.Store} store The data store to unbind
29159 unbind : function(ds){
29160 ds.un("beforeload", this.beforeLoad, this);
29161 ds.un("load", this.onLoad, this);
29162 ds.un("loadexception", this.onLoadError, this);
29163 ds.un("remove", this.updateInfo, this);
29164 ds.un("add", this.updateInfo, this);
29165 this.ds = undefined;
29169 * Binds the paging toolbar to the specified {@link Roo.data.Store}
29170 * @param {Roo.data.Store} store The data store to bind
29172 bind : function(ds){
29173 ds.on("beforeload", this.beforeLoad, this);
29174 ds.on("load", this.onLoad, this);
29175 ds.on("loadexception", this.onLoadError, this);
29176 ds.on("remove", this.updateInfo, this);
29177 ds.on("add", this.updateInfo, this);
29182 * Ext JS Library 1.1.1
29183 * Copyright(c) 2006-2007, Ext JS, LLC.
29185 * Originally Released Under LGPL - original licence link has changed is not relivant.
29188 * <script type="text/javascript">
29192 * @class Roo.Resizable
29193 * @extends Roo.util.Observable
29194 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
29195 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
29196 * 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
29197 * the element will be wrapped for you automatically.</p>
29198 * <p>Here is the list of valid resize handles:</p>
29201 ------ -------------------
29210 'hd' horizontal drag
29213 * <p>Here's an example showing the creation of a typical Resizable:</p>
29215 var resizer = new Roo.Resizable("element-id", {
29223 resizer.on("resize", myHandler);
29225 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29226 * resizer.east.setDisplayed(false);</p>
29227 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29228 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29229 * resize operation's new size (defaults to [0, 0])
29230 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29231 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29232 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29233 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29234 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29235 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29236 * @cfg {Number} width The width of the element in pixels (defaults to null)
29237 * @cfg {Number} height The height of the element in pixels (defaults to null)
29238 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29239 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29240 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29241 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29242 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29243 * in favor of the handles config option (defaults to false)
29244 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29245 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29246 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29247 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29248 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29249 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29250 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29251 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29252 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29253 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29254 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29256 * Create a new resizable component
29257 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29258 * @param {Object} config configuration options
29260 Roo.Resizable = function(el, config)
29262 this.el = Roo.get(el);
29264 if(config && config.wrap){
29265 config.resizeChild = this.el;
29266 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29267 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29268 this.el.setStyle("overflow", "hidden");
29269 this.el.setPositioning(config.resizeChild.getPositioning());
29270 config.resizeChild.clearPositioning();
29271 if(!config.width || !config.height){
29272 var csize = config.resizeChild.getSize();
29273 this.el.setSize(csize.width, csize.height);
29275 if(config.pinned && !config.adjustments){
29276 config.adjustments = "auto";
29280 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29281 this.proxy.unselectable();
29282 this.proxy.enableDisplayMode('block');
29284 Roo.apply(this, config);
29287 this.disableTrackOver = true;
29288 this.el.addClass("x-resizable-pinned");
29290 // if the element isn't positioned, make it relative
29291 var position = this.el.getStyle("position");
29292 if(position != "absolute" && position != "fixed"){
29293 this.el.setStyle("position", "relative");
29295 if(!this.handles){ // no handles passed, must be legacy style
29296 this.handles = 's,e,se';
29297 if(this.multiDirectional){
29298 this.handles += ',n,w';
29301 if(this.handles == "all"){
29302 this.handles = "n s e w ne nw se sw";
29304 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29305 var ps = Roo.Resizable.positions;
29306 for(var i = 0, len = hs.length; i < len; i++){
29307 if(hs[i] && ps[hs[i]]){
29308 var pos = ps[hs[i]];
29309 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29313 this.corner = this.southeast;
29315 // updateBox = the box can move..
29316 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29317 this.updateBox = true;
29320 this.activeHandle = null;
29322 if(this.resizeChild){
29323 if(typeof this.resizeChild == "boolean"){
29324 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29326 this.resizeChild = Roo.get(this.resizeChild, true);
29330 if(this.adjustments == "auto"){
29331 var rc = this.resizeChild;
29332 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29333 if(rc && (hw || hn)){
29334 rc.position("relative");
29335 rc.setLeft(hw ? hw.el.getWidth() : 0);
29336 rc.setTop(hn ? hn.el.getHeight() : 0);
29338 this.adjustments = [
29339 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29340 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29344 if(this.draggable){
29345 this.dd = this.dynamic ?
29346 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29347 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29353 * @event beforeresize
29354 * Fired before resize is allowed. Set enabled to false to cancel resize.
29355 * @param {Roo.Resizable} this
29356 * @param {Roo.EventObject} e The mousedown event
29358 "beforeresize" : true,
29361 * Fired a resizing.
29362 * @param {Roo.Resizable} this
29363 * @param {Number} x The new x position
29364 * @param {Number} y The new y position
29365 * @param {Number} w The new w width
29366 * @param {Number} h The new h hight
29367 * @param {Roo.EventObject} e The mouseup event
29372 * Fired after a resize.
29373 * @param {Roo.Resizable} this
29374 * @param {Number} width The new width
29375 * @param {Number} height The new height
29376 * @param {Roo.EventObject} e The mouseup event
29381 if(this.width !== null && this.height !== null){
29382 this.resizeTo(this.width, this.height);
29384 this.updateChildSize();
29387 this.el.dom.style.zoom = 1;
29389 Roo.Resizable.superclass.constructor.call(this);
29392 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29393 resizeChild : false,
29394 adjustments : [0, 0],
29404 multiDirectional : false,
29405 disableTrackOver : false,
29406 easing : 'easeOutStrong',
29407 widthIncrement : 0,
29408 heightIncrement : 0,
29412 preserveRatio : false,
29413 transparent: false,
29419 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29421 constrainTo: undefined,
29423 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29425 resizeRegion: undefined,
29429 * Perform a manual resize
29430 * @param {Number} width
29431 * @param {Number} height
29433 resizeTo : function(width, height){
29434 this.el.setSize(width, height);
29435 this.updateChildSize();
29436 this.fireEvent("resize", this, width, height, null);
29440 startSizing : function(e, handle){
29441 this.fireEvent("beforeresize", this, e);
29442 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29445 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29446 this.overlay.unselectable();
29447 this.overlay.enableDisplayMode("block");
29448 this.overlay.on("mousemove", this.onMouseMove, this);
29449 this.overlay.on("mouseup", this.onMouseUp, this);
29451 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29453 this.resizing = true;
29454 this.startBox = this.el.getBox();
29455 this.startPoint = e.getXY();
29456 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29457 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29459 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29460 this.overlay.show();
29462 if(this.constrainTo) {
29463 var ct = Roo.get(this.constrainTo);
29464 this.resizeRegion = ct.getRegion().adjust(
29465 ct.getFrameWidth('t'),
29466 ct.getFrameWidth('l'),
29467 -ct.getFrameWidth('b'),
29468 -ct.getFrameWidth('r')
29472 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29474 this.proxy.setBox(this.startBox);
29476 this.proxy.setStyle('visibility', 'visible');
29482 onMouseDown : function(handle, e){
29485 this.activeHandle = handle;
29486 this.startSizing(e, handle);
29491 onMouseUp : function(e){
29492 var size = this.resizeElement();
29493 this.resizing = false;
29495 this.overlay.hide();
29497 this.fireEvent("resize", this, size.width, size.height, e);
29501 updateChildSize : function(){
29503 if(this.resizeChild){
29505 var child = this.resizeChild;
29506 var adj = this.adjustments;
29507 if(el.dom.offsetWidth){
29508 var b = el.getSize(true);
29509 child.setSize(b.width+adj[0], b.height+adj[1]);
29511 // Second call here for IE
29512 // The first call enables instant resizing and
29513 // the second call corrects scroll bars if they
29516 setTimeout(function(){
29517 if(el.dom.offsetWidth){
29518 var b = el.getSize(true);
29519 child.setSize(b.width+adj[0], b.height+adj[1]);
29527 snap : function(value, inc, min){
29528 if(!inc || !value) {
29531 var newValue = value;
29532 var m = value % inc;
29535 newValue = value + (inc-m);
29537 newValue = value - m;
29540 return Math.max(min, newValue);
29544 resizeElement : function(){
29545 var box = this.proxy.getBox();
29546 if(this.updateBox){
29547 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29549 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29551 this.updateChildSize();
29559 constrain : function(v, diff, m, mx){
29562 }else if(v - diff > mx){
29569 onMouseMove : function(e){
29572 try{// try catch so if something goes wrong the user doesn't get hung
29574 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29578 //var curXY = this.startPoint;
29579 var curSize = this.curSize || this.startBox;
29580 var x = this.startBox.x, y = this.startBox.y;
29581 var ox = x, oy = y;
29582 var w = curSize.width, h = curSize.height;
29583 var ow = w, oh = h;
29584 var mw = this.minWidth, mh = this.minHeight;
29585 var mxw = this.maxWidth, mxh = this.maxHeight;
29586 var wi = this.widthIncrement;
29587 var hi = this.heightIncrement;
29589 var eventXY = e.getXY();
29590 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29591 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29593 var pos = this.activeHandle.position;
29598 w = Math.min(Math.max(mw, w), mxw);
29603 h = Math.min(Math.max(mh, h), mxh);
29608 w = Math.min(Math.max(mw, w), mxw);
29609 h = Math.min(Math.max(mh, h), mxh);
29612 diffY = this.constrain(h, diffY, mh, mxh);
29619 var adiffX = Math.abs(diffX);
29620 var sub = (adiffX % wi); // how much
29621 if (sub > (wi/2)) { // far enough to snap
29622 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29624 // remove difference..
29625 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29629 x = Math.max(this.minX, x);
29632 diffX = this.constrain(w, diffX, mw, mxw);
29638 w = Math.min(Math.max(mw, w), mxw);
29639 diffY = this.constrain(h, diffY, mh, mxh);
29644 diffX = this.constrain(w, diffX, mw, mxw);
29645 diffY = this.constrain(h, diffY, mh, mxh);
29652 diffX = this.constrain(w, diffX, mw, mxw);
29654 h = Math.min(Math.max(mh, h), mxh);
29660 var sw = this.snap(w, wi, mw);
29661 var sh = this.snap(h, hi, mh);
29662 if(sw != w || sh != h){
29685 if(this.preserveRatio){
29690 h = Math.min(Math.max(mh, h), mxh);
29695 w = Math.min(Math.max(mw, w), mxw);
29700 w = Math.min(Math.max(mw, w), mxw);
29706 w = Math.min(Math.max(mw, w), mxw);
29712 h = Math.min(Math.max(mh, h), mxh);
29720 h = Math.min(Math.max(mh, h), mxh);
29730 h = Math.min(Math.max(mh, h), mxh);
29738 if (pos == 'hdrag') {
29741 this.proxy.setBounds(x, y, w, h);
29743 this.resizeElement();
29747 this.fireEvent("resizing", this, x, y, w, h, e);
29751 handleOver : function(){
29753 this.el.addClass("x-resizable-over");
29758 handleOut : function(){
29759 if(!this.resizing){
29760 this.el.removeClass("x-resizable-over");
29765 * Returns the element this component is bound to.
29766 * @return {Roo.Element}
29768 getEl : function(){
29773 * Returns the resizeChild element (or null).
29774 * @return {Roo.Element}
29776 getResizeChild : function(){
29777 return this.resizeChild;
29779 groupHandler : function()
29784 * Destroys this resizable. If the element was wrapped and
29785 * removeEl is not true then the element remains.
29786 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29788 destroy : function(removeEl){
29789 this.proxy.remove();
29791 this.overlay.removeAllListeners();
29792 this.overlay.remove();
29794 var ps = Roo.Resizable.positions;
29796 if(typeof ps[k] != "function" && this[ps[k]]){
29797 var h = this[ps[k]];
29798 h.el.removeAllListeners();
29803 this.el.update("");
29810 // hash to map config positions to true positions
29811 Roo.Resizable.positions = {
29812 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29817 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29819 // only initialize the template if resizable is used
29820 var tpl = Roo.DomHelper.createTemplate(
29821 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29824 Roo.Resizable.Handle.prototype.tpl = tpl;
29826 this.position = pos;
29828 // show north drag fro topdra
29829 var handlepos = pos == 'hdrag' ? 'north' : pos;
29831 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29832 if (pos == 'hdrag') {
29833 this.el.setStyle('cursor', 'pointer');
29835 this.el.unselectable();
29837 this.el.setOpacity(0);
29839 this.el.on("mousedown", this.onMouseDown, this);
29840 if(!disableTrackOver){
29841 this.el.on("mouseover", this.onMouseOver, this);
29842 this.el.on("mouseout", this.onMouseOut, this);
29847 Roo.Resizable.Handle.prototype = {
29848 afterResize : function(rz){
29853 onMouseDown : function(e){
29854 this.rz.onMouseDown(this, e);
29857 onMouseOver : function(e){
29858 this.rz.handleOver(this, e);
29861 onMouseOut : function(e){
29862 this.rz.handleOut(this, e);
29866 * Ext JS Library 1.1.1
29867 * Copyright(c) 2006-2007, Ext JS, LLC.
29869 * Originally Released Under LGPL - original licence link has changed is not relivant.
29872 * <script type="text/javascript">
29876 * @class Roo.Editor
29877 * @extends Roo.Component
29878 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29880 * Create a new Editor
29881 * @param {Roo.form.Field} field The Field object (or descendant)
29882 * @param {Object} config The config object
29884 Roo.Editor = function(field, config){
29885 Roo.Editor.superclass.constructor.call(this, config);
29886 this.field = field;
29889 * @event beforestartedit
29890 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29891 * false from the handler of this event.
29892 * @param {Editor} this
29893 * @param {Roo.Element} boundEl The underlying element bound to this editor
29894 * @param {Mixed} value The field value being set
29896 "beforestartedit" : true,
29899 * Fires when this editor is displayed
29900 * @param {Roo.Element} boundEl The underlying element bound to this editor
29901 * @param {Mixed} value The starting field value
29903 "startedit" : true,
29905 * @event beforecomplete
29906 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29907 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29908 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29909 * event will not fire since no edit actually occurred.
29910 * @param {Editor} this
29911 * @param {Mixed} value The current field value
29912 * @param {Mixed} startValue The original field value
29914 "beforecomplete" : true,
29917 * Fires after editing is complete and any changed value has been written to the underlying field.
29918 * @param {Editor} this
29919 * @param {Mixed} value The current field value
29920 * @param {Mixed} startValue The original field value
29924 * @event specialkey
29925 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29926 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29927 * @param {Roo.form.Field} this
29928 * @param {Roo.EventObject} e The event object
29930 "specialkey" : true
29934 Roo.extend(Roo.Editor, Roo.Component, {
29936 * @cfg {Boolean/String} autosize
29937 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29938 * or "height" to adopt the height only (defaults to false)
29941 * @cfg {Boolean} revertInvalid
29942 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29943 * validation fails (defaults to true)
29946 * @cfg {Boolean} ignoreNoChange
29947 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29948 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29949 * will never be ignored.
29952 * @cfg {Boolean} hideEl
29953 * False to keep the bound element visible while the editor is displayed (defaults to true)
29956 * @cfg {Mixed} value
29957 * The data value of the underlying field (defaults to "")
29961 * @cfg {String} alignment
29962 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29966 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29967 * for bottom-right shadow (defaults to "frame")
29971 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29975 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29977 completeOnEnter : false,
29979 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29981 cancelOnEsc : false,
29983 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29988 onRender : function(ct, position){
29989 this.el = new Roo.Layer({
29990 shadow: this.shadow,
29996 constrain: this.constrain
29998 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29999 if(this.field.msgTarget != 'title'){
30000 this.field.msgTarget = 'qtip';
30002 this.field.render(this.el);
30004 this.field.el.dom.setAttribute('autocomplete', 'off');
30006 this.field.on("specialkey", this.onSpecialKey, this);
30007 if(this.swallowKeys){
30008 this.field.el.swallowEvent(['keydown','keypress']);
30011 this.field.on("blur", this.onBlur, this);
30012 if(this.field.grow){
30013 this.field.on("autosize", this.el.sync, this.el, {delay:1});
30017 onSpecialKey : function(field, e)
30019 //Roo.log('editor onSpecialKey');
30020 if(this.completeOnEnter && e.getKey() == e.ENTER){
30022 this.completeEdit();
30025 // do not fire special key otherwise it might hide close the editor...
30026 if(e.getKey() == e.ENTER){
30029 if(this.cancelOnEsc && e.getKey() == e.ESC){
30033 this.fireEvent('specialkey', field, e);
30038 * Starts the editing process and shows the editor.
30039 * @param {String/HTMLElement/Element} el The element to edit
30040 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
30041 * to the innerHTML of el.
30043 startEdit : function(el, value){
30045 this.completeEdit();
30047 this.boundEl = Roo.get(el);
30048 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
30049 if(!this.rendered){
30050 this.render(this.parentEl || document.body);
30052 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
30055 this.startValue = v;
30056 this.field.setValue(v);
30058 var sz = this.boundEl.getSize();
30059 switch(this.autoSize){
30061 this.setSize(sz.width, "");
30064 this.setSize("", sz.height);
30067 this.setSize(sz.width, sz.height);
30070 this.el.alignTo(this.boundEl, this.alignment);
30071 this.editing = true;
30073 Roo.QuickTips.disable();
30079 * Sets the height and width of this editor.
30080 * @param {Number} width The new width
30081 * @param {Number} height The new height
30083 setSize : function(w, h){
30084 this.field.setSize(w, h);
30091 * Realigns the editor to the bound field based on the current alignment config value.
30093 realign : function(){
30094 this.el.alignTo(this.boundEl, this.alignment);
30098 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
30099 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
30101 completeEdit : function(remainVisible){
30105 var v = this.getValue();
30106 if(this.revertInvalid !== false && !this.field.isValid()){
30107 v = this.startValue;
30108 this.cancelEdit(true);
30110 if(String(v) === String(this.startValue) && this.ignoreNoChange){
30111 this.editing = false;
30115 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
30116 this.editing = false;
30117 if(this.updateEl && this.boundEl){
30118 this.boundEl.update(v);
30120 if(remainVisible !== true){
30123 this.fireEvent("complete", this, v, this.startValue);
30128 onShow : function(){
30130 if(this.hideEl !== false){
30131 this.boundEl.hide();
30134 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
30135 this.fixIEFocus = true;
30136 this.deferredFocus.defer(50, this);
30138 this.field.focus();
30140 this.fireEvent("startedit", this.boundEl, this.startValue);
30143 deferredFocus : function(){
30145 this.field.focus();
30150 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
30151 * reverted to the original starting value.
30152 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
30153 * cancel (defaults to false)
30155 cancelEdit : function(remainVisible){
30157 this.setValue(this.startValue);
30158 if(remainVisible !== true){
30165 onBlur : function(){
30166 if(this.allowBlur !== true && this.editing){
30167 this.completeEdit();
30172 onHide : function(){
30174 this.completeEdit();
30178 if(this.field.collapse){
30179 this.field.collapse();
30182 if(this.hideEl !== false){
30183 this.boundEl.show();
30186 Roo.QuickTips.enable();
30191 * Sets the data value of the editor
30192 * @param {Mixed} value Any valid value supported by the underlying field
30194 setValue : function(v){
30195 this.field.setValue(v);
30199 * Gets the data value of the editor
30200 * @return {Mixed} The data value
30202 getValue : function(){
30203 return this.field.getValue();
30207 * Ext JS Library 1.1.1
30208 * Copyright(c) 2006-2007, Ext JS, LLC.
30210 * Originally Released Under LGPL - original licence link has changed is not relivant.
30213 * <script type="text/javascript">
30217 * @class Roo.BasicDialog
30218 * @extends Roo.util.Observable
30219 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
30221 var dlg = new Roo.BasicDialog("my-dlg", {
30230 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30231 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30232 dlg.addButton('Cancel', dlg.hide, dlg);
30235 <b>A Dialog should always be a direct child of the body element.</b>
30236 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30237 * @cfg {String} title Default text to display in the title bar (defaults to null)
30238 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30239 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30240 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30241 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30242 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30243 * (defaults to null with no animation)
30244 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30245 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30246 * property for valid values (defaults to 'all')
30247 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30248 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30249 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30250 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30251 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30252 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30253 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30254 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30255 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30256 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30257 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30258 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30259 * draggable = true (defaults to false)
30260 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30261 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30262 * shadow (defaults to false)
30263 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30264 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30265 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30266 * @cfg {Array} buttons Array of buttons
30267 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30269 * Create a new BasicDialog.
30270 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30271 * @param {Object} config Configuration options
30273 Roo.BasicDialog = function(el, config){
30274 this.el = Roo.get(el);
30275 var dh = Roo.DomHelper;
30276 if(!this.el && config && config.autoCreate){
30277 if(typeof config.autoCreate == "object"){
30278 if(!config.autoCreate.id){
30279 config.autoCreate.id = el;
30281 this.el = dh.append(document.body,
30282 config.autoCreate, true);
30284 this.el = dh.append(document.body,
30285 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30289 el.setDisplayed(true);
30290 el.hide = this.hideAction;
30292 el.addClass("x-dlg");
30294 Roo.apply(this, config);
30296 this.proxy = el.createProxy("x-dlg-proxy");
30297 this.proxy.hide = this.hideAction;
30298 this.proxy.setOpacity(.5);
30302 el.setWidth(config.width);
30305 el.setHeight(config.height);
30307 this.size = el.getSize();
30308 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30309 this.xy = [config.x,config.y];
30311 this.xy = el.getCenterXY(true);
30313 /** The header element @type Roo.Element */
30314 this.header = el.child("> .x-dlg-hd");
30315 /** The body element @type Roo.Element */
30316 this.body = el.child("> .x-dlg-bd");
30317 /** The footer element @type Roo.Element */
30318 this.footer = el.child("> .x-dlg-ft");
30321 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30324 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30327 this.header.unselectable();
30329 this.header.update(this.title);
30331 // this element allows the dialog to be focused for keyboard event
30332 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30333 this.focusEl.swallowEvent("click", true);
30335 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30337 // wrap the body and footer for special rendering
30338 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30340 this.bwrap.dom.appendChild(this.footer.dom);
30343 this.bg = this.el.createChild({
30344 tag: "div", cls:"x-dlg-bg",
30345 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30347 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30350 if(this.autoScroll !== false && !this.autoTabs){
30351 this.body.setStyle("overflow", "auto");
30354 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30356 if(this.closable !== false){
30357 this.el.addClass("x-dlg-closable");
30358 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30359 this.close.on("click", this.closeClick, this);
30360 this.close.addClassOnOver("x-dlg-close-over");
30362 if(this.collapsible !== false){
30363 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30364 this.collapseBtn.on("click", this.collapseClick, this);
30365 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30366 this.header.on("dblclick", this.collapseClick, this);
30368 if(this.resizable !== false){
30369 this.el.addClass("x-dlg-resizable");
30370 this.resizer = new Roo.Resizable(el, {
30371 minWidth: this.minWidth || 80,
30372 minHeight:this.minHeight || 80,
30373 handles: this.resizeHandles || "all",
30376 this.resizer.on("beforeresize", this.beforeResize, this);
30377 this.resizer.on("resize", this.onResize, this);
30379 if(this.draggable !== false){
30380 el.addClass("x-dlg-draggable");
30381 if (!this.proxyDrag) {
30382 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30385 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30387 dd.setHandleElId(this.header.id);
30388 dd.endDrag = this.endMove.createDelegate(this);
30389 dd.startDrag = this.startMove.createDelegate(this);
30390 dd.onDrag = this.onDrag.createDelegate(this);
30395 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30396 this.mask.enableDisplayMode("block");
30398 this.el.addClass("x-dlg-modal");
30401 this.shadow = new Roo.Shadow({
30402 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30403 offset : this.shadowOffset
30406 this.shadowOffset = 0;
30408 if(Roo.useShims && this.shim !== false){
30409 this.shim = this.el.createShim();
30410 this.shim.hide = this.hideAction;
30418 if (this.buttons) {
30419 var bts= this.buttons;
30421 Roo.each(bts, function(b) {
30430 * Fires when a key is pressed
30431 * @param {Roo.BasicDialog} this
30432 * @param {Roo.EventObject} e
30437 * Fires when this dialog is moved by the user.
30438 * @param {Roo.BasicDialog} this
30439 * @param {Number} x The new page X
30440 * @param {Number} y The new page Y
30445 * Fires when this dialog is resized by the user.
30446 * @param {Roo.BasicDialog} this
30447 * @param {Number} width The new width
30448 * @param {Number} height The new height
30452 * @event beforehide
30453 * Fires before this dialog is hidden.
30454 * @param {Roo.BasicDialog} this
30456 "beforehide" : true,
30459 * Fires when this dialog is hidden.
30460 * @param {Roo.BasicDialog} this
30464 * @event beforeshow
30465 * Fires before this dialog is shown.
30466 * @param {Roo.BasicDialog} this
30468 "beforeshow" : true,
30471 * Fires when this dialog is shown.
30472 * @param {Roo.BasicDialog} this
30476 el.on("keydown", this.onKeyDown, this);
30477 el.on("mousedown", this.toFront, this);
30478 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30480 Roo.DialogManager.register(this);
30481 Roo.BasicDialog.superclass.constructor.call(this);
30484 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30485 shadowOffset: Roo.isIE ? 6 : 5,
30488 minButtonWidth: 75,
30489 defaultButton: null,
30490 buttonAlign: "right",
30495 * Sets the dialog title text
30496 * @param {String} text The title text to display
30497 * @return {Roo.BasicDialog} this
30499 setTitle : function(text){
30500 this.header.update(text);
30505 closeClick : function(){
30510 collapseClick : function(){
30511 this[this.collapsed ? "expand" : "collapse"]();
30515 * Collapses the dialog to its minimized state (only the title bar is visible).
30516 * Equivalent to the user clicking the collapse dialog button.
30518 collapse : function(){
30519 if(!this.collapsed){
30520 this.collapsed = true;
30521 this.el.addClass("x-dlg-collapsed");
30522 this.restoreHeight = this.el.getHeight();
30523 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30528 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30529 * clicking the expand dialog button.
30531 expand : function(){
30532 if(this.collapsed){
30533 this.collapsed = false;
30534 this.el.removeClass("x-dlg-collapsed");
30535 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30540 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30541 * @return {Roo.TabPanel} The tabs component
30543 initTabs : function(){
30544 var tabs = this.getTabs();
30545 while(tabs.getTab(0)){
30548 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30550 tabs.addTab(Roo.id(dom), dom.title);
30558 beforeResize : function(){
30559 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30563 onResize : function(){
30564 this.refreshSize();
30565 this.syncBodyHeight();
30566 this.adjustAssets();
30568 this.fireEvent("resize", this, this.size.width, this.size.height);
30572 onKeyDown : function(e){
30573 if(this.isVisible()){
30574 this.fireEvent("keydown", this, e);
30579 * Resizes the dialog.
30580 * @param {Number} width
30581 * @param {Number} height
30582 * @return {Roo.BasicDialog} this
30584 resizeTo : function(width, height){
30585 this.el.setSize(width, height);
30586 this.size = {width: width, height: height};
30587 this.syncBodyHeight();
30588 if(this.fixedcenter){
30591 if(this.isVisible()){
30592 this.constrainXY();
30593 this.adjustAssets();
30595 this.fireEvent("resize", this, width, height);
30601 * Resizes the dialog to fit the specified content size.
30602 * @param {Number} width
30603 * @param {Number} height
30604 * @return {Roo.BasicDialog} this
30606 setContentSize : function(w, h){
30607 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30608 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30609 //if(!this.el.isBorderBox()){
30610 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30611 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30614 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30615 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30617 this.resizeTo(w, h);
30622 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30623 * executed in response to a particular key being pressed while the dialog is active.
30624 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30625 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30626 * @param {Function} fn The function to call
30627 * @param {Object} scope (optional) The scope of the function
30628 * @return {Roo.BasicDialog} this
30630 addKeyListener : function(key, fn, scope){
30631 var keyCode, shift, ctrl, alt;
30632 if(typeof key == "object" && !(key instanceof Array)){
30633 keyCode = key["key"];
30634 shift = key["shift"];
30635 ctrl = key["ctrl"];
30640 var handler = function(dlg, e){
30641 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30642 var k = e.getKey();
30643 if(keyCode instanceof Array){
30644 for(var i = 0, len = keyCode.length; i < len; i++){
30645 if(keyCode[i] == k){
30646 fn.call(scope || window, dlg, k, e);
30652 fn.call(scope || window, dlg, k, e);
30657 this.on("keydown", handler);
30662 * Returns the TabPanel component (creates it if it doesn't exist).
30663 * Note: If you wish to simply check for the existence of tabs without creating them,
30664 * check for a null 'tabs' property.
30665 * @return {Roo.TabPanel} The tabs component
30667 getTabs : function(){
30669 this.el.addClass("x-dlg-auto-tabs");
30670 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30671 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30677 * Adds a button to the footer section of the dialog.
30678 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30679 * object or a valid Roo.DomHelper element config
30680 * @param {Function} handler The function called when the button is clicked
30681 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30682 * @return {Roo.Button} The new button
30684 addButton : function(config, handler, scope){
30685 var dh = Roo.DomHelper;
30687 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30689 if(!this.btnContainer){
30690 var tb = this.footer.createChild({
30692 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30693 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30695 this.btnContainer = tb.firstChild.firstChild.firstChild;
30700 minWidth: this.minButtonWidth,
30703 if(typeof config == "string"){
30704 bconfig.text = config;
30707 bconfig.dhconfig = config;
30709 Roo.apply(bconfig, config);
30713 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30714 bconfig.position = Math.max(0, bconfig.position);
30715 fc = this.btnContainer.childNodes[bconfig.position];
30718 var btn = new Roo.Button(
30720 this.btnContainer.insertBefore(document.createElement("td"),fc)
30721 : this.btnContainer.appendChild(document.createElement("td")),
30722 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30725 this.syncBodyHeight();
30728 * Array of all the buttons that have been added to this dialog via addButton
30733 this.buttons.push(btn);
30738 * Sets the default button to be focused when the dialog is displayed.
30739 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30740 * @return {Roo.BasicDialog} this
30742 setDefaultButton : function(btn){
30743 this.defaultButton = btn;
30748 getHeaderFooterHeight : function(safe){
30751 height += this.header.getHeight();
30754 var fm = this.footer.getMargins();
30755 height += (this.footer.getHeight()+fm.top+fm.bottom);
30757 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30758 height += this.centerBg.getPadding("tb");
30763 syncBodyHeight : function()
30765 var bd = this.body, // the text
30766 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30768 var height = this.size.height - this.getHeaderFooterHeight(false);
30769 bd.setHeight(height-bd.getMargins("tb"));
30770 var hh = this.header.getHeight();
30771 var h = this.size.height-hh;
30774 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30775 bw.setHeight(h-cb.getPadding("tb"));
30777 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30778 bd.setWidth(bw.getWidth(true));
30780 this.tabs.syncHeight();
30782 this.tabs.el.repaint();
30788 * Restores the previous state of the dialog if Roo.state is configured.
30789 * @return {Roo.BasicDialog} this
30791 restoreState : function(){
30792 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30793 if(box && box.width){
30794 this.xy = [box.x, box.y];
30795 this.resizeTo(box.width, box.height);
30801 beforeShow : function(){
30803 if(this.fixedcenter){
30804 this.xy = this.el.getCenterXY(true);
30807 Roo.get(document.body).addClass("x-body-masked");
30808 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30811 this.constrainXY();
30815 animShow : function(){
30816 var b = Roo.get(this.animateTarget).getBox();
30817 this.proxy.setSize(b.width, b.height);
30818 this.proxy.setLocation(b.x, b.y);
30820 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30821 true, .35, this.showEl.createDelegate(this));
30825 * Shows the dialog.
30826 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30827 * @return {Roo.BasicDialog} this
30829 show : function(animateTarget){
30830 if (this.fireEvent("beforeshow", this) === false){
30833 if(this.syncHeightBeforeShow){
30834 this.syncBodyHeight();
30835 }else if(this.firstShow){
30836 this.firstShow = false;
30837 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30839 this.animateTarget = animateTarget || this.animateTarget;
30840 if(!this.el.isVisible()){
30842 if(this.animateTarget && Roo.get(this.animateTarget)){
30852 showEl : function(){
30854 this.el.setXY(this.xy);
30856 this.adjustAssets(true);
30859 // IE peekaboo bug - fix found by Dave Fenwick
30863 this.fireEvent("show", this);
30867 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30868 * dialog itself will receive focus.
30870 focus : function(){
30871 if(this.defaultButton){
30872 this.defaultButton.focus();
30874 this.focusEl.focus();
30879 constrainXY : function(){
30880 if(this.constraintoviewport !== false){
30881 if(!this.viewSize){
30882 if(this.container){
30883 var s = this.container.getSize();
30884 this.viewSize = [s.width, s.height];
30886 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30889 var s = Roo.get(this.container||document).getScroll();
30891 var x = this.xy[0], y = this.xy[1];
30892 var w = this.size.width, h = this.size.height;
30893 var vw = this.viewSize[0], vh = this.viewSize[1];
30894 // only move it if it needs it
30896 // first validate right/bottom
30897 if(x + w > vw+s.left){
30901 if(y + h > vh+s.top){
30905 // then make sure top/left isn't negative
30917 if(this.isVisible()){
30918 this.el.setLocation(x, y);
30919 this.adjustAssets();
30926 onDrag : function(){
30927 if(!this.proxyDrag){
30928 this.xy = this.el.getXY();
30929 this.adjustAssets();
30934 adjustAssets : function(doShow){
30935 var x = this.xy[0], y = this.xy[1];
30936 var w = this.size.width, h = this.size.height;
30937 if(doShow === true){
30939 this.shadow.show(this.el);
30945 if(this.shadow && this.shadow.isVisible()){
30946 this.shadow.show(this.el);
30948 if(this.shim && this.shim.isVisible()){
30949 this.shim.setBounds(x, y, w, h);
30954 adjustViewport : function(w, h){
30956 w = Roo.lib.Dom.getViewWidth();
30957 h = Roo.lib.Dom.getViewHeight();
30960 this.viewSize = [w, h];
30961 if(this.modal && this.mask.isVisible()){
30962 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30963 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30965 if(this.isVisible()){
30966 this.constrainXY();
30971 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30972 * shadow, proxy, mask, etc.) Also removes all event listeners.
30973 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30975 destroy : function(removeEl){
30976 if(this.isVisible()){
30977 this.animateTarget = null;
30980 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30982 this.tabs.destroy(removeEl);
30995 for(var i = 0, len = this.buttons.length; i < len; i++){
30996 this.buttons[i].destroy();
30999 this.el.removeAllListeners();
31000 if(removeEl === true){
31001 this.el.update("");
31004 Roo.DialogManager.unregister(this);
31008 startMove : function(){
31009 if(this.proxyDrag){
31012 if(this.constraintoviewport !== false){
31013 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
31018 endMove : function(){
31019 if(!this.proxyDrag){
31020 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
31022 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
31025 this.refreshSize();
31026 this.adjustAssets();
31028 this.fireEvent("move", this, this.xy[0], this.xy[1]);
31032 * Brings this dialog to the front of any other visible dialogs
31033 * @return {Roo.BasicDialog} this
31035 toFront : function(){
31036 Roo.DialogManager.bringToFront(this);
31041 * Sends this dialog to the back (under) of any other visible dialogs
31042 * @return {Roo.BasicDialog} this
31044 toBack : function(){
31045 Roo.DialogManager.sendToBack(this);
31050 * Centers this dialog in the viewport
31051 * @return {Roo.BasicDialog} this
31053 center : function(){
31054 var xy = this.el.getCenterXY(true);
31055 this.moveTo(xy[0], xy[1]);
31060 * Moves the dialog's top-left corner to the specified point
31061 * @param {Number} x
31062 * @param {Number} y
31063 * @return {Roo.BasicDialog} this
31065 moveTo : function(x, y){
31067 if(this.isVisible()){
31068 this.el.setXY(this.xy);
31069 this.adjustAssets();
31075 * Aligns the dialog to the specified element
31076 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31077 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
31078 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31079 * @return {Roo.BasicDialog} this
31081 alignTo : function(element, position, offsets){
31082 this.xy = this.el.getAlignToXY(element, position, offsets);
31083 if(this.isVisible()){
31084 this.el.setXY(this.xy);
31085 this.adjustAssets();
31091 * Anchors an element to another element and realigns it when the window is resized.
31092 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31093 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
31094 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31095 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
31096 * is a number, it is used as the buffer delay (defaults to 50ms).
31097 * @return {Roo.BasicDialog} this
31099 anchorTo : function(el, alignment, offsets, monitorScroll){
31100 var action = function(){
31101 this.alignTo(el, alignment, offsets);
31103 Roo.EventManager.onWindowResize(action, this);
31104 var tm = typeof monitorScroll;
31105 if(tm != 'undefined'){
31106 Roo.EventManager.on(window, 'scroll', action, this,
31107 {buffer: tm == 'number' ? monitorScroll : 50});
31114 * Returns true if the dialog is visible
31115 * @return {Boolean}
31117 isVisible : function(){
31118 return this.el.isVisible();
31122 animHide : function(callback){
31123 var b = Roo.get(this.animateTarget).getBox();
31125 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
31127 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
31128 this.hideEl.createDelegate(this, [callback]));
31132 * Hides the dialog.
31133 * @param {Function} callback (optional) Function to call when the dialog is hidden
31134 * @return {Roo.BasicDialog} this
31136 hide : function(callback){
31137 if (this.fireEvent("beforehide", this) === false){
31141 this.shadow.hide();
31146 // sometimes animateTarget seems to get set.. causing problems...
31147 // this just double checks..
31148 if(this.animateTarget && Roo.get(this.animateTarget)) {
31149 this.animHide(callback);
31152 this.hideEl(callback);
31158 hideEl : function(callback){
31162 Roo.get(document.body).removeClass("x-body-masked");
31164 this.fireEvent("hide", this);
31165 if(typeof callback == "function"){
31171 hideAction : function(){
31172 this.setLeft("-10000px");
31173 this.setTop("-10000px");
31174 this.setStyle("visibility", "hidden");
31178 refreshSize : function(){
31179 this.size = this.el.getSize();
31180 this.xy = this.el.getXY();
31181 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
31185 // z-index is managed by the DialogManager and may be overwritten at any time
31186 setZIndex : function(index){
31188 this.mask.setStyle("z-index", index);
31191 this.shim.setStyle("z-index", ++index);
31194 this.shadow.setZIndex(++index);
31196 this.el.setStyle("z-index", ++index);
31198 this.proxy.setStyle("z-index", ++index);
31201 this.resizer.proxy.setStyle("z-index", ++index);
31204 this.lastZIndex = index;
31208 * Returns the element for this dialog
31209 * @return {Roo.Element} The underlying dialog Element
31211 getEl : function(){
31217 * @class Roo.DialogManager
31218 * Provides global access to BasicDialogs that have been created and
31219 * support for z-indexing (layering) multiple open dialogs.
31221 Roo.DialogManager = function(){
31223 var accessList = [];
31227 var sortDialogs = function(d1, d2){
31228 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31232 var orderDialogs = function(){
31233 accessList.sort(sortDialogs);
31234 var seed = Roo.DialogManager.zseed;
31235 for(var i = 0, len = accessList.length; i < len; i++){
31236 var dlg = accessList[i];
31238 dlg.setZIndex(seed + (i*10));
31245 * The starting z-index for BasicDialogs (defaults to 9000)
31246 * @type Number The z-index value
31251 register : function(dlg){
31252 list[dlg.id] = dlg;
31253 accessList.push(dlg);
31257 unregister : function(dlg){
31258 delete list[dlg.id];
31261 if(!accessList.indexOf){
31262 for( i = 0, len = accessList.length; i < len; i++){
31263 if(accessList[i] == dlg){
31264 accessList.splice(i, 1);
31269 i = accessList.indexOf(dlg);
31271 accessList.splice(i, 1);
31277 * Gets a registered dialog by id
31278 * @param {String/Object} id The id of the dialog or a dialog
31279 * @return {Roo.BasicDialog} this
31281 get : function(id){
31282 return typeof id == "object" ? id : list[id];
31286 * Brings the specified dialog to the front
31287 * @param {String/Object} dlg The id of the dialog or a dialog
31288 * @return {Roo.BasicDialog} this
31290 bringToFront : function(dlg){
31291 dlg = this.get(dlg);
31294 dlg._lastAccess = new Date().getTime();
31301 * Sends the specified dialog to the back
31302 * @param {String/Object} dlg The id of the dialog or a dialog
31303 * @return {Roo.BasicDialog} this
31305 sendToBack : function(dlg){
31306 dlg = this.get(dlg);
31307 dlg._lastAccess = -(new Date().getTime());
31313 * Hides all dialogs
31315 hideAll : function(){
31316 for(var id in list){
31317 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31326 * @class Roo.LayoutDialog
31327 * @extends Roo.BasicDialog
31328 * Dialog which provides adjustments for working with a layout in a Dialog.
31329 * Add your necessary layout config options to the dialog's config.<br>
31330 * Example usage (including a nested layout):
31333 dialog = new Roo.LayoutDialog("download-dlg", {
31342 // layout config merges with the dialog config
31344 tabPosition: "top",
31345 alwaysShowTabs: true
31348 dialog.addKeyListener(27, dialog.hide, dialog);
31349 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31350 dialog.addButton("Build It!", this.getDownload, this);
31352 // we can even add nested layouts
31353 var innerLayout = new Roo.BorderLayout("dl-inner", {
31363 innerLayout.beginUpdate();
31364 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31365 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31366 innerLayout.endUpdate(true);
31368 var layout = dialog.getLayout();
31369 layout.beginUpdate();
31370 layout.add("center", new Roo.ContentPanel("standard-panel",
31371 {title: "Download the Source", fitToFrame:true}));
31372 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31373 {title: "Build your own roo.js"}));
31374 layout.getRegion("center").showPanel(sp);
31375 layout.endUpdate();
31379 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31380 * @param {Object} config configuration options
31382 Roo.LayoutDialog = function(el, cfg){
31385 if (typeof(cfg) == 'undefined') {
31386 config = Roo.apply({}, el);
31387 // not sure why we use documentElement here.. - it should always be body.
31388 // IE7 borks horribly if we use documentElement.
31389 // webkit also does not like documentElement - it creates a body element...
31390 el = Roo.get( document.body || document.documentElement ).createChild();
31391 //config.autoCreate = true;
31395 config.autoTabs = false;
31396 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31397 this.body.setStyle({overflow:"hidden", position:"relative"});
31398 this.layout = new Roo.BorderLayout(this.body.dom, config);
31399 this.layout.monitorWindowResize = false;
31400 this.el.addClass("x-dlg-auto-layout");
31401 // fix case when center region overwrites center function
31402 this.center = Roo.BasicDialog.prototype.center;
31403 this.on("show", this.layout.layout, this.layout, true);
31404 if (config.items) {
31405 var xitems = config.items;
31406 delete config.items;
31407 Roo.each(xitems, this.addxtype, this);
31412 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31414 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31417 endUpdate : function(){
31418 this.layout.endUpdate();
31422 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31425 beginUpdate : function(){
31426 this.layout.beginUpdate();
31430 * Get the BorderLayout for this dialog
31431 * @return {Roo.BorderLayout}
31433 getLayout : function(){
31434 return this.layout;
31437 showEl : function(){
31438 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31440 this.layout.layout();
31445 // Use the syncHeightBeforeShow config option to control this automatically
31446 syncBodyHeight : function(){
31447 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31448 if(this.layout){this.layout.layout();}
31452 * Add an xtype element (actually adds to the layout.)
31453 * @return {Object} xdata xtype object data.
31456 addxtype : function(c) {
31457 return this.layout.addxtype(c);
31461 * Ext JS Library 1.1.1
31462 * Copyright(c) 2006-2007, Ext JS, LLC.
31464 * Originally Released Under LGPL - original licence link has changed is not relivant.
31467 * <script type="text/javascript">
31471 * @class Roo.MessageBox
31472 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31476 Roo.Msg.alert('Status', 'Changes saved successfully.');
31478 // Prompt for user data:
31479 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31481 // process text value...
31485 // Show a dialog using config options:
31487 title:'Save Changes?',
31488 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31489 buttons: Roo.Msg.YESNOCANCEL,
31496 Roo.MessageBox = function(){
31497 var dlg, opt, mask, waitTimer;
31498 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31499 var buttons, activeTextEl, bwidth;
31502 var handleButton = function(button){
31504 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31508 var handleHide = function(){
31509 if(opt && opt.cls){
31510 dlg.el.removeClass(opt.cls);
31513 Roo.TaskMgr.stop(waitTimer);
31519 var updateButtons = function(b){
31522 buttons["ok"].hide();
31523 buttons["cancel"].hide();
31524 buttons["yes"].hide();
31525 buttons["no"].hide();
31526 dlg.footer.dom.style.display = 'none';
31529 dlg.footer.dom.style.display = '';
31530 for(var k in buttons){
31531 if(typeof buttons[k] != "function"){
31534 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31535 width += buttons[k].el.getWidth()+15;
31545 var handleEsc = function(d, k, e){
31546 if(opt && opt.closable !== false){
31556 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31557 * @return {Roo.BasicDialog} The BasicDialog element
31559 getDialog : function(){
31561 dlg = new Roo.BasicDialog("x-msg-box", {
31566 constraintoviewport:false,
31568 collapsible : false,
31571 width:400, height:100,
31572 buttonAlign:"center",
31573 closeClick : function(){
31574 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31575 handleButton("no");
31577 handleButton("cancel");
31581 dlg.on("hide", handleHide);
31583 dlg.addKeyListener(27, handleEsc);
31585 var bt = this.buttonText;
31586 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31587 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31588 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31589 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31590 bodyEl = dlg.body.createChild({
31592 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>'
31594 msgEl = bodyEl.dom.firstChild;
31595 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31596 textboxEl.enableDisplayMode();
31597 textboxEl.addKeyListener([10,13], function(){
31598 if(dlg.isVisible() && opt && opt.buttons){
31599 if(opt.buttons.ok){
31600 handleButton("ok");
31601 }else if(opt.buttons.yes){
31602 handleButton("yes");
31606 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31607 textareaEl.enableDisplayMode();
31608 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31609 progressEl.enableDisplayMode();
31610 var pf = progressEl.dom.firstChild;
31612 pp = Roo.get(pf.firstChild);
31613 pp.setHeight(pf.offsetHeight);
31621 * Updates the message box body text
31622 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31623 * the XHTML-compliant non-breaking space character '&#160;')
31624 * @return {Roo.MessageBox} This message box
31626 updateText : function(text){
31627 if(!dlg.isVisible() && !opt.width){
31628 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31630 msgEl.innerHTML = text || ' ';
31632 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31633 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31635 Math.min(opt.width || cw , this.maxWidth),
31636 Math.max(opt.minWidth || this.minWidth, bwidth)
31639 activeTextEl.setWidth(w);
31641 if(dlg.isVisible()){
31642 dlg.fixedcenter = false;
31644 // to big, make it scroll. = But as usual stupid IE does not support
31647 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31648 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31649 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31651 bodyEl.dom.style.height = '';
31652 bodyEl.dom.style.overflowY = '';
31655 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31657 bodyEl.dom.style.overflowX = '';
31660 dlg.setContentSize(w, bodyEl.getHeight());
31661 if(dlg.isVisible()){
31662 dlg.fixedcenter = true;
31668 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31669 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31670 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31671 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31672 * @return {Roo.MessageBox} This message box
31674 updateProgress : function(value, text){
31676 this.updateText(text);
31678 if (pp) { // weird bug on my firefox - for some reason this is not defined
31679 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31685 * Returns true if the message box is currently displayed
31686 * @return {Boolean} True if the message box is visible, else false
31688 isVisible : function(){
31689 return dlg && dlg.isVisible();
31693 * Hides the message box if it is displayed
31696 if(this.isVisible()){
31702 * Displays a new message box, or reinitializes an existing message box, based on the config options
31703 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31704 * The following config object properties are supported:
31706 Property Type Description
31707 ---------- --------------- ------------------------------------------------------------------------------------
31708 animEl String/Element An id or Element from which the message box should animate as it opens and
31709 closes (defaults to undefined)
31710 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31711 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31712 closable Boolean False to hide the top-right close button (defaults to true). Note that
31713 progress and wait dialogs will ignore this property and always hide the
31714 close button as they can only be closed programmatically.
31715 cls String A custom CSS class to apply to the message box element
31716 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31717 displayed (defaults to 75)
31718 fn Function A callback function to execute after closing the dialog. The arguments to the
31719 function will be btn (the name of the button that was clicked, if applicable,
31720 e.g. "ok"), and text (the value of the active text field, if applicable).
31721 Progress and wait dialogs will ignore this option since they do not respond to
31722 user actions and can only be closed programmatically, so any required function
31723 should be called by the same code after it closes the dialog.
31724 icon String A CSS class that provides a background image to be used as an icon for
31725 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31726 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31727 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31728 modal Boolean False to allow user interaction with the page while the message box is
31729 displayed (defaults to true)
31730 msg String A string that will replace the existing message box body text (defaults
31731 to the XHTML-compliant non-breaking space character ' ')
31732 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31733 progress Boolean True to display a progress bar (defaults to false)
31734 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31735 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31736 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31737 title String The title text
31738 value String The string value to set into the active textbox element if displayed
31739 wait Boolean True to display a progress bar (defaults to false)
31740 width Number The width of the dialog in pixels
31747 msg: 'Please enter your address:',
31749 buttons: Roo.MessageBox.OKCANCEL,
31752 animEl: 'addAddressBtn'
31755 * @param {Object} config Configuration options
31756 * @return {Roo.MessageBox} This message box
31758 show : function(options)
31761 // this causes nightmares if you show one dialog after another
31762 // especially on callbacks..
31764 if(this.isVisible()){
31767 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31768 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31769 Roo.log("New Dialog Message:" + options.msg )
31770 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31771 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31774 var d = this.getDialog();
31776 d.setTitle(opt.title || " ");
31777 d.close.setDisplayed(opt.closable !== false);
31778 activeTextEl = textboxEl;
31779 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31784 textareaEl.setHeight(typeof opt.multiline == "number" ?
31785 opt.multiline : this.defaultTextHeight);
31786 activeTextEl = textareaEl;
31795 progressEl.setDisplayed(opt.progress === true);
31796 this.updateProgress(0);
31797 activeTextEl.dom.value = opt.value || "";
31799 dlg.setDefaultButton(activeTextEl);
31801 var bs = opt.buttons;
31804 db = buttons["ok"];
31805 }else if(bs && bs.yes){
31806 db = buttons["yes"];
31808 dlg.setDefaultButton(db);
31810 bwidth = updateButtons(opt.buttons);
31811 this.updateText(opt.msg);
31813 d.el.addClass(opt.cls);
31815 d.proxyDrag = opt.proxyDrag === true;
31816 d.modal = opt.modal !== false;
31817 d.mask = opt.modal !== false ? mask : false;
31818 if(!d.isVisible()){
31819 // force it to the end of the z-index stack so it gets a cursor in FF
31820 document.body.appendChild(dlg.el.dom);
31821 d.animateTarget = null;
31822 d.show(options.animEl);
31828 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31829 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31830 * and closing the message box when the process is complete.
31831 * @param {String} title The title bar text
31832 * @param {String} msg The message box body text
31833 * @return {Roo.MessageBox} This message box
31835 progress : function(title, msg){
31842 minWidth: this.minProgressWidth,
31849 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31850 * If a callback function is passed it will be called after the user clicks the button, and the
31851 * id of the button that was clicked will be passed as the only parameter to the callback
31852 * (could also be the top-right close button).
31853 * @param {String} title The title bar text
31854 * @param {String} msg The message box body text
31855 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31856 * @param {Object} scope (optional) The scope of the callback function
31857 * @return {Roo.MessageBox} This message box
31859 alert : function(title, msg, fn, scope){
31872 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31873 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31874 * You are responsible for closing the message box when the process is complete.
31875 * @param {String} msg The message box body text
31876 * @param {String} title (optional) The title bar text
31877 * @return {Roo.MessageBox} This message box
31879 wait : function(msg, title){
31890 waitTimer = Roo.TaskMgr.start({
31892 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31900 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31901 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31902 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31903 * @param {String} title The title bar text
31904 * @param {String} msg The message box body text
31905 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31906 * @param {Object} scope (optional) The scope of the callback function
31907 * @return {Roo.MessageBox} This message box
31909 confirm : function(title, msg, fn, scope){
31913 buttons: this.YESNO,
31922 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31923 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31924 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31925 * (could also be the top-right close button) and the text that was entered will be passed as the two
31926 * parameters to the callback.
31927 * @param {String} title The title bar text
31928 * @param {String} msg The message box body text
31929 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31930 * @param {Object} scope (optional) The scope of the callback function
31931 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31932 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31933 * @return {Roo.MessageBox} This message box
31935 prompt : function(title, msg, fn, scope, multiline){
31939 buttons: this.OKCANCEL,
31944 multiline: multiline,
31951 * Button config that displays a single OK button
31956 * Button config that displays Yes and No buttons
31959 YESNO : {yes:true, no:true},
31961 * Button config that displays OK and Cancel buttons
31964 OKCANCEL : {ok:true, cancel:true},
31966 * Button config that displays Yes, No and Cancel buttons
31969 YESNOCANCEL : {yes:true, no:true, cancel:true},
31972 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31975 defaultTextHeight : 75,
31977 * The maximum width in pixels of the message box (defaults to 600)
31982 * The minimum width in pixels of the message box (defaults to 100)
31987 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31988 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31991 minProgressWidth : 250,
31993 * An object containing the default button text strings that can be overriden for localized language support.
31994 * Supported properties are: ok, cancel, yes and no.
31995 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
32008 * Shorthand for {@link Roo.MessageBox}
32010 Roo.Msg = Roo.MessageBox;/*
32012 * Ext JS Library 1.1.1
32013 * Copyright(c) 2006-2007, Ext JS, LLC.
32015 * Originally Released Under LGPL - original licence link has changed is not relivant.
32018 * <script type="text/javascript">
32021 * @class Roo.QuickTips
32022 * Provides attractive and customizable tooltips for any element.
32025 Roo.QuickTips = function(){
32026 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
32027 var ce, bd, xy, dd;
32028 var visible = false, disabled = true, inited = false;
32029 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
32031 var onOver = function(e){
32035 var t = e.getTarget();
32036 if(!t || t.nodeType !== 1 || t == document || t == document.body){
32039 if(ce && t == ce.el){
32040 clearTimeout(hideProc);
32043 if(t && tagEls[t.id]){
32044 tagEls[t.id].el = t;
32045 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
32048 var ttp, et = Roo.fly(t);
32049 var ns = cfg.namespace;
32050 if(tm.interceptTitles && t.title){
32053 t.removeAttribute("title");
32054 e.preventDefault();
32056 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
32059 showProc = show.defer(tm.showDelay, tm, [{
32062 width: et.getAttributeNS(ns, cfg.width),
32063 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
32064 title: et.getAttributeNS(ns, cfg.title),
32065 cls: et.getAttributeNS(ns, cfg.cls)
32070 var onOut = function(e){
32071 clearTimeout(showProc);
32072 var t = e.getTarget();
32073 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
32074 hideProc = setTimeout(hide, tm.hideDelay);
32078 var onMove = function(e){
32084 if(tm.trackMouse && ce){
32089 var onDown = function(e){
32090 clearTimeout(showProc);
32091 clearTimeout(hideProc);
32093 if(tm.hideOnClick){
32096 tm.enable.defer(100, tm);
32101 var getPad = function(){
32102 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
32105 var show = function(o){
32109 clearTimeout(dismissProc);
32111 if(removeCls){ // in case manually hidden
32112 el.removeClass(removeCls);
32116 el.addClass(ce.cls);
32117 removeCls = ce.cls;
32120 tipTitle.update(ce.title);
32123 tipTitle.update('');
32126 el.dom.style.width = tm.maxWidth+'px';
32127 //tipBody.dom.style.width = '';
32128 tipBodyText.update(o.text);
32129 var p = getPad(), w = ce.width;
32131 var td = tipBodyText.dom;
32132 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
32133 if(aw > tm.maxWidth){
32135 }else if(aw < tm.minWidth){
32141 //tipBody.setWidth(w);
32142 el.setWidth(parseInt(w, 10) + p);
32143 if(ce.autoHide === false){
32144 close.setDisplayed(true);
32149 close.setDisplayed(false);
32155 el.avoidY = xy[1]-18;
32160 el.setStyle("visibility", "visible");
32161 el.fadeIn({callback: afterShow});
32167 var afterShow = function(){
32171 if(tm.autoDismiss && ce.autoHide !== false){
32172 dismissProc = setTimeout(hide, tm.autoDismissDelay);
32177 var hide = function(noanim){
32178 clearTimeout(dismissProc);
32179 clearTimeout(hideProc);
32181 if(el.isVisible()){
32183 if(noanim !== true && tm.animate){
32184 el.fadeOut({callback: afterHide});
32191 var afterHide = function(){
32194 el.removeClass(removeCls);
32201 * @cfg {Number} minWidth
32202 * The minimum width of the quick tip (defaults to 40)
32206 * @cfg {Number} maxWidth
32207 * The maximum width of the quick tip (defaults to 300)
32211 * @cfg {Boolean} interceptTitles
32212 * True to automatically use the element's DOM title value if available (defaults to false)
32214 interceptTitles : false,
32216 * @cfg {Boolean} trackMouse
32217 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
32219 trackMouse : false,
32221 * @cfg {Boolean} hideOnClick
32222 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32224 hideOnClick : true,
32226 * @cfg {Number} showDelay
32227 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32231 * @cfg {Number} hideDelay
32232 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32236 * @cfg {Boolean} autoHide
32237 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32238 * Used in conjunction with hideDelay.
32243 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32244 * (defaults to true). Used in conjunction with autoDismissDelay.
32246 autoDismiss : true,
32249 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32251 autoDismissDelay : 5000,
32253 * @cfg {Boolean} animate
32254 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32259 * @cfg {String} title
32260 * Title text to display (defaults to ''). This can be any valid HTML markup.
32264 * @cfg {String} text
32265 * Body text to display (defaults to ''). This can be any valid HTML markup.
32269 * @cfg {String} cls
32270 * A CSS class to apply to the base quick tip element (defaults to '').
32274 * @cfg {Number} width
32275 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32276 * minWidth or maxWidth.
32281 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32282 * or display QuickTips in a page.
32285 tm = Roo.QuickTips;
32286 cfg = tm.tagConfig;
32288 if(!Roo.isReady){ // allow calling of init() before onReady
32289 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32292 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32293 el.fxDefaults = {stopFx: true};
32294 // maximum custom styling
32295 //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>');
32296 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>');
32297 tipTitle = el.child('h3');
32298 tipTitle.enableDisplayMode("block");
32299 tipBody = el.child('div.x-tip-bd');
32300 tipBodyText = el.child('div.x-tip-bd-inner');
32301 //bdLeft = el.child('div.x-tip-bd-left');
32302 //bdRight = el.child('div.x-tip-bd-right');
32303 close = el.child('div.x-tip-close');
32304 close.enableDisplayMode("block");
32305 close.on("click", hide);
32306 var d = Roo.get(document);
32307 d.on("mousedown", onDown);
32308 d.on("mouseover", onOver);
32309 d.on("mouseout", onOut);
32310 d.on("mousemove", onMove);
32311 esc = d.addKeyListener(27, hide);
32314 dd = el.initDD("default", null, {
32315 onDrag : function(){
32319 dd.setHandleElId(tipTitle.id);
32328 * Configures a new quick tip instance and assigns it to a target element. The following config options
32331 Property Type Description
32332 ---------- --------------------- ------------------------------------------------------------------------
32333 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32335 * @param {Object} config The config object
32337 register : function(config){
32338 var cs = config instanceof Array ? config : arguments;
32339 for(var i = 0, len = cs.length; i < len; i++) {
32341 var target = c.target;
32343 if(target instanceof Array){
32344 for(var j = 0, jlen = target.length; j < jlen; j++){
32345 tagEls[target[j]] = c;
32348 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32355 * Removes this quick tip from its element and destroys it.
32356 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32358 unregister : function(el){
32359 delete tagEls[Roo.id(el)];
32363 * Enable this quick tip.
32365 enable : function(){
32366 if(inited && disabled){
32368 if(locks.length < 1){
32375 * Disable this quick tip.
32377 disable : function(){
32379 clearTimeout(showProc);
32380 clearTimeout(hideProc);
32381 clearTimeout(dismissProc);
32389 * Returns true if the quick tip is enabled, else false.
32391 isEnabled : function(){
32397 namespace : "roo", // was ext?? this may break..
32398 alt_namespace : "ext",
32399 attribute : "qtip",
32409 // backwards compat
32410 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32412 * Ext JS Library 1.1.1
32413 * Copyright(c) 2006-2007, Ext JS, LLC.
32415 * Originally Released Under LGPL - original licence link has changed is not relivant.
32418 * <script type="text/javascript">
32423 * @class Roo.tree.TreePanel
32424 * @extends Roo.data.Tree
32426 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32427 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32428 * @cfg {Boolean} enableDD true to enable drag and drop
32429 * @cfg {Boolean} enableDrag true to enable just drag
32430 * @cfg {Boolean} enableDrop true to enable just drop
32431 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32432 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32433 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32434 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32435 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32436 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32437 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32438 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32439 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32440 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32441 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32442 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32443 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32444 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32445 * @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>
32446 * @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>
32449 * @param {String/HTMLElement/Element} el The container element
32450 * @param {Object} config
32452 Roo.tree.TreePanel = function(el, config){
32454 var loader = false;
32456 root = config.root;
32457 delete config.root;
32459 if (config.loader) {
32460 loader = config.loader;
32461 delete config.loader;
32464 Roo.apply(this, config);
32465 Roo.tree.TreePanel.superclass.constructor.call(this);
32466 this.el = Roo.get(el);
32467 this.el.addClass('x-tree');
32468 //console.log(root);
32470 this.setRootNode( Roo.factory(root, Roo.tree));
32473 this.loader = Roo.factory(loader, Roo.tree);
32476 * Read-only. The id of the container element becomes this TreePanel's id.
32478 this.id = this.el.id;
32481 * @event beforeload
32482 * Fires before a node is loaded, return false to cancel
32483 * @param {Node} node The node being loaded
32485 "beforeload" : true,
32488 * Fires when a node is loaded
32489 * @param {Node} node The node that was loaded
32493 * @event textchange
32494 * Fires when the text for a node is changed
32495 * @param {Node} node The node
32496 * @param {String} text The new text
32497 * @param {String} oldText The old text
32499 "textchange" : true,
32501 * @event beforeexpand
32502 * Fires before a node is expanded, return false to cancel.
32503 * @param {Node} node The node
32504 * @param {Boolean} deep
32505 * @param {Boolean} anim
32507 "beforeexpand" : true,
32509 * @event beforecollapse
32510 * Fires before a node is collapsed, return false to cancel.
32511 * @param {Node} node The node
32512 * @param {Boolean} deep
32513 * @param {Boolean} anim
32515 "beforecollapse" : true,
32518 * Fires when a node is expanded
32519 * @param {Node} node The node
32523 * @event disabledchange
32524 * Fires when the disabled status of a node changes
32525 * @param {Node} node The node
32526 * @param {Boolean} disabled
32528 "disabledchange" : true,
32531 * Fires when a node is collapsed
32532 * @param {Node} node The node
32536 * @event beforeclick
32537 * Fires before click processing on a node. Return false to cancel the default action.
32538 * @param {Node} node The node
32539 * @param {Roo.EventObject} e The event object
32541 "beforeclick":true,
32543 * @event checkchange
32544 * Fires when a node with a checkbox's checked property changes
32545 * @param {Node} this This node
32546 * @param {Boolean} checked
32548 "checkchange":true,
32551 * Fires when a node is clicked
32552 * @param {Node} node The node
32553 * @param {Roo.EventObject} e The event object
32558 * Fires when a node is double clicked
32559 * @param {Node} node The node
32560 * @param {Roo.EventObject} e The event object
32564 * @event contextmenu
32565 * Fires when a node is right clicked
32566 * @param {Node} node The node
32567 * @param {Roo.EventObject} e The event object
32569 "contextmenu":true,
32571 * @event beforechildrenrendered
32572 * Fires right before the child nodes for a node are rendered
32573 * @param {Node} node The node
32575 "beforechildrenrendered":true,
32578 * Fires when a node starts being dragged
32579 * @param {Roo.tree.TreePanel} this
32580 * @param {Roo.tree.TreeNode} node
32581 * @param {event} e The raw browser event
32583 "startdrag" : true,
32586 * Fires when a drag operation is complete
32587 * @param {Roo.tree.TreePanel} this
32588 * @param {Roo.tree.TreeNode} node
32589 * @param {event} e The raw browser event
32594 * Fires when a dragged node is dropped on a valid DD target
32595 * @param {Roo.tree.TreePanel} this
32596 * @param {Roo.tree.TreeNode} node
32597 * @param {DD} dd The dd it was dropped on
32598 * @param {event} e The raw browser event
32602 * @event beforenodedrop
32603 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32604 * passed to handlers has the following properties:<br />
32605 * <ul style="padding:5px;padding-left:16px;">
32606 * <li>tree - The TreePanel</li>
32607 * <li>target - The node being targeted for the drop</li>
32608 * <li>data - The drag data from the drag source</li>
32609 * <li>point - The point of the drop - append, above or below</li>
32610 * <li>source - The drag source</li>
32611 * <li>rawEvent - Raw mouse event</li>
32612 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32613 * to be inserted by setting them on this object.</li>
32614 * <li>cancel - Set this to true to cancel the drop.</li>
32616 * @param {Object} dropEvent
32618 "beforenodedrop" : true,
32621 * Fires after a DD object is dropped on a node in this tree. The dropEvent
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 - Dropped node(s).</li>
32632 * @param {Object} dropEvent
32636 * @event nodedragover
32637 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32638 * passed to handlers has the following properties:<br />
32639 * <ul style="padding:5px;padding-left:16px;">
32640 * <li>tree - The TreePanel</li>
32641 * <li>target - The node being targeted for the drop</li>
32642 * <li>data - The drag data from the drag source</li>
32643 * <li>point - The point of the drop - append, above or below</li>
32644 * <li>source - The drag source</li>
32645 * <li>rawEvent - Raw mouse event</li>
32646 * <li>dropNode - Drop node(s) provided by the source.</li>
32647 * <li>cancel - Set this to true to signal drop not allowed.</li>
32649 * @param {Object} dragOverEvent
32651 "nodedragover" : true
32654 if(this.singleExpand){
32655 this.on("beforeexpand", this.restrictExpand, this);
32658 this.editor.tree = this;
32659 this.editor = Roo.factory(this.editor, Roo.tree);
32662 if (this.selModel) {
32663 this.selModel = Roo.factory(this.selModel, Roo.tree);
32667 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32668 rootVisible : true,
32669 animate: Roo.enableFx,
32672 hlDrop : Roo.enableFx,
32676 rendererTip: false,
32678 restrictExpand : function(node){
32679 var p = node.parentNode;
32681 if(p.expandedChild && p.expandedChild.parentNode == p){
32682 p.expandedChild.collapse();
32684 p.expandedChild = node;
32688 // private override
32689 setRootNode : function(node){
32690 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32691 if(!this.rootVisible){
32692 node.ui = new Roo.tree.RootTreeNodeUI(node);
32698 * Returns the container element for this TreePanel
32700 getEl : function(){
32705 * Returns the default TreeLoader for this TreePanel
32707 getLoader : function(){
32708 return this.loader;
32714 expandAll : function(){
32715 this.root.expand(true);
32719 * Collapse all nodes
32721 collapseAll : function(){
32722 this.root.collapse(true);
32726 * Returns the selection model used by this TreePanel
32728 getSelectionModel : function(){
32729 if(!this.selModel){
32730 this.selModel = new Roo.tree.DefaultSelectionModel();
32732 return this.selModel;
32736 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32737 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32738 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32741 getChecked : function(a, startNode){
32742 startNode = startNode || this.root;
32744 var f = function(){
32745 if(this.attributes.checked){
32746 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32749 startNode.cascade(f);
32754 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32755 * @param {String} path
32756 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32757 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32758 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32760 expandPath : function(path, attr, callback){
32761 attr = attr || "id";
32762 var keys = path.split(this.pathSeparator);
32763 var curNode = this.root;
32764 if(curNode.attributes[attr] != keys[1]){ // invalid root
32766 callback(false, null);
32771 var f = function(){
32772 if(++index == keys.length){
32774 callback(true, curNode);
32778 var c = curNode.findChild(attr, keys[index]);
32781 callback(false, curNode);
32786 c.expand(false, false, f);
32788 curNode.expand(false, false, f);
32792 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32793 * @param {String} path
32794 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32795 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32796 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32798 selectPath : function(path, attr, callback){
32799 attr = attr || "id";
32800 var keys = path.split(this.pathSeparator);
32801 var v = keys.pop();
32802 if(keys.length > 0){
32803 var f = function(success, node){
32804 if(success && node){
32805 var n = node.findChild(attr, v);
32811 }else if(callback){
32812 callback(false, n);
32816 callback(false, n);
32820 this.expandPath(keys.join(this.pathSeparator), attr, f);
32822 this.root.select();
32824 callback(true, this.root);
32829 getTreeEl : function(){
32834 * Trigger rendering of this TreePanel
32836 render : function(){
32837 if (this.innerCt) {
32838 return this; // stop it rendering more than once!!
32841 this.innerCt = this.el.createChild({tag:"ul",
32842 cls:"x-tree-root-ct " +
32843 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32845 if(this.containerScroll){
32846 Roo.dd.ScrollManager.register(this.el);
32848 if((this.enableDD || this.enableDrop) && !this.dropZone){
32850 * The dropZone used by this tree if drop is enabled
32851 * @type Roo.tree.TreeDropZone
32853 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32854 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32857 if((this.enableDD || this.enableDrag) && !this.dragZone){
32859 * The dragZone used by this tree if drag is enabled
32860 * @type Roo.tree.TreeDragZone
32862 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32863 ddGroup: this.ddGroup || "TreeDD",
32864 scroll: this.ddScroll
32867 this.getSelectionModel().init(this);
32869 Roo.log("ROOT not set in tree");
32872 this.root.render();
32873 if(!this.rootVisible){
32874 this.root.renderChildren();
32880 * Ext JS Library 1.1.1
32881 * Copyright(c) 2006-2007, Ext JS, LLC.
32883 * Originally Released Under LGPL - original licence link has changed is not relivant.
32886 * <script type="text/javascript">
32891 * @class Roo.tree.DefaultSelectionModel
32892 * @extends Roo.util.Observable
32893 * The default single selection for a TreePanel.
32894 * @param {Object} cfg Configuration
32896 Roo.tree.DefaultSelectionModel = function(cfg){
32897 this.selNode = null;
32903 * @event selectionchange
32904 * Fires when the selected node changes
32905 * @param {DefaultSelectionModel} this
32906 * @param {TreeNode} node the new selection
32908 "selectionchange" : true,
32911 * @event beforeselect
32912 * Fires before the selected node changes, return false to cancel the change
32913 * @param {DefaultSelectionModel} this
32914 * @param {TreeNode} node the new selection
32915 * @param {TreeNode} node the old selection
32917 "beforeselect" : true
32920 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32923 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32924 init : function(tree){
32926 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32927 tree.on("click", this.onNodeClick, this);
32930 onNodeClick : function(node, e){
32931 if (e.ctrlKey && this.selNode == node) {
32932 this.unselect(node);
32940 * @param {TreeNode} node The node to select
32941 * @return {TreeNode} The selected node
32943 select : function(node){
32944 var last = this.selNode;
32945 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32947 last.ui.onSelectedChange(false);
32949 this.selNode = node;
32950 node.ui.onSelectedChange(true);
32951 this.fireEvent("selectionchange", this, node, last);
32958 * @param {TreeNode} node The node to unselect
32960 unselect : function(node){
32961 if(this.selNode == node){
32962 this.clearSelections();
32967 * Clear all selections
32969 clearSelections : function(){
32970 var n = this.selNode;
32972 n.ui.onSelectedChange(false);
32973 this.selNode = null;
32974 this.fireEvent("selectionchange", this, null);
32980 * Get the selected node
32981 * @return {TreeNode} The selected node
32983 getSelectedNode : function(){
32984 return this.selNode;
32988 * Returns true if the node is selected
32989 * @param {TreeNode} node The node to check
32990 * @return {Boolean}
32992 isSelected : function(node){
32993 return this.selNode == node;
32997 * Selects the node above the selected node in the tree, intelligently walking the nodes
32998 * @return TreeNode The new selection
33000 selectPrevious : function(){
33001 var s = this.selNode || this.lastSelNode;
33005 var ps = s.previousSibling;
33007 if(!ps.isExpanded() || ps.childNodes.length < 1){
33008 return this.select(ps);
33010 var lc = ps.lastChild;
33011 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
33014 return this.select(lc);
33016 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
33017 return this.select(s.parentNode);
33023 * Selects the node above the selected node in the tree, intelligently walking the nodes
33024 * @return TreeNode The new selection
33026 selectNext : function(){
33027 var s = this.selNode || this.lastSelNode;
33031 if(s.firstChild && s.isExpanded()){
33032 return this.select(s.firstChild);
33033 }else if(s.nextSibling){
33034 return this.select(s.nextSibling);
33035 }else if(s.parentNode){
33037 s.parentNode.bubble(function(){
33038 if(this.nextSibling){
33039 newS = this.getOwnerTree().selModel.select(this.nextSibling);
33048 onKeyDown : function(e){
33049 var s = this.selNode || this.lastSelNode;
33050 // undesirable, but required
33055 var k = e.getKey();
33063 this.selectPrevious();
33066 e.preventDefault();
33067 if(s.hasChildNodes()){
33068 if(!s.isExpanded()){
33070 }else if(s.firstChild){
33071 this.select(s.firstChild, e);
33076 e.preventDefault();
33077 if(s.hasChildNodes() && s.isExpanded()){
33079 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
33080 this.select(s.parentNode, e);
33088 * @class Roo.tree.MultiSelectionModel
33089 * @extends Roo.util.Observable
33090 * Multi selection for a TreePanel.
33091 * @param {Object} cfg Configuration
33093 Roo.tree.MultiSelectionModel = function(){
33094 this.selNodes = [];
33098 * @event selectionchange
33099 * Fires when the selected nodes change
33100 * @param {MultiSelectionModel} this
33101 * @param {Array} nodes Array of the selected nodes
33103 "selectionchange" : true
33105 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
33109 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
33110 init : function(tree){
33112 tree.getTreeEl().on("keydown", this.onKeyDown, this);
33113 tree.on("click", this.onNodeClick, this);
33116 onNodeClick : function(node, e){
33117 this.select(node, e, e.ctrlKey);
33122 * @param {TreeNode} node The node to select
33123 * @param {EventObject} e (optional) An event associated with the selection
33124 * @param {Boolean} keepExisting True to retain existing selections
33125 * @return {TreeNode} The selected node
33127 select : function(node, e, keepExisting){
33128 if(keepExisting !== true){
33129 this.clearSelections(true);
33131 if(this.isSelected(node)){
33132 this.lastSelNode = node;
33135 this.selNodes.push(node);
33136 this.selMap[node.id] = node;
33137 this.lastSelNode = node;
33138 node.ui.onSelectedChange(true);
33139 this.fireEvent("selectionchange", this, this.selNodes);
33145 * @param {TreeNode} node The node to unselect
33147 unselect : function(node){
33148 if(this.selMap[node.id]){
33149 node.ui.onSelectedChange(false);
33150 var sn = this.selNodes;
33153 index = sn.indexOf(node);
33155 for(var i = 0, len = sn.length; i < len; i++){
33163 this.selNodes.splice(index, 1);
33165 delete this.selMap[node.id];
33166 this.fireEvent("selectionchange", this, this.selNodes);
33171 * Clear all selections
33173 clearSelections : function(suppressEvent){
33174 var sn = this.selNodes;
33176 for(var i = 0, len = sn.length; i < len; i++){
33177 sn[i].ui.onSelectedChange(false);
33179 this.selNodes = [];
33181 if(suppressEvent !== true){
33182 this.fireEvent("selectionchange", this, this.selNodes);
33188 * Returns true if the node is selected
33189 * @param {TreeNode} node The node to check
33190 * @return {Boolean}
33192 isSelected : function(node){
33193 return this.selMap[node.id] ? true : false;
33197 * Returns an array of the selected nodes
33200 getSelectedNodes : function(){
33201 return this.selNodes;
33204 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
33206 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
33208 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
33211 * Ext JS Library 1.1.1
33212 * Copyright(c) 2006-2007, Ext JS, LLC.
33214 * Originally Released Under LGPL - original licence link has changed is not relivant.
33217 * <script type="text/javascript">
33221 * @class Roo.tree.TreeNode
33222 * @extends Roo.data.Node
33223 * @cfg {String} text The text for this node
33224 * @cfg {Boolean} expanded true to start the node expanded
33225 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33226 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33227 * @cfg {Boolean} disabled true to start the node disabled
33228 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33229 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33230 * @cfg {String} cls A css class to be added to the node
33231 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33232 * @cfg {String} href URL of the link used for the node (defaults to #)
33233 * @cfg {String} hrefTarget target frame for the link
33234 * @cfg {String} qtip An Ext QuickTip for the node
33235 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33236 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33237 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33238 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33239 * (defaults to undefined with no checkbox rendered)
33241 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33243 Roo.tree.TreeNode = function(attributes){
33244 attributes = attributes || {};
33245 if(typeof attributes == "string"){
33246 attributes = {text: attributes};
33248 this.childrenRendered = false;
33249 this.rendered = false;
33250 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33251 this.expanded = attributes.expanded === true;
33252 this.isTarget = attributes.isTarget !== false;
33253 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33254 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33257 * Read-only. The text for this node. To change it use setText().
33260 this.text = attributes.text;
33262 * True if this node is disabled.
33265 this.disabled = attributes.disabled === true;
33269 * @event textchange
33270 * Fires when the text for this node is changed
33271 * @param {Node} this This node
33272 * @param {String} text The new text
33273 * @param {String} oldText The old text
33275 "textchange" : true,
33277 * @event beforeexpand
33278 * Fires before this node is expanded, return false to cancel.
33279 * @param {Node} this This node
33280 * @param {Boolean} deep
33281 * @param {Boolean} anim
33283 "beforeexpand" : true,
33285 * @event beforecollapse
33286 * Fires before this node is collapsed, return false to cancel.
33287 * @param {Node} this This node
33288 * @param {Boolean} deep
33289 * @param {Boolean} anim
33291 "beforecollapse" : true,
33294 * Fires when this node is expanded
33295 * @param {Node} this This node
33299 * @event disabledchange
33300 * Fires when the disabled status of this node changes
33301 * @param {Node} this This node
33302 * @param {Boolean} disabled
33304 "disabledchange" : true,
33307 * Fires when this node is collapsed
33308 * @param {Node} this This node
33312 * @event beforeclick
33313 * Fires before click processing. Return false to cancel the default action.
33314 * @param {Node} this This node
33315 * @param {Roo.EventObject} e The event object
33317 "beforeclick":true,
33319 * @event checkchange
33320 * Fires when a node with a checkbox's checked property changes
33321 * @param {Node} this This node
33322 * @param {Boolean} checked
33324 "checkchange":true,
33327 * Fires when this node is clicked
33328 * @param {Node} this This node
33329 * @param {Roo.EventObject} e The event object
33334 * Fires when this node is double clicked
33335 * @param {Node} this This node
33336 * @param {Roo.EventObject} e The event object
33340 * @event contextmenu
33341 * Fires when this node is right clicked
33342 * @param {Node} this This node
33343 * @param {Roo.EventObject} e The event object
33345 "contextmenu":true,
33347 * @event beforechildrenrendered
33348 * Fires right before the child nodes for this node are rendered
33349 * @param {Node} this This node
33351 "beforechildrenrendered":true
33354 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33357 * Read-only. The UI for this node
33360 this.ui = new uiClass(this);
33362 // finally support items[]
33363 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33368 Roo.each(this.attributes.items, function(c) {
33369 this.appendChild(Roo.factory(c,Roo.Tree));
33371 delete this.attributes.items;
33376 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33377 preventHScroll: true,
33379 * Returns true if this node is expanded
33380 * @return {Boolean}
33382 isExpanded : function(){
33383 return this.expanded;
33387 * Returns the UI object for this node
33388 * @return {TreeNodeUI}
33390 getUI : function(){
33394 // private override
33395 setFirstChild : function(node){
33396 var of = this.firstChild;
33397 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33398 if(this.childrenRendered && of && node != of){
33399 of.renderIndent(true, true);
33402 this.renderIndent(true, true);
33406 // private override
33407 setLastChild : function(node){
33408 var ol = this.lastChild;
33409 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33410 if(this.childrenRendered && ol && node != ol){
33411 ol.renderIndent(true, true);
33414 this.renderIndent(true, true);
33418 // these methods are overridden to provide lazy rendering support
33419 // private override
33420 appendChild : function()
33422 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33423 if(node && this.childrenRendered){
33426 this.ui.updateExpandIcon();
33430 // private override
33431 removeChild : function(node){
33432 this.ownerTree.getSelectionModel().unselect(node);
33433 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33434 // if it's been rendered remove dom node
33435 if(this.childrenRendered){
33438 if(this.childNodes.length < 1){
33439 this.collapse(false, false);
33441 this.ui.updateExpandIcon();
33443 if(!this.firstChild) {
33444 this.childrenRendered = false;
33449 // private override
33450 insertBefore : function(node, refNode){
33451 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33452 if(newNode && refNode && this.childrenRendered){
33455 this.ui.updateExpandIcon();
33460 * Sets the text for this node
33461 * @param {String} text
33463 setText : function(text){
33464 var oldText = this.text;
33466 this.attributes.text = text;
33467 if(this.rendered){ // event without subscribing
33468 this.ui.onTextChange(this, text, oldText);
33470 this.fireEvent("textchange", this, text, oldText);
33474 * Triggers selection of this node
33476 select : function(){
33477 this.getOwnerTree().getSelectionModel().select(this);
33481 * Triggers deselection of this node
33483 unselect : function(){
33484 this.getOwnerTree().getSelectionModel().unselect(this);
33488 * Returns true if this node is selected
33489 * @return {Boolean}
33491 isSelected : function(){
33492 return this.getOwnerTree().getSelectionModel().isSelected(this);
33496 * Expand this node.
33497 * @param {Boolean} deep (optional) True to expand all children as well
33498 * @param {Boolean} anim (optional) false to cancel the default animation
33499 * @param {Function} callback (optional) A callback to be called when
33500 * expanding this node completes (does not wait for deep expand to complete).
33501 * Called with 1 parameter, this node.
33503 expand : function(deep, anim, callback){
33504 if(!this.expanded){
33505 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33508 if(!this.childrenRendered){
33509 this.renderChildren();
33511 this.expanded = true;
33512 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33513 this.ui.animExpand(function(){
33514 this.fireEvent("expand", this);
33515 if(typeof callback == "function"){
33519 this.expandChildNodes(true);
33521 }.createDelegate(this));
33525 this.fireEvent("expand", this);
33526 if(typeof callback == "function"){
33531 if(typeof callback == "function"){
33536 this.expandChildNodes(true);
33540 isHiddenRoot : function(){
33541 return this.isRoot && !this.getOwnerTree().rootVisible;
33545 * Collapse this node.
33546 * @param {Boolean} deep (optional) True to collapse all children as well
33547 * @param {Boolean} anim (optional) false to cancel the default animation
33549 collapse : function(deep, anim){
33550 if(this.expanded && !this.isHiddenRoot()){
33551 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33554 this.expanded = false;
33555 if((this.getOwnerTree().animate && anim !== false) || anim){
33556 this.ui.animCollapse(function(){
33557 this.fireEvent("collapse", this);
33559 this.collapseChildNodes(true);
33561 }.createDelegate(this));
33564 this.ui.collapse();
33565 this.fireEvent("collapse", this);
33569 var cs = this.childNodes;
33570 for(var i = 0, len = cs.length; i < len; i++) {
33571 cs[i].collapse(true, false);
33577 delayedExpand : function(delay){
33578 if(!this.expandProcId){
33579 this.expandProcId = this.expand.defer(delay, this);
33584 cancelExpand : function(){
33585 if(this.expandProcId){
33586 clearTimeout(this.expandProcId);
33588 this.expandProcId = false;
33592 * Toggles expanded/collapsed state of the node
33594 toggle : function(){
33603 * Ensures all parent nodes are expanded
33605 ensureVisible : function(callback){
33606 var tree = this.getOwnerTree();
33607 tree.expandPath(this.parentNode.getPath(), false, function(){
33608 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33609 Roo.callback(callback);
33610 }.createDelegate(this));
33614 * Expand all child nodes
33615 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33617 expandChildNodes : function(deep){
33618 var cs = this.childNodes;
33619 for(var i = 0, len = cs.length; i < len; i++) {
33620 cs[i].expand(deep);
33625 * Collapse all child nodes
33626 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33628 collapseChildNodes : function(deep){
33629 var cs = this.childNodes;
33630 for(var i = 0, len = cs.length; i < len; i++) {
33631 cs[i].collapse(deep);
33636 * Disables this node
33638 disable : function(){
33639 this.disabled = true;
33641 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33642 this.ui.onDisableChange(this, true);
33644 this.fireEvent("disabledchange", this, true);
33648 * Enables this node
33650 enable : function(){
33651 this.disabled = false;
33652 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33653 this.ui.onDisableChange(this, false);
33655 this.fireEvent("disabledchange", this, false);
33659 renderChildren : function(suppressEvent){
33660 if(suppressEvent !== false){
33661 this.fireEvent("beforechildrenrendered", this);
33663 var cs = this.childNodes;
33664 for(var i = 0, len = cs.length; i < len; i++){
33665 cs[i].render(true);
33667 this.childrenRendered = true;
33671 sort : function(fn, scope){
33672 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33673 if(this.childrenRendered){
33674 var cs = this.childNodes;
33675 for(var i = 0, len = cs.length; i < len; i++){
33676 cs[i].render(true);
33682 render : function(bulkRender){
33683 this.ui.render(bulkRender);
33684 if(!this.rendered){
33685 this.rendered = true;
33687 this.expanded = false;
33688 this.expand(false, false);
33694 renderIndent : function(deep, refresh){
33696 this.ui.childIndent = null;
33698 this.ui.renderIndent();
33699 if(deep === true && this.childrenRendered){
33700 var cs = this.childNodes;
33701 for(var i = 0, len = cs.length; i < len; i++){
33702 cs[i].renderIndent(true, refresh);
33708 * Ext JS Library 1.1.1
33709 * Copyright(c) 2006-2007, Ext JS, LLC.
33711 * Originally Released Under LGPL - original licence link has changed is not relivant.
33714 * <script type="text/javascript">
33718 * @class Roo.tree.AsyncTreeNode
33719 * @extends Roo.tree.TreeNode
33720 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33722 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33724 Roo.tree.AsyncTreeNode = function(config){
33725 this.loaded = false;
33726 this.loading = false;
33727 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33729 * @event beforeload
33730 * Fires before this node is loaded, return false to cancel
33731 * @param {Node} this This node
33733 this.addEvents({'beforeload':true, 'load': true});
33736 * Fires when this node is loaded
33737 * @param {Node} this This node
33740 * The loader used by this node (defaults to using the tree's defined loader)
33745 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33746 expand : function(deep, anim, callback){
33747 if(this.loading){ // if an async load is already running, waiting til it's done
33749 var f = function(){
33750 if(!this.loading){ // done loading
33751 clearInterval(timer);
33752 this.expand(deep, anim, callback);
33754 }.createDelegate(this);
33755 timer = setInterval(f, 200);
33759 if(this.fireEvent("beforeload", this) === false){
33762 this.loading = true;
33763 this.ui.beforeLoad(this);
33764 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33766 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33770 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33774 * Returns true if this node is currently loading
33775 * @return {Boolean}
33777 isLoading : function(){
33778 return this.loading;
33781 loadComplete : function(deep, anim, callback){
33782 this.loading = false;
33783 this.loaded = true;
33784 this.ui.afterLoad(this);
33785 this.fireEvent("load", this);
33786 this.expand(deep, anim, callback);
33790 * Returns true if this node has been loaded
33791 * @return {Boolean}
33793 isLoaded : function(){
33794 return this.loaded;
33797 hasChildNodes : function(){
33798 if(!this.isLeaf() && !this.loaded){
33801 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33806 * Trigger a reload for this node
33807 * @param {Function} callback
33809 reload : function(callback){
33810 this.collapse(false, false);
33811 while(this.firstChild){
33812 this.removeChild(this.firstChild);
33814 this.childrenRendered = false;
33815 this.loaded = false;
33816 if(this.isHiddenRoot()){
33817 this.expanded = false;
33819 this.expand(false, false, callback);
33823 * Ext JS Library 1.1.1
33824 * Copyright(c) 2006-2007, Ext JS, LLC.
33826 * Originally Released Under LGPL - original licence link has changed is not relivant.
33829 * <script type="text/javascript">
33833 * @class Roo.tree.TreeNodeUI
33835 * @param {Object} node The node to render
33836 * The TreeNode UI implementation is separate from the
33837 * tree implementation. Unless you are customizing the tree UI,
33838 * you should never have to use this directly.
33840 Roo.tree.TreeNodeUI = function(node){
33842 this.rendered = false;
33843 this.animating = false;
33844 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33847 Roo.tree.TreeNodeUI.prototype = {
33848 removeChild : function(node){
33850 this.ctNode.removeChild(node.ui.getEl());
33854 beforeLoad : function(){
33855 this.addClass("x-tree-node-loading");
33858 afterLoad : function(){
33859 this.removeClass("x-tree-node-loading");
33862 onTextChange : function(node, text, oldText){
33864 this.textNode.innerHTML = text;
33868 onDisableChange : function(node, state){
33869 this.disabled = state;
33871 this.addClass("x-tree-node-disabled");
33873 this.removeClass("x-tree-node-disabled");
33877 onSelectedChange : function(state){
33880 this.addClass("x-tree-selected");
33883 this.removeClass("x-tree-selected");
33887 onMove : function(tree, node, oldParent, newParent, index, refNode){
33888 this.childIndent = null;
33890 var targetNode = newParent.ui.getContainer();
33891 if(!targetNode){//target not rendered
33892 this.holder = document.createElement("div");
33893 this.holder.appendChild(this.wrap);
33896 var insertBefore = refNode ? refNode.ui.getEl() : null;
33898 targetNode.insertBefore(this.wrap, insertBefore);
33900 targetNode.appendChild(this.wrap);
33902 this.node.renderIndent(true);
33906 addClass : function(cls){
33908 Roo.fly(this.elNode).addClass(cls);
33912 removeClass : function(cls){
33914 Roo.fly(this.elNode).removeClass(cls);
33918 remove : function(){
33920 this.holder = document.createElement("div");
33921 this.holder.appendChild(this.wrap);
33925 fireEvent : function(){
33926 return this.node.fireEvent.apply(this.node, arguments);
33929 initEvents : function(){
33930 this.node.on("move", this.onMove, this);
33931 var E = Roo.EventManager;
33932 var a = this.anchor;
33934 var el = Roo.fly(a, '_treeui');
33936 if(Roo.isOpera){ // opera render bug ignores the CSS
33937 el.setStyle("text-decoration", "none");
33940 el.on("click", this.onClick, this);
33941 el.on("dblclick", this.onDblClick, this);
33944 Roo.EventManager.on(this.checkbox,
33945 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33948 el.on("contextmenu", this.onContextMenu, this);
33950 var icon = Roo.fly(this.iconNode);
33951 icon.on("click", this.onClick, this);
33952 icon.on("dblclick", this.onDblClick, this);
33953 icon.on("contextmenu", this.onContextMenu, this);
33954 E.on(this.ecNode, "click", this.ecClick, this, true);
33956 if(this.node.disabled){
33957 this.addClass("x-tree-node-disabled");
33959 if(this.node.hidden){
33960 this.addClass("x-tree-node-disabled");
33962 var ot = this.node.getOwnerTree();
33963 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33964 if(dd && (!this.node.isRoot || ot.rootVisible)){
33965 Roo.dd.Registry.register(this.elNode, {
33967 handles: this.getDDHandles(),
33973 getDDHandles : function(){
33974 return [this.iconNode, this.textNode];
33979 this.wrap.style.display = "none";
33985 this.wrap.style.display = "";
33989 onContextMenu : function(e){
33990 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33991 e.preventDefault();
33993 this.fireEvent("contextmenu", this.node, e);
33997 onClick : function(e){
34002 if(this.fireEvent("beforeclick", this.node, e) !== false){
34003 if(!this.disabled && this.node.attributes.href){
34004 this.fireEvent("click", this.node, e);
34007 e.preventDefault();
34012 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
34013 this.node.toggle();
34016 this.fireEvent("click", this.node, e);
34022 onDblClick : function(e){
34023 e.preventDefault();
34028 this.toggleCheck();
34030 if(!this.animating && this.node.hasChildNodes()){
34031 this.node.toggle();
34033 this.fireEvent("dblclick", this.node, e);
34036 onCheckChange : function(){
34037 var checked = this.checkbox.checked;
34038 this.node.attributes.checked = checked;
34039 this.fireEvent('checkchange', this.node, checked);
34042 ecClick : function(e){
34043 if(!this.animating && this.node.hasChildNodes()){
34044 this.node.toggle();
34048 startDrop : function(){
34049 this.dropping = true;
34052 // delayed drop so the click event doesn't get fired on a drop
34053 endDrop : function(){
34054 setTimeout(function(){
34055 this.dropping = false;
34056 }.createDelegate(this), 50);
34059 expand : function(){
34060 this.updateExpandIcon();
34061 this.ctNode.style.display = "";
34064 focus : function(){
34065 if(!this.node.preventHScroll){
34066 try{this.anchor.focus();
34068 }else if(!Roo.isIE){
34070 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
34071 var l = noscroll.scrollLeft;
34072 this.anchor.focus();
34073 noscroll.scrollLeft = l;
34078 toggleCheck : function(value){
34079 var cb = this.checkbox;
34081 cb.checked = (value === undefined ? !cb.checked : value);
34087 this.anchor.blur();
34091 animExpand : function(callback){
34092 var ct = Roo.get(this.ctNode);
34094 if(!this.node.hasChildNodes()){
34095 this.updateExpandIcon();
34096 this.ctNode.style.display = "";
34097 Roo.callback(callback);
34100 this.animating = true;
34101 this.updateExpandIcon();
34104 callback : function(){
34105 this.animating = false;
34106 Roo.callback(callback);
34109 duration: this.node.ownerTree.duration || .25
34113 highlight : function(){
34114 var tree = this.node.getOwnerTree();
34115 Roo.fly(this.wrap).highlight(
34116 tree.hlColor || "C3DAF9",
34117 {endColor: tree.hlBaseColor}
34121 collapse : function(){
34122 this.updateExpandIcon();
34123 this.ctNode.style.display = "none";
34126 animCollapse : function(callback){
34127 var ct = Roo.get(this.ctNode);
34128 ct.enableDisplayMode('block');
34131 this.animating = true;
34132 this.updateExpandIcon();
34135 callback : function(){
34136 this.animating = false;
34137 Roo.callback(callback);
34140 duration: this.node.ownerTree.duration || .25
34144 getContainer : function(){
34145 return this.ctNode;
34148 getEl : function(){
34152 appendDDGhost : function(ghostNode){
34153 ghostNode.appendChild(this.elNode.cloneNode(true));
34156 getDDRepairXY : function(){
34157 return Roo.lib.Dom.getXY(this.iconNode);
34160 onRender : function(){
34164 render : function(bulkRender){
34165 var n = this.node, a = n.attributes;
34166 var targetNode = n.parentNode ?
34167 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
34169 if(!this.rendered){
34170 this.rendered = true;
34172 this.renderElements(n, a, targetNode, bulkRender);
34175 if(this.textNode.setAttributeNS){
34176 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
34178 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
34181 this.textNode.setAttribute("ext:qtip", a.qtip);
34183 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
34186 }else if(a.qtipCfg){
34187 a.qtipCfg.target = Roo.id(this.textNode);
34188 Roo.QuickTips.register(a.qtipCfg);
34191 if(!this.node.expanded){
34192 this.updateExpandIcon();
34195 if(bulkRender === true) {
34196 targetNode.appendChild(this.wrap);
34201 renderElements : function(n, a, targetNode, bulkRender)
34203 // add some indent caching, this helps performance when rendering a large tree
34204 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34205 var t = n.getOwnerTree();
34206 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
34207 if (typeof(n.attributes.html) != 'undefined') {
34208 txt = n.attributes.html;
34210 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
34211 var cb = typeof a.checked == 'boolean';
34212 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34213 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
34214 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
34215 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
34216 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
34217 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
34218 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
34219 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
34220 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
34221 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34224 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34225 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34226 n.nextSibling.ui.getEl(), buf.join(""));
34228 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34231 this.elNode = this.wrap.childNodes[0];
34232 this.ctNode = this.wrap.childNodes[1];
34233 var cs = this.elNode.childNodes;
34234 this.indentNode = cs[0];
34235 this.ecNode = cs[1];
34236 this.iconNode = cs[2];
34239 this.checkbox = cs[3];
34242 this.anchor = cs[index];
34243 this.textNode = cs[index].firstChild;
34246 getAnchor : function(){
34247 return this.anchor;
34250 getTextEl : function(){
34251 return this.textNode;
34254 getIconEl : function(){
34255 return this.iconNode;
34258 isChecked : function(){
34259 return this.checkbox ? this.checkbox.checked : false;
34262 updateExpandIcon : function(){
34264 var n = this.node, c1, c2;
34265 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34266 var hasChild = n.hasChildNodes();
34270 c1 = "x-tree-node-collapsed";
34271 c2 = "x-tree-node-expanded";
34274 c1 = "x-tree-node-expanded";
34275 c2 = "x-tree-node-collapsed";
34278 this.removeClass("x-tree-node-leaf");
34279 this.wasLeaf = false;
34281 if(this.c1 != c1 || this.c2 != c2){
34282 Roo.fly(this.elNode).replaceClass(c1, c2);
34283 this.c1 = c1; this.c2 = c2;
34286 // this changes non-leafs into leafs if they have no children.
34287 // it's not very rational behaviour..
34289 if(!this.wasLeaf && this.node.leaf){
34290 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34293 this.wasLeaf = true;
34296 var ecc = "x-tree-ec-icon "+cls;
34297 if(this.ecc != ecc){
34298 this.ecNode.className = ecc;
34304 getChildIndent : function(){
34305 if(!this.childIndent){
34309 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34311 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34313 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34318 this.childIndent = buf.join("");
34320 return this.childIndent;
34323 renderIndent : function(){
34326 var p = this.node.parentNode;
34328 indent = p.ui.getChildIndent();
34330 if(this.indentMarkup != indent){ // don't rerender if not required
34331 this.indentNode.innerHTML = indent;
34332 this.indentMarkup = indent;
34334 this.updateExpandIcon();
34339 Roo.tree.RootTreeNodeUI = function(){
34340 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34342 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34343 render : function(){
34344 if(!this.rendered){
34345 var targetNode = this.node.ownerTree.innerCt.dom;
34346 this.node.expanded = true;
34347 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34348 this.wrap = this.ctNode = targetNode.firstChild;
34351 collapse : function(){
34353 expand : function(){
34357 * Ext JS Library 1.1.1
34358 * Copyright(c) 2006-2007, Ext JS, LLC.
34360 * Originally Released Under LGPL - original licence link has changed is not relivant.
34363 * <script type="text/javascript">
34366 * @class Roo.tree.TreeLoader
34367 * @extends Roo.util.Observable
34368 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34369 * nodes from a specified URL. The response must be a javascript Array definition
34370 * who's elements are node definition objects. eg:
34375 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34376 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34383 * The old style respose with just an array is still supported, but not recommended.
34386 * A server request is sent, and child nodes are loaded only when a node is expanded.
34387 * The loading node's id is passed to the server under the parameter name "node" to
34388 * enable the server to produce the correct child nodes.
34390 * To pass extra parameters, an event handler may be attached to the "beforeload"
34391 * event, and the parameters specified in the TreeLoader's baseParams property:
34393 myTreeLoader.on("beforeload", function(treeLoader, node) {
34394 this.baseParams.category = node.attributes.category;
34397 * This would pass an HTTP parameter called "category" to the server containing
34398 * the value of the Node's "category" attribute.
34400 * Creates a new Treeloader.
34401 * @param {Object} config A config object containing config properties.
34403 Roo.tree.TreeLoader = function(config){
34404 this.baseParams = {};
34405 this.requestMethod = "POST";
34406 Roo.apply(this, config);
34411 * @event beforeload
34412 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34413 * @param {Object} This TreeLoader object.
34414 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34415 * @param {Object} callback The callback function specified in the {@link #load} call.
34420 * Fires when the node has been successfuly loaded.
34421 * @param {Object} This TreeLoader object.
34422 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34423 * @param {Object} response The response object containing the data from the server.
34427 * @event loadexception
34428 * Fires if the network request failed.
34429 * @param {Object} This TreeLoader object.
34430 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34431 * @param {Object} response The response object containing the data from the server.
34433 loadexception : true,
34436 * Fires before a node is created, enabling you to return custom Node types
34437 * @param {Object} This TreeLoader object.
34438 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34443 Roo.tree.TreeLoader.superclass.constructor.call(this);
34446 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34448 * @cfg {String} dataUrl The URL from which to request a Json string which
34449 * specifies an array of node definition object representing the child nodes
34453 * @cfg {String} requestMethod either GET or POST
34454 * defaults to POST (due to BC)
34458 * @cfg {Object} baseParams (optional) An object containing properties which
34459 * specify HTTP parameters to be passed to each request for child nodes.
34462 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34463 * created by this loader. If the attributes sent by the server have an attribute in this object,
34464 * they take priority.
34467 * @cfg {Object} uiProviders (optional) An object containing properties which
34469 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34470 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34471 * <i>uiProvider</i> attribute of a returned child node is a string rather
34472 * than a reference to a TreeNodeUI implementation, this that string value
34473 * is used as a property name in the uiProviders object. You can define the provider named
34474 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34479 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34480 * child nodes before loading.
34482 clearOnLoad : true,
34485 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34486 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34487 * Grid query { data : [ .....] }
34492 * @cfg {String} queryParam (optional)
34493 * Name of the query as it will be passed on the querystring (defaults to 'node')
34494 * eg. the request will be ?node=[id]
34501 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34502 * This is called automatically when a node is expanded, but may be used to reload
34503 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34504 * @param {Roo.tree.TreeNode} node
34505 * @param {Function} callback
34507 load : function(node, callback){
34508 if(this.clearOnLoad){
34509 while(node.firstChild){
34510 node.removeChild(node.firstChild);
34513 if(node.attributes.children){ // preloaded json children
34514 var cs = node.attributes.children;
34515 for(var i = 0, len = cs.length; i < len; i++){
34516 node.appendChild(this.createNode(cs[i]));
34518 if(typeof callback == "function"){
34521 }else if(this.dataUrl){
34522 this.requestData(node, callback);
34526 getParams: function(node){
34527 var buf = [], bp = this.baseParams;
34528 for(var key in bp){
34529 if(typeof bp[key] != "function"){
34530 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34533 var n = this.queryParam === false ? 'node' : this.queryParam;
34534 buf.push(n + "=", encodeURIComponent(node.id));
34535 return buf.join("");
34538 requestData : function(node, callback){
34539 if(this.fireEvent("beforeload", this, node, callback) !== false){
34540 this.transId = Roo.Ajax.request({
34541 method:this.requestMethod,
34542 url: this.dataUrl||this.url,
34543 success: this.handleResponse,
34544 failure: this.handleFailure,
34546 argument: {callback: callback, node: node},
34547 params: this.getParams(node)
34550 // if the load is cancelled, make sure we notify
34551 // the node that we are done
34552 if(typeof callback == "function"){
34558 isLoading : function(){
34559 return this.transId ? true : false;
34562 abort : function(){
34563 if(this.isLoading()){
34564 Roo.Ajax.abort(this.transId);
34569 createNode : function(attr)
34571 // apply baseAttrs, nice idea Corey!
34572 if(this.baseAttrs){
34573 Roo.applyIf(attr, this.baseAttrs);
34575 if(this.applyLoader !== false){
34576 attr.loader = this;
34578 // uiProvider = depreciated..
34580 if(typeof(attr.uiProvider) == 'string'){
34581 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34582 /** eval:var:attr */ eval(attr.uiProvider);
34584 if(typeof(this.uiProviders['default']) != 'undefined') {
34585 attr.uiProvider = this.uiProviders['default'];
34588 this.fireEvent('create', this, attr);
34590 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34592 new Roo.tree.TreeNode(attr) :
34593 new Roo.tree.AsyncTreeNode(attr));
34596 processResponse : function(response, node, callback)
34598 var json = response.responseText;
34601 var o = Roo.decode(json);
34603 if (this.root === false && typeof(o.success) != undefined) {
34604 this.root = 'data'; // the default behaviour for list like data..
34607 if (this.root !== false && !o.success) {
34608 // it's a failure condition.
34609 var a = response.argument;
34610 this.fireEvent("loadexception", this, a.node, response);
34611 Roo.log("Load failed - should have a handler really");
34617 if (this.root !== false) {
34621 for(var i = 0, len = o.length; i < len; i++){
34622 var n = this.createNode(o[i]);
34624 node.appendChild(n);
34627 if(typeof callback == "function"){
34628 callback(this, node);
34631 this.handleFailure(response);
34635 handleResponse : function(response){
34636 this.transId = false;
34637 var a = response.argument;
34638 this.processResponse(response, a.node, a.callback);
34639 this.fireEvent("load", this, a.node, response);
34642 handleFailure : function(response)
34644 // should handle failure better..
34645 this.transId = false;
34646 var a = response.argument;
34647 this.fireEvent("loadexception", this, a.node, response);
34648 if(typeof a.callback == "function"){
34649 a.callback(this, a.node);
34654 * Ext JS Library 1.1.1
34655 * Copyright(c) 2006-2007, Ext JS, LLC.
34657 * Originally Released Under LGPL - original licence link has changed is not relivant.
34660 * <script type="text/javascript">
34664 * @class Roo.tree.TreeFilter
34665 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34666 * @param {TreePanel} tree
34667 * @param {Object} config (optional)
34669 Roo.tree.TreeFilter = function(tree, config){
34671 this.filtered = {};
34672 Roo.apply(this, config);
34675 Roo.tree.TreeFilter.prototype = {
34682 * Filter the data by a specific attribute.
34683 * @param {String/RegExp} value Either string that the attribute value
34684 * should start with or a RegExp to test against the attribute
34685 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34686 * @param {TreeNode} startNode (optional) The node to start the filter at.
34688 filter : function(value, attr, startNode){
34689 attr = attr || "text";
34691 if(typeof value == "string"){
34692 var vlen = value.length;
34693 // auto clear empty filter
34694 if(vlen == 0 && this.clearBlank){
34698 value = value.toLowerCase();
34700 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34702 }else if(value.exec){ // regex?
34704 return value.test(n.attributes[attr]);
34707 throw 'Illegal filter type, must be string or regex';
34709 this.filterBy(f, null, startNode);
34713 * Filter by a function. The passed function will be called with each
34714 * node in the tree (or from the startNode). If the function returns true, the node is kept
34715 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34716 * @param {Function} fn The filter function
34717 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34719 filterBy : function(fn, scope, startNode){
34720 startNode = startNode || this.tree.root;
34721 if(this.autoClear){
34724 var af = this.filtered, rv = this.reverse;
34725 var f = function(n){
34726 if(n == startNode){
34732 var m = fn.call(scope || n, n);
34740 startNode.cascade(f);
34743 if(typeof id != "function"){
34745 if(n && n.parentNode){
34746 n.parentNode.removeChild(n);
34754 * Clears the current filter. Note: with the "remove" option
34755 * set a filter cannot be cleared.
34757 clear : function(){
34759 var af = this.filtered;
34761 if(typeof id != "function"){
34768 this.filtered = {};
34773 * Ext JS Library 1.1.1
34774 * Copyright(c) 2006-2007, Ext JS, LLC.
34776 * Originally Released Under LGPL - original licence link has changed is not relivant.
34779 * <script type="text/javascript">
34784 * @class Roo.tree.TreeSorter
34785 * Provides sorting of nodes in a TreePanel
34787 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34788 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34789 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34790 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34791 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34792 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34794 * @param {TreePanel} tree
34795 * @param {Object} config
34797 Roo.tree.TreeSorter = function(tree, config){
34798 Roo.apply(this, config);
34799 tree.on("beforechildrenrendered", this.doSort, this);
34800 tree.on("append", this.updateSort, this);
34801 tree.on("insert", this.updateSort, this);
34803 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34804 var p = this.property || "text";
34805 var sortType = this.sortType;
34806 var fs = this.folderSort;
34807 var cs = this.caseSensitive === true;
34808 var leafAttr = this.leafAttr || 'leaf';
34810 this.sortFn = function(n1, n2){
34812 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34815 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34819 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34820 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34822 return dsc ? +1 : -1;
34824 return dsc ? -1 : +1;
34831 Roo.tree.TreeSorter.prototype = {
34832 doSort : function(node){
34833 node.sort(this.sortFn);
34836 compareNodes : function(n1, n2){
34837 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34840 updateSort : function(tree, node){
34841 if(node.childrenRendered){
34842 this.doSort.defer(1, this, [node]);
34847 * Ext JS Library 1.1.1
34848 * Copyright(c) 2006-2007, Ext JS, LLC.
34850 * Originally Released Under LGPL - original licence link has changed is not relivant.
34853 * <script type="text/javascript">
34856 if(Roo.dd.DropZone){
34858 Roo.tree.TreeDropZone = function(tree, config){
34859 this.allowParentInsert = false;
34860 this.allowContainerDrop = false;
34861 this.appendOnly = false;
34862 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34864 this.lastInsertClass = "x-tree-no-status";
34865 this.dragOverData = {};
34868 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34869 ddGroup : "TreeDD",
34872 expandDelay : 1000,
34874 expandNode : function(node){
34875 if(node.hasChildNodes() && !node.isExpanded()){
34876 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34880 queueExpand : function(node){
34881 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34884 cancelExpand : function(){
34885 if(this.expandProcId){
34886 clearTimeout(this.expandProcId);
34887 this.expandProcId = false;
34891 isValidDropPoint : function(n, pt, dd, e, data){
34892 if(!n || !data){ return false; }
34893 var targetNode = n.node;
34894 var dropNode = data.node;
34895 // default drop rules
34896 if(!(targetNode && targetNode.isTarget && pt)){
34899 if(pt == "append" && targetNode.allowChildren === false){
34902 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34905 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34908 // reuse the object
34909 var overEvent = this.dragOverData;
34910 overEvent.tree = this.tree;
34911 overEvent.target = targetNode;
34912 overEvent.data = data;
34913 overEvent.point = pt;
34914 overEvent.source = dd;
34915 overEvent.rawEvent = e;
34916 overEvent.dropNode = dropNode;
34917 overEvent.cancel = false;
34918 var result = this.tree.fireEvent("nodedragover", overEvent);
34919 return overEvent.cancel === false && result !== false;
34922 getDropPoint : function(e, n, dd)
34926 return tn.allowChildren !== false ? "append" : false; // always append for root
34928 var dragEl = n.ddel;
34929 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34930 var y = Roo.lib.Event.getPageY(e);
34931 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34933 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34934 var noAppend = tn.allowChildren === false;
34935 if(this.appendOnly || tn.parentNode.allowChildren === false){
34936 return noAppend ? false : "append";
34938 var noBelow = false;
34939 if(!this.allowParentInsert){
34940 noBelow = tn.hasChildNodes() && tn.isExpanded();
34942 var q = (b - t) / (noAppend ? 2 : 3);
34943 if(y >= t && y < (t + q)){
34945 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34952 onNodeEnter : function(n, dd, e, data)
34954 this.cancelExpand();
34957 onNodeOver : function(n, dd, e, data)
34960 var pt = this.getDropPoint(e, n, dd);
34963 // auto node expand check
34964 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34965 this.queueExpand(node);
34966 }else if(pt != "append"){
34967 this.cancelExpand();
34970 // set the insert point style on the target node
34971 var returnCls = this.dropNotAllowed;
34972 if(this.isValidDropPoint(n, pt, dd, e, data)){
34977 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34978 cls = "x-tree-drag-insert-above";
34979 }else if(pt == "below"){
34980 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34981 cls = "x-tree-drag-insert-below";
34983 returnCls = "x-tree-drop-ok-append";
34984 cls = "x-tree-drag-append";
34986 if(this.lastInsertClass != cls){
34987 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34988 this.lastInsertClass = cls;
34995 onNodeOut : function(n, dd, e, data){
34997 this.cancelExpand();
34998 this.removeDropIndicators(n);
35001 onNodeDrop : function(n, dd, e, data){
35002 var point = this.getDropPoint(e, n, dd);
35003 var targetNode = n.node;
35004 targetNode.ui.startDrop();
35005 if(!this.isValidDropPoint(n, point, dd, e, data)){
35006 targetNode.ui.endDrop();
35009 // first try to find the drop node
35010 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
35013 target: targetNode,
35018 dropNode: dropNode,
35021 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
35022 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
35023 targetNode.ui.endDrop();
35026 // allow target changing
35027 targetNode = dropEvent.target;
35028 if(point == "append" && !targetNode.isExpanded()){
35029 targetNode.expand(false, null, function(){
35030 this.completeDrop(dropEvent);
35031 }.createDelegate(this));
35033 this.completeDrop(dropEvent);
35038 completeDrop : function(de){
35039 var ns = de.dropNode, p = de.point, t = de.target;
35040 if(!(ns instanceof Array)){
35044 for(var i = 0, len = ns.length; i < len; i++){
35047 t.parentNode.insertBefore(n, t);
35048 }else if(p == "below"){
35049 t.parentNode.insertBefore(n, t.nextSibling);
35055 if(this.tree.hlDrop){
35059 this.tree.fireEvent("nodedrop", de);
35062 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
35063 if(this.tree.hlDrop){
35064 dropNode.ui.focus();
35065 dropNode.ui.highlight();
35067 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
35070 getTree : function(){
35074 removeDropIndicators : function(n){
35077 Roo.fly(el).removeClass([
35078 "x-tree-drag-insert-above",
35079 "x-tree-drag-insert-below",
35080 "x-tree-drag-append"]);
35081 this.lastInsertClass = "_noclass";
35085 beforeDragDrop : function(target, e, id){
35086 this.cancelExpand();
35090 afterRepair : function(data){
35091 if(data && Roo.enableFx){
35092 data.node.ui.highlight();
35102 * Ext JS Library 1.1.1
35103 * Copyright(c) 2006-2007, Ext JS, LLC.
35105 * Originally Released Under LGPL - original licence link has changed is not relivant.
35108 * <script type="text/javascript">
35112 if(Roo.dd.DragZone){
35113 Roo.tree.TreeDragZone = function(tree, config){
35114 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
35118 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
35119 ddGroup : "TreeDD",
35121 onBeforeDrag : function(data, e){
35123 return n && n.draggable && !n.disabled;
35127 onInitDrag : function(e){
35128 var data = this.dragData;
35129 this.tree.getSelectionModel().select(data.node);
35130 this.proxy.update("");
35131 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
35132 this.tree.fireEvent("startdrag", this.tree, data.node, e);
35135 getRepairXY : function(e, data){
35136 return data.node.ui.getDDRepairXY();
35139 onEndDrag : function(data, e){
35140 this.tree.fireEvent("enddrag", this.tree, data.node, e);
35145 onValidDrop : function(dd, e, id){
35146 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
35150 beforeInvalidDrop : function(e, id){
35151 // this scrolls the original position back into view
35152 var sm = this.tree.getSelectionModel();
35153 sm.clearSelections();
35154 sm.select(this.dragData.node);
35159 * Ext JS Library 1.1.1
35160 * Copyright(c) 2006-2007, Ext JS, LLC.
35162 * Originally Released Under LGPL - original licence link has changed is not relivant.
35165 * <script type="text/javascript">
35168 * @class Roo.tree.TreeEditor
35169 * @extends Roo.Editor
35170 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
35171 * as the editor field.
35173 * @param {Object} config (used to be the tree panel.)
35174 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
35176 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
35177 * @cfg {Roo.form.TextField|Object} field The field configuration
35181 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
35184 if (oldconfig) { // old style..
35185 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
35188 tree = config.tree;
35189 config.field = config.field || {};
35190 config.field.xtype = 'TextField';
35191 field = Roo.factory(config.field, Roo.form);
35193 config = config || {};
35198 * @event beforenodeedit
35199 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
35200 * false from the handler of this event.
35201 * @param {Editor} this
35202 * @param {Roo.tree.Node} node
35204 "beforenodeedit" : true
35208 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
35212 tree.on('beforeclick', this.beforeNodeClick, this);
35213 tree.getTreeEl().on('mousedown', this.hide, this);
35214 this.on('complete', this.updateNode, this);
35215 this.on('beforestartedit', this.fitToTree, this);
35216 this.on('startedit', this.bindScroll, this, {delay:10});
35217 this.on('specialkey', this.onSpecialKey, this);
35220 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
35222 * @cfg {String} alignment
35223 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35229 * @cfg {Boolean} hideEl
35230 * True to hide the bound element while the editor is displayed (defaults to false)
35234 * @cfg {String} cls
35235 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35237 cls: "x-small-editor x-tree-editor",
35239 * @cfg {Boolean} shim
35240 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35246 * @cfg {Number} maxWidth
35247 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35248 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35249 * scroll and client offsets into account prior to each edit.
35256 fitToTree : function(ed, el){
35257 var td = this.tree.getTreeEl().dom, nd = el.dom;
35258 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35259 td.scrollLeft = nd.offsetLeft;
35263 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35264 this.setSize(w, '');
35266 return this.fireEvent('beforenodeedit', this, this.editNode);
35271 triggerEdit : function(node){
35272 this.completeEdit();
35273 this.editNode = node;
35274 this.startEdit(node.ui.textNode, node.text);
35278 bindScroll : function(){
35279 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35283 beforeNodeClick : function(node, e){
35284 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35285 this.lastClick = new Date();
35286 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35288 this.triggerEdit(node);
35295 updateNode : function(ed, value){
35296 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35297 this.editNode.setText(value);
35301 onHide : function(){
35302 Roo.tree.TreeEditor.superclass.onHide.call(this);
35304 this.editNode.ui.focus();
35309 onSpecialKey : function(field, e){
35310 var k = e.getKey();
35314 }else if(k == e.ENTER && !e.hasModifier()){
35316 this.completeEdit();
35319 });//<Script type="text/javascript">
35322 * Ext JS Library 1.1.1
35323 * Copyright(c) 2006-2007, Ext JS, LLC.
35325 * Originally Released Under LGPL - original licence link has changed is not relivant.
35328 * <script type="text/javascript">
35332 * Not documented??? - probably should be...
35335 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35336 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35338 renderElements : function(n, a, targetNode, bulkRender){
35339 //consel.log("renderElements?");
35340 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35342 var t = n.getOwnerTree();
35343 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35345 var cols = t.columns;
35346 var bw = t.borderWidth;
35348 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35349 var cb = typeof a.checked == "boolean";
35350 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35351 var colcls = 'x-t-' + tid + '-c0';
35353 '<li class="x-tree-node">',
35356 '<div class="x-tree-node-el ', a.cls,'">',
35358 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35361 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35362 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35363 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35364 (a.icon ? ' x-tree-node-inline-icon' : ''),
35365 (a.iconCls ? ' '+a.iconCls : ''),
35366 '" unselectable="on" />',
35367 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35368 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35370 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35371 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35372 '<span unselectable="on" qtip="' + tx + '">',
35376 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35377 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35379 for(var i = 1, len = cols.length; i < len; i++){
35381 colcls = 'x-t-' + tid + '-c' +i;
35382 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35383 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35384 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35390 '<div class="x-clear"></div></div>',
35391 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35394 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35395 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35396 n.nextSibling.ui.getEl(), buf.join(""));
35398 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35400 var el = this.wrap.firstChild;
35402 this.elNode = el.firstChild;
35403 this.ranchor = el.childNodes[1];
35404 this.ctNode = this.wrap.childNodes[1];
35405 var cs = el.firstChild.childNodes;
35406 this.indentNode = cs[0];
35407 this.ecNode = cs[1];
35408 this.iconNode = cs[2];
35411 this.checkbox = cs[3];
35414 this.anchor = cs[index];
35416 this.textNode = cs[index].firstChild;
35418 //el.on("click", this.onClick, this);
35419 //el.on("dblclick", this.onDblClick, this);
35422 // console.log(this);
35424 initEvents : function(){
35425 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35428 var a = this.ranchor;
35430 var el = Roo.get(a);
35432 if(Roo.isOpera){ // opera render bug ignores the CSS
35433 el.setStyle("text-decoration", "none");
35436 el.on("click", this.onClick, this);
35437 el.on("dblclick", this.onDblClick, this);
35438 el.on("contextmenu", this.onContextMenu, this);
35442 /*onSelectedChange : function(state){
35445 this.addClass("x-tree-selected");
35448 this.removeClass("x-tree-selected");
35451 addClass : function(cls){
35453 Roo.fly(this.elRow).addClass(cls);
35459 removeClass : function(cls){
35461 Roo.fly(this.elRow).removeClass(cls);
35467 });//<Script type="text/javascript">
35471 * Ext JS Library 1.1.1
35472 * Copyright(c) 2006-2007, Ext JS, LLC.
35474 * Originally Released Under LGPL - original licence link has changed is not relivant.
35477 * <script type="text/javascript">
35482 * @class Roo.tree.ColumnTree
35483 * @extends Roo.data.TreePanel
35484 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35485 * @cfg {int} borderWidth compined right/left border allowance
35487 * @param {String/HTMLElement/Element} el The container element
35488 * @param {Object} config
35490 Roo.tree.ColumnTree = function(el, config)
35492 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35496 * Fire this event on a container when it resizes
35497 * @param {int} w Width
35498 * @param {int} h Height
35502 this.on('resize', this.onResize, this);
35505 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35509 borderWidth: Roo.isBorderBox ? 0 : 2,
35512 render : function(){
35513 // add the header.....
35515 Roo.tree.ColumnTree.superclass.render.apply(this);
35517 this.el.addClass('x-column-tree');
35519 this.headers = this.el.createChild(
35520 {cls:'x-tree-headers'},this.innerCt.dom);
35522 var cols = this.columns, c;
35523 var totalWidth = 0;
35525 var len = cols.length;
35526 for(var i = 0; i < len; i++){
35528 totalWidth += c.width;
35529 this.headEls.push(this.headers.createChild({
35530 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35532 cls:'x-tree-hd-text',
35535 style:'width:'+(c.width-this.borderWidth)+'px;'
35538 this.headers.createChild({cls:'x-clear'});
35539 // prevent floats from wrapping when clipped
35540 this.headers.setWidth(totalWidth);
35541 //this.innerCt.setWidth(totalWidth);
35542 this.innerCt.setStyle({ overflow: 'auto' });
35543 this.onResize(this.width, this.height);
35547 onResize : function(w,h)
35552 this.innerCt.setWidth(this.width);
35553 this.innerCt.setHeight(this.height-20);
35556 var cols = this.columns, c;
35557 var totalWidth = 0;
35559 var len = cols.length;
35560 for(var i = 0; i < len; i++){
35562 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35563 // it's the expander..
35564 expEl = this.headEls[i];
35567 totalWidth += c.width;
35571 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35573 this.headers.setWidth(w-20);
35582 * Ext JS Library 1.1.1
35583 * Copyright(c) 2006-2007, Ext JS, LLC.
35585 * Originally Released Under LGPL - original licence link has changed is not relivant.
35588 * <script type="text/javascript">
35592 * @class Roo.menu.Menu
35593 * @extends Roo.util.Observable
35594 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35595 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35597 * Creates a new Menu
35598 * @param {Object} config Configuration options
35600 Roo.menu.Menu = function(config){
35601 Roo.apply(this, config);
35602 this.id = this.id || Roo.id();
35605 * @event beforeshow
35606 * Fires before this menu is displayed
35607 * @param {Roo.menu.Menu} this
35611 * @event beforehide
35612 * Fires before this menu is hidden
35613 * @param {Roo.menu.Menu} this
35618 * Fires after this menu is displayed
35619 * @param {Roo.menu.Menu} this
35624 * Fires after this menu is hidden
35625 * @param {Roo.menu.Menu} this
35630 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35631 * @param {Roo.menu.Menu} this
35632 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35633 * @param {Roo.EventObject} e
35638 * Fires when the mouse is hovering over this menu
35639 * @param {Roo.menu.Menu} this
35640 * @param {Roo.EventObject} e
35641 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35646 * Fires when the mouse exits this menu
35647 * @param {Roo.menu.Menu} this
35648 * @param {Roo.EventObject} e
35649 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35654 * Fires when a menu item contained in this menu is clicked
35655 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35656 * @param {Roo.EventObject} e
35660 if (this.registerMenu) {
35661 Roo.menu.MenuMgr.register(this);
35664 var mis = this.items;
35665 this.items = new Roo.util.MixedCollection();
35667 this.add.apply(this, mis);
35671 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35673 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35677 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35678 * for bottom-right shadow (defaults to "sides")
35682 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35683 * this menu (defaults to "tl-tr?")
35685 subMenuAlign : "tl-tr?",
35687 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35688 * relative to its element of origin (defaults to "tl-bl?")
35690 defaultAlign : "tl-bl?",
35692 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35694 allowOtherMenus : false,
35696 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35698 registerMenu : true,
35703 render : function(){
35707 var el = this.el = new Roo.Layer({
35709 shadow:this.shadow,
35711 parentEl: this.parentEl || document.body,
35715 this.keyNav = new Roo.menu.MenuNav(this);
35718 el.addClass("x-menu-plain");
35721 el.addClass(this.cls);
35723 // generic focus element
35724 this.focusEl = el.createChild({
35725 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35727 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35728 //disabling touch- as it's causing issues ..
35729 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35730 ul.on('click' , this.onClick, this);
35733 ul.on("mouseover", this.onMouseOver, this);
35734 ul.on("mouseout", this.onMouseOut, this);
35735 this.items.each(function(item){
35740 var li = document.createElement("li");
35741 li.className = "x-menu-list-item";
35742 ul.dom.appendChild(li);
35743 item.render(li, this);
35750 autoWidth : function(){
35751 var el = this.el, ul = this.ul;
35755 var w = this.width;
35758 }else if(Roo.isIE){
35759 el.setWidth(this.minWidth);
35760 var t = el.dom.offsetWidth; // force recalc
35761 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35766 delayAutoWidth : function(){
35769 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35771 this.awTask.delay(20);
35776 findTargetItem : function(e){
35777 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35778 if(t && t.menuItemId){
35779 return this.items.get(t.menuItemId);
35784 onClick : function(e){
35785 Roo.log("menu.onClick");
35786 var t = this.findTargetItem(e);
35791 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35792 if(t == this.activeItem && t.shouldDeactivate(e)){
35793 this.activeItem.deactivate();
35794 delete this.activeItem;
35798 this.setActiveItem(t, true);
35806 this.fireEvent("click", this, t, e);
35810 setActiveItem : function(item, autoExpand){
35811 if(item != this.activeItem){
35812 if(this.activeItem){
35813 this.activeItem.deactivate();
35815 this.activeItem = item;
35816 item.activate(autoExpand);
35817 }else if(autoExpand){
35823 tryActivate : function(start, step){
35824 var items = this.items;
35825 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35826 var item = items.get(i);
35827 if(!item.disabled && item.canActivate){
35828 this.setActiveItem(item, false);
35836 onMouseOver : function(e){
35838 if(t = this.findTargetItem(e)){
35839 if(t.canActivate && !t.disabled){
35840 this.setActiveItem(t, true);
35843 this.fireEvent("mouseover", this, e, t);
35847 onMouseOut : function(e){
35849 if(t = this.findTargetItem(e)){
35850 if(t == this.activeItem && t.shouldDeactivate(e)){
35851 this.activeItem.deactivate();
35852 delete this.activeItem;
35855 this.fireEvent("mouseout", this, e, t);
35859 * Read-only. Returns true if the menu is currently displayed, else false.
35862 isVisible : function(){
35863 return this.el && !this.hidden;
35867 * Displays this menu relative to another element
35868 * @param {String/HTMLElement/Roo.Element} element The element to align to
35869 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35870 * the element (defaults to this.defaultAlign)
35871 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35873 show : function(el, pos, parentMenu){
35874 this.parentMenu = parentMenu;
35878 this.fireEvent("beforeshow", this);
35879 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35883 * Displays this menu at a specific xy position
35884 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35885 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35887 showAt : function(xy, parentMenu, /* private: */_e){
35888 this.parentMenu = parentMenu;
35893 this.fireEvent("beforeshow", this);
35894 xy = this.el.adjustForConstraints(xy);
35898 this.hidden = false;
35900 this.fireEvent("show", this);
35903 focus : function(){
35905 this.doFocus.defer(50, this);
35909 doFocus : function(){
35911 this.focusEl.focus();
35916 * Hides this menu and optionally all parent menus
35917 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35919 hide : function(deep){
35920 if(this.el && this.isVisible()){
35921 this.fireEvent("beforehide", this);
35922 if(this.activeItem){
35923 this.activeItem.deactivate();
35924 this.activeItem = null;
35927 this.hidden = true;
35928 this.fireEvent("hide", this);
35930 if(deep === true && this.parentMenu){
35931 this.parentMenu.hide(true);
35936 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35937 * Any of the following are valid:
35939 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35940 * <li>An HTMLElement object which will be converted to a menu item</li>
35941 * <li>A menu item config object that will be created as a new menu item</li>
35942 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35943 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35948 var menu = new Roo.menu.Menu();
35950 // Create a menu item to add by reference
35951 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35953 // Add a bunch of items at once using different methods.
35954 // Only the last item added will be returned.
35955 var item = menu.add(
35956 menuItem, // add existing item by ref
35957 'Dynamic Item', // new TextItem
35958 '-', // new separator
35959 { text: 'Config Item' } // new item by config
35962 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35963 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35966 var a = arguments, l = a.length, item;
35967 for(var i = 0; i < l; i++){
35969 if ((typeof(el) == "object") && el.xtype && el.xns) {
35970 el = Roo.factory(el, Roo.menu);
35973 if(el.render){ // some kind of Item
35974 item = this.addItem(el);
35975 }else if(typeof el == "string"){ // string
35976 if(el == "separator" || el == "-"){
35977 item = this.addSeparator();
35979 item = this.addText(el);
35981 }else if(el.tagName || el.el){ // element
35982 item = this.addElement(el);
35983 }else if(typeof el == "object"){ // must be menu item config?
35984 item = this.addMenuItem(el);
35991 * Returns this menu's underlying {@link Roo.Element} object
35992 * @return {Roo.Element} The element
35994 getEl : function(){
36002 * Adds a separator bar to the menu
36003 * @return {Roo.menu.Item} The menu item that was added
36005 addSeparator : function(){
36006 return this.addItem(new Roo.menu.Separator());
36010 * Adds an {@link Roo.Element} object to the menu
36011 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
36012 * @return {Roo.menu.Item} The menu item that was added
36014 addElement : function(el){
36015 return this.addItem(new Roo.menu.BaseItem(el));
36019 * Adds an existing object based on {@link Roo.menu.Item} to the menu
36020 * @param {Roo.menu.Item} item The menu item to add
36021 * @return {Roo.menu.Item} The menu item that was added
36023 addItem : function(item){
36024 this.items.add(item);
36026 var li = document.createElement("li");
36027 li.className = "x-menu-list-item";
36028 this.ul.dom.appendChild(li);
36029 item.render(li, this);
36030 this.delayAutoWidth();
36036 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
36037 * @param {Object} config A MenuItem config object
36038 * @return {Roo.menu.Item} The menu item that was added
36040 addMenuItem : function(config){
36041 if(!(config instanceof Roo.menu.Item)){
36042 if(typeof config.checked == "boolean"){ // must be check menu item config?
36043 config = new Roo.menu.CheckItem(config);
36045 config = new Roo.menu.Item(config);
36048 return this.addItem(config);
36052 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
36053 * @param {String} text The text to display in the menu item
36054 * @return {Roo.menu.Item} The menu item that was added
36056 addText : function(text){
36057 return this.addItem(new Roo.menu.TextItem({ text : text }));
36061 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
36062 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
36063 * @param {Roo.menu.Item} item The menu item to add
36064 * @return {Roo.menu.Item} The menu item that was added
36066 insert : function(index, item){
36067 this.items.insert(index, item);
36069 var li = document.createElement("li");
36070 li.className = "x-menu-list-item";
36071 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
36072 item.render(li, this);
36073 this.delayAutoWidth();
36079 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
36080 * @param {Roo.menu.Item} item The menu item to remove
36082 remove : function(item){
36083 this.items.removeKey(item.id);
36088 * Removes and destroys all items in the menu
36090 removeAll : function(){
36092 while(f = this.items.first()){
36098 // MenuNav is a private utility class used internally by the Menu
36099 Roo.menu.MenuNav = function(menu){
36100 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
36101 this.scope = this.menu = menu;
36104 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
36105 doRelay : function(e, h){
36106 var k = e.getKey();
36107 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
36108 this.menu.tryActivate(0, 1);
36111 return h.call(this.scope || this, e, this.menu);
36114 up : function(e, m){
36115 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
36116 m.tryActivate(m.items.length-1, -1);
36120 down : function(e, m){
36121 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
36122 m.tryActivate(0, 1);
36126 right : function(e, m){
36128 m.activeItem.expandMenu(true);
36132 left : function(e, m){
36134 if(m.parentMenu && m.parentMenu.activeItem){
36135 m.parentMenu.activeItem.activate();
36139 enter : function(e, m){
36141 e.stopPropagation();
36142 m.activeItem.onClick(e);
36143 m.fireEvent("click", this, m.activeItem);
36149 * Ext JS Library 1.1.1
36150 * Copyright(c) 2006-2007, Ext JS, LLC.
36152 * Originally Released Under LGPL - original licence link has changed is not relivant.
36155 * <script type="text/javascript">
36159 * @class Roo.menu.MenuMgr
36160 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
36163 Roo.menu.MenuMgr = function(){
36164 var menus, active, groups = {}, attached = false, lastShow = new Date();
36166 // private - called when first menu is created
36169 active = new Roo.util.MixedCollection();
36170 Roo.get(document).addKeyListener(27, function(){
36171 if(active.length > 0){
36178 function hideAll(){
36179 if(active && active.length > 0){
36180 var c = active.clone();
36181 c.each(function(m){
36188 function onHide(m){
36190 if(active.length < 1){
36191 Roo.get(document).un("mousedown", onMouseDown);
36197 function onShow(m){
36198 var last = active.last();
36199 lastShow = new Date();
36202 Roo.get(document).on("mousedown", onMouseDown);
36206 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
36207 m.parentMenu.activeChild = m;
36208 }else if(last && last.isVisible()){
36209 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
36214 function onBeforeHide(m){
36216 m.activeChild.hide();
36218 if(m.autoHideTimer){
36219 clearTimeout(m.autoHideTimer);
36220 delete m.autoHideTimer;
36225 function onBeforeShow(m){
36226 var pm = m.parentMenu;
36227 if(!pm && !m.allowOtherMenus){
36229 }else if(pm && pm.activeChild && active != m){
36230 pm.activeChild.hide();
36235 function onMouseDown(e){
36236 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36242 function onBeforeCheck(mi, state){
36244 var g = groups[mi.group];
36245 for(var i = 0, l = g.length; i < l; i++){
36247 g[i].setChecked(false);
36256 * Hides all menus that are currently visible
36258 hideAll : function(){
36263 register : function(menu){
36267 menus[menu.id] = menu;
36268 menu.on("beforehide", onBeforeHide);
36269 menu.on("hide", onHide);
36270 menu.on("beforeshow", onBeforeShow);
36271 menu.on("show", onShow);
36272 var g = menu.group;
36273 if(g && menu.events["checkchange"]){
36277 groups[g].push(menu);
36278 menu.on("checkchange", onCheck);
36283 * Returns a {@link Roo.menu.Menu} object
36284 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36285 * be used to generate and return a new Menu instance.
36287 get : function(menu){
36288 if(typeof menu == "string"){ // menu id
36289 return menus[menu];
36290 }else if(menu.events){ // menu instance
36292 }else if(typeof menu.length == 'number'){ // array of menu items?
36293 return new Roo.menu.Menu({items:menu});
36294 }else{ // otherwise, must be a config
36295 return new Roo.menu.Menu(menu);
36300 unregister : function(menu){
36301 delete menus[menu.id];
36302 menu.un("beforehide", onBeforeHide);
36303 menu.un("hide", onHide);
36304 menu.un("beforeshow", onBeforeShow);
36305 menu.un("show", onShow);
36306 var g = menu.group;
36307 if(g && menu.events["checkchange"]){
36308 groups[g].remove(menu);
36309 menu.un("checkchange", onCheck);
36314 registerCheckable : function(menuItem){
36315 var g = menuItem.group;
36320 groups[g].push(menuItem);
36321 menuItem.on("beforecheckchange", onBeforeCheck);
36326 unregisterCheckable : function(menuItem){
36327 var g = menuItem.group;
36329 groups[g].remove(menuItem);
36330 menuItem.un("beforecheckchange", onBeforeCheck);
36336 * Ext JS Library 1.1.1
36337 * Copyright(c) 2006-2007, Ext JS, LLC.
36339 * Originally Released Under LGPL - original licence link has changed is not relivant.
36342 * <script type="text/javascript">
36347 * @class Roo.menu.BaseItem
36348 * @extends Roo.Component
36349 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36350 * management and base configuration options shared by all menu components.
36352 * Creates a new BaseItem
36353 * @param {Object} config Configuration options
36355 Roo.menu.BaseItem = function(config){
36356 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36361 * Fires when this item is clicked
36362 * @param {Roo.menu.BaseItem} this
36363 * @param {Roo.EventObject} e
36368 * Fires when this item is activated
36369 * @param {Roo.menu.BaseItem} this
36373 * @event deactivate
36374 * Fires when this item is deactivated
36375 * @param {Roo.menu.BaseItem} this
36381 this.on("click", this.handler, this.scope, true);
36385 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36387 * @cfg {Function} handler
36388 * A function that will handle the click event of this menu item (defaults to undefined)
36391 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36393 canActivate : false,
36396 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36401 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36403 activeClass : "x-menu-item-active",
36405 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36407 hideOnClick : true,
36409 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36414 ctype: "Roo.menu.BaseItem",
36417 actionMode : "container",
36420 render : function(container, parentMenu){
36421 this.parentMenu = parentMenu;
36422 Roo.menu.BaseItem.superclass.render.call(this, container);
36423 this.container.menuItemId = this.id;
36427 onRender : function(container, position){
36428 this.el = Roo.get(this.el);
36429 container.dom.appendChild(this.el.dom);
36433 onClick : function(e){
36434 if(!this.disabled && this.fireEvent("click", this, e) !== false
36435 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36436 this.handleClick(e);
36443 activate : function(){
36447 var li = this.container;
36448 li.addClass(this.activeClass);
36449 this.region = li.getRegion().adjust(2, 2, -2, -2);
36450 this.fireEvent("activate", this);
36455 deactivate : function(){
36456 this.container.removeClass(this.activeClass);
36457 this.fireEvent("deactivate", this);
36461 shouldDeactivate : function(e){
36462 return !this.region || !this.region.contains(e.getPoint());
36466 handleClick : function(e){
36467 if(this.hideOnClick){
36468 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36473 expandMenu : function(autoActivate){
36478 hideMenu : function(){
36483 * Ext JS Library 1.1.1
36484 * Copyright(c) 2006-2007, Ext JS, LLC.
36486 * Originally Released Under LGPL - original licence link has changed is not relivant.
36489 * <script type="text/javascript">
36493 * @class Roo.menu.Adapter
36494 * @extends Roo.menu.BaseItem
36495 * 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.
36496 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36498 * Creates a new Adapter
36499 * @param {Object} config Configuration options
36501 Roo.menu.Adapter = function(component, config){
36502 Roo.menu.Adapter.superclass.constructor.call(this, config);
36503 this.component = component;
36505 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36507 canActivate : true,
36510 onRender : function(container, position){
36511 this.component.render(container);
36512 this.el = this.component.getEl();
36516 activate : function(){
36520 this.component.focus();
36521 this.fireEvent("activate", this);
36526 deactivate : function(){
36527 this.fireEvent("deactivate", this);
36531 disable : function(){
36532 this.component.disable();
36533 Roo.menu.Adapter.superclass.disable.call(this);
36537 enable : function(){
36538 this.component.enable();
36539 Roo.menu.Adapter.superclass.enable.call(this);
36543 * Ext JS Library 1.1.1
36544 * Copyright(c) 2006-2007, Ext JS, LLC.
36546 * Originally Released Under LGPL - original licence link has changed is not relivant.
36549 * <script type="text/javascript">
36553 * @class Roo.menu.TextItem
36554 * @extends Roo.menu.BaseItem
36555 * Adds a static text string to a menu, usually used as either a heading or group separator.
36556 * Note: old style constructor with text is still supported.
36559 * Creates a new TextItem
36560 * @param {Object} cfg Configuration
36562 Roo.menu.TextItem = function(cfg){
36563 if (typeof(cfg) == 'string') {
36566 Roo.apply(this,cfg);
36569 Roo.menu.TextItem.superclass.constructor.call(this);
36572 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36574 * @cfg {Boolean} text Text to show on item.
36579 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36581 hideOnClick : false,
36583 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36585 itemCls : "x-menu-text",
36588 onRender : function(){
36589 var s = document.createElement("span");
36590 s.className = this.itemCls;
36591 s.innerHTML = this.text;
36593 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36597 * Ext JS Library 1.1.1
36598 * Copyright(c) 2006-2007, Ext JS, LLC.
36600 * Originally Released Under LGPL - original licence link has changed is not relivant.
36603 * <script type="text/javascript">
36607 * @class Roo.menu.Separator
36608 * @extends Roo.menu.BaseItem
36609 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36610 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36612 * @param {Object} config Configuration options
36614 Roo.menu.Separator = function(config){
36615 Roo.menu.Separator.superclass.constructor.call(this, config);
36618 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36620 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36622 itemCls : "x-menu-sep",
36624 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36626 hideOnClick : false,
36629 onRender : function(li){
36630 var s = document.createElement("span");
36631 s.className = this.itemCls;
36632 s.innerHTML = " ";
36634 li.addClass("x-menu-sep-li");
36635 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36639 * Ext JS Library 1.1.1
36640 * Copyright(c) 2006-2007, Ext JS, LLC.
36642 * Originally Released Under LGPL - original licence link has changed is not relivant.
36645 * <script type="text/javascript">
36648 * @class Roo.menu.Item
36649 * @extends Roo.menu.BaseItem
36650 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36651 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36652 * activation and click handling.
36654 * Creates a new Item
36655 * @param {Object} config Configuration options
36657 Roo.menu.Item = function(config){
36658 Roo.menu.Item.superclass.constructor.call(this, config);
36660 this.menu = Roo.menu.MenuMgr.get(this.menu);
36663 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36666 * @cfg {String} text
36667 * The text to show on the menu item.
36671 * @cfg {String} HTML to render in menu
36672 * The text to show on the menu item (HTML version).
36676 * @cfg {String} icon
36677 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36681 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36683 itemCls : "x-menu-item",
36685 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36687 canActivate : true,
36689 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36692 // doc'd in BaseItem
36696 ctype: "Roo.menu.Item",
36699 onRender : function(container, position){
36700 var el = document.createElement("a");
36701 el.hideFocus = true;
36702 el.unselectable = "on";
36703 el.href = this.href || "#";
36704 if(this.hrefTarget){
36705 el.target = this.hrefTarget;
36707 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36709 var html = this.html.length ? this.html : String.format('{0}',this.text);
36711 el.innerHTML = String.format(
36712 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36713 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36715 Roo.menu.Item.superclass.onRender.call(this, container, position);
36719 * Sets the text to display in this menu item
36720 * @param {String} text The text to display
36721 * @param {Boolean} isHTML true to indicate text is pure html.
36723 setText : function(text, isHTML){
36731 var html = this.html.length ? this.html : String.format('{0}',this.text);
36733 this.el.update(String.format(
36734 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36735 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36736 this.parentMenu.autoWidth();
36741 handleClick : function(e){
36742 if(!this.href){ // if no link defined, stop the event automatically
36745 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36749 activate : function(autoExpand){
36750 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36760 shouldDeactivate : function(e){
36761 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36762 if(this.menu && this.menu.isVisible()){
36763 return !this.menu.getEl().getRegion().contains(e.getPoint());
36771 deactivate : function(){
36772 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36777 expandMenu : function(autoActivate){
36778 if(!this.disabled && this.menu){
36779 clearTimeout(this.hideTimer);
36780 delete this.hideTimer;
36781 if(!this.menu.isVisible() && !this.showTimer){
36782 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36783 }else if (this.menu.isVisible() && autoActivate){
36784 this.menu.tryActivate(0, 1);
36790 deferExpand : function(autoActivate){
36791 delete this.showTimer;
36792 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36794 this.menu.tryActivate(0, 1);
36799 hideMenu : function(){
36800 clearTimeout(this.showTimer);
36801 delete this.showTimer;
36802 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36803 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36808 deferHide : function(){
36809 delete this.hideTimer;
36814 * Ext JS Library 1.1.1
36815 * Copyright(c) 2006-2007, Ext JS, LLC.
36817 * Originally Released Under LGPL - original licence link has changed is not relivant.
36820 * <script type="text/javascript">
36824 * @class Roo.menu.CheckItem
36825 * @extends Roo.menu.Item
36826 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36828 * Creates a new CheckItem
36829 * @param {Object} config Configuration options
36831 Roo.menu.CheckItem = function(config){
36832 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36835 * @event beforecheckchange
36836 * Fires before the checked value is set, providing an opportunity to cancel if needed
36837 * @param {Roo.menu.CheckItem} this
36838 * @param {Boolean} checked The new checked value that will be set
36840 "beforecheckchange" : true,
36842 * @event checkchange
36843 * Fires after the checked value has been set
36844 * @param {Roo.menu.CheckItem} this
36845 * @param {Boolean} checked The checked value that was set
36847 "checkchange" : true
36849 if(this.checkHandler){
36850 this.on('checkchange', this.checkHandler, this.scope);
36853 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36855 * @cfg {String} group
36856 * All check items with the same group name will automatically be grouped into a single-select
36857 * radio button group (defaults to '')
36860 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36862 itemCls : "x-menu-item x-menu-check-item",
36864 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36866 groupClass : "x-menu-group-item",
36869 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36870 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36871 * initialized with checked = true will be rendered as checked.
36876 ctype: "Roo.menu.CheckItem",
36879 onRender : function(c){
36880 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36882 this.el.addClass(this.groupClass);
36884 Roo.menu.MenuMgr.registerCheckable(this);
36886 this.checked = false;
36887 this.setChecked(true, true);
36892 destroy : function(){
36894 Roo.menu.MenuMgr.unregisterCheckable(this);
36896 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36900 * Set the checked state of this item
36901 * @param {Boolean} checked The new checked value
36902 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36904 setChecked : function(state, suppressEvent){
36905 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36906 if(this.container){
36907 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36909 this.checked = state;
36910 if(suppressEvent !== true){
36911 this.fireEvent("checkchange", this, state);
36917 handleClick : function(e){
36918 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36919 this.setChecked(!this.checked);
36921 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36925 * Ext JS Library 1.1.1
36926 * Copyright(c) 2006-2007, Ext JS, LLC.
36928 * Originally Released Under LGPL - original licence link has changed is not relivant.
36931 * <script type="text/javascript">
36935 * @class Roo.menu.DateItem
36936 * @extends Roo.menu.Adapter
36937 * A menu item that wraps the {@link Roo.DatPicker} component.
36939 * Creates a new DateItem
36940 * @param {Object} config Configuration options
36942 Roo.menu.DateItem = function(config){
36943 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36944 /** The Roo.DatePicker object @type Roo.DatePicker */
36945 this.picker = this.component;
36946 this.addEvents({select: true});
36948 this.picker.on("render", function(picker){
36949 picker.getEl().swallowEvent("click");
36950 picker.container.addClass("x-menu-date-item");
36953 this.picker.on("select", this.onSelect, this);
36956 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36958 onSelect : function(picker, date){
36959 this.fireEvent("select", this, date, picker);
36960 Roo.menu.DateItem.superclass.handleClick.call(this);
36964 * Ext JS Library 1.1.1
36965 * Copyright(c) 2006-2007, Ext JS, LLC.
36967 * Originally Released Under LGPL - original licence link has changed is not relivant.
36970 * <script type="text/javascript">
36974 * @class Roo.menu.ColorItem
36975 * @extends Roo.menu.Adapter
36976 * A menu item that wraps the {@link Roo.ColorPalette} component.
36978 * Creates a new ColorItem
36979 * @param {Object} config Configuration options
36981 Roo.menu.ColorItem = function(config){
36982 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36983 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36984 this.palette = this.component;
36985 this.relayEvents(this.palette, ["select"]);
36986 if(this.selectHandler){
36987 this.on('select', this.selectHandler, this.scope);
36990 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36992 * Ext JS Library 1.1.1
36993 * Copyright(c) 2006-2007, Ext JS, LLC.
36995 * Originally Released Under LGPL - original licence link has changed is not relivant.
36998 * <script type="text/javascript">
37003 * @class Roo.menu.DateMenu
37004 * @extends Roo.menu.Menu
37005 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
37007 * Creates a new DateMenu
37008 * @param {Object} config Configuration options
37010 Roo.menu.DateMenu = function(config){
37011 Roo.menu.DateMenu.superclass.constructor.call(this, config);
37013 var di = new Roo.menu.DateItem(config);
37016 * The {@link Roo.DatePicker} instance for this DateMenu
37019 this.picker = di.picker;
37022 * @param {DatePicker} picker
37023 * @param {Date} date
37025 this.relayEvents(di, ["select"]);
37026 this.on('beforeshow', function(){
37028 this.picker.hideMonthPicker(false);
37032 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
37036 * Ext JS Library 1.1.1
37037 * Copyright(c) 2006-2007, Ext JS, LLC.
37039 * Originally Released Under LGPL - original licence link has changed is not relivant.
37042 * <script type="text/javascript">
37047 * @class Roo.menu.ColorMenu
37048 * @extends Roo.menu.Menu
37049 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
37051 * Creates a new ColorMenu
37052 * @param {Object} config Configuration options
37054 Roo.menu.ColorMenu = function(config){
37055 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
37057 var ci = new Roo.menu.ColorItem(config);
37060 * The {@link Roo.ColorPalette} instance for this ColorMenu
37061 * @type ColorPalette
37063 this.palette = ci.palette;
37066 * @param {ColorPalette} palette
37067 * @param {String} color
37069 this.relayEvents(ci, ["select"]);
37071 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
37073 * Ext JS Library 1.1.1
37074 * Copyright(c) 2006-2007, Ext JS, LLC.
37076 * Originally Released Under LGPL - original licence link has changed is not relivant.
37079 * <script type="text/javascript">
37083 * @class Roo.form.Field
37084 * @extends Roo.BoxComponent
37085 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
37087 * Creates a new Field
37088 * @param {Object} config Configuration options
37090 Roo.form.Field = function(config){
37091 Roo.form.Field.superclass.constructor.call(this, config);
37094 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
37096 * @cfg {String} fieldLabel Label to use when rendering a form.
37099 * @cfg {String} qtip Mouse over tip
37103 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
37105 invalidClass : "x-form-invalid",
37107 * @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")
37109 invalidText : "The value in this field is invalid",
37111 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
37113 focusClass : "x-form-focus",
37115 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
37116 automatic validation (defaults to "keyup").
37118 validationEvent : "keyup",
37120 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
37122 validateOnBlur : true,
37124 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
37126 validationDelay : 250,
37128 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37129 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
37131 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
37133 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
37135 fieldClass : "x-form-field",
37137 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
37140 ----------- ----------------------------------------------------------------------
37141 qtip Display a quick tip when the user hovers over the field
37142 title Display a default browser title attribute popup
37143 under Add a block div beneath the field containing the error text
37144 side Add an error icon to the right of the field with a popup on hover
37145 [element id] Add the error text directly to the innerHTML of the specified element
37148 msgTarget : 'qtip',
37150 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
37155 * @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.
37160 * @cfg {Boolean} disabled True to disable the field (defaults to false).
37165 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
37167 inputType : undefined,
37170 * @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).
37172 tabIndex : undefined,
37175 isFormField : true,
37180 * @property {Roo.Element} fieldEl
37181 * Element Containing the rendered Field (with label etc.)
37184 * @cfg {Mixed} value A value to initialize this field with.
37189 * @cfg {String} name The field's HTML name attribute.
37192 * @cfg {String} cls A CSS class to apply to the field's underlying element.
37195 loadedValue : false,
37199 initComponent : function(){
37200 Roo.form.Field.superclass.initComponent.call(this);
37204 * Fires when this field receives input focus.
37205 * @param {Roo.form.Field} this
37210 * Fires when this field loses input focus.
37211 * @param {Roo.form.Field} this
37215 * @event specialkey
37216 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
37217 * {@link Roo.EventObject#getKey} to determine which key was pressed.
37218 * @param {Roo.form.Field} this
37219 * @param {Roo.EventObject} e The event object
37224 * Fires just before the field blurs if the field value has changed.
37225 * @param {Roo.form.Field} this
37226 * @param {Mixed} newValue The new value
37227 * @param {Mixed} oldValue The original value
37232 * Fires after the field has been marked as invalid.
37233 * @param {Roo.form.Field} this
37234 * @param {String} msg The validation message
37239 * Fires after the field has been validated with no errors.
37240 * @param {Roo.form.Field} this
37245 * Fires after the key up
37246 * @param {Roo.form.Field} this
37247 * @param {Roo.EventObject} e The event Object
37254 * Returns the name attribute of the field if available
37255 * @return {String} name The field name
37257 getName: function(){
37258 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37262 onRender : function(ct, position){
37263 Roo.form.Field.superclass.onRender.call(this, ct, position);
37265 var cfg = this.getAutoCreate();
37267 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37269 if (!cfg.name.length) {
37272 if(this.inputType){
37273 cfg.type = this.inputType;
37275 this.el = ct.createChild(cfg, position);
37277 var type = this.el.dom.type;
37279 if(type == 'password'){
37282 this.el.addClass('x-form-'+type);
37285 this.el.dom.readOnly = true;
37287 if(this.tabIndex !== undefined){
37288 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37291 this.el.addClass([this.fieldClass, this.cls]);
37296 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37297 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37298 * @return {Roo.form.Field} this
37300 applyTo : function(target){
37301 this.allowDomMove = false;
37302 this.el = Roo.get(target);
37303 this.render(this.el.dom.parentNode);
37308 initValue : function(){
37309 if(this.value !== undefined){
37310 this.setValue(this.value);
37311 }else if(this.el.dom.value.length > 0){
37312 this.setValue(this.el.dom.value);
37317 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37318 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
37320 isDirty : function() {
37321 if(this.disabled) {
37324 return String(this.getValue()) !== String(this.originalValue);
37328 * stores the current value in loadedValue
37330 resetHasChanged : function()
37332 this.loadedValue = String(this.getValue());
37335 * checks the current value against the 'loaded' value.
37336 * Note - will return false if 'resetHasChanged' has not been called first.
37338 hasChanged : function()
37340 if(this.disabled || this.readOnly) {
37343 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
37349 afterRender : function(){
37350 Roo.form.Field.superclass.afterRender.call(this);
37355 fireKey : function(e){
37356 //Roo.log('field ' + e.getKey());
37357 if(e.isNavKeyPress()){
37358 this.fireEvent("specialkey", this, e);
37363 * Resets the current field value to the originally loaded value and clears any validation messages
37365 reset : function(){
37366 this.setValue(this.resetValue);
37367 this.clearInvalid();
37371 initEvents : function(){
37372 // safari killled keypress - so keydown is now used..
37373 this.el.on("keydown" , this.fireKey, this);
37374 this.el.on("focus", this.onFocus, this);
37375 this.el.on("blur", this.onBlur, this);
37376 this.el.relayEvent('keyup', this);
37378 // reference to original value for reset
37379 this.originalValue = this.getValue();
37380 this.resetValue = this.getValue();
37384 onFocus : function(){
37385 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37386 this.el.addClass(this.focusClass);
37388 if(!this.hasFocus){
37389 this.hasFocus = true;
37390 this.startValue = this.getValue();
37391 this.fireEvent("focus", this);
37395 beforeBlur : Roo.emptyFn,
37398 onBlur : function(){
37400 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37401 this.el.removeClass(this.focusClass);
37403 this.hasFocus = false;
37404 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37407 var v = this.getValue();
37408 if(String(v) !== String(this.startValue)){
37409 this.fireEvent('change', this, v, this.startValue);
37411 this.fireEvent("blur", this);
37415 * Returns whether or not the field value is currently valid
37416 * @param {Boolean} preventMark True to disable marking the field invalid
37417 * @return {Boolean} True if the value is valid, else false
37419 isValid : function(preventMark){
37423 var restore = this.preventMark;
37424 this.preventMark = preventMark === true;
37425 var v = this.validateValue(this.processValue(this.getRawValue()));
37426 this.preventMark = restore;
37431 * Validates the field value
37432 * @return {Boolean} True if the value is valid, else false
37434 validate : function(){
37435 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37436 this.clearInvalid();
37442 processValue : function(value){
37447 // Subclasses should provide the validation implementation by overriding this
37448 validateValue : function(value){
37453 * Mark this field as invalid
37454 * @param {String} msg The validation message
37456 markInvalid : function(msg){
37457 if(!this.rendered || this.preventMark){ // not rendered
37461 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37463 obj.el.addClass(this.invalidClass);
37464 msg = msg || this.invalidText;
37465 switch(this.msgTarget){
37467 obj.el.dom.qtip = msg;
37468 obj.el.dom.qclass = 'x-form-invalid-tip';
37469 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37470 Roo.QuickTips.enable();
37474 this.el.dom.title = msg;
37478 var elp = this.el.findParent('.x-form-element', 5, true);
37479 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37480 this.errorEl.setWidth(elp.getWidth(true)-20);
37482 this.errorEl.update(msg);
37483 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37486 if(!this.errorIcon){
37487 var elp = this.el.findParent('.x-form-element', 5, true);
37488 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37490 this.alignErrorIcon();
37491 this.errorIcon.dom.qtip = msg;
37492 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37493 this.errorIcon.show();
37494 this.on('resize', this.alignErrorIcon, this);
37497 var t = Roo.getDom(this.msgTarget);
37499 t.style.display = this.msgDisplay;
37502 this.fireEvent('invalid', this, msg);
37506 alignErrorIcon : function(){
37507 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37511 * Clear any invalid styles/messages for this field
37513 clearInvalid : function(){
37514 if(!this.rendered || this.preventMark){ // not rendered
37517 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37519 obj.el.removeClass(this.invalidClass);
37520 switch(this.msgTarget){
37522 obj.el.dom.qtip = '';
37525 this.el.dom.title = '';
37529 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37533 if(this.errorIcon){
37534 this.errorIcon.dom.qtip = '';
37535 this.errorIcon.hide();
37536 this.un('resize', this.alignErrorIcon, this);
37540 var t = Roo.getDom(this.msgTarget);
37542 t.style.display = 'none';
37545 this.fireEvent('valid', this);
37549 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37550 * @return {Mixed} value The field value
37552 getRawValue : function(){
37553 var v = this.el.getValue();
37559 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37560 * @return {Mixed} value The field value
37562 getValue : function(){
37563 var v = this.el.getValue();
37569 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37570 * @param {Mixed} value The value to set
37572 setRawValue : function(v){
37573 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37577 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37578 * @param {Mixed} value The value to set
37580 setValue : function(v){
37583 this.el.dom.value = (v === null || v === undefined ? '' : v);
37588 adjustSize : function(w, h){
37589 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37590 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37594 adjustWidth : function(tag, w){
37595 tag = tag.toLowerCase();
37596 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37597 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37598 if(tag == 'input'){
37601 if(tag == 'textarea'){
37604 }else if(Roo.isOpera){
37605 if(tag == 'input'){
37608 if(tag == 'textarea'){
37618 // anything other than normal should be considered experimental
37619 Roo.form.Field.msgFx = {
37621 show: function(msgEl, f){
37622 msgEl.setDisplayed('block');
37625 hide : function(msgEl, f){
37626 msgEl.setDisplayed(false).update('');
37631 show: function(msgEl, f){
37632 msgEl.slideIn('t', {stopFx:true});
37635 hide : function(msgEl, f){
37636 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37641 show: function(msgEl, f){
37642 msgEl.fixDisplay();
37643 msgEl.alignTo(f.el, 'tl-tr');
37644 msgEl.slideIn('l', {stopFx:true});
37647 hide : function(msgEl, f){
37648 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37653 * Ext JS Library 1.1.1
37654 * Copyright(c) 2006-2007, Ext JS, LLC.
37656 * Originally Released Under LGPL - original licence link has changed is not relivant.
37659 * <script type="text/javascript">
37664 * @class Roo.form.TextField
37665 * @extends Roo.form.Field
37666 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37667 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37669 * Creates a new TextField
37670 * @param {Object} config Configuration options
37672 Roo.form.TextField = function(config){
37673 Roo.form.TextField.superclass.constructor.call(this, config);
37677 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37678 * according to the default logic, but this event provides a hook for the developer to apply additional
37679 * logic at runtime to resize the field if needed.
37680 * @param {Roo.form.Field} this This text field
37681 * @param {Number} width The new field width
37687 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37689 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37693 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37697 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37701 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37705 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37709 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37711 disableKeyFilter : false,
37713 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37717 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37721 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37723 maxLength : Number.MAX_VALUE,
37725 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37727 minLengthText : "The minimum length for this field is {0}",
37729 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37731 maxLengthText : "The maximum length for this field is {0}",
37733 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37735 selectOnFocus : false,
37737 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37739 blankText : "This field is required",
37741 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37742 * If available, this function will be called only after the basic validators all return true, and will be passed the
37743 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37747 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37748 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37749 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37753 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37757 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37763 initEvents : function()
37765 if (this.emptyText) {
37766 this.el.attr('placeholder', this.emptyText);
37769 Roo.form.TextField.superclass.initEvents.call(this);
37770 if(this.validationEvent == 'keyup'){
37771 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37772 this.el.on('keyup', this.filterValidation, this);
37774 else if(this.validationEvent !== false){
37775 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37778 if(this.selectOnFocus){
37779 this.on("focus", this.preFocus, this);
37782 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37783 this.el.on("keypress", this.filterKeys, this);
37786 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37787 this.el.on("click", this.autoSize, this);
37789 if(this.el.is('input[type=password]') && Roo.isSafari){
37790 this.el.on('keydown', this.SafariOnKeyDown, this);
37794 processValue : function(value){
37795 if(this.stripCharsRe){
37796 var newValue = value.replace(this.stripCharsRe, '');
37797 if(newValue !== value){
37798 this.setRawValue(newValue);
37805 filterValidation : function(e){
37806 if(!e.isNavKeyPress()){
37807 this.validationTask.delay(this.validationDelay);
37812 onKeyUp : function(e){
37813 if(!e.isNavKeyPress()){
37819 * Resets the current field value to the originally-loaded value and clears any validation messages.
37822 reset : function(){
37823 Roo.form.TextField.superclass.reset.call(this);
37829 preFocus : function(){
37831 if(this.selectOnFocus){
37832 this.el.dom.select();
37838 filterKeys : function(e){
37839 var k = e.getKey();
37840 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37843 var c = e.getCharCode(), cc = String.fromCharCode(c);
37844 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37847 if(!this.maskRe.test(cc)){
37852 setValue : function(v){
37854 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37860 * Validates a value according to the field's validation rules and marks the field as invalid
37861 * if the validation fails
37862 * @param {Mixed} value The value to validate
37863 * @return {Boolean} True if the value is valid, else false
37865 validateValue : function(value){
37866 if(value.length < 1) { // if it's blank
37867 if(this.allowBlank){
37868 this.clearInvalid();
37871 this.markInvalid(this.blankText);
37875 if(value.length < this.minLength){
37876 this.markInvalid(String.format(this.minLengthText, this.minLength));
37879 if(value.length > this.maxLength){
37880 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37884 var vt = Roo.form.VTypes;
37885 if(!vt[this.vtype](value, this)){
37886 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37890 if(typeof this.validator == "function"){
37891 var msg = this.validator(value);
37893 this.markInvalid(msg);
37897 if(this.regex && !this.regex.test(value)){
37898 this.markInvalid(this.regexText);
37905 * Selects text in this field
37906 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37907 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37909 selectText : function(start, end){
37910 var v = this.getRawValue();
37912 start = start === undefined ? 0 : start;
37913 end = end === undefined ? v.length : end;
37914 var d = this.el.dom;
37915 if(d.setSelectionRange){
37916 d.setSelectionRange(start, end);
37917 }else if(d.createTextRange){
37918 var range = d.createTextRange();
37919 range.moveStart("character", start);
37920 range.moveEnd("character", v.length-end);
37927 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37928 * This only takes effect if grow = true, and fires the autosize event.
37930 autoSize : function(){
37931 if(!this.grow || !this.rendered){
37935 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37938 var v = el.dom.value;
37939 var d = document.createElement('div');
37940 d.appendChild(document.createTextNode(v));
37944 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37945 this.el.setWidth(w);
37946 this.fireEvent("autosize", this, w);
37950 SafariOnKeyDown : function(event)
37952 // this is a workaround for a password hang bug on chrome/ webkit.
37954 var isSelectAll = false;
37956 if(this.el.dom.selectionEnd > 0){
37957 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37959 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37960 event.preventDefault();
37965 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
37967 event.preventDefault();
37968 // this is very hacky as keydown always get's upper case.
37970 var cc = String.fromCharCode(event.getCharCode());
37973 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37981 * Ext JS Library 1.1.1
37982 * Copyright(c) 2006-2007, Ext JS, LLC.
37984 * Originally Released Under LGPL - original licence link has changed is not relivant.
37987 * <script type="text/javascript">
37991 * @class Roo.form.Hidden
37992 * @extends Roo.form.TextField
37993 * Simple Hidden element used on forms
37995 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37998 * Creates a new Hidden form element.
37999 * @param {Object} config Configuration options
38004 // easy hidden field...
38005 Roo.form.Hidden = function(config){
38006 Roo.form.Hidden.superclass.constructor.call(this, config);
38009 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
38011 inputType: 'hidden',
38014 labelSeparator: '',
38016 itemCls : 'x-form-item-display-none'
38024 * Ext JS Library 1.1.1
38025 * Copyright(c) 2006-2007, Ext JS, LLC.
38027 * Originally Released Under LGPL - original licence link has changed is not relivant.
38030 * <script type="text/javascript">
38034 * @class Roo.form.TriggerField
38035 * @extends Roo.form.TextField
38036 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
38037 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
38038 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
38039 * for which you can provide a custom implementation. For example:
38041 var trigger = new Roo.form.TriggerField();
38042 trigger.onTriggerClick = myTriggerFn;
38043 trigger.applyTo('my-field');
38046 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
38047 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
38048 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
38049 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
38051 * Create a new TriggerField.
38052 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
38053 * to the base TextField)
38055 Roo.form.TriggerField = function(config){
38056 this.mimicing = false;
38057 Roo.form.TriggerField.superclass.constructor.call(this, config);
38060 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
38062 * @cfg {String} triggerClass A CSS class to apply to the trigger
38065 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38066 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
38068 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
38070 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
38074 /** @cfg {Boolean} grow @hide */
38075 /** @cfg {Number} growMin @hide */
38076 /** @cfg {Number} growMax @hide */
38082 autoSize: Roo.emptyFn,
38086 deferHeight : true,
38089 actionMode : 'wrap',
38091 onResize : function(w, h){
38092 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
38093 if(typeof w == 'number'){
38094 var x = w - this.trigger.getWidth();
38095 this.el.setWidth(this.adjustWidth('input', x));
38096 this.trigger.setStyle('left', x+'px');
38101 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38104 getResizeEl : function(){
38109 getPositionEl : function(){
38114 alignErrorIcon : function(){
38115 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
38119 onRender : function(ct, position){
38120 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
38121 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
38122 this.trigger = this.wrap.createChild(this.triggerConfig ||
38123 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
38124 if(this.hideTrigger){
38125 this.trigger.setDisplayed(false);
38127 this.initTrigger();
38129 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
38134 initTrigger : function(){
38135 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
38136 this.trigger.addClassOnOver('x-form-trigger-over');
38137 this.trigger.addClassOnClick('x-form-trigger-click');
38141 onDestroy : function(){
38143 this.trigger.removeAllListeners();
38144 this.trigger.remove();
38147 this.wrap.remove();
38149 Roo.form.TriggerField.superclass.onDestroy.call(this);
38153 onFocus : function(){
38154 Roo.form.TriggerField.superclass.onFocus.call(this);
38155 if(!this.mimicing){
38156 this.wrap.addClass('x-trigger-wrap-focus');
38157 this.mimicing = true;
38158 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
38159 if(this.monitorTab){
38160 this.el.on("keydown", this.checkTab, this);
38166 checkTab : function(e){
38167 if(e.getKey() == e.TAB){
38168 this.triggerBlur();
38173 onBlur : function(){
38178 mimicBlur : function(e, t){
38179 if(!this.wrap.contains(t) && this.validateBlur()){
38180 this.triggerBlur();
38185 triggerBlur : function(){
38186 this.mimicing = false;
38187 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
38188 if(this.monitorTab){
38189 this.el.un("keydown", this.checkTab, this);
38191 this.wrap.removeClass('x-trigger-wrap-focus');
38192 Roo.form.TriggerField.superclass.onBlur.call(this);
38196 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
38197 validateBlur : function(e, t){
38202 onDisable : function(){
38203 Roo.form.TriggerField.superclass.onDisable.call(this);
38205 this.wrap.addClass('x-item-disabled');
38210 onEnable : function(){
38211 Roo.form.TriggerField.superclass.onEnable.call(this);
38213 this.wrap.removeClass('x-item-disabled');
38218 onShow : function(){
38219 var ae = this.getActionEl();
38222 ae.dom.style.display = '';
38223 ae.dom.style.visibility = 'visible';
38229 onHide : function(){
38230 var ae = this.getActionEl();
38231 ae.dom.style.display = 'none';
38235 * The function that should handle the trigger's click event. This method does nothing by default until overridden
38236 * by an implementing function.
38238 * @param {EventObject} e
38240 onTriggerClick : Roo.emptyFn
38243 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
38244 // to be extended by an implementing class. For an example of implementing this class, see the custom
38245 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
38246 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
38247 initComponent : function(){
38248 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
38250 this.triggerConfig = {
38251 tag:'span', cls:'x-form-twin-triggers', cn:[
38252 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38253 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38257 getTrigger : function(index){
38258 return this.triggers[index];
38261 initTrigger : function(){
38262 var ts = this.trigger.select('.x-form-trigger', true);
38263 this.wrap.setStyle('overflow', 'hidden');
38264 var triggerField = this;
38265 ts.each(function(t, all, index){
38266 t.hide = function(){
38267 var w = triggerField.wrap.getWidth();
38268 this.dom.style.display = 'none';
38269 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38271 t.show = function(){
38272 var w = triggerField.wrap.getWidth();
38273 this.dom.style.display = '';
38274 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38276 var triggerIndex = 'Trigger'+(index+1);
38278 if(this['hide'+triggerIndex]){
38279 t.dom.style.display = 'none';
38281 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38282 t.addClassOnOver('x-form-trigger-over');
38283 t.addClassOnClick('x-form-trigger-click');
38285 this.triggers = ts.elements;
38288 onTrigger1Click : Roo.emptyFn,
38289 onTrigger2Click : Roo.emptyFn
38292 * Ext JS Library 1.1.1
38293 * Copyright(c) 2006-2007, Ext JS, LLC.
38295 * Originally Released Under LGPL - original licence link has changed is not relivant.
38298 * <script type="text/javascript">
38302 * @class Roo.form.TextArea
38303 * @extends Roo.form.TextField
38304 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38305 * support for auto-sizing.
38307 * Creates a new TextArea
38308 * @param {Object} config Configuration options
38310 Roo.form.TextArea = function(config){
38311 Roo.form.TextArea.superclass.constructor.call(this, config);
38312 // these are provided exchanges for backwards compat
38313 // minHeight/maxHeight were replaced by growMin/growMax to be
38314 // compatible with TextField growing config values
38315 if(this.minHeight !== undefined){
38316 this.growMin = this.minHeight;
38318 if(this.maxHeight !== undefined){
38319 this.growMax = this.maxHeight;
38323 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38325 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38329 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38333 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38334 * in the field (equivalent to setting overflow: hidden, defaults to false)
38336 preventScrollbars: false,
38338 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38339 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38343 onRender : function(ct, position){
38345 this.defaultAutoCreate = {
38347 style:"width:300px;height:60px;",
38348 autocomplete: "new-password"
38351 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38353 this.textSizeEl = Roo.DomHelper.append(document.body, {
38354 tag: "pre", cls: "x-form-grow-sizer"
38356 if(this.preventScrollbars){
38357 this.el.setStyle("overflow", "hidden");
38359 this.el.setHeight(this.growMin);
38363 onDestroy : function(){
38364 if(this.textSizeEl){
38365 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38367 Roo.form.TextArea.superclass.onDestroy.call(this);
38371 onKeyUp : function(e){
38372 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38378 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38379 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38381 autoSize : function(){
38382 if(!this.grow || !this.textSizeEl){
38386 var v = el.dom.value;
38387 var ts = this.textSizeEl;
38390 ts.appendChild(document.createTextNode(v));
38393 Roo.fly(ts).setWidth(this.el.getWidth());
38395 v = "  ";
38398 v = v.replace(/\n/g, '<p> </p>');
38400 v += " \n ";
38403 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38404 if(h != this.lastHeight){
38405 this.lastHeight = h;
38406 this.el.setHeight(h);
38407 this.fireEvent("autosize", this, h);
38412 * Ext JS Library 1.1.1
38413 * Copyright(c) 2006-2007, Ext JS, LLC.
38415 * Originally Released Under LGPL - original licence link has changed is not relivant.
38418 * <script type="text/javascript">
38423 * @class Roo.form.NumberField
38424 * @extends Roo.form.TextField
38425 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38427 * Creates a new NumberField
38428 * @param {Object} config Configuration options
38430 Roo.form.NumberField = function(config){
38431 Roo.form.NumberField.superclass.constructor.call(this, config);
38434 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38436 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38438 fieldClass: "x-form-field x-form-num-field",
38440 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38442 allowDecimals : true,
38444 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38446 decimalSeparator : ".",
38448 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38450 decimalPrecision : 2,
38452 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38454 allowNegative : true,
38456 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38458 minValue : Number.NEGATIVE_INFINITY,
38460 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38462 maxValue : Number.MAX_VALUE,
38464 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38466 minText : "The minimum value for this field is {0}",
38468 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38470 maxText : "The maximum value for this field is {0}",
38472 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38473 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38475 nanText : "{0} is not a valid number",
38478 initEvents : function(){
38479 Roo.form.NumberField.superclass.initEvents.call(this);
38480 var allowed = "0123456789";
38481 if(this.allowDecimals){
38482 allowed += this.decimalSeparator;
38484 if(this.allowNegative){
38487 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38488 var keyPress = function(e){
38489 var k = e.getKey();
38490 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38493 var c = e.getCharCode();
38494 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38498 this.el.on("keypress", keyPress, this);
38502 validateValue : function(value){
38503 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38506 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38509 var num = this.parseValue(value);
38511 this.markInvalid(String.format(this.nanText, value));
38514 if(num < this.minValue){
38515 this.markInvalid(String.format(this.minText, this.minValue));
38518 if(num > this.maxValue){
38519 this.markInvalid(String.format(this.maxText, this.maxValue));
38525 getValue : function(){
38526 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38530 parseValue : function(value){
38531 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38532 return isNaN(value) ? '' : value;
38536 fixPrecision : function(value){
38537 var nan = isNaN(value);
38538 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38539 return nan ? '' : value;
38541 return parseFloat(value).toFixed(this.decimalPrecision);
38544 setValue : function(v){
38545 v = this.fixPrecision(v);
38546 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38550 decimalPrecisionFcn : function(v){
38551 return Math.floor(v);
38554 beforeBlur : function(){
38555 var v = this.parseValue(this.getRawValue());
38562 * Ext JS Library 1.1.1
38563 * Copyright(c) 2006-2007, Ext JS, LLC.
38565 * Originally Released Under LGPL - original licence link has changed is not relivant.
38568 * <script type="text/javascript">
38572 * @class Roo.form.DateField
38573 * @extends Roo.form.TriggerField
38574 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38576 * Create a new DateField
38577 * @param {Object} config
38579 Roo.form.DateField = function(config){
38580 Roo.form.DateField.superclass.constructor.call(this, config);
38586 * Fires when a date is selected
38587 * @param {Roo.form.DateField} combo This combo box
38588 * @param {Date} date The date selected
38595 if(typeof this.minValue == "string") {
38596 this.minValue = this.parseDate(this.minValue);
38598 if(typeof this.maxValue == "string") {
38599 this.maxValue = this.parseDate(this.maxValue);
38601 this.ddMatch = null;
38602 if(this.disabledDates){
38603 var dd = this.disabledDates;
38605 for(var i = 0; i < dd.length; i++){
38607 if(i != dd.length-1) {
38611 this.ddMatch = new RegExp(re + ")");
38615 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38617 * @cfg {String} format
38618 * The default date format string which can be overriden for localization support. The format must be
38619 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38623 * @cfg {String} altFormats
38624 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38625 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38627 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38629 * @cfg {Array} disabledDays
38630 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38632 disabledDays : null,
38634 * @cfg {String} disabledDaysText
38635 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38637 disabledDaysText : "Disabled",
38639 * @cfg {Array} disabledDates
38640 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38641 * expression so they are very powerful. Some examples:
38643 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38644 * <li>["03/08", "09/16"] would disable those days for every year</li>
38645 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38646 * <li>["03/../2006"] would disable every day in March 2006</li>
38647 * <li>["^03"] would disable every day in every March</li>
38649 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38650 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38652 disabledDates : null,
38654 * @cfg {String} disabledDatesText
38655 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38657 disabledDatesText : "Disabled",
38659 * @cfg {Date/String} minValue
38660 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38661 * valid format (defaults to null).
38665 * @cfg {Date/String} maxValue
38666 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38667 * valid format (defaults to null).
38671 * @cfg {String} minText
38672 * The error text to display when the date in the cell is before minValue (defaults to
38673 * 'The date in this field must be after {minValue}').
38675 minText : "The date in this field must be equal to or after {0}",
38677 * @cfg {String} maxText
38678 * The error text to display when the date in the cell is after maxValue (defaults to
38679 * 'The date in this field must be before {maxValue}').
38681 maxText : "The date in this field must be equal to or before {0}",
38683 * @cfg {String} invalidText
38684 * The error text to display when the date in the field is invalid (defaults to
38685 * '{value} is not a valid date - it must be in the format {format}').
38687 invalidText : "{0} is not a valid date - it must be in the format {1}",
38689 * @cfg {String} triggerClass
38690 * An additional CSS class used to style the trigger button. The trigger will always get the
38691 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38692 * which displays a calendar icon).
38694 triggerClass : 'x-form-date-trigger',
38698 * @cfg {Boolean} useIso
38699 * if enabled, then the date field will use a hidden field to store the
38700 * real value as iso formated date. default (false)
38704 * @cfg {String/Object} autoCreate
38705 * A DomHelper element spec, or true for a default element spec (defaults to
38706 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38709 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38712 hiddenField: false,
38714 onRender : function(ct, position)
38716 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38718 //this.el.dom.removeAttribute('name');
38719 Roo.log("Changing name?");
38720 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38721 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38723 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38724 // prevent input submission
38725 this.hiddenName = this.name;
38732 validateValue : function(value)
38734 value = this.formatDate(value);
38735 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38736 Roo.log('super failed');
38739 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38742 var svalue = value;
38743 value = this.parseDate(value);
38745 Roo.log('parse date failed' + svalue);
38746 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38749 var time = value.getTime();
38750 if(this.minValue && time < this.minValue.getTime()){
38751 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38754 if(this.maxValue && time > this.maxValue.getTime()){
38755 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38758 if(this.disabledDays){
38759 var day = value.getDay();
38760 for(var i = 0; i < this.disabledDays.length; i++) {
38761 if(day === this.disabledDays[i]){
38762 this.markInvalid(this.disabledDaysText);
38767 var fvalue = this.formatDate(value);
38768 if(this.ddMatch && this.ddMatch.test(fvalue)){
38769 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38776 // Provides logic to override the default TriggerField.validateBlur which just returns true
38777 validateBlur : function(){
38778 return !this.menu || !this.menu.isVisible();
38781 getName: function()
38783 // returns hidden if it's set..
38784 if (!this.rendered) {return ''};
38785 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38790 * Returns the current date value of the date field.
38791 * @return {Date} The date value
38793 getValue : function(){
38795 return this.hiddenField ?
38796 this.hiddenField.value :
38797 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38801 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38802 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38803 * (the default format used is "m/d/y").
38806 //All of these calls set the same date value (May 4, 2006)
38808 //Pass a date object:
38809 var dt = new Date('5/4/06');
38810 dateField.setValue(dt);
38812 //Pass a date string (default format):
38813 dateField.setValue('5/4/06');
38815 //Pass a date string (custom format):
38816 dateField.format = 'Y-m-d';
38817 dateField.setValue('2006-5-4');
38819 * @param {String/Date} date The date or valid date string
38821 setValue : function(date){
38822 if (this.hiddenField) {
38823 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38825 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38826 // make sure the value field is always stored as a date..
38827 this.value = this.parseDate(date);
38833 parseDate : function(value){
38834 if(!value || value instanceof Date){
38837 var v = Date.parseDate(value, this.format);
38838 if (!v && this.useIso) {
38839 v = Date.parseDate(value, 'Y-m-d');
38841 if(!v && this.altFormats){
38842 if(!this.altFormatsArray){
38843 this.altFormatsArray = this.altFormats.split("|");
38845 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38846 v = Date.parseDate(value, this.altFormatsArray[i]);
38853 formatDate : function(date, fmt){
38854 return (!date || !(date instanceof Date)) ?
38855 date : date.dateFormat(fmt || this.format);
38860 select: function(m, d){
38863 this.fireEvent('select', this, d);
38865 show : function(){ // retain focus styling
38869 this.focus.defer(10, this);
38870 var ml = this.menuListeners;
38871 this.menu.un("select", ml.select, this);
38872 this.menu.un("show", ml.show, this);
38873 this.menu.un("hide", ml.hide, this);
38878 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38879 onTriggerClick : function(){
38883 if(this.menu == null){
38884 this.menu = new Roo.menu.DateMenu();
38886 Roo.apply(this.menu.picker, {
38887 showClear: this.allowBlank,
38888 minDate : this.minValue,
38889 maxDate : this.maxValue,
38890 disabledDatesRE : this.ddMatch,
38891 disabledDatesText : this.disabledDatesText,
38892 disabledDays : this.disabledDays,
38893 disabledDaysText : this.disabledDaysText,
38894 format : this.useIso ? 'Y-m-d' : this.format,
38895 minText : String.format(this.minText, this.formatDate(this.minValue)),
38896 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38898 this.menu.on(Roo.apply({}, this.menuListeners, {
38901 this.menu.picker.setValue(this.getValue() || new Date());
38902 this.menu.show(this.el, "tl-bl?");
38905 beforeBlur : function(){
38906 var v = this.parseDate(this.getRawValue());
38916 isDirty : function() {
38917 if(this.disabled) {
38921 if(typeof(this.startValue) === 'undefined'){
38925 return String(this.getValue()) !== String(this.startValue);
38930 * Ext JS Library 1.1.1
38931 * Copyright(c) 2006-2007, Ext JS, LLC.
38933 * Originally Released Under LGPL - original licence link has changed is not relivant.
38936 * <script type="text/javascript">
38940 * @class Roo.form.MonthField
38941 * @extends Roo.form.TriggerField
38942 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38944 * Create a new MonthField
38945 * @param {Object} config
38947 Roo.form.MonthField = function(config){
38949 Roo.form.MonthField.superclass.constructor.call(this, config);
38955 * Fires when a date is selected
38956 * @param {Roo.form.MonthFieeld} combo This combo box
38957 * @param {Date} date The date selected
38964 if(typeof this.minValue == "string") {
38965 this.minValue = this.parseDate(this.minValue);
38967 if(typeof this.maxValue == "string") {
38968 this.maxValue = this.parseDate(this.maxValue);
38970 this.ddMatch = null;
38971 if(this.disabledDates){
38972 var dd = this.disabledDates;
38974 for(var i = 0; i < dd.length; i++){
38976 if(i != dd.length-1) {
38980 this.ddMatch = new RegExp(re + ")");
38984 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38986 * @cfg {String} format
38987 * The default date format string which can be overriden for localization support. The format must be
38988 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38992 * @cfg {String} altFormats
38993 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38994 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38996 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38998 * @cfg {Array} disabledDays
38999 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
39001 disabledDays : [0,1,2,3,4,5,6],
39003 * @cfg {String} disabledDaysText
39004 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
39006 disabledDaysText : "Disabled",
39008 * @cfg {Array} disabledDates
39009 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
39010 * expression so they are very powerful. Some examples:
39012 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
39013 * <li>["03/08", "09/16"] would disable those days for every year</li>
39014 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
39015 * <li>["03/../2006"] would disable every day in March 2006</li>
39016 * <li>["^03"] would disable every day in every March</li>
39018 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
39019 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
39021 disabledDates : null,
39023 * @cfg {String} disabledDatesText
39024 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
39026 disabledDatesText : "Disabled",
39028 * @cfg {Date/String} minValue
39029 * The minimum allowed date. Can be either a Javascript date object or a string date in a
39030 * valid format (defaults to null).
39034 * @cfg {Date/String} maxValue
39035 * The maximum allowed date. Can be either a Javascript date object or a string date in a
39036 * valid format (defaults to null).
39040 * @cfg {String} minText
39041 * The error text to display when the date in the cell is before minValue (defaults to
39042 * 'The date in this field must be after {minValue}').
39044 minText : "The date in this field must be equal to or after {0}",
39046 * @cfg {String} maxTextf
39047 * The error text to display when the date in the cell is after maxValue (defaults to
39048 * 'The date in this field must be before {maxValue}').
39050 maxText : "The date in this field must be equal to or before {0}",
39052 * @cfg {String} invalidText
39053 * The error text to display when the date in the field is invalid (defaults to
39054 * '{value} is not a valid date - it must be in the format {format}').
39056 invalidText : "{0} is not a valid date - it must be in the format {1}",
39058 * @cfg {String} triggerClass
39059 * An additional CSS class used to style the trigger button. The trigger will always get the
39060 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
39061 * which displays a calendar icon).
39063 triggerClass : 'x-form-date-trigger',
39067 * @cfg {Boolean} useIso
39068 * if enabled, then the date field will use a hidden field to store the
39069 * real value as iso formated date. default (true)
39073 * @cfg {String/Object} autoCreate
39074 * A DomHelper element spec, or true for a default element spec (defaults to
39075 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
39078 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
39081 hiddenField: false,
39083 hideMonthPicker : false,
39085 onRender : function(ct, position)
39087 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
39089 this.el.dom.removeAttribute('name');
39090 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
39092 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
39093 // prevent input submission
39094 this.hiddenName = this.name;
39101 validateValue : function(value)
39103 value = this.formatDate(value);
39104 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
39107 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39110 var svalue = value;
39111 value = this.parseDate(value);
39113 this.markInvalid(String.format(this.invalidText, svalue, this.format));
39116 var time = value.getTime();
39117 if(this.minValue && time < this.minValue.getTime()){
39118 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
39121 if(this.maxValue && time > this.maxValue.getTime()){
39122 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
39125 /*if(this.disabledDays){
39126 var day = value.getDay();
39127 for(var i = 0; i < this.disabledDays.length; i++) {
39128 if(day === this.disabledDays[i]){
39129 this.markInvalid(this.disabledDaysText);
39135 var fvalue = this.formatDate(value);
39136 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
39137 this.markInvalid(String.format(this.disabledDatesText, fvalue));
39145 // Provides logic to override the default TriggerField.validateBlur which just returns true
39146 validateBlur : function(){
39147 return !this.menu || !this.menu.isVisible();
39151 * Returns the current date value of the date field.
39152 * @return {Date} The date value
39154 getValue : function(){
39158 return this.hiddenField ?
39159 this.hiddenField.value :
39160 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
39164 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
39165 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
39166 * (the default format used is "m/d/y").
39169 //All of these calls set the same date value (May 4, 2006)
39171 //Pass a date object:
39172 var dt = new Date('5/4/06');
39173 monthField.setValue(dt);
39175 //Pass a date string (default format):
39176 monthField.setValue('5/4/06');
39178 //Pass a date string (custom format):
39179 monthField.format = 'Y-m-d';
39180 monthField.setValue('2006-5-4');
39182 * @param {String/Date} date The date or valid date string
39184 setValue : function(date){
39185 Roo.log('month setValue' + date);
39186 // can only be first of month..
39188 var val = this.parseDate(date);
39190 if (this.hiddenField) {
39191 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
39193 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
39194 this.value = this.parseDate(date);
39198 parseDate : function(value){
39199 if(!value || value instanceof Date){
39200 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
39203 var v = Date.parseDate(value, this.format);
39204 if (!v && this.useIso) {
39205 v = Date.parseDate(value, 'Y-m-d');
39209 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
39213 if(!v && this.altFormats){
39214 if(!this.altFormatsArray){
39215 this.altFormatsArray = this.altFormats.split("|");
39217 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
39218 v = Date.parseDate(value, this.altFormatsArray[i]);
39225 formatDate : function(date, fmt){
39226 return (!date || !(date instanceof Date)) ?
39227 date : date.dateFormat(fmt || this.format);
39232 select: function(m, d){
39234 this.fireEvent('select', this, d);
39236 show : function(){ // retain focus styling
39240 this.focus.defer(10, this);
39241 var ml = this.menuListeners;
39242 this.menu.un("select", ml.select, this);
39243 this.menu.un("show", ml.show, this);
39244 this.menu.un("hide", ml.hide, this);
39248 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
39249 onTriggerClick : function(){
39253 if(this.menu == null){
39254 this.menu = new Roo.menu.DateMenu();
39258 Roo.apply(this.menu.picker, {
39260 showClear: this.allowBlank,
39261 minDate : this.minValue,
39262 maxDate : this.maxValue,
39263 disabledDatesRE : this.ddMatch,
39264 disabledDatesText : this.disabledDatesText,
39266 format : this.useIso ? 'Y-m-d' : this.format,
39267 minText : String.format(this.minText, this.formatDate(this.minValue)),
39268 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39271 this.menu.on(Roo.apply({}, this.menuListeners, {
39279 // hide month picker get's called when we called by 'before hide';
39281 var ignorehide = true;
39282 p.hideMonthPicker = function(disableAnim){
39286 if(this.monthPicker){
39287 Roo.log("hideMonthPicker called");
39288 if(disableAnim === true){
39289 this.monthPicker.hide();
39291 this.monthPicker.slideOut('t', {duration:.2});
39292 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39293 p.fireEvent("select", this, this.value);
39299 Roo.log('picker set value');
39300 Roo.log(this.getValue());
39301 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39302 m.show(this.el, 'tl-bl?');
39303 ignorehide = false;
39304 // this will trigger hideMonthPicker..
39307 // hidden the day picker
39308 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39314 p.showMonthPicker.defer(100, p);
39320 beforeBlur : function(){
39321 var v = this.parseDate(this.getRawValue());
39327 /** @cfg {Boolean} grow @hide */
39328 /** @cfg {Number} growMin @hide */
39329 /** @cfg {Number} growMax @hide */
39336 * Ext JS Library 1.1.1
39337 * Copyright(c) 2006-2007, Ext JS, LLC.
39339 * Originally Released Under LGPL - original licence link has changed is not relivant.
39342 * <script type="text/javascript">
39347 * @class Roo.form.ComboBox
39348 * @extends Roo.form.TriggerField
39349 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39351 * Create a new ComboBox.
39352 * @param {Object} config Configuration options
39354 Roo.form.ComboBox = function(config){
39355 Roo.form.ComboBox.superclass.constructor.call(this, config);
39359 * Fires when the dropdown list is expanded
39360 * @param {Roo.form.ComboBox} combo This combo box
39365 * Fires when the dropdown list is collapsed
39366 * @param {Roo.form.ComboBox} combo This combo box
39370 * @event beforeselect
39371 * Fires before a list item is selected. Return false to cancel the selection.
39372 * @param {Roo.form.ComboBox} combo This combo box
39373 * @param {Roo.data.Record} record The data record returned from the underlying store
39374 * @param {Number} index The index of the selected item in the dropdown list
39376 'beforeselect' : true,
39379 * Fires when a list item is selected
39380 * @param {Roo.form.ComboBox} combo This combo box
39381 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39382 * @param {Number} index The index of the selected item in the dropdown list
39386 * @event beforequery
39387 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39388 * The event object passed has these properties:
39389 * @param {Roo.form.ComboBox} combo This combo box
39390 * @param {String} query The query
39391 * @param {Boolean} forceAll true to force "all" query
39392 * @param {Boolean} cancel true to cancel the query
39393 * @param {Object} e The query event object
39395 'beforequery': true,
39398 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39399 * @param {Roo.form.ComboBox} combo This combo box
39404 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39405 * @param {Roo.form.ComboBox} combo This combo box
39406 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39412 if(this.transform){
39413 this.allowDomMove = false;
39414 var s = Roo.getDom(this.transform);
39415 if(!this.hiddenName){
39416 this.hiddenName = s.name;
39419 this.mode = 'local';
39420 var d = [], opts = s.options;
39421 for(var i = 0, len = opts.length;i < len; i++){
39423 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39425 this.value = value;
39427 d.push([value, o.text]);
39429 this.store = new Roo.data.SimpleStore({
39431 fields: ['value', 'text'],
39434 this.valueField = 'value';
39435 this.displayField = 'text';
39437 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39438 if(!this.lazyRender){
39439 this.target = true;
39440 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39441 s.parentNode.removeChild(s); // remove it
39442 this.render(this.el.parentNode);
39444 s.parentNode.removeChild(s); // remove it
39449 this.store = Roo.factory(this.store, Roo.data);
39452 this.selectedIndex = -1;
39453 if(this.mode == 'local'){
39454 if(config.queryDelay === undefined){
39455 this.queryDelay = 10;
39457 if(config.minChars === undefined){
39463 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39465 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39468 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39469 * rendering into an Roo.Editor, defaults to false)
39472 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39473 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39476 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39479 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39480 * the dropdown list (defaults to undefined, with no header element)
39484 * @cfg {String/Roo.Template} tpl The template to use to render the output
39488 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39490 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39492 listWidth: undefined,
39494 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39495 * mode = 'remote' or 'text' if mode = 'local')
39497 displayField: undefined,
39499 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39500 * mode = 'remote' or 'value' if mode = 'local').
39501 * Note: use of a valueField requires the user make a selection
39502 * in order for a value to be mapped.
39504 valueField: undefined,
39508 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39509 * field's data value (defaults to the underlying DOM element's name)
39511 hiddenName: undefined,
39513 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39517 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39519 selectedClass: 'x-combo-selected',
39521 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39522 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39523 * which displays a downward arrow icon).
39525 triggerClass : 'x-form-arrow-trigger',
39527 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39531 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39532 * anchor positions (defaults to 'tl-bl')
39534 listAlign: 'tl-bl?',
39536 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39540 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39541 * query specified by the allQuery config option (defaults to 'query')
39543 triggerAction: 'query',
39545 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39546 * (defaults to 4, does not apply if editable = false)
39550 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39551 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39555 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39556 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39560 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39561 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39565 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39566 * when editable = true (defaults to false)
39568 selectOnFocus:false,
39570 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39572 queryParam: 'query',
39574 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39575 * when mode = 'remote' (defaults to 'Loading...')
39577 loadingText: 'Loading...',
39579 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39583 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39587 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39588 * traditional select (defaults to true)
39592 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39596 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39600 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39601 * listWidth has a higher value)
39605 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39606 * allow the user to set arbitrary text into the field (defaults to false)
39608 forceSelection:false,
39610 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39611 * if typeAhead = true (defaults to 250)
39613 typeAheadDelay : 250,
39615 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39616 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39618 valueNotFoundText : undefined,
39620 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39622 blockFocus : false,
39625 * @cfg {Boolean} disableClear Disable showing of clear button.
39627 disableClear : false,
39629 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39631 alwaysQuery : false,
39637 // element that contains real text value.. (when hidden is used..)
39640 onRender : function(ct, position){
39641 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39642 if(this.hiddenName){
39643 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39645 this.hiddenField.value =
39646 this.hiddenValue !== undefined ? this.hiddenValue :
39647 this.value !== undefined ? this.value : '';
39649 // prevent input submission
39650 this.el.dom.removeAttribute('name');
39655 this.el.dom.setAttribute('autocomplete', 'off');
39658 var cls = 'x-combo-list';
39660 this.list = new Roo.Layer({
39661 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39664 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39665 this.list.setWidth(lw);
39666 this.list.swallowEvent('mousewheel');
39667 this.assetHeight = 0;
39670 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39671 this.assetHeight += this.header.getHeight();
39674 this.innerList = this.list.createChild({cls:cls+'-inner'});
39675 this.innerList.on('mouseover', this.onViewOver, this);
39676 this.innerList.on('mousemove', this.onViewMove, this);
39677 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39679 if(this.allowBlank && !this.pageSize && !this.disableClear){
39680 this.footer = this.list.createChild({cls:cls+'-ft'});
39681 this.pageTb = new Roo.Toolbar(this.footer);
39685 this.footer = this.list.createChild({cls:cls+'-ft'});
39686 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39687 {pageSize: this.pageSize});
39691 if (this.pageTb && this.allowBlank && !this.disableClear) {
39693 this.pageTb.add(new Roo.Toolbar.Fill(), {
39694 cls: 'x-btn-icon x-btn-clear',
39696 handler: function()
39699 _this.clearValue();
39700 _this.onSelect(false, -1);
39705 this.assetHeight += this.footer.getHeight();
39710 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39713 this.view = new Roo.View(this.innerList, this.tpl, {
39714 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39717 this.view.on('click', this.onViewClick, this);
39719 this.store.on('beforeload', this.onBeforeLoad, this);
39720 this.store.on('load', this.onLoad, this);
39721 this.store.on('loadexception', this.onLoadException, this);
39723 if(this.resizable){
39724 this.resizer = new Roo.Resizable(this.list, {
39725 pinned:true, handles:'se'
39727 this.resizer.on('resize', function(r, w, h){
39728 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39729 this.listWidth = w;
39730 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39731 this.restrictHeight();
39733 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39735 if(!this.editable){
39736 this.editable = true;
39737 this.setEditable(false);
39741 if (typeof(this.events.add.listeners) != 'undefined') {
39743 this.addicon = this.wrap.createChild(
39744 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39746 this.addicon.on('click', function(e) {
39747 this.fireEvent('add', this);
39750 if (typeof(this.events.edit.listeners) != 'undefined') {
39752 this.editicon = this.wrap.createChild(
39753 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39754 if (this.addicon) {
39755 this.editicon.setStyle('margin-left', '40px');
39757 this.editicon.on('click', function(e) {
39759 // we fire even if inothing is selected..
39760 this.fireEvent('edit', this, this.lastData );
39770 initEvents : function(){
39771 Roo.form.ComboBox.superclass.initEvents.call(this);
39773 this.keyNav = new Roo.KeyNav(this.el, {
39774 "up" : function(e){
39775 this.inKeyMode = true;
39779 "down" : function(e){
39780 if(!this.isExpanded()){
39781 this.onTriggerClick();
39783 this.inKeyMode = true;
39788 "enter" : function(e){
39789 this.onViewClick();
39793 "esc" : function(e){
39797 "tab" : function(e){
39798 this.onViewClick(false);
39799 this.fireEvent("specialkey", this, e);
39805 doRelay : function(foo, bar, hname){
39806 if(hname == 'down' || this.scope.isExpanded()){
39807 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39814 this.queryDelay = Math.max(this.queryDelay || 10,
39815 this.mode == 'local' ? 10 : 250);
39816 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39817 if(this.typeAhead){
39818 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39820 if(this.editable !== false){
39821 this.el.on("keyup", this.onKeyUp, this);
39823 if(this.forceSelection){
39824 this.on('blur', this.doForce, this);
39828 onDestroy : function(){
39830 this.view.setStore(null);
39831 this.view.el.removeAllListeners();
39832 this.view.el.remove();
39833 this.view.purgeListeners();
39836 this.list.destroy();
39839 this.store.un('beforeload', this.onBeforeLoad, this);
39840 this.store.un('load', this.onLoad, this);
39841 this.store.un('loadexception', this.onLoadException, this);
39843 Roo.form.ComboBox.superclass.onDestroy.call(this);
39847 fireKey : function(e){
39848 if(e.isNavKeyPress() && !this.list.isVisible()){
39849 this.fireEvent("specialkey", this, e);
39854 onResize: function(w, h){
39855 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39857 if(typeof w != 'number'){
39858 // we do not handle it!?!?
39861 var tw = this.trigger.getWidth();
39862 tw += this.addicon ? this.addicon.getWidth() : 0;
39863 tw += this.editicon ? this.editicon.getWidth() : 0;
39865 this.el.setWidth( this.adjustWidth('input', x));
39867 this.trigger.setStyle('left', x+'px');
39869 if(this.list && this.listWidth === undefined){
39870 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39871 this.list.setWidth(lw);
39872 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39880 * Allow or prevent the user from directly editing the field text. If false is passed,
39881 * the user will only be able to select from the items defined in the dropdown list. This method
39882 * is the runtime equivalent of setting the 'editable' config option at config time.
39883 * @param {Boolean} value True to allow the user to directly edit the field text
39885 setEditable : function(value){
39886 if(value == this.editable){
39889 this.editable = value;
39891 this.el.dom.setAttribute('readOnly', true);
39892 this.el.on('mousedown', this.onTriggerClick, this);
39893 this.el.addClass('x-combo-noedit');
39895 this.el.dom.setAttribute('readOnly', false);
39896 this.el.un('mousedown', this.onTriggerClick, this);
39897 this.el.removeClass('x-combo-noedit');
39902 onBeforeLoad : function(){
39903 if(!this.hasFocus){
39906 this.innerList.update(this.loadingText ?
39907 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39908 this.restrictHeight();
39909 this.selectedIndex = -1;
39913 onLoad : function(){
39914 if(!this.hasFocus){
39917 if(this.store.getCount() > 0){
39919 this.restrictHeight();
39920 if(this.lastQuery == this.allQuery){
39922 this.el.dom.select();
39924 if(!this.selectByValue(this.value, true)){
39925 this.select(0, true);
39929 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39930 this.taTask.delay(this.typeAheadDelay);
39934 this.onEmptyResults();
39939 onLoadException : function()
39942 Roo.log(this.store.reader.jsonData);
39943 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39944 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39950 onTypeAhead : function(){
39951 if(this.store.getCount() > 0){
39952 var r = this.store.getAt(0);
39953 var newValue = r.data[this.displayField];
39954 var len = newValue.length;
39955 var selStart = this.getRawValue().length;
39956 if(selStart != len){
39957 this.setRawValue(newValue);
39958 this.selectText(selStart, newValue.length);
39964 onSelect : function(record, index){
39965 if(this.fireEvent('beforeselect', this, record, index) !== false){
39966 this.setFromData(index > -1 ? record.data : false);
39968 this.fireEvent('select', this, record, index);
39973 * Returns the currently selected field value or empty string if no value is set.
39974 * @return {String} value The selected value
39976 getValue : function(){
39977 if(this.valueField){
39978 return typeof this.value != 'undefined' ? this.value : '';
39980 return Roo.form.ComboBox.superclass.getValue.call(this);
39984 * Clears any text/value currently set in the field
39986 clearValue : function(){
39987 if(this.hiddenField){
39988 this.hiddenField.value = '';
39991 this.setRawValue('');
39992 this.lastSelectionText = '';
39997 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39998 * will be displayed in the field. If the value does not match the data value of an existing item,
39999 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
40000 * Otherwise the field will be blank (although the value will still be set).
40001 * @param {String} value The value to match
40003 setValue : function(v){
40005 if(this.valueField){
40006 var r = this.findRecord(this.valueField, v);
40008 text = r.data[this.displayField];
40009 }else if(this.valueNotFoundText !== undefined){
40010 text = this.valueNotFoundText;
40013 this.lastSelectionText = text;
40014 if(this.hiddenField){
40015 this.hiddenField.value = v;
40017 Roo.form.ComboBox.superclass.setValue.call(this, text);
40021 * @property {Object} the last set data for the element
40026 * Sets the value of the field based on a object which is related to the record format for the store.
40027 * @param {Object} value the value to set as. or false on reset?
40029 setFromData : function(o){
40030 var dv = ''; // display value
40031 var vv = ''; // value value..
40033 if (this.displayField) {
40034 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
40036 // this is an error condition!!!
40037 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
40040 if(this.valueField){
40041 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
40043 if(this.hiddenField){
40044 this.hiddenField.value = vv;
40046 this.lastSelectionText = dv;
40047 Roo.form.ComboBox.superclass.setValue.call(this, dv);
40051 // no hidden field.. - we store the value in 'value', but still display
40052 // display field!!!!
40053 this.lastSelectionText = dv;
40054 Roo.form.ComboBox.superclass.setValue.call(this, dv);
40060 reset : function(){
40061 // overridden so that last data is reset..
40062 this.setValue(this.resetValue);
40063 this.clearInvalid();
40064 this.lastData = false;
40066 this.view.clearSelections();
40070 findRecord : function(prop, value){
40072 if(this.store.getCount() > 0){
40073 this.store.each(function(r){
40074 if(r.data[prop] == value){
40084 getName: function()
40086 // returns hidden if it's set..
40087 if (!this.rendered) {return ''};
40088 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40092 onViewMove : function(e, t){
40093 this.inKeyMode = false;
40097 onViewOver : function(e, t){
40098 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
40101 var item = this.view.findItemFromChild(t);
40103 var index = this.view.indexOf(item);
40104 this.select(index, false);
40109 onViewClick : function(doFocus)
40111 var index = this.view.getSelectedIndexes()[0];
40112 var r = this.store.getAt(index);
40114 this.onSelect(r, index);
40116 if(doFocus !== false && !this.blockFocus){
40122 restrictHeight : function(){
40123 this.innerList.dom.style.height = '';
40124 var inner = this.innerList.dom;
40125 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
40126 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
40127 this.list.beginUpdate();
40128 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
40129 this.list.alignTo(this.el, this.listAlign);
40130 this.list.endUpdate();
40134 onEmptyResults : function(){
40139 * Returns true if the dropdown list is expanded, else false.
40141 isExpanded : function(){
40142 return this.list.isVisible();
40146 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
40147 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40148 * @param {String} value The data value of the item to select
40149 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40150 * selected item if it is not currently in view (defaults to true)
40151 * @return {Boolean} True if the value matched an item in the list, else false
40153 selectByValue : function(v, scrollIntoView){
40154 if(v !== undefined && v !== null){
40155 var r = this.findRecord(this.valueField || this.displayField, v);
40157 this.select(this.store.indexOf(r), scrollIntoView);
40165 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
40166 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40167 * @param {Number} index The zero-based index of the list item to select
40168 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40169 * selected item if it is not currently in view (defaults to true)
40171 select : function(index, scrollIntoView){
40172 this.selectedIndex = index;
40173 this.view.select(index);
40174 if(scrollIntoView !== false){
40175 var el = this.view.getNode(index);
40177 this.innerList.scrollChildIntoView(el, false);
40183 selectNext : function(){
40184 var ct = this.store.getCount();
40186 if(this.selectedIndex == -1){
40188 }else if(this.selectedIndex < ct-1){
40189 this.select(this.selectedIndex+1);
40195 selectPrev : function(){
40196 var ct = this.store.getCount();
40198 if(this.selectedIndex == -1){
40200 }else if(this.selectedIndex != 0){
40201 this.select(this.selectedIndex-1);
40207 onKeyUp : function(e){
40208 if(this.editable !== false && !e.isSpecialKey()){
40209 this.lastKey = e.getKey();
40210 this.dqTask.delay(this.queryDelay);
40215 validateBlur : function(){
40216 return !this.list || !this.list.isVisible();
40220 initQuery : function(){
40221 this.doQuery(this.getRawValue());
40225 doForce : function(){
40226 if(this.el.dom.value.length > 0){
40227 this.el.dom.value =
40228 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
40234 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
40235 * query allowing the query action to be canceled if needed.
40236 * @param {String} query The SQL query to execute
40237 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
40238 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
40239 * saved in the current store (defaults to false)
40241 doQuery : function(q, forceAll){
40242 if(q === undefined || q === null){
40247 forceAll: forceAll,
40251 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
40255 forceAll = qe.forceAll;
40256 if(forceAll === true || (q.length >= this.minChars)){
40257 if(this.lastQuery != q || this.alwaysQuery){
40258 this.lastQuery = q;
40259 if(this.mode == 'local'){
40260 this.selectedIndex = -1;
40262 this.store.clearFilter();
40264 this.store.filter(this.displayField, q);
40268 this.store.baseParams[this.queryParam] = q;
40270 params: this.getParams(q)
40275 this.selectedIndex = -1;
40282 getParams : function(q){
40284 //p[this.queryParam] = q;
40287 p.limit = this.pageSize;
40293 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40295 collapse : function(){
40296 if(!this.isExpanded()){
40300 Roo.get(document).un('mousedown', this.collapseIf, this);
40301 Roo.get(document).un('mousewheel', this.collapseIf, this);
40302 if (!this.editable) {
40303 Roo.get(document).un('keydown', this.listKeyPress, this);
40305 this.fireEvent('collapse', this);
40309 collapseIf : function(e){
40310 if(!e.within(this.wrap) && !e.within(this.list)){
40316 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40318 expand : function(){
40319 if(this.isExpanded() || !this.hasFocus){
40322 this.list.alignTo(this.el, this.listAlign);
40324 Roo.get(document).on('mousedown', this.collapseIf, this);
40325 Roo.get(document).on('mousewheel', this.collapseIf, this);
40326 if (!this.editable) {
40327 Roo.get(document).on('keydown', this.listKeyPress, this);
40330 this.fireEvent('expand', this);
40334 // Implements the default empty TriggerField.onTriggerClick function
40335 onTriggerClick : function(){
40339 if(this.isExpanded()){
40341 if (!this.blockFocus) {
40346 this.hasFocus = true;
40347 if(this.triggerAction == 'all') {
40348 this.doQuery(this.allQuery, true);
40350 this.doQuery(this.getRawValue());
40352 if (!this.blockFocus) {
40357 listKeyPress : function(e)
40359 //Roo.log('listkeypress');
40360 // scroll to first matching element based on key pres..
40361 if (e.isSpecialKey()) {
40364 var k = String.fromCharCode(e.getKey()).toUpperCase();
40367 var csel = this.view.getSelectedNodes();
40368 var cselitem = false;
40370 var ix = this.view.indexOf(csel[0]);
40371 cselitem = this.store.getAt(ix);
40372 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40378 this.store.each(function(v) {
40380 // start at existing selection.
40381 if (cselitem.id == v.id) {
40387 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40388 match = this.store.indexOf(v);
40393 if (match === false) {
40394 return true; // no more action?
40397 this.view.select(match);
40398 var sn = Roo.get(this.view.getSelectedNodes()[0]);
40399 sn.scrollIntoView(sn.dom.parentNode, false);
40403 * @cfg {Boolean} grow
40407 * @cfg {Number} growMin
40411 * @cfg {Number} growMax
40419 * Copyright(c) 2010-2012, Roo J Solutions Limited
40426 * @class Roo.form.ComboBoxArray
40427 * @extends Roo.form.TextField
40428 * A facebook style adder... for lists of email / people / countries etc...
40429 * pick multiple items from a combo box, and shows each one.
40431 * Fred [x] Brian [x] [Pick another |v]
40434 * For this to work: it needs various extra information
40435 * - normal combo problay has
40437 * + displayField, valueField
40439 * For our purpose...
40442 * If we change from 'extends' to wrapping...
40449 * Create a new ComboBoxArray.
40450 * @param {Object} config Configuration options
40454 Roo.form.ComboBoxArray = function(config)
40458 * @event beforeremove
40459 * Fires before remove the value from the list
40460 * @param {Roo.form.ComboBoxArray} _self This combo box array
40461 * @param {Roo.form.ComboBoxArray.Item} item removed item
40463 'beforeremove' : true,
40466 * Fires when remove the value from the list
40467 * @param {Roo.form.ComboBoxArray} _self This combo box array
40468 * @param {Roo.form.ComboBoxArray.Item} item removed item
40475 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40477 this.items = new Roo.util.MixedCollection(false);
40479 // construct the child combo...
40489 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40492 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40497 // behavies liek a hiddne field
40498 inputType: 'hidden',
40500 * @cfg {Number} width The width of the box that displays the selected element
40507 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40511 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40513 hiddenName : false,
40516 // private the array of items that are displayed..
40518 // private - the hidden field el.
40520 // private - the filed el..
40523 //validateValue : function() { return true; }, // all values are ok!
40524 //onAddClick: function() { },
40526 onRender : function(ct, position)
40529 // create the standard hidden element
40530 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40533 // give fake names to child combo;
40534 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40535 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40537 this.combo = Roo.factory(this.combo, Roo.form);
40538 this.combo.onRender(ct, position);
40539 if (typeof(this.combo.width) != 'undefined') {
40540 this.combo.onResize(this.combo.width,0);
40543 this.combo.initEvents();
40545 // assigned so form know we need to do this..
40546 this.store = this.combo.store;
40547 this.valueField = this.combo.valueField;
40548 this.displayField = this.combo.displayField ;
40551 this.combo.wrap.addClass('x-cbarray-grp');
40553 var cbwrap = this.combo.wrap.createChild(
40554 {tag: 'div', cls: 'x-cbarray-cb'},
40559 this.hiddenEl = this.combo.wrap.createChild({
40560 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40562 this.el = this.combo.wrap.createChild({
40563 tag: 'input', type:'hidden' , name: this.name, value : ''
40565 // this.el.dom.removeAttribute("name");
40568 this.outerWrap = this.combo.wrap;
40569 this.wrap = cbwrap;
40571 this.outerWrap.setWidth(this.width);
40572 this.outerWrap.dom.removeChild(this.el.dom);
40574 this.wrap.dom.appendChild(this.el.dom);
40575 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40576 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40578 this.combo.trigger.setStyle('position','relative');
40579 this.combo.trigger.setStyle('left', '0px');
40580 this.combo.trigger.setStyle('top', '2px');
40582 this.combo.el.setStyle('vertical-align', 'text-bottom');
40584 //this.trigger.setStyle('vertical-align', 'top');
40586 // this should use the code from combo really... on('add' ....)
40590 this.adder = this.outerWrap.createChild(
40591 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40593 this.adder.on('click', function(e) {
40594 _t.fireEvent('adderclick', this, e);
40598 //this.adder.on('click', this.onAddClick, _t);
40601 this.combo.on('select', function(cb, rec, ix) {
40602 this.addItem(rec.data);
40605 cb.el.dom.value = '';
40606 //cb.lastData = rec.data;
40615 getName: function()
40617 // returns hidden if it's set..
40618 if (!this.rendered) {return ''};
40619 return this.hiddenName ? this.hiddenName : this.name;
40624 onResize: function(w, h){
40627 // not sure if this is needed..
40628 //this.combo.onResize(w,h);
40630 if(typeof w != 'number'){
40631 // we do not handle it!?!?
40634 var tw = this.combo.trigger.getWidth();
40635 tw += this.addicon ? this.addicon.getWidth() : 0;
40636 tw += this.editicon ? this.editicon.getWidth() : 0;
40638 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40640 this.combo.trigger.setStyle('left', '0px');
40642 if(this.list && this.listWidth === undefined){
40643 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40644 this.list.setWidth(lw);
40645 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40652 addItem: function(rec)
40654 var valueField = this.combo.valueField;
40655 var displayField = this.combo.displayField;
40656 if (this.items.indexOfKey(rec[valueField]) > -1) {
40657 //console.log("GOT " + rec.data.id);
40661 var x = new Roo.form.ComboBoxArray.Item({
40662 //id : rec[this.idField],
40664 displayField : displayField ,
40665 tipField : displayField ,
40669 this.items.add(rec[valueField],x);
40670 // add it before the element..
40671 this.updateHiddenEl();
40672 x.render(this.outerWrap, this.wrap.dom);
40673 // add the image handler..
40676 updateHiddenEl : function()
40679 if (!this.hiddenEl) {
40683 var idField = this.combo.valueField;
40685 this.items.each(function(f) {
40686 ar.push(f.data[idField]);
40689 this.hiddenEl.dom.value = ar.join(',');
40695 this.items.clear();
40697 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
40701 this.el.dom.value = '';
40702 if (this.hiddenEl) {
40703 this.hiddenEl.dom.value = '';
40707 getValue: function()
40709 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40711 setValue: function(v) // not a valid action - must use addItems..
40718 if (this.store.isLocal && (typeof(v) == 'string')) {
40719 // then we can use the store to find the values..
40720 // comma seperated at present.. this needs to allow JSON based encoding..
40721 this.hiddenEl.value = v;
40723 Roo.each(v.split(','), function(k) {
40724 Roo.log("CHECK " + this.valueField + ',' + k);
40725 var li = this.store.query(this.valueField, k);
40730 add[this.valueField] = k;
40731 add[this.displayField] = li.item(0).data[this.displayField];
40737 if (typeof(v) == 'object' ) {
40738 // then let's assume it's an array of objects..
40739 Roo.each(v, function(l) {
40747 setFromData: function(v)
40749 // this recieves an object, if setValues is called.
40751 this.el.dom.value = v[this.displayField];
40752 this.hiddenEl.dom.value = v[this.valueField];
40753 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40756 var kv = v[this.valueField];
40757 var dv = v[this.displayField];
40758 kv = typeof(kv) != 'string' ? '' : kv;
40759 dv = typeof(dv) != 'string' ? '' : dv;
40762 var keys = kv.split(',');
40763 var display = dv.split(',');
40764 for (var i = 0 ; i < keys.length; i++) {
40767 add[this.valueField] = keys[i];
40768 add[this.displayField] = display[i];
40776 * Validates the combox array value
40777 * @return {Boolean} True if the value is valid, else false
40779 validate : function(){
40780 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40781 this.clearInvalid();
40787 validateValue : function(value){
40788 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40796 isDirty : function() {
40797 if(this.disabled) {
40802 var d = Roo.decode(String(this.originalValue));
40804 return String(this.getValue()) !== String(this.originalValue);
40807 var originalValue = [];
40809 for (var i = 0; i < d.length; i++){
40810 originalValue.push(d[i][this.valueField]);
40813 return String(this.getValue()) !== String(originalValue.join(','));
40822 * @class Roo.form.ComboBoxArray.Item
40823 * @extends Roo.BoxComponent
40824 * A selected item in the list
40825 * Fred [x] Brian [x] [Pick another |v]
40828 * Create a new item.
40829 * @param {Object} config Configuration options
40832 Roo.form.ComboBoxArray.Item = function(config) {
40833 config.id = Roo.id();
40834 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40837 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40840 displayField : false,
40844 defaultAutoCreate : {
40846 cls: 'x-cbarray-item',
40853 src : Roo.BLANK_IMAGE_URL ,
40861 onRender : function(ct, position)
40863 Roo.form.Field.superclass.onRender.call(this, ct, position);
40866 var cfg = this.getAutoCreate();
40867 this.el = ct.createChild(cfg, position);
40870 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40872 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40873 this.cb.renderer(this.data) :
40874 String.format('{0}',this.data[this.displayField]);
40877 this.el.child('div').dom.setAttribute('qtip',
40878 String.format('{0}',this.data[this.tipField])
40881 this.el.child('img').on('click', this.remove, this);
40885 remove : function()
40887 if(this.cb.disabled){
40891 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
40892 this.cb.items.remove(this);
40893 this.el.child('img').un('click', this.remove, this);
40895 this.cb.updateHiddenEl();
40897 this.cb.fireEvent('remove', this.cb, this);
40903 * Ext JS Library 1.1.1
40904 * Copyright(c) 2006-2007, Ext JS, LLC.
40906 * Originally Released Under LGPL - original licence link has changed is not relivant.
40909 * <script type="text/javascript">
40912 * @class Roo.form.Checkbox
40913 * @extends Roo.form.Field
40914 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40916 * Creates a new Checkbox
40917 * @param {Object} config Configuration options
40919 Roo.form.Checkbox = function(config){
40920 Roo.form.Checkbox.superclass.constructor.call(this, config);
40924 * Fires when the checkbox is checked or unchecked.
40925 * @param {Roo.form.Checkbox} this This checkbox
40926 * @param {Boolean} checked The new checked value
40932 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40934 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40936 focusClass : undefined,
40938 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40940 fieldClass: "x-form-field",
40942 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40946 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40947 * {tag: "input", type: "checkbox", autocomplete: "off"})
40949 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40951 * @cfg {String} boxLabel The text that appears beside the checkbox
40955 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40959 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40961 valueOff: '0', // value when not checked..
40963 actionMode : 'viewEl',
40966 itemCls : 'x-menu-check-item x-form-item',
40967 groupClass : 'x-menu-group-item',
40968 inputType : 'hidden',
40971 inSetChecked: false, // check that we are not calling self...
40973 inputElement: false, // real input element?
40974 basedOn: false, // ????
40976 isFormField: true, // not sure where this is needed!!!!
40978 onResize : function(){
40979 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40980 if(!this.boxLabel){
40981 this.el.alignTo(this.wrap, 'c-c');
40985 initEvents : function(){
40986 Roo.form.Checkbox.superclass.initEvents.call(this);
40987 this.el.on("click", this.onClick, this);
40988 this.el.on("change", this.onClick, this);
40992 getResizeEl : function(){
40996 getPositionEl : function(){
41001 onRender : function(ct, position){
41002 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
41004 if(this.inputValue !== undefined){
41005 this.el.dom.value = this.inputValue;
41008 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
41009 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
41010 var viewEl = this.wrap.createChild({
41011 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
41012 this.viewEl = viewEl;
41013 this.wrap.on('click', this.onClick, this);
41015 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
41016 this.el.on('propertychange', this.setFromHidden, this); //ie
41021 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
41022 // viewEl.on('click', this.onClick, this);
41024 //if(this.checked){
41025 this.setChecked(this.checked);
41027 //this.checked = this.el.dom;
41033 initValue : Roo.emptyFn,
41036 * Returns the checked state of the checkbox.
41037 * @return {Boolean} True if checked, else false
41039 getValue : function(){
41041 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
41043 return this.valueOff;
41048 onClick : function(){
41049 if (this.disabled) {
41052 this.setChecked(!this.checked);
41054 //if(this.el.dom.checked != this.checked){
41055 // this.setValue(this.el.dom.checked);
41060 * Sets the checked state of the checkbox.
41061 * On is always based on a string comparison between inputValue and the param.
41062 * @param {Boolean/String} value - the value to set
41063 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
41065 setValue : function(v,suppressEvent){
41068 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
41069 //if(this.el && this.el.dom){
41070 // this.el.dom.checked = this.checked;
41071 // this.el.dom.defaultChecked = this.checked;
41073 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
41074 //this.fireEvent("check", this, this.checked);
41077 setChecked : function(state,suppressEvent)
41079 if (this.inSetChecked) {
41080 this.checked = state;
41086 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
41088 this.checked = state;
41089 if(suppressEvent !== true){
41090 this.fireEvent('check', this, state);
41092 this.inSetChecked = true;
41093 this.el.dom.value = state ? this.inputValue : this.valueOff;
41094 this.inSetChecked = false;
41097 // handle setting of hidden value by some other method!!?!?
41098 setFromHidden: function()
41103 //console.log("SET FROM HIDDEN");
41104 //alert('setFrom hidden');
41105 this.setValue(this.el.dom.value);
41108 onDestroy : function()
41111 Roo.get(this.viewEl).remove();
41114 Roo.form.Checkbox.superclass.onDestroy.call(this);
41117 setBoxLabel : function(str)
41119 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
41124 * Ext JS Library 1.1.1
41125 * Copyright(c) 2006-2007, Ext JS, LLC.
41127 * Originally Released Under LGPL - original licence link has changed is not relivant.
41130 * <script type="text/javascript">
41134 * @class Roo.form.Radio
41135 * @extends Roo.form.Checkbox
41136 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
41137 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
41139 * Creates a new Radio
41140 * @param {Object} config Configuration options
41142 Roo.form.Radio = function(){
41143 Roo.form.Radio.superclass.constructor.apply(this, arguments);
41145 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
41146 inputType: 'radio',
41149 * If this radio is part of a group, it will return the selected value
41152 getGroupValue : function(){
41153 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
41157 onRender : function(ct, position){
41158 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
41160 if(this.inputValue !== undefined){
41161 this.el.dom.value = this.inputValue;
41164 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
41165 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
41166 //var viewEl = this.wrap.createChild({
41167 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
41168 //this.viewEl = viewEl;
41169 //this.wrap.on('click', this.onClick, this);
41171 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
41172 //this.el.on('propertychange', this.setFromHidden, this); //ie
41177 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
41178 // viewEl.on('click', this.onClick, this);
41181 this.el.dom.checked = 'checked' ;
41187 });//<script type="text/javascript">
41190 * Based Ext JS Library 1.1.1
41191 * Copyright(c) 2006-2007, Ext JS, LLC.
41197 * @class Roo.HtmlEditorCore
41198 * @extends Roo.Component
41199 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
41201 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
41204 Roo.HtmlEditorCore = function(config){
41207 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
41212 * @event initialize
41213 * Fires when the editor is fully initialized (including the iframe)
41214 * @param {Roo.HtmlEditorCore} this
41219 * Fires when the editor is first receives the focus. Any insertion must wait
41220 * until after this event.
41221 * @param {Roo.HtmlEditorCore} this
41225 * @event beforesync
41226 * Fires before the textarea is updated with content from the editor iframe. Return false
41227 * to cancel the sync.
41228 * @param {Roo.HtmlEditorCore} this
41229 * @param {String} html
41233 * @event beforepush
41234 * Fires before the iframe editor is updated with content from the textarea. Return false
41235 * to cancel the push.
41236 * @param {Roo.HtmlEditorCore} this
41237 * @param {String} html
41242 * Fires when the textarea is updated with content from the editor iframe.
41243 * @param {Roo.HtmlEditorCore} this
41244 * @param {String} html
41249 * Fires when the iframe editor is updated with content from the textarea.
41250 * @param {Roo.HtmlEditorCore} this
41251 * @param {String} html
41256 * @event editorevent
41257 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41258 * @param {Roo.HtmlEditorCore} this
41264 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
41266 // defaults : white / black...
41267 this.applyBlacklists();
41274 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41278 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41284 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41289 * @cfg {Number} height (in pixels)
41293 * @cfg {Number} width (in pixels)
41298 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41301 stylesheets: false,
41306 // private properties
41307 validationEvent : false,
41309 initialized : false,
41311 sourceEditMode : false,
41312 onFocus : Roo.emptyFn,
41314 hideMode:'offsets',
41318 // blacklist + whitelisted elements..
41325 * Protected method that will not generally be called directly. It
41326 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41327 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41329 getDocMarkup : function(){
41333 // inherit styels from page...??
41334 if (this.stylesheets === false) {
41336 Roo.get(document.head).select('style').each(function(node) {
41337 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41340 Roo.get(document.head).select('link').each(function(node) {
41341 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41344 } else if (!this.stylesheets.length) {
41346 st = '<style type="text/css">' +
41347 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41353 st += '<style type="text/css">' +
41354 'IMG { cursor: pointer } ' +
41358 return '<html><head>' + st +
41359 //<style type="text/css">' +
41360 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41362 ' </head><body class="roo-htmleditor-body"></body></html>';
41366 onRender : function(ct, position)
41369 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41370 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41373 this.el.dom.style.border = '0 none';
41374 this.el.dom.setAttribute('tabIndex', -1);
41375 this.el.addClass('x-hidden hide');
41379 if(Roo.isIE){ // fix IE 1px bogus margin
41380 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41384 this.frameId = Roo.id();
41388 var iframe = this.owner.wrap.createChild({
41390 cls: 'form-control', // bootstrap..
41392 name: this.frameId,
41393 frameBorder : 'no',
41394 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41399 this.iframe = iframe.dom;
41401 this.assignDocWin();
41403 this.doc.designMode = 'on';
41406 this.doc.write(this.getDocMarkup());
41410 var task = { // must defer to wait for browser to be ready
41412 //console.log("run task?" + this.doc.readyState);
41413 this.assignDocWin();
41414 if(this.doc.body || this.doc.readyState == 'complete'){
41416 this.doc.designMode="on";
41420 Roo.TaskMgr.stop(task);
41421 this.initEditor.defer(10, this);
41428 Roo.TaskMgr.start(task);
41433 onResize : function(w, h)
41435 Roo.log('resize: ' +w + ',' + h );
41436 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41440 if(typeof w == 'number'){
41442 this.iframe.style.width = w + 'px';
41444 if(typeof h == 'number'){
41446 this.iframe.style.height = h + 'px';
41448 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41455 * Toggles the editor between standard and source edit mode.
41456 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41458 toggleSourceEdit : function(sourceEditMode){
41460 this.sourceEditMode = sourceEditMode === true;
41462 if(this.sourceEditMode){
41464 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41467 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41468 //this.iframe.className = '';
41471 //this.setSize(this.owner.wrap.getSize());
41472 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41479 * Protected method that will not generally be called directly. If you need/want
41480 * custom HTML cleanup, this is the method you should override.
41481 * @param {String} html The HTML to be cleaned
41482 * return {String} The cleaned HTML
41484 cleanHtml : function(html){
41485 html = String(html);
41486 if(html.length > 5){
41487 if(Roo.isSafari){ // strip safari nonsense
41488 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41491 if(html == ' '){
41498 * HTML Editor -> Textarea
41499 * Protected method that will not generally be called directly. Syncs the contents
41500 * of the editor iframe with the textarea.
41502 syncValue : function(){
41503 if(this.initialized){
41504 var bd = (this.doc.body || this.doc.documentElement);
41505 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41506 var html = bd.innerHTML;
41508 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41509 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41511 html = '<div style="'+m[0]+'">' + html + '</div>';
41514 html = this.cleanHtml(html);
41515 // fix up the special chars.. normaly like back quotes in word...
41516 // however we do not want to do this with chinese..
41517 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41518 var cc = b.charCodeAt();
41520 (cc >= 0x4E00 && cc < 0xA000 ) ||
41521 (cc >= 0x3400 && cc < 0x4E00 ) ||
41522 (cc >= 0xf900 && cc < 0xfb00 )
41528 if(this.owner.fireEvent('beforesync', this, html) !== false){
41529 this.el.dom.value = html;
41530 this.owner.fireEvent('sync', this, html);
41536 * Protected method that will not generally be called directly. Pushes the value of the textarea
41537 * into the iframe editor.
41539 pushValue : function(){
41540 if(this.initialized){
41541 var v = this.el.dom.value.trim();
41543 // if(v.length < 1){
41547 if(this.owner.fireEvent('beforepush', this, v) !== false){
41548 var d = (this.doc.body || this.doc.documentElement);
41550 this.cleanUpPaste();
41551 this.el.dom.value = d.innerHTML;
41552 this.owner.fireEvent('push', this, v);
41558 deferFocus : function(){
41559 this.focus.defer(10, this);
41563 focus : function(){
41564 if(this.win && !this.sourceEditMode){
41571 assignDocWin: function()
41573 var iframe = this.iframe;
41576 this.doc = iframe.contentWindow.document;
41577 this.win = iframe.contentWindow;
41579 // if (!Roo.get(this.frameId)) {
41582 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41583 // this.win = Roo.get(this.frameId).dom.contentWindow;
41585 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
41589 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41590 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
41595 initEditor : function(){
41596 //console.log("INIT EDITOR");
41597 this.assignDocWin();
41601 this.doc.designMode="on";
41603 this.doc.write(this.getDocMarkup());
41606 var dbody = (this.doc.body || this.doc.documentElement);
41607 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41608 // this copies styles from the containing element into thsi one..
41609 // not sure why we need all of this..
41610 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41612 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41613 //ss['background-attachment'] = 'fixed'; // w3c
41614 dbody.bgProperties = 'fixed'; // ie
41615 //Roo.DomHelper.applyStyles(dbody, ss);
41616 Roo.EventManager.on(this.doc, {
41617 //'mousedown': this.onEditorEvent,
41618 'mouseup': this.onEditorEvent,
41619 'dblclick': this.onEditorEvent,
41620 'click': this.onEditorEvent,
41621 'keyup': this.onEditorEvent,
41626 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41628 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41629 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41631 this.initialized = true;
41633 this.owner.fireEvent('initialize', this);
41638 onDestroy : function(){
41644 //for (var i =0; i < this.toolbars.length;i++) {
41645 // // fixme - ask toolbars for heights?
41646 // this.toolbars[i].onDestroy();
41649 //this.wrap.dom.innerHTML = '';
41650 //this.wrap.remove();
41655 onFirstFocus : function(){
41657 this.assignDocWin();
41660 this.activated = true;
41663 if(Roo.isGecko){ // prevent silly gecko errors
41665 var s = this.win.getSelection();
41666 if(!s.focusNode || s.focusNode.nodeType != 3){
41667 var r = s.getRangeAt(0);
41668 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41673 this.execCmd('useCSS', true);
41674 this.execCmd('styleWithCSS', false);
41677 this.owner.fireEvent('activate', this);
41681 adjustFont: function(btn){
41682 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41683 //if(Roo.isSafari){ // safari
41686 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41687 if(Roo.isSafari){ // safari
41688 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41689 v = (v < 10) ? 10 : v;
41690 v = (v > 48) ? 48 : v;
41691 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41696 v = Math.max(1, v+adjust);
41698 this.execCmd('FontSize', v );
41701 onEditorEvent : function(e)
41703 this.owner.fireEvent('editorevent', this, e);
41704 // this.updateToolbar();
41705 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41708 insertTag : function(tg)
41710 // could be a bit smarter... -> wrap the current selected tRoo..
41711 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41713 range = this.createRange(this.getSelection());
41714 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41715 wrappingNode.appendChild(range.extractContents());
41716 range.insertNode(wrappingNode);
41723 this.execCmd("formatblock", tg);
41727 insertText : function(txt)
41731 var range = this.createRange();
41732 range.deleteContents();
41733 //alert(Sender.getAttribute('label'));
41735 range.insertNode(this.doc.createTextNode(txt));
41741 * Executes a Midas editor command on the editor document and performs necessary focus and
41742 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41743 * @param {String} cmd The Midas command
41744 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41746 relayCmd : function(cmd, value){
41748 this.execCmd(cmd, value);
41749 this.owner.fireEvent('editorevent', this);
41750 //this.updateToolbar();
41751 this.owner.deferFocus();
41755 * Executes a Midas editor command directly on the editor document.
41756 * For visual commands, you should use {@link #relayCmd} instead.
41757 * <b>This should only be called after the editor is initialized.</b>
41758 * @param {String} cmd The Midas command
41759 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41761 execCmd : function(cmd, value){
41762 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41769 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41771 * @param {String} text | dom node..
41773 insertAtCursor : function(text)
41778 if(!this.activated){
41784 var r = this.doc.selection.createRange();
41795 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41799 // from jquery ui (MIT licenced)
41801 var win = this.win;
41803 if (win.getSelection && win.getSelection().getRangeAt) {
41804 range = win.getSelection().getRangeAt(0);
41805 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41806 range.insertNode(node);
41807 } else if (win.document.selection && win.document.selection.createRange) {
41808 // no firefox support
41809 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41810 win.document.selection.createRange().pasteHTML(txt);
41812 // no firefox support
41813 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41814 this.execCmd('InsertHTML', txt);
41823 mozKeyPress : function(e){
41825 var c = e.getCharCode(), cmd;
41828 c = String.fromCharCode(c).toLowerCase();
41842 this.cleanUpPaste.defer(100, this);
41850 e.preventDefault();
41858 fixKeys : function(){ // load time branching for fastest keydown performance
41860 return function(e){
41861 var k = e.getKey(), r;
41864 r = this.doc.selection.createRange();
41867 r.pasteHTML('    ');
41874 r = this.doc.selection.createRange();
41876 var target = r.parentElement();
41877 if(!target || target.tagName.toLowerCase() != 'li'){
41879 r.pasteHTML('<br />');
41885 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41886 this.cleanUpPaste.defer(100, this);
41892 }else if(Roo.isOpera){
41893 return function(e){
41894 var k = e.getKey();
41898 this.execCmd('InsertHTML','    ');
41901 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41902 this.cleanUpPaste.defer(100, this);
41907 }else if(Roo.isSafari){
41908 return function(e){
41909 var k = e.getKey();
41913 this.execCmd('InsertText','\t');
41917 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41918 this.cleanUpPaste.defer(100, this);
41926 getAllAncestors: function()
41928 var p = this.getSelectedNode();
41931 a.push(p); // push blank onto stack..
41932 p = this.getParentElement();
41936 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41940 a.push(this.doc.body);
41944 lastSelNode : false,
41947 getSelection : function()
41949 this.assignDocWin();
41950 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41953 getSelectedNode: function()
41955 // this may only work on Gecko!!!
41957 // should we cache this!!!!
41962 var range = this.createRange(this.getSelection()).cloneRange();
41965 var parent = range.parentElement();
41967 var testRange = range.duplicate();
41968 testRange.moveToElementText(parent);
41969 if (testRange.inRange(range)) {
41972 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41975 parent = parent.parentElement;
41980 // is ancestor a text element.
41981 var ac = range.commonAncestorContainer;
41982 if (ac.nodeType == 3) {
41983 ac = ac.parentNode;
41986 var ar = ac.childNodes;
41989 var other_nodes = [];
41990 var has_other_nodes = false;
41991 for (var i=0;i<ar.length;i++) {
41992 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41995 // fullly contained node.
41997 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
42002 // probably selected..
42003 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
42004 other_nodes.push(ar[i]);
42008 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
42013 has_other_nodes = true;
42015 if (!nodes.length && other_nodes.length) {
42016 nodes= other_nodes;
42018 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
42024 createRange: function(sel)
42026 // this has strange effects when using with
42027 // top toolbar - not sure if it's a great idea.
42028 //this.editor.contentWindow.focus();
42029 if (typeof sel != "undefined") {
42031 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
42033 return this.doc.createRange();
42036 return this.doc.createRange();
42039 getParentElement: function()
42042 this.assignDocWin();
42043 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
42045 var range = this.createRange(sel);
42048 var p = range.commonAncestorContainer;
42049 while (p.nodeType == 3) { // text node
42060 * Range intersection.. the hard stuff...
42064 * [ -- selected range --- ]
42068 * if end is before start or hits it. fail.
42069 * if start is after end or hits it fail.
42071 * if either hits (but other is outside. - then it's not
42077 // @see http://www.thismuchiknow.co.uk/?p=64.
42078 rangeIntersectsNode : function(range, node)
42080 var nodeRange = node.ownerDocument.createRange();
42082 nodeRange.selectNode(node);
42084 nodeRange.selectNodeContents(node);
42087 var rangeStartRange = range.cloneRange();
42088 rangeStartRange.collapse(true);
42090 var rangeEndRange = range.cloneRange();
42091 rangeEndRange.collapse(false);
42093 var nodeStartRange = nodeRange.cloneRange();
42094 nodeStartRange.collapse(true);
42096 var nodeEndRange = nodeRange.cloneRange();
42097 nodeEndRange.collapse(false);
42099 return rangeStartRange.compareBoundaryPoints(
42100 Range.START_TO_START, nodeEndRange) == -1 &&
42101 rangeEndRange.compareBoundaryPoints(
42102 Range.START_TO_START, nodeStartRange) == 1;
42106 rangeCompareNode : function(range, node)
42108 var nodeRange = node.ownerDocument.createRange();
42110 nodeRange.selectNode(node);
42112 nodeRange.selectNodeContents(node);
42116 range.collapse(true);
42118 nodeRange.collapse(true);
42120 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
42121 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
42123 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
42125 var nodeIsBefore = ss == 1;
42126 var nodeIsAfter = ee == -1;
42128 if (nodeIsBefore && nodeIsAfter) {
42131 if (!nodeIsBefore && nodeIsAfter) {
42132 return 1; //right trailed.
42135 if (nodeIsBefore && !nodeIsAfter) {
42136 return 2; // left trailed.
42142 // private? - in a new class?
42143 cleanUpPaste : function()
42145 // cleans up the whole document..
42146 Roo.log('cleanuppaste');
42148 this.cleanUpChildren(this.doc.body);
42149 var clean = this.cleanWordChars(this.doc.body.innerHTML);
42150 if (clean != this.doc.body.innerHTML) {
42151 this.doc.body.innerHTML = clean;
42156 cleanWordChars : function(input) {// change the chars to hex code
42157 var he = Roo.HtmlEditorCore;
42159 var output = input;
42160 Roo.each(he.swapCodes, function(sw) {
42161 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
42163 output = output.replace(swapper, sw[1]);
42170 cleanUpChildren : function (n)
42172 if (!n.childNodes.length) {
42175 for (var i = n.childNodes.length-1; i > -1 ; i--) {
42176 this.cleanUpChild(n.childNodes[i]);
42183 cleanUpChild : function (node)
42186 //console.log(node);
42187 if (node.nodeName == "#text") {
42188 // clean up silly Windows -- stuff?
42191 if (node.nodeName == "#comment") {
42192 node.parentNode.removeChild(node);
42193 // clean up silly Windows -- stuff?
42196 var lcname = node.tagName.toLowerCase();
42197 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
42198 // whitelist of tags..
42200 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
42202 node.parentNode.removeChild(node);
42207 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
42209 // remove <a name=....> as rendering on yahoo mailer is borked with this.
42210 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
42212 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
42213 // remove_keep_children = true;
42216 if (remove_keep_children) {
42217 this.cleanUpChildren(node);
42218 // inserts everything just before this node...
42219 while (node.childNodes.length) {
42220 var cn = node.childNodes[0];
42221 node.removeChild(cn);
42222 node.parentNode.insertBefore(cn, node);
42224 node.parentNode.removeChild(node);
42228 if (!node.attributes || !node.attributes.length) {
42229 this.cleanUpChildren(node);
42233 function cleanAttr(n,v)
42236 if (v.match(/^\./) || v.match(/^\//)) {
42239 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
42242 if (v.match(/^#/)) {
42245 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
42246 node.removeAttribute(n);
42250 var cwhite = this.cwhite;
42251 var cblack = this.cblack;
42253 function cleanStyle(n,v)
42255 if (v.match(/expression/)) { //XSS?? should we even bother..
42256 node.removeAttribute(n);
42260 var parts = v.split(/;/);
42263 Roo.each(parts, function(p) {
42264 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42268 var l = p.split(':').shift().replace(/\s+/g,'');
42269 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42271 if ( cwhite.length && cblack.indexOf(l) > -1) {
42272 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42273 //node.removeAttribute(n);
42277 // only allow 'c whitelisted system attributes'
42278 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42279 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42280 //node.removeAttribute(n);
42290 if (clean.length) {
42291 node.setAttribute(n, clean.join(';'));
42293 node.removeAttribute(n);
42299 for (var i = node.attributes.length-1; i > -1 ; i--) {
42300 var a = node.attributes[i];
42303 if (a.name.toLowerCase().substr(0,2)=='on') {
42304 node.removeAttribute(a.name);
42307 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42308 node.removeAttribute(a.name);
42311 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42312 cleanAttr(a.name,a.value); // fixme..
42315 if (a.name == 'style') {
42316 cleanStyle(a.name,a.value);
42319 /// clean up MS crap..
42320 // tecnically this should be a list of valid class'es..
42323 if (a.name == 'class') {
42324 if (a.value.match(/^Mso/)) {
42325 node.className = '';
42328 if (a.value.match(/body/)) {
42329 node.className = '';
42340 this.cleanUpChildren(node);
42346 * Clean up MS wordisms...
42348 cleanWord : function(node)
42353 this.cleanWord(this.doc.body);
42356 if (node.nodeName == "#text") {
42357 // clean up silly Windows -- stuff?
42360 if (node.nodeName == "#comment") {
42361 node.parentNode.removeChild(node);
42362 // clean up silly Windows -- stuff?
42366 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42367 node.parentNode.removeChild(node);
42371 // remove - but keep children..
42372 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42373 while (node.childNodes.length) {
42374 var cn = node.childNodes[0];
42375 node.removeChild(cn);
42376 node.parentNode.insertBefore(cn, node);
42378 node.parentNode.removeChild(node);
42379 this.iterateChildren(node, this.cleanWord);
42383 if (node.className.length) {
42385 var cn = node.className.split(/\W+/);
42387 Roo.each(cn, function(cls) {
42388 if (cls.match(/Mso[a-zA-Z]+/)) {
42393 node.className = cna.length ? cna.join(' ') : '';
42395 node.removeAttribute("class");
42399 if (node.hasAttribute("lang")) {
42400 node.removeAttribute("lang");
42403 if (node.hasAttribute("style")) {
42405 var styles = node.getAttribute("style").split(";");
42407 Roo.each(styles, function(s) {
42408 if (!s.match(/:/)) {
42411 var kv = s.split(":");
42412 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42415 // what ever is left... we allow.
42418 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42419 if (!nstyle.length) {
42420 node.removeAttribute('style');
42423 this.iterateChildren(node, this.cleanWord);
42429 * iterateChildren of a Node, calling fn each time, using this as the scole..
42430 * @param {DomNode} node node to iterate children of.
42431 * @param {Function} fn method of this class to call on each item.
42433 iterateChildren : function(node, fn)
42435 if (!node.childNodes.length) {
42438 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42439 fn.call(this, node.childNodes[i])
42445 * cleanTableWidths.
42447 * Quite often pasting from word etc.. results in tables with column and widths.
42448 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
42451 cleanTableWidths : function(node)
42456 this.cleanTableWidths(this.doc.body);
42461 if (node.nodeName == "#text" || node.nodeName == "#comment") {
42464 Roo.log(node.tagName);
42465 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
42466 this.iterateChildren(node, this.cleanTableWidths);
42469 if (node.hasAttribute('width')) {
42470 node.removeAttribute('width');
42474 if (node.hasAttribute("style")) {
42477 var styles = node.getAttribute("style").split(";");
42479 Roo.each(styles, function(s) {
42480 if (!s.match(/:/)) {
42483 var kv = s.split(":");
42484 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
42487 // what ever is left... we allow.
42490 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42491 if (!nstyle.length) {
42492 node.removeAttribute('style');
42496 this.iterateChildren(node, this.cleanTableWidths);
42504 domToHTML : function(currentElement, depth, nopadtext) {
42506 depth = depth || 0;
42507 nopadtext = nopadtext || false;
42509 if (!currentElement) {
42510 return this.domToHTML(this.doc.body);
42513 //Roo.log(currentElement);
42515 var allText = false;
42516 var nodeName = currentElement.nodeName;
42517 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42519 if (nodeName == '#text') {
42521 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
42526 if (nodeName != 'BODY') {
42529 // Prints the node tagName, such as <A>, <IMG>, etc
42532 for(i = 0; i < currentElement.attributes.length;i++) {
42534 var aname = currentElement.attributes.item(i).name;
42535 if (!currentElement.attributes.item(i).value.length) {
42538 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42541 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42550 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42553 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42558 // Traverse the tree
42560 var currentElementChild = currentElement.childNodes.item(i);
42561 var allText = true;
42562 var innerHTML = '';
42564 while (currentElementChild) {
42565 // Formatting code (indent the tree so it looks nice on the screen)
42566 var nopad = nopadtext;
42567 if (lastnode == 'SPAN') {
42571 if (currentElementChild.nodeName == '#text') {
42572 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42573 toadd = nopadtext ? toadd : toadd.trim();
42574 if (!nopad && toadd.length > 80) {
42575 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42577 innerHTML += toadd;
42580 currentElementChild = currentElement.childNodes.item(i);
42586 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42588 // Recursively traverse the tree structure of the child node
42589 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42590 lastnode = currentElementChild.nodeName;
42592 currentElementChild=currentElement.childNodes.item(i);
42598 // The remaining code is mostly for formatting the tree
42599 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42604 ret+= "</"+tagName+">";
42610 applyBlacklists : function()
42612 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
42613 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
42617 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
42618 if (b.indexOf(tag) > -1) {
42621 this.white.push(tag);
42625 Roo.each(w, function(tag) {
42626 if (b.indexOf(tag) > -1) {
42629 if (this.white.indexOf(tag) > -1) {
42632 this.white.push(tag);
42637 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
42638 if (w.indexOf(tag) > -1) {
42641 this.black.push(tag);
42645 Roo.each(b, function(tag) {
42646 if (w.indexOf(tag) > -1) {
42649 if (this.black.indexOf(tag) > -1) {
42652 this.black.push(tag);
42657 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
42658 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
42662 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
42663 if (b.indexOf(tag) > -1) {
42666 this.cwhite.push(tag);
42670 Roo.each(w, function(tag) {
42671 if (b.indexOf(tag) > -1) {
42674 if (this.cwhite.indexOf(tag) > -1) {
42677 this.cwhite.push(tag);
42682 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
42683 if (w.indexOf(tag) > -1) {
42686 this.cblack.push(tag);
42690 Roo.each(b, function(tag) {
42691 if (w.indexOf(tag) > -1) {
42694 if (this.cblack.indexOf(tag) > -1) {
42697 this.cblack.push(tag);
42702 setStylesheets : function(stylesheets)
42704 if(typeof(stylesheets) == 'string'){
42705 Roo.get(this.iframe.contentDocument.head).createChild({
42707 rel : 'stylesheet',
42716 Roo.each(stylesheets, function(s) {
42721 Roo.get(_this.iframe.contentDocument.head).createChild({
42723 rel : 'stylesheet',
42732 removeStylesheets : function()
42736 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
42741 // hide stuff that is not compatible
42755 * @event specialkey
42759 * @cfg {String} fieldClass @hide
42762 * @cfg {String} focusClass @hide
42765 * @cfg {String} autoCreate @hide
42768 * @cfg {String} inputType @hide
42771 * @cfg {String} invalidClass @hide
42774 * @cfg {String} invalidText @hide
42777 * @cfg {String} msgFx @hide
42780 * @cfg {String} validateOnBlur @hide
42784 Roo.HtmlEditorCore.white = [
42785 'area', 'br', 'img', 'input', 'hr', 'wbr',
42787 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42788 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42789 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42790 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42791 'table', 'ul', 'xmp',
42793 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42796 'dir', 'menu', 'ol', 'ul', 'dl',
42802 Roo.HtmlEditorCore.black = [
42803 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42805 'base', 'basefont', 'bgsound', 'blink', 'body',
42806 'frame', 'frameset', 'head', 'html', 'ilayer',
42807 'iframe', 'layer', 'link', 'meta', 'object',
42808 'script', 'style' ,'title', 'xml' // clean later..
42810 Roo.HtmlEditorCore.clean = [
42811 'script', 'style', 'title', 'xml'
42813 Roo.HtmlEditorCore.remove = [
42818 Roo.HtmlEditorCore.ablack = [
42822 Roo.HtmlEditorCore.aclean = [
42823 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42827 Roo.HtmlEditorCore.pwhite= [
42828 'http', 'https', 'mailto'
42831 // white listed style attributes.
42832 Roo.HtmlEditorCore.cwhite= [
42833 // 'text-align', /// default is to allow most things..
42839 // black listed style attributes.
42840 Roo.HtmlEditorCore.cblack= [
42841 // 'font-size' -- this can be set by the project
42845 Roo.HtmlEditorCore.swapCodes =[
42856 //<script type="text/javascript">
42859 * Ext JS Library 1.1.1
42860 * Copyright(c) 2006-2007, Ext JS, LLC.
42866 Roo.form.HtmlEditor = function(config){
42870 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42872 if (!this.toolbars) {
42873 this.toolbars = [];
42875 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42881 * @class Roo.form.HtmlEditor
42882 * @extends Roo.form.Field
42883 * Provides a lightweight HTML Editor component.
42885 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42887 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42888 * supported by this editor.</b><br/><br/>
42889 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42890 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42892 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42894 * @cfg {Boolean} clearUp
42898 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42903 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42908 * @cfg {Number} height (in pixels)
42912 * @cfg {Number} width (in pixels)
42917 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42920 stylesheets: false,
42924 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
42929 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
42935 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
42940 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
42948 // private properties
42949 validationEvent : false,
42951 initialized : false,
42954 onFocus : Roo.emptyFn,
42956 hideMode:'offsets',
42958 actionMode : 'container', // defaults to hiding it...
42960 defaultAutoCreate : { // modified by initCompnoent..
42962 style:"width:500px;height:300px;",
42963 autocomplete: "new-password"
42967 initComponent : function(){
42970 * @event initialize
42971 * Fires when the editor is fully initialized (including the iframe)
42972 * @param {HtmlEditor} this
42977 * Fires when the editor is first receives the focus. Any insertion must wait
42978 * until after this event.
42979 * @param {HtmlEditor} this
42983 * @event beforesync
42984 * Fires before the textarea is updated with content from the editor iframe. Return false
42985 * to cancel the sync.
42986 * @param {HtmlEditor} this
42987 * @param {String} html
42991 * @event beforepush
42992 * Fires before the iframe editor is updated with content from the textarea. Return false
42993 * to cancel the push.
42994 * @param {HtmlEditor} this
42995 * @param {String} html
43000 * Fires when the textarea is updated with content from the editor iframe.
43001 * @param {HtmlEditor} this
43002 * @param {String} html
43007 * Fires when the iframe editor is updated with content from the textarea.
43008 * @param {HtmlEditor} this
43009 * @param {String} html
43013 * @event editmodechange
43014 * Fires when the editor switches edit modes
43015 * @param {HtmlEditor} this
43016 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
43018 editmodechange: true,
43020 * @event editorevent
43021 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
43022 * @param {HtmlEditor} this
43026 * @event firstfocus
43027 * Fires when on first focus - needed by toolbars..
43028 * @param {HtmlEditor} this
43033 * Auto save the htmlEditor value as a file into Events
43034 * @param {HtmlEditor} this
43038 * @event savedpreview
43039 * preview the saved version of htmlEditor
43040 * @param {HtmlEditor} this
43042 savedpreview: true,
43045 * @event stylesheetsclick
43046 * Fires when press the Sytlesheets button
43047 * @param {Roo.HtmlEditorCore} this
43049 stylesheetsclick: true
43051 this.defaultAutoCreate = {
43053 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
43054 autocomplete: "new-password"
43059 * Protected method that will not generally be called directly. It
43060 * is called when the editor creates its toolbar. Override this method if you need to
43061 * add custom toolbar buttons.
43062 * @param {HtmlEditor} editor
43064 createToolbar : function(editor){
43065 Roo.log("create toolbars");
43066 if (!editor.toolbars || !editor.toolbars.length) {
43067 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
43070 for (var i =0 ; i < editor.toolbars.length;i++) {
43071 editor.toolbars[i] = Roo.factory(
43072 typeof(editor.toolbars[i]) == 'string' ?
43073 { xtype: editor.toolbars[i]} : editor.toolbars[i],
43074 Roo.form.HtmlEditor);
43075 editor.toolbars[i].init(editor);
43083 onRender : function(ct, position)
43086 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
43088 this.wrap = this.el.wrap({
43089 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
43092 this.editorcore.onRender(ct, position);
43094 if (this.resizable) {
43095 this.resizeEl = new Roo.Resizable(this.wrap, {
43099 minHeight : this.height,
43100 height: this.height,
43101 handles : this.resizable,
43104 resize : function(r, w, h) {
43105 _t.onResize(w,h); // -something
43111 this.createToolbar(this);
43115 this.setSize(this.wrap.getSize());
43117 if (this.resizeEl) {
43118 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
43119 // should trigger onReize..
43122 this.keyNav = new Roo.KeyNav(this.el, {
43124 "tab" : function(e){
43125 e.preventDefault();
43127 var value = this.getValue();
43129 var start = this.el.dom.selectionStart;
43130 var end = this.el.dom.selectionEnd;
43134 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
43135 this.el.dom.setSelectionRange(end + 1, end + 1);
43139 var f = value.substring(0, start).split("\t");
43141 if(f.pop().length != 0){
43145 this.setValue(f.join("\t") + value.substring(end));
43146 this.el.dom.setSelectionRange(start - 1, start - 1);
43150 "home" : function(e){
43151 e.preventDefault();
43153 var curr = this.el.dom.selectionStart;
43154 var lines = this.getValue().split("\n");
43161 this.el.dom.setSelectionRange(0, 0);
43167 for (var i = 0; i < lines.length;i++) {
43168 pos += lines[i].length;
43178 pos -= lines[i].length;
43184 this.el.dom.setSelectionRange(pos, pos);
43188 this.el.dom.selectionStart = pos;
43189 this.el.dom.selectionEnd = curr;
43192 "end" : function(e){
43193 e.preventDefault();
43195 var curr = this.el.dom.selectionStart;
43196 var lines = this.getValue().split("\n");
43203 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
43209 for (var i = 0; i < lines.length;i++) {
43211 pos += lines[i].length;
43225 this.el.dom.setSelectionRange(pos, pos);
43229 this.el.dom.selectionStart = curr;
43230 this.el.dom.selectionEnd = pos;
43235 doRelay : function(foo, bar, hname){
43236 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
43242 // if(this.autosave && this.w){
43243 // this.autoSaveFn = setInterval(this.autosave, 1000);
43248 onResize : function(w, h)
43250 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
43255 if(typeof w == 'number'){
43256 var aw = w - this.wrap.getFrameWidth('lr');
43257 this.el.setWidth(this.adjustWidth('textarea', aw));
43260 if(typeof h == 'number'){
43262 for (var i =0; i < this.toolbars.length;i++) {
43263 // fixme - ask toolbars for heights?
43264 tbh += this.toolbars[i].tb.el.getHeight();
43265 if (this.toolbars[i].footer) {
43266 tbh += this.toolbars[i].footer.el.getHeight();
43273 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
43274 ah -= 5; // knock a few pixes off for look..
43276 this.el.setHeight(this.adjustWidth('textarea', ah));
43280 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
43281 this.editorcore.onResize(ew,eh);
43286 * Toggles the editor between standard and source edit mode.
43287 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43289 toggleSourceEdit : function(sourceEditMode)
43291 this.editorcore.toggleSourceEdit(sourceEditMode);
43293 if(this.editorcore.sourceEditMode){
43294 Roo.log('editor - showing textarea');
43297 // Roo.log(this.syncValue());
43298 this.editorcore.syncValue();
43299 this.el.removeClass('x-hidden');
43300 this.el.dom.removeAttribute('tabIndex');
43303 for (var i = 0; i < this.toolbars.length; i++) {
43304 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43305 this.toolbars[i].tb.hide();
43306 this.toolbars[i].footer.hide();
43311 Roo.log('editor - hiding textarea');
43313 // Roo.log(this.pushValue());
43314 this.editorcore.pushValue();
43316 this.el.addClass('x-hidden');
43317 this.el.dom.setAttribute('tabIndex', -1);
43319 for (var i = 0; i < this.toolbars.length; i++) {
43320 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43321 this.toolbars[i].tb.show();
43322 this.toolbars[i].footer.show();
43326 //this.deferFocus();
43329 this.setSize(this.wrap.getSize());
43330 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
43332 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
43335 // private (for BoxComponent)
43336 adjustSize : Roo.BoxComponent.prototype.adjustSize,
43338 // private (for BoxComponent)
43339 getResizeEl : function(){
43343 // private (for BoxComponent)
43344 getPositionEl : function(){
43349 initEvents : function(){
43350 this.originalValue = this.getValue();
43354 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43357 markInvalid : Roo.emptyFn,
43359 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43362 clearInvalid : Roo.emptyFn,
43364 setValue : function(v){
43365 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
43366 this.editorcore.pushValue();
43371 deferFocus : function(){
43372 this.focus.defer(10, this);
43376 focus : function(){
43377 this.editorcore.focus();
43383 onDestroy : function(){
43389 for (var i =0; i < this.toolbars.length;i++) {
43390 // fixme - ask toolbars for heights?
43391 this.toolbars[i].onDestroy();
43394 this.wrap.dom.innerHTML = '';
43395 this.wrap.remove();
43400 onFirstFocus : function(){
43401 //Roo.log("onFirstFocus");
43402 this.editorcore.onFirstFocus();
43403 for (var i =0; i < this.toolbars.length;i++) {
43404 this.toolbars[i].onFirstFocus();
43410 syncValue : function()
43412 this.editorcore.syncValue();
43415 pushValue : function()
43417 this.editorcore.pushValue();
43420 setStylesheets : function(stylesheets)
43422 this.editorcore.setStylesheets(stylesheets);
43425 removeStylesheets : function()
43427 this.editorcore.removeStylesheets();
43431 // hide stuff that is not compatible
43445 * @event specialkey
43449 * @cfg {String} fieldClass @hide
43452 * @cfg {String} focusClass @hide
43455 * @cfg {String} autoCreate @hide
43458 * @cfg {String} inputType @hide
43461 * @cfg {String} invalidClass @hide
43464 * @cfg {String} invalidText @hide
43467 * @cfg {String} msgFx @hide
43470 * @cfg {String} validateOnBlur @hide
43474 // <script type="text/javascript">
43477 * Ext JS Library 1.1.1
43478 * Copyright(c) 2006-2007, Ext JS, LLC.
43484 * @class Roo.form.HtmlEditorToolbar1
43489 new Roo.form.HtmlEditor({
43492 new Roo.form.HtmlEditorToolbar1({
43493 disable : { fonts: 1 , format: 1, ..., ... , ...],
43499 * @cfg {Object} disable List of elements to disable..
43500 * @cfg {Array} btns List of additional buttons.
43504 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
43507 Roo.form.HtmlEditor.ToolbarStandard = function(config)
43510 Roo.apply(this, config);
43512 // default disabled, based on 'good practice'..
43513 this.disable = this.disable || {};
43514 Roo.applyIf(this.disable, {
43517 specialElements : true
43521 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43522 // dont call parent... till later.
43525 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
43532 editorcore : false,
43534 * @cfg {Object} disable List of toolbar elements to disable
43541 * @cfg {String} createLinkText The default text for the create link prompt
43543 createLinkText : 'Please enter the URL for the link:',
43545 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
43547 defaultLinkValue : 'http:/'+'/',
43551 * @cfg {Array} fontFamilies An array of available font families
43569 // "á" , ?? a acute?
43574 "°" // , // degrees
43576 // "é" , // e ecute
43577 // "ú" , // u ecute?
43580 specialElements : [
43582 text: "Insert Table",
43585 ihtml : '<table><tr><td>Cell</td></tr></table>'
43589 text: "Insert Image",
43592 ihtml : '<img src="about:blank"/>'
43601 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
43602 "input:submit", "input:button", "select", "textarea", "label" ],
43605 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
43607 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
43615 * @cfg {String} defaultFont default font to use.
43617 defaultFont: 'tahoma',
43619 fontSelect : false,
43622 formatCombo : false,
43624 init : function(editor)
43626 this.editor = editor;
43627 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43628 var editorcore = this.editorcore;
43632 var fid = editorcore.frameId;
43634 function btn(id, toggle, handler){
43635 var xid = fid + '-'+ id ;
43639 cls : 'x-btn-icon x-edit-'+id,
43640 enableToggle:toggle !== false,
43641 scope: _t, // was editor...
43642 handler:handler||_t.relayBtnCmd,
43643 clickEvent:'mousedown',
43644 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43651 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43653 // stop form submits
43654 tb.el.on('click', function(e){
43655 e.preventDefault(); // what does this do?
43658 if(!this.disable.font) { // && !Roo.isSafari){
43659 /* why no safari for fonts
43660 editor.fontSelect = tb.el.createChild({
43663 cls:'x-font-select',
43664 html: this.createFontOptions()
43667 editor.fontSelect.on('change', function(){
43668 var font = editor.fontSelect.dom.value;
43669 editor.relayCmd('fontname', font);
43670 editor.deferFocus();
43674 editor.fontSelect.dom,
43680 if(!this.disable.formats){
43681 this.formatCombo = new Roo.form.ComboBox({
43682 store: new Roo.data.SimpleStore({
43685 data : this.formats // from states.js
43689 //autoCreate : {tag: "div", size: "20"},
43690 displayField:'tag',
43694 triggerAction: 'all',
43695 emptyText:'Add tag',
43696 selectOnFocus:true,
43699 'select': function(c, r, i) {
43700 editorcore.insertTag(r.get('tag'));
43706 tb.addField(this.formatCombo);
43710 if(!this.disable.format){
43715 btn('strikethrough')
43718 if(!this.disable.fontSize){
43723 btn('increasefontsize', false, editorcore.adjustFont),
43724 btn('decreasefontsize', false, editorcore.adjustFont)
43729 if(!this.disable.colors){
43732 id:editorcore.frameId +'-forecolor',
43733 cls:'x-btn-icon x-edit-forecolor',
43734 clickEvent:'mousedown',
43735 tooltip: this.buttonTips['forecolor'] || undefined,
43737 menu : new Roo.menu.ColorMenu({
43738 allowReselect: true,
43739 focus: Roo.emptyFn,
43742 selectHandler: function(cp, color){
43743 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43744 editor.deferFocus();
43747 clickEvent:'mousedown'
43750 id:editorcore.frameId +'backcolor',
43751 cls:'x-btn-icon x-edit-backcolor',
43752 clickEvent:'mousedown',
43753 tooltip: this.buttonTips['backcolor'] || undefined,
43755 menu : new Roo.menu.ColorMenu({
43756 focus: Roo.emptyFn,
43759 allowReselect: true,
43760 selectHandler: function(cp, color){
43762 editorcore.execCmd('useCSS', false);
43763 editorcore.execCmd('hilitecolor', color);
43764 editorcore.execCmd('useCSS', true);
43765 editor.deferFocus();
43767 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43768 Roo.isSafari || Roo.isIE ? '#'+color : color);
43769 editor.deferFocus();
43773 clickEvent:'mousedown'
43778 // now add all the items...
43781 if(!this.disable.alignments){
43784 btn('justifyleft'),
43785 btn('justifycenter'),
43786 btn('justifyright')
43790 //if(!Roo.isSafari){
43791 if(!this.disable.links){
43794 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43798 if(!this.disable.lists){
43801 btn('insertorderedlist'),
43802 btn('insertunorderedlist')
43805 if(!this.disable.sourceEdit){
43808 btn('sourceedit', true, function(btn){
43809 this.toggleSourceEdit(btn.pressed);
43816 // special menu.. - needs to be tidied up..
43817 if (!this.disable.special) {
43820 cls: 'x-edit-none',
43826 for (var i =0; i < this.specialChars.length; i++) {
43827 smenu.menu.items.push({
43829 html: this.specialChars[i],
43830 handler: function(a,b) {
43831 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43832 //editor.insertAtCursor(a.html);
43846 if (!this.disable.cleanStyles) {
43848 cls: 'x-btn-icon x-btn-clear',
43854 for (var i =0; i < this.cleanStyles.length; i++) {
43855 cmenu.menu.items.push({
43856 actiontype : this.cleanStyles[i],
43857 html: 'Remove ' + this.cleanStyles[i],
43858 handler: function(a,b) {
43861 var c = Roo.get(editorcore.doc.body);
43862 c.select('[style]').each(function(s) {
43863 s.dom.style.removeProperty(a.actiontype);
43865 editorcore.syncValue();
43870 cmenu.menu.items.push({
43871 actiontype : 'tablewidths',
43872 html: 'Remove Table Widths',
43873 handler: function(a,b) {
43874 editorcore.cleanTableWidths();
43875 editorcore.syncValue();
43879 cmenu.menu.items.push({
43880 actiontype : 'word',
43881 html: 'Remove MS Word Formating',
43882 handler: function(a,b) {
43883 editorcore.cleanWord();
43884 editorcore.syncValue();
43889 cmenu.menu.items.push({
43890 actiontype : 'all',
43891 html: 'Remove All Styles',
43892 handler: function(a,b) {
43894 var c = Roo.get(editorcore.doc.body);
43895 c.select('[style]').each(function(s) {
43896 s.dom.removeAttribute('style');
43898 editorcore.syncValue();
43903 cmenu.menu.items.push({
43904 actiontype : 'all',
43905 html: 'Remove All CSS Classes',
43906 handler: function(a,b) {
43908 var c = Roo.get(editorcore.doc.body);
43909 c.select('[class]').each(function(s) {
43910 s.dom.className = '';
43912 editorcore.syncValue();
43917 cmenu.menu.items.push({
43918 actiontype : 'tidy',
43919 html: 'Tidy HTML Source',
43920 handler: function(a,b) {
43921 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43922 editorcore.syncValue();
43931 if (!this.disable.specialElements) {
43934 cls: 'x-edit-none',
43939 for (var i =0; i < this.specialElements.length; i++) {
43940 semenu.menu.items.push(
43942 handler: function(a,b) {
43943 editor.insertAtCursor(this.ihtml);
43945 }, this.specialElements[i])
43957 for(var i =0; i< this.btns.length;i++) {
43958 var b = Roo.factory(this.btns[i],Roo.form);
43959 b.cls = 'x-edit-none';
43961 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
43962 b.cls += ' x-init-enable';
43965 b.scope = editorcore;
43973 // disable everything...
43975 this.tb.items.each(function(item){
43978 item.id != editorcore.frameId+ '-sourceedit' &&
43979 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
43985 this.rendered = true;
43987 // the all the btns;
43988 editor.on('editorevent', this.updateToolbar, this);
43989 // other toolbars need to implement this..
43990 //editor.on('editmodechange', this.updateToolbar, this);
43994 relayBtnCmd : function(btn) {
43995 this.editorcore.relayCmd(btn.cmd);
43997 // private used internally
43998 createLink : function(){
43999 Roo.log("create link?");
44000 var url = prompt(this.createLinkText, this.defaultLinkValue);
44001 if(url && url != 'http:/'+'/'){
44002 this.editorcore.relayCmd('createlink', url);
44008 * Protected method that will not generally be called directly. It triggers
44009 * a toolbar update by reading the markup state of the current selection in the editor.
44011 updateToolbar: function(){
44013 if(!this.editorcore.activated){
44014 this.editor.onFirstFocus();
44018 var btns = this.tb.items.map,
44019 doc = this.editorcore.doc,
44020 frameId = this.editorcore.frameId;
44022 if(!this.disable.font && !Roo.isSafari){
44024 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
44025 if(name != this.fontSelect.dom.value){
44026 this.fontSelect.dom.value = name;
44030 if(!this.disable.format){
44031 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
44032 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
44033 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
44034 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
44036 if(!this.disable.alignments){
44037 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
44038 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
44039 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
44041 if(!Roo.isSafari && !this.disable.lists){
44042 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
44043 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
44046 var ans = this.editorcore.getAllAncestors();
44047 if (this.formatCombo) {
44050 var store = this.formatCombo.store;
44051 this.formatCombo.setValue("");
44052 for (var i =0; i < ans.length;i++) {
44053 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
44055 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
44063 // hides menus... - so this cant be on a menu...
44064 Roo.menu.MenuMgr.hideAll();
44066 //this.editorsyncValue();
44070 createFontOptions : function(){
44071 var buf = [], fs = this.fontFamilies, ff, lc;
44075 for(var i = 0, len = fs.length; i< len; i++){
44077 lc = ff.toLowerCase();
44079 '<option value="',lc,'" style="font-family:',ff,';"',
44080 (this.defaultFont == lc ? ' selected="true">' : '>'),
44085 return buf.join('');
44088 toggleSourceEdit : function(sourceEditMode){
44090 Roo.log("toolbar toogle");
44091 if(sourceEditMode === undefined){
44092 sourceEditMode = !this.sourceEditMode;
44094 this.sourceEditMode = sourceEditMode === true;
44095 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
44096 // just toggle the button?
44097 if(btn.pressed !== this.sourceEditMode){
44098 btn.toggle(this.sourceEditMode);
44102 if(sourceEditMode){
44103 Roo.log("disabling buttons");
44104 this.tb.items.each(function(item){
44105 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
44111 Roo.log("enabling buttons");
44112 if(this.editorcore.initialized){
44113 this.tb.items.each(function(item){
44119 Roo.log("calling toggole on editor");
44120 // tell the editor that it's been pressed..
44121 this.editor.toggleSourceEdit(sourceEditMode);
44125 * Object collection of toolbar tooltips for the buttons in the editor. The key
44126 * is the command id associated with that button and the value is a valid QuickTips object.
44131 title: 'Bold (Ctrl+B)',
44132 text: 'Make the selected text bold.',
44133 cls: 'x-html-editor-tip'
44136 title: 'Italic (Ctrl+I)',
44137 text: 'Make the selected text italic.',
44138 cls: 'x-html-editor-tip'
44146 title: 'Bold (Ctrl+B)',
44147 text: 'Make the selected text bold.',
44148 cls: 'x-html-editor-tip'
44151 title: 'Italic (Ctrl+I)',
44152 text: 'Make the selected text italic.',
44153 cls: 'x-html-editor-tip'
44156 title: 'Underline (Ctrl+U)',
44157 text: 'Underline the selected text.',
44158 cls: 'x-html-editor-tip'
44161 title: 'Strikethrough',
44162 text: 'Strikethrough the selected text.',
44163 cls: 'x-html-editor-tip'
44165 increasefontsize : {
44166 title: 'Grow Text',
44167 text: 'Increase the font size.',
44168 cls: 'x-html-editor-tip'
44170 decreasefontsize : {
44171 title: 'Shrink Text',
44172 text: 'Decrease the font size.',
44173 cls: 'x-html-editor-tip'
44176 title: 'Text Highlight Color',
44177 text: 'Change the background color of the selected text.',
44178 cls: 'x-html-editor-tip'
44181 title: 'Font Color',
44182 text: 'Change the color of the selected text.',
44183 cls: 'x-html-editor-tip'
44186 title: 'Align Text Left',
44187 text: 'Align text to the left.',
44188 cls: 'x-html-editor-tip'
44191 title: 'Center Text',
44192 text: 'Center text in the editor.',
44193 cls: 'x-html-editor-tip'
44196 title: 'Align Text Right',
44197 text: 'Align text to the right.',
44198 cls: 'x-html-editor-tip'
44200 insertunorderedlist : {
44201 title: 'Bullet List',
44202 text: 'Start a bulleted list.',
44203 cls: 'x-html-editor-tip'
44205 insertorderedlist : {
44206 title: 'Numbered List',
44207 text: 'Start a numbered list.',
44208 cls: 'x-html-editor-tip'
44211 title: 'Hyperlink',
44212 text: 'Make the selected text a hyperlink.',
44213 cls: 'x-html-editor-tip'
44216 title: 'Source Edit',
44217 text: 'Switch to source editing mode.',
44218 cls: 'x-html-editor-tip'
44222 onDestroy : function(){
44225 this.tb.items.each(function(item){
44227 item.menu.removeAll();
44229 item.menu.el.destroy();
44237 onFirstFocus: function() {
44238 this.tb.items.each(function(item){
44247 // <script type="text/javascript">
44250 * Ext JS Library 1.1.1
44251 * Copyright(c) 2006-2007, Ext JS, LLC.
44258 * @class Roo.form.HtmlEditor.ToolbarContext
44263 new Roo.form.HtmlEditor({
44266 { xtype: 'ToolbarStandard', styles : {} }
44267 { xtype: 'ToolbarContext', disable : {} }
44273 * @config : {Object} disable List of elements to disable.. (not done yet.)
44274 * @config : {Object} styles Map of styles available.
44278 Roo.form.HtmlEditor.ToolbarContext = function(config)
44281 Roo.apply(this, config);
44282 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44283 // dont call parent... till later.
44284 this.styles = this.styles || {};
44289 Roo.form.HtmlEditor.ToolbarContext.types = {
44301 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
44367 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
44372 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
44382 style : 'fontFamily',
44383 displayField: 'display',
44384 optname : 'font-family',
44433 // should we really allow this??
44434 // should this just be
44445 style : 'fontFamily',
44446 displayField: 'display',
44447 optname : 'font-family',
44454 style : 'fontFamily',
44455 displayField: 'display',
44456 optname : 'font-family',
44463 style : 'fontFamily',
44464 displayField: 'display',
44465 optname : 'font-family',
44476 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
44477 Roo.form.HtmlEditor.ToolbarContext.stores = false;
44479 Roo.form.HtmlEditor.ToolbarContext.options = {
44481 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
44482 [ 'Courier New', 'Courier New'],
44483 [ 'Tahoma', 'Tahoma'],
44484 [ 'Times New Roman,serif', 'Times'],
44485 [ 'Verdana','Verdana' ]
44489 // fixme - these need to be configurable..
44492 //Roo.form.HtmlEditor.ToolbarContext.types
44495 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
44502 editorcore : false,
44504 * @cfg {Object} disable List of toolbar elements to disable
44509 * @cfg {Object} styles List of styles
44510 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
44512 * These must be defined in the page, so they get rendered correctly..
44523 init : function(editor)
44525 this.editor = editor;
44526 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44527 var editorcore = this.editorcore;
44529 var fid = editorcore.frameId;
44531 function btn(id, toggle, handler){
44532 var xid = fid + '-'+ id ;
44536 cls : 'x-btn-icon x-edit-'+id,
44537 enableToggle:toggle !== false,
44538 scope: editorcore, // was editor...
44539 handler:handler||editorcore.relayBtnCmd,
44540 clickEvent:'mousedown',
44541 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44545 // create a new element.
44546 var wdiv = editor.wrap.createChild({
44548 }, editor.wrap.dom.firstChild.nextSibling, true);
44550 // can we do this more than once??
44552 // stop form submits
44555 // disable everything...
44556 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44557 this.toolbars = {};
44559 for (var i in ty) {
44561 this.toolbars[i] = this.buildToolbar(ty[i],i);
44563 this.tb = this.toolbars.BODY;
44565 this.buildFooter();
44566 this.footer.show();
44567 editor.on('hide', function( ) { this.footer.hide() }, this);
44568 editor.on('show', function( ) { this.footer.show() }, this);
44571 this.rendered = true;
44573 // the all the btns;
44574 editor.on('editorevent', this.updateToolbar, this);
44575 // other toolbars need to implement this..
44576 //editor.on('editmodechange', this.updateToolbar, this);
44582 * Protected method that will not generally be called directly. It triggers
44583 * a toolbar update by reading the markup state of the current selection in the editor.
44585 * Note you can force an update by calling on('editorevent', scope, false)
44587 updateToolbar: function(editor,ev,sel){
44590 // capture mouse up - this is handy for selecting images..
44591 // perhaps should go somewhere else...
44592 if(!this.editorcore.activated){
44593 this.editor.onFirstFocus();
44599 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
44600 // selectNode - might want to handle IE?
44602 (ev.type == 'mouseup' || ev.type == 'click' ) &&
44603 ev.target && ev.target.tagName == 'IMG') {
44604 // they have click on an image...
44605 // let's see if we can change the selection...
44608 var nodeRange = sel.ownerDocument.createRange();
44610 nodeRange.selectNode(sel);
44612 nodeRange.selectNodeContents(sel);
44614 //nodeRange.collapse(true);
44615 var s = this.editorcore.win.getSelection();
44616 s.removeAllRanges();
44617 s.addRange(nodeRange);
44621 var updateFooter = sel ? false : true;
44624 var ans = this.editorcore.getAllAncestors();
44627 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44630 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
44631 sel = sel ? sel : this.editorcore.doc.body;
44632 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
44635 // pick a menu that exists..
44636 var tn = sel.tagName.toUpperCase();
44637 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
44639 tn = sel.tagName.toUpperCase();
44641 var lastSel = this.tb.selectedNode;
44643 this.tb.selectedNode = sel;
44645 // if current menu does not match..
44647 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
44650 ///console.log("show: " + tn);
44651 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
44654 this.tb.items.first().el.innerHTML = tn + ': ';
44657 // update attributes
44658 if (this.tb.fields) {
44659 this.tb.fields.each(function(e) {
44661 e.setValue(sel.style[e.stylename]);
44664 e.setValue(sel.getAttribute(e.attrname));
44668 var hasStyles = false;
44669 for(var i in this.styles) {
44676 var st = this.tb.fields.item(0);
44678 st.store.removeAll();
44681 var cn = sel.className.split(/\s+/);
44684 if (this.styles['*']) {
44686 Roo.each(this.styles['*'], function(v) {
44687 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44690 if (this.styles[tn]) {
44691 Roo.each(this.styles[tn], function(v) {
44692 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44696 st.store.loadData(avs);
44700 // flag our selected Node.
44701 this.tb.selectedNode = sel;
44704 Roo.menu.MenuMgr.hideAll();
44708 if (!updateFooter) {
44709 //this.footDisp.dom.innerHTML = '';
44712 // update the footer
44716 this.footerEls = ans.reverse();
44717 Roo.each(this.footerEls, function(a,i) {
44718 if (!a) { return; }
44719 html += html.length ? ' > ' : '';
44721 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44726 var sz = this.footDisp.up('td').getSize();
44727 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44728 this.footDisp.dom.style.marginLeft = '5px';
44730 this.footDisp.dom.style.overflow = 'hidden';
44732 this.footDisp.dom.innerHTML = html;
44734 //this.editorsyncValue();
44741 onDestroy : function(){
44744 this.tb.items.each(function(item){
44746 item.menu.removeAll();
44748 item.menu.el.destroy();
44756 onFirstFocus: function() {
44757 // need to do this for all the toolbars..
44758 this.tb.items.each(function(item){
44762 buildToolbar: function(tlist, nm)
44764 var editor = this.editor;
44765 var editorcore = this.editorcore;
44766 // create a new element.
44767 var wdiv = editor.wrap.createChild({
44769 }, editor.wrap.dom.firstChild.nextSibling, true);
44772 var tb = new Roo.Toolbar(wdiv);
44775 tb.add(nm+ ": ");
44778 for(var i in this.styles) {
44783 if (styles && styles.length) {
44785 // this needs a multi-select checkbox...
44786 tb.addField( new Roo.form.ComboBox({
44787 store: new Roo.data.SimpleStore({
44789 fields: ['val', 'selected'],
44792 name : '-roo-edit-className',
44793 attrname : 'className',
44794 displayField: 'val',
44798 triggerAction: 'all',
44799 emptyText:'Select Style',
44800 selectOnFocus:true,
44803 'select': function(c, r, i) {
44804 // initial support only for on class per el..
44805 tb.selectedNode.className = r ? r.get('val') : '';
44806 editorcore.syncValue();
44813 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44814 var tbops = tbc.options;
44816 for (var i in tlist) {
44818 var item = tlist[i];
44819 tb.add(item.title + ": ");
44822 //optname == used so you can configure the options available..
44823 var opts = item.opts ? item.opts : false;
44824 if (item.optname) {
44825 opts = tbops[item.optname];
44830 // opts == pulldown..
44831 tb.addField( new Roo.form.ComboBox({
44832 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44834 fields: ['val', 'display'],
44837 name : '-roo-edit-' + i,
44839 stylename : item.style ? item.style : false,
44840 displayField: item.displayField ? item.displayField : 'val',
44841 valueField : 'val',
44843 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44845 triggerAction: 'all',
44846 emptyText:'Select',
44847 selectOnFocus:true,
44848 width: item.width ? item.width : 130,
44850 'select': function(c, r, i) {
44852 tb.selectedNode.style[c.stylename] = r.get('val');
44855 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44864 tb.addField( new Roo.form.TextField({
44867 //allowBlank:false,
44872 tb.addField( new Roo.form.TextField({
44873 name: '-roo-edit-' + i,
44880 'change' : function(f, nv, ov) {
44881 tb.selectedNode.setAttribute(f.attrname, nv);
44894 text: 'Stylesheets',
44897 click : function ()
44899 _this.editor.fireEvent('stylesheetsclick', _this.editor);
44907 text: 'Remove Tag',
44910 click : function ()
44913 // undo does not work.
44915 var sn = tb.selectedNode;
44917 var pn = sn.parentNode;
44919 var stn = sn.childNodes[0];
44920 var en = sn.childNodes[sn.childNodes.length - 1 ];
44921 while (sn.childNodes.length) {
44922 var node = sn.childNodes[0];
44923 sn.removeChild(node);
44925 pn.insertBefore(node, sn);
44928 pn.removeChild(sn);
44929 var range = editorcore.createRange();
44931 range.setStart(stn,0);
44932 range.setEnd(en,0); //????
44933 //range.selectNode(sel);
44936 var selection = editorcore.getSelection();
44937 selection.removeAllRanges();
44938 selection.addRange(range);
44942 //_this.updateToolbar(null, null, pn);
44943 _this.updateToolbar(null, null, null);
44944 _this.footDisp.dom.innerHTML = '';
44954 tb.el.on('click', function(e){
44955 e.preventDefault(); // what does this do?
44957 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44960 // dont need to disable them... as they will get hidden
44965 buildFooter : function()
44968 var fel = this.editor.wrap.createChild();
44969 this.footer = new Roo.Toolbar(fel);
44970 // toolbar has scrolly on left / right?
44971 var footDisp= new Roo.Toolbar.Fill();
44977 handler : function() {
44978 _t.footDisp.scrollTo('left',0,true)
44982 this.footer.add( footDisp );
44987 handler : function() {
44989 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44993 var fel = Roo.get(footDisp.el);
44994 fel.addClass('x-editor-context');
44995 this.footDispWrap = fel;
44996 this.footDispWrap.overflow = 'hidden';
44998 this.footDisp = fel.createChild();
44999 this.footDispWrap.on('click', this.onContextClick, this)
45003 onContextClick : function (ev,dom)
45005 ev.preventDefault();
45006 var cn = dom.className;
45008 if (!cn.match(/x-ed-loc-/)) {
45011 var n = cn.split('-').pop();
45012 var ans = this.footerEls;
45016 var range = this.editorcore.createRange();
45018 range.selectNodeContents(sel);
45019 //range.selectNode(sel);
45022 var selection = this.editorcore.getSelection();
45023 selection.removeAllRanges();
45024 selection.addRange(range);
45028 this.updateToolbar(null, null, sel);
45045 * Ext JS Library 1.1.1
45046 * Copyright(c) 2006-2007, Ext JS, LLC.
45048 * Originally Released Under LGPL - original licence link has changed is not relivant.
45051 * <script type="text/javascript">
45055 * @class Roo.form.BasicForm
45056 * @extends Roo.util.Observable
45057 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
45059 * @param {String/HTMLElement/Roo.Element} el The form element or its id
45060 * @param {Object} config Configuration options
45062 Roo.form.BasicForm = function(el, config){
45063 this.allItems = [];
45064 this.childForms = [];
45065 Roo.apply(this, config);
45067 * The Roo.form.Field items in this form.
45068 * @type MixedCollection
45072 this.items = new Roo.util.MixedCollection(false, function(o){
45073 return o.id || (o.id = Roo.id());
45077 * @event beforeaction
45078 * Fires before any action is performed. Return false to cancel the action.
45079 * @param {Form} this
45080 * @param {Action} action The action to be performed
45082 beforeaction: true,
45084 * @event actionfailed
45085 * Fires when an action fails.
45086 * @param {Form} this
45087 * @param {Action} action The action that failed
45089 actionfailed : true,
45091 * @event actioncomplete
45092 * Fires when an action is completed.
45093 * @param {Form} this
45094 * @param {Action} action The action that completed
45096 actioncomplete : true
45101 Roo.form.BasicForm.superclass.constructor.call(this);
45104 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
45106 * @cfg {String} method
45107 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
45110 * @cfg {DataReader} reader
45111 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
45112 * This is optional as there is built-in support for processing JSON.
45115 * @cfg {DataReader} errorReader
45116 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
45117 * This is completely optional as there is built-in support for processing JSON.
45120 * @cfg {String} url
45121 * The URL to use for form actions if one isn't supplied in the action options.
45124 * @cfg {Boolean} fileUpload
45125 * Set to true if this form is a file upload.
45129 * @cfg {Object} baseParams
45130 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
45135 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
45140 activeAction : null,
45143 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
45144 * or setValues() data instead of when the form was first created.
45146 trackResetOnLoad : false,
45150 * childForms - used for multi-tab forms
45153 childForms : false,
45156 * allItems - full list of fields.
45162 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
45163 * element by passing it or its id or mask the form itself by passing in true.
45166 waitMsgTarget : false,
45169 initEl : function(el){
45170 this.el = Roo.get(el);
45171 this.id = this.el.id || Roo.id();
45172 this.el.on('submit', this.onSubmit, this);
45173 this.el.addClass('x-form');
45177 onSubmit : function(e){
45182 * Returns true if client-side validation on the form is successful.
45185 isValid : function(){
45187 this.items.each(function(f){
45196 * DEPRICATED Returns true if any fields in this form have changed since their original load.
45199 isDirty : function(){
45201 this.items.each(function(f){
45211 * Returns true if any fields in this form have changed since their original load. (New version)
45215 hasChanged : function()
45218 this.items.each(function(f){
45219 if(f.hasChanged()){
45228 * Resets all hasChanged to 'false' -
45229 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
45230 * So hasChanged storage is only to be used for this purpose
45233 resetHasChanged : function()
45235 this.items.each(function(f){
45236 f.resetHasChanged();
45243 * Performs a predefined action (submit or load) or custom actions you define on this form.
45244 * @param {String} actionName The name of the action type
45245 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
45246 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
45247 * accept other config options):
45249 Property Type Description
45250 ---------------- --------------- ----------------------------------------------------------------------------------
45251 url String The url for the action (defaults to the form's url)
45252 method String The form method to use (defaults to the form's method, or POST if not defined)
45253 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
45254 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
45255 validate the form on the client (defaults to false)
45257 * @return {BasicForm} this
45259 doAction : function(action, options){
45260 if(typeof action == 'string'){
45261 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
45263 if(this.fireEvent('beforeaction', this, action) !== false){
45264 this.beforeAction(action);
45265 action.run.defer(100, action);
45271 * Shortcut to do a submit action.
45272 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45273 * @return {BasicForm} this
45275 submit : function(options){
45276 this.doAction('submit', options);
45281 * Shortcut to do a load action.
45282 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45283 * @return {BasicForm} this
45285 load : function(options){
45286 this.doAction('load', options);
45291 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
45292 * @param {Record} record The record to edit
45293 * @return {BasicForm} this
45295 updateRecord : function(record){
45296 record.beginEdit();
45297 var fs = record.fields;
45298 fs.each(function(f){
45299 var field = this.findField(f.name);
45301 record.set(f.name, field.getValue());
45309 * Loads an Roo.data.Record into this form.
45310 * @param {Record} record The record to load
45311 * @return {BasicForm} this
45313 loadRecord : function(record){
45314 this.setValues(record.data);
45319 beforeAction : function(action){
45320 var o = action.options;
45323 if(this.waitMsgTarget === true){
45324 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
45325 }else if(this.waitMsgTarget){
45326 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
45327 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
45329 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
45335 afterAction : function(action, success){
45336 this.activeAction = null;
45337 var o = action.options;
45339 if(this.waitMsgTarget === true){
45341 }else if(this.waitMsgTarget){
45342 this.waitMsgTarget.unmask();
45344 Roo.MessageBox.updateProgress(1);
45345 Roo.MessageBox.hide();
45352 Roo.callback(o.success, o.scope, [this, action]);
45353 this.fireEvent('actioncomplete', this, action);
45357 // failure condition..
45358 // we have a scenario where updates need confirming.
45359 // eg. if a locking scenario exists..
45360 // we look for { errors : { needs_confirm : true }} in the response.
45362 (typeof(action.result) != 'undefined') &&
45363 (typeof(action.result.errors) != 'undefined') &&
45364 (typeof(action.result.errors.needs_confirm) != 'undefined')
45367 Roo.MessageBox.confirm(
45368 "Change requires confirmation",
45369 action.result.errorMsg,
45374 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
45384 Roo.callback(o.failure, o.scope, [this, action]);
45385 // show an error message if no failed handler is set..
45386 if (!this.hasListener('actionfailed')) {
45387 Roo.MessageBox.alert("Error",
45388 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
45389 action.result.errorMsg :
45390 "Saving Failed, please check your entries or try again"
45394 this.fireEvent('actionfailed', this, action);
45400 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
45401 * @param {String} id The value to search for
45404 findField : function(id){
45405 var field = this.items.get(id);
45407 this.items.each(function(f){
45408 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
45414 return field || null;
45418 * Add a secondary form to this one,
45419 * Used to provide tabbed forms. One form is primary, with hidden values
45420 * which mirror the elements from the other forms.
45422 * @param {Roo.form.Form} form to add.
45425 addForm : function(form)
45428 if (this.childForms.indexOf(form) > -1) {
45432 this.childForms.push(form);
45434 Roo.each(form.allItems, function (fe) {
45436 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
45437 if (this.findField(n)) { // already added..
45440 var add = new Roo.form.Hidden({
45443 add.render(this.el);
45450 * Mark fields in this form invalid in bulk.
45451 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
45452 * @return {BasicForm} this
45454 markInvalid : function(errors){
45455 if(errors instanceof Array){
45456 for(var i = 0, len = errors.length; i < len; i++){
45457 var fieldError = errors[i];
45458 var f = this.findField(fieldError.id);
45460 f.markInvalid(fieldError.msg);
45466 if(typeof errors[id] != 'function' && (field = this.findField(id))){
45467 field.markInvalid(errors[id]);
45471 Roo.each(this.childForms || [], function (f) {
45472 f.markInvalid(errors);
45479 * Set values for fields in this form in bulk.
45480 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
45481 * @return {BasicForm} this
45483 setValues : function(values){
45484 if(values instanceof Array){ // array of objects
45485 for(var i = 0, len = values.length; i < len; i++){
45487 var f = this.findField(v.id);
45489 f.setValue(v.value);
45490 if(this.trackResetOnLoad){
45491 f.originalValue = f.getValue();
45495 }else{ // object hash
45498 if(typeof values[id] != 'function' && (field = this.findField(id))){
45500 if (field.setFromData &&
45501 field.valueField &&
45502 field.displayField &&
45503 // combos' with local stores can
45504 // be queried via setValue()
45505 // to set their value..
45506 (field.store && !field.store.isLocal)
45510 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
45511 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
45512 field.setFromData(sd);
45515 field.setValue(values[id]);
45519 if(this.trackResetOnLoad){
45520 field.originalValue = field.getValue();
45525 this.resetHasChanged();
45528 Roo.each(this.childForms || [], function (f) {
45529 f.setValues(values);
45530 f.resetHasChanged();
45537 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
45538 * they are returned as an array.
45539 * @param {Boolean} asString
45542 getValues : function(asString){
45543 if (this.childForms) {
45544 // copy values from the child forms
45545 Roo.each(this.childForms, function (f) {
45546 this.setValues(f.getValues());
45552 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
45553 if(asString === true){
45556 return Roo.urlDecode(fs);
45560 * Returns the fields in this form as an object with key/value pairs.
45561 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
45564 getFieldValues : function(with_hidden)
45566 if (this.childForms) {
45567 // copy values from the child forms
45568 // should this call getFieldValues - probably not as we do not currently copy
45569 // hidden fields when we generate..
45570 Roo.each(this.childForms, function (f) {
45571 this.setValues(f.getValues());
45576 this.items.each(function(f){
45577 if (!f.getName()) {
45580 var v = f.getValue();
45581 if (f.inputType =='radio') {
45582 if (typeof(ret[f.getName()]) == 'undefined') {
45583 ret[f.getName()] = ''; // empty..
45586 if (!f.el.dom.checked) {
45590 v = f.el.dom.value;
45594 // not sure if this supported any more..
45595 if ((typeof(v) == 'object') && f.getRawValue) {
45596 v = f.getRawValue() ; // dates..
45598 // combo boxes where name != hiddenName...
45599 if (f.name != f.getName()) {
45600 ret[f.name] = f.getRawValue();
45602 ret[f.getName()] = v;
45609 * Clears all invalid messages in this form.
45610 * @return {BasicForm} this
45612 clearInvalid : function(){
45613 this.items.each(function(f){
45617 Roo.each(this.childForms || [], function (f) {
45626 * Resets this form.
45627 * @return {BasicForm} this
45629 reset : function(){
45630 this.items.each(function(f){
45634 Roo.each(this.childForms || [], function (f) {
45637 this.resetHasChanged();
45643 * Add Roo.form components to this form.
45644 * @param {Field} field1
45645 * @param {Field} field2 (optional)
45646 * @param {Field} etc (optional)
45647 * @return {BasicForm} this
45650 this.items.addAll(Array.prototype.slice.call(arguments, 0));
45656 * Removes a field from the items collection (does NOT remove its markup).
45657 * @param {Field} field
45658 * @return {BasicForm} this
45660 remove : function(field){
45661 this.items.remove(field);
45666 * Looks at the fields in this form, checks them for an id attribute,
45667 * and calls applyTo on the existing dom element with that id.
45668 * @return {BasicForm} this
45670 render : function(){
45671 this.items.each(function(f){
45672 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
45680 * Calls {@link Ext#apply} for all fields in this form with the passed object.
45681 * @param {Object} values
45682 * @return {BasicForm} this
45684 applyToFields : function(o){
45685 this.items.each(function(f){
45692 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
45693 * @param {Object} values
45694 * @return {BasicForm} this
45696 applyIfToFields : function(o){
45697 this.items.each(function(f){
45705 Roo.BasicForm = Roo.form.BasicForm;/*
45707 * Ext JS Library 1.1.1
45708 * Copyright(c) 2006-2007, Ext JS, LLC.
45710 * Originally Released Under LGPL - original licence link has changed is not relivant.
45713 * <script type="text/javascript">
45717 * @class Roo.form.Form
45718 * @extends Roo.form.BasicForm
45719 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
45721 * @param {Object} config Configuration options
45723 Roo.form.Form = function(config){
45725 if (config.items) {
45726 xitems = config.items;
45727 delete config.items;
45731 Roo.form.Form.superclass.constructor.call(this, null, config);
45732 this.url = this.url || this.action;
45734 this.root = new Roo.form.Layout(Roo.applyIf({
45738 this.active = this.root;
45740 * Array of all the buttons that have been added to this form via {@link addButton}
45744 this.allItems = [];
45747 * @event clientvalidation
45748 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45749 * @param {Form} this
45750 * @param {Boolean} valid true if the form has passed client-side validation
45752 clientvalidation: true,
45755 * Fires when the form is rendered
45756 * @param {Roo.form.Form} form
45761 if (this.progressUrl) {
45762 // push a hidden field onto the list of fields..
45766 name : 'UPLOAD_IDENTIFIER'
45771 Roo.each(xitems, this.addxtype, this);
45777 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45779 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45782 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45785 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45787 buttonAlign:'center',
45790 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45795 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45796 * This property cascades to child containers if not set.
45801 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45802 * fires a looping event with that state. This is required to bind buttons to the valid
45803 * state using the config value formBind:true on the button.
45805 monitorValid : false,
45808 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45813 * @cfg {String} progressUrl - Url to return progress data
45816 progressUrl : false,
45819 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45820 * fields are added and the column is closed. If no fields are passed the column remains open
45821 * until end() is called.
45822 * @param {Object} config The config to pass to the column
45823 * @param {Field} field1 (optional)
45824 * @param {Field} field2 (optional)
45825 * @param {Field} etc (optional)
45826 * @return Column The column container object
45828 column : function(c){
45829 var col = new Roo.form.Column(c);
45831 if(arguments.length > 1){ // duplicate code required because of Opera
45832 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45839 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45840 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45841 * until end() is called.
45842 * @param {Object} config The config to pass to the fieldset
45843 * @param {Field} field1 (optional)
45844 * @param {Field} field2 (optional)
45845 * @param {Field} etc (optional)
45846 * @return FieldSet The fieldset container object
45848 fieldset : function(c){
45849 var fs = new Roo.form.FieldSet(c);
45851 if(arguments.length > 1){ // duplicate code required because of Opera
45852 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45859 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45860 * fields are added and the container is closed. If no fields are passed the container remains open
45861 * until end() is called.
45862 * @param {Object} config The config to pass to the Layout
45863 * @param {Field} field1 (optional)
45864 * @param {Field} field2 (optional)
45865 * @param {Field} etc (optional)
45866 * @return Layout The container object
45868 container : function(c){
45869 var l = new Roo.form.Layout(c);
45871 if(arguments.length > 1){ // duplicate code required because of Opera
45872 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45879 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45880 * @param {Object} container A Roo.form.Layout or subclass of Layout
45881 * @return {Form} this
45883 start : function(c){
45884 // cascade label info
45885 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45886 this.active.stack.push(c);
45887 c.ownerCt = this.active;
45893 * Closes the current open container
45894 * @return {Form} this
45897 if(this.active == this.root){
45900 this.active = this.active.ownerCt;
45905 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45906 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45907 * as the label of the field.
45908 * @param {Field} field1
45909 * @param {Field} field2 (optional)
45910 * @param {Field} etc. (optional)
45911 * @return {Form} this
45914 this.active.stack.push.apply(this.active.stack, arguments);
45915 this.allItems.push.apply(this.allItems,arguments);
45917 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45918 if(a[i].isFormField){
45923 Roo.form.Form.superclass.add.apply(this, r);
45933 * Find any element that has been added to a form, using it's ID or name
45934 * This can include framesets, columns etc. along with regular fields..
45935 * @param {String} id - id or name to find.
45937 * @return {Element} e - or false if nothing found.
45939 findbyId : function(id)
45945 Roo.each(this.allItems, function(f){
45946 if (f.id == id || f.name == id ){
45957 * Render this form into the passed container. This should only be called once!
45958 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45959 * @return {Form} this
45961 render : function(ct)
45967 var o = this.autoCreate || {
45969 method : this.method || 'POST',
45970 id : this.id || Roo.id()
45972 this.initEl(ct.createChild(o));
45974 this.root.render(this.el);
45978 this.items.each(function(f){
45979 f.render('x-form-el-'+f.id);
45982 if(this.buttons.length > 0){
45983 // tables are required to maintain order and for correct IE layout
45984 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45985 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45986 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45988 var tr = tb.getElementsByTagName('tr')[0];
45989 for(var i = 0, len = this.buttons.length; i < len; i++) {
45990 var b = this.buttons[i];
45991 var td = document.createElement('td');
45992 td.className = 'x-form-btn-td';
45993 b.render(tr.appendChild(td));
45996 if(this.monitorValid){ // initialize after render
45997 this.startMonitoring();
45999 this.fireEvent('rendered', this);
46004 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
46005 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
46006 * object or a valid Roo.DomHelper element config
46007 * @param {Function} handler The function called when the button is clicked
46008 * @param {Object} scope (optional) The scope of the handler function
46009 * @return {Roo.Button}
46011 addButton : function(config, handler, scope){
46015 minWidth: this.minButtonWidth,
46018 if(typeof config == "string"){
46021 Roo.apply(bc, config);
46023 var btn = new Roo.Button(null, bc);
46024 this.buttons.push(btn);
46029 * Adds a series of form elements (using the xtype property as the factory method.
46030 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
46031 * @param {Object} config
46034 addxtype : function()
46036 var ar = Array.prototype.slice.call(arguments, 0);
46038 for(var i = 0; i < ar.length; i++) {
46040 continue; // skip -- if this happends something invalid got sent, we
46041 // should ignore it, as basically that interface element will not show up
46042 // and that should be pretty obvious!!
46045 if (Roo.form[ar[i].xtype]) {
46047 var fe = Roo.factory(ar[i], Roo.form);
46053 fe.store.form = this;
46058 this.allItems.push(fe);
46059 if (fe.items && fe.addxtype) {
46060 fe.addxtype.apply(fe, fe.items);
46070 // console.log('adding ' + ar[i].xtype);
46072 if (ar[i].xtype == 'Button') {
46073 //console.log('adding button');
46074 //console.log(ar[i]);
46075 this.addButton(ar[i]);
46076 this.allItems.push(fe);
46080 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
46081 alert('end is not supported on xtype any more, use items');
46083 // //console.log('adding end');
46091 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
46092 * option "monitorValid"
46094 startMonitoring : function(){
46097 Roo.TaskMgr.start({
46098 run : this.bindHandler,
46099 interval : this.monitorPoll || 200,
46106 * Stops monitoring of the valid state of this form
46108 stopMonitoring : function(){
46109 this.bound = false;
46113 bindHandler : function(){
46115 return false; // stops binding
46118 this.items.each(function(f){
46119 if(!f.isValid(true)){
46124 for(var i = 0, len = this.buttons.length; i < len; i++){
46125 var btn = this.buttons[i];
46126 if(btn.formBind === true && btn.disabled === valid){
46127 btn.setDisabled(!valid);
46130 this.fireEvent('clientvalidation', this, valid);
46144 Roo.Form = Roo.form.Form;
46147 * Ext JS Library 1.1.1
46148 * Copyright(c) 2006-2007, Ext JS, LLC.
46150 * Originally Released Under LGPL - original licence link has changed is not relivant.
46153 * <script type="text/javascript">
46156 // as we use this in bootstrap.
46157 Roo.namespace('Roo.form');
46159 * @class Roo.form.Action
46160 * Internal Class used to handle form actions
46162 * @param {Roo.form.BasicForm} el The form element or its id
46163 * @param {Object} config Configuration options
46168 // define the action interface
46169 Roo.form.Action = function(form, options){
46171 this.options = options || {};
46174 * Client Validation Failed
46177 Roo.form.Action.CLIENT_INVALID = 'client';
46179 * Server Validation Failed
46182 Roo.form.Action.SERVER_INVALID = 'server';
46184 * Connect to Server Failed
46187 Roo.form.Action.CONNECT_FAILURE = 'connect';
46189 * Reading Data from Server Failed
46192 Roo.form.Action.LOAD_FAILURE = 'load';
46194 Roo.form.Action.prototype = {
46196 failureType : undefined,
46197 response : undefined,
46198 result : undefined,
46200 // interface method
46201 run : function(options){
46205 // interface method
46206 success : function(response){
46210 // interface method
46211 handleResponse : function(response){
46215 // default connection failure
46216 failure : function(response){
46218 this.response = response;
46219 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46220 this.form.afterAction(this, false);
46223 processResponse : function(response){
46224 this.response = response;
46225 if(!response.responseText){
46228 this.result = this.handleResponse(response);
46229 return this.result;
46232 // utility functions used internally
46233 getUrl : function(appendParams){
46234 var url = this.options.url || this.form.url || this.form.el.dom.action;
46236 var p = this.getParams();
46238 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
46244 getMethod : function(){
46245 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
46248 getParams : function(){
46249 var bp = this.form.baseParams;
46250 var p = this.options.params;
46252 if(typeof p == "object"){
46253 p = Roo.urlEncode(Roo.applyIf(p, bp));
46254 }else if(typeof p == 'string' && bp){
46255 p += '&' + Roo.urlEncode(bp);
46258 p = Roo.urlEncode(bp);
46263 createCallback : function(){
46265 success: this.success,
46266 failure: this.failure,
46268 timeout: (this.form.timeout*1000),
46269 upload: this.form.fileUpload ? this.success : undefined
46274 Roo.form.Action.Submit = function(form, options){
46275 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
46278 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
46281 haveProgress : false,
46282 uploadComplete : false,
46284 // uploadProgress indicator.
46285 uploadProgress : function()
46287 if (!this.form.progressUrl) {
46291 if (!this.haveProgress) {
46292 Roo.MessageBox.progress("Uploading", "Uploading");
46294 if (this.uploadComplete) {
46295 Roo.MessageBox.hide();
46299 this.haveProgress = true;
46301 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
46303 var c = new Roo.data.Connection();
46305 url : this.form.progressUrl,
46310 success : function(req){
46311 //console.log(data);
46315 rdata = Roo.decode(req.responseText)
46317 Roo.log("Invalid data from server..");
46321 if (!rdata || !rdata.success) {
46323 Roo.MessageBox.alert(Roo.encode(rdata));
46326 var data = rdata.data;
46328 if (this.uploadComplete) {
46329 Roo.MessageBox.hide();
46334 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
46335 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
46338 this.uploadProgress.defer(2000,this);
46341 failure: function(data) {
46342 Roo.log('progress url failed ');
46353 // run get Values on the form, so it syncs any secondary forms.
46354 this.form.getValues();
46356 var o = this.options;
46357 var method = this.getMethod();
46358 var isPost = method == 'POST';
46359 if(o.clientValidation === false || this.form.isValid()){
46361 if (this.form.progressUrl) {
46362 this.form.findField('UPLOAD_IDENTIFIER').setValue(
46363 (new Date() * 1) + '' + Math.random());
46368 Roo.Ajax.request(Roo.apply(this.createCallback(), {
46369 form:this.form.el.dom,
46370 url:this.getUrl(!isPost),
46372 params:isPost ? this.getParams() : null,
46373 isUpload: this.form.fileUpload
46376 this.uploadProgress();
46378 }else if (o.clientValidation !== false){ // client validation failed
46379 this.failureType = Roo.form.Action.CLIENT_INVALID;
46380 this.form.afterAction(this, false);
46384 success : function(response)
46386 this.uploadComplete= true;
46387 if (this.haveProgress) {
46388 Roo.MessageBox.hide();
46392 var result = this.processResponse(response);
46393 if(result === true || result.success){
46394 this.form.afterAction(this, true);
46398 this.form.markInvalid(result.errors);
46399 this.failureType = Roo.form.Action.SERVER_INVALID;
46401 this.form.afterAction(this, false);
46403 failure : function(response)
46405 this.uploadComplete= true;
46406 if (this.haveProgress) {
46407 Roo.MessageBox.hide();
46410 this.response = response;
46411 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46412 this.form.afterAction(this, false);
46415 handleResponse : function(response){
46416 if(this.form.errorReader){
46417 var rs = this.form.errorReader.read(response);
46420 for(var i = 0, len = rs.records.length; i < len; i++) {
46421 var r = rs.records[i];
46422 errors[i] = r.data;
46425 if(errors.length < 1){
46429 success : rs.success,
46435 ret = Roo.decode(response.responseText);
46439 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
46449 Roo.form.Action.Load = function(form, options){
46450 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
46451 this.reader = this.form.reader;
46454 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
46459 Roo.Ajax.request(Roo.apply(
46460 this.createCallback(), {
46461 method:this.getMethod(),
46462 url:this.getUrl(false),
46463 params:this.getParams()
46467 success : function(response){
46469 var result = this.processResponse(response);
46470 if(result === true || !result.success || !result.data){
46471 this.failureType = Roo.form.Action.LOAD_FAILURE;
46472 this.form.afterAction(this, false);
46475 this.form.clearInvalid();
46476 this.form.setValues(result.data);
46477 this.form.afterAction(this, true);
46480 handleResponse : function(response){
46481 if(this.form.reader){
46482 var rs = this.form.reader.read(response);
46483 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
46485 success : rs.success,
46489 return Roo.decode(response.responseText);
46493 Roo.form.Action.ACTION_TYPES = {
46494 'load' : Roo.form.Action.Load,
46495 'submit' : Roo.form.Action.Submit
46498 * Ext JS Library 1.1.1
46499 * Copyright(c) 2006-2007, Ext JS, LLC.
46501 * Originally Released Under LGPL - original licence link has changed is not relivant.
46504 * <script type="text/javascript">
46508 * @class Roo.form.Layout
46509 * @extends Roo.Component
46510 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
46512 * @param {Object} config Configuration options
46514 Roo.form.Layout = function(config){
46516 if (config.items) {
46517 xitems = config.items;
46518 delete config.items;
46520 Roo.form.Layout.superclass.constructor.call(this, config);
46522 Roo.each(xitems, this.addxtype, this);
46526 Roo.extend(Roo.form.Layout, Roo.Component, {
46528 * @cfg {String/Object} autoCreate
46529 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
46532 * @cfg {String/Object/Function} style
46533 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
46534 * a function which returns such a specification.
46537 * @cfg {String} labelAlign
46538 * Valid values are "left," "top" and "right" (defaults to "left")
46541 * @cfg {Number} labelWidth
46542 * Fixed width in pixels of all field labels (defaults to undefined)
46545 * @cfg {Boolean} clear
46546 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
46550 * @cfg {String} labelSeparator
46551 * The separator to use after field labels (defaults to ':')
46553 labelSeparator : ':',
46555 * @cfg {Boolean} hideLabels
46556 * True to suppress the display of field labels in this layout (defaults to false)
46558 hideLabels : false,
46561 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
46566 onRender : function(ct, position){
46567 if(this.el){ // from markup
46568 this.el = Roo.get(this.el);
46569 }else { // generate
46570 var cfg = this.getAutoCreate();
46571 this.el = ct.createChild(cfg, position);
46574 this.el.applyStyles(this.style);
46576 if(this.labelAlign){
46577 this.el.addClass('x-form-label-'+this.labelAlign);
46579 if(this.hideLabels){
46580 this.labelStyle = "display:none";
46581 this.elementStyle = "padding-left:0;";
46583 if(typeof this.labelWidth == 'number'){
46584 this.labelStyle = "width:"+this.labelWidth+"px;";
46585 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
46587 if(this.labelAlign == 'top'){
46588 this.labelStyle = "width:auto;";
46589 this.elementStyle = "padding-left:0;";
46592 var stack = this.stack;
46593 var slen = stack.length;
46595 if(!this.fieldTpl){
46596 var t = new Roo.Template(
46597 '<div class="x-form-item {5}">',
46598 '<label for="{0}" style="{2}">{1}{4}</label>',
46599 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46601 '</div><div class="x-form-clear-left"></div>'
46603 t.disableFormats = true;
46605 Roo.form.Layout.prototype.fieldTpl = t;
46607 for(var i = 0; i < slen; i++) {
46608 if(stack[i].isFormField){
46609 this.renderField(stack[i]);
46611 this.renderComponent(stack[i]);
46616 this.el.createChild({cls:'x-form-clear'});
46621 renderField : function(f){
46622 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
46625 f.labelStyle||this.labelStyle||'', //2
46626 this.elementStyle||'', //3
46627 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
46628 f.itemCls||this.itemCls||'' //5
46629 ], true).getPrevSibling());
46633 renderComponent : function(c){
46634 c.render(c.isLayout ? this.el : this.el.createChild());
46637 * Adds a object form elements (using the xtype property as the factory method.)
46638 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
46639 * @param {Object} config
46641 addxtype : function(o)
46643 // create the lement.
46644 o.form = this.form;
46645 var fe = Roo.factory(o, Roo.form);
46646 this.form.allItems.push(fe);
46647 this.stack.push(fe);
46649 if (fe.isFormField) {
46650 this.form.items.add(fe);
46658 * @class Roo.form.Column
46659 * @extends Roo.form.Layout
46660 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
46662 * @param {Object} config Configuration options
46664 Roo.form.Column = function(config){
46665 Roo.form.Column.superclass.constructor.call(this, config);
46668 Roo.extend(Roo.form.Column, Roo.form.Layout, {
46670 * @cfg {Number/String} width
46671 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46674 * @cfg {String/Object} autoCreate
46675 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
46679 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
46682 onRender : function(ct, position){
46683 Roo.form.Column.superclass.onRender.call(this, ct, position);
46685 this.el.setWidth(this.width);
46692 * @class Roo.form.Row
46693 * @extends Roo.form.Layout
46694 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
46696 * @param {Object} config Configuration options
46700 Roo.form.Row = function(config){
46701 Roo.form.Row.superclass.constructor.call(this, config);
46704 Roo.extend(Roo.form.Row, Roo.form.Layout, {
46706 * @cfg {Number/String} width
46707 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46710 * @cfg {Number/String} height
46711 * The fixed height of the column in pixels or CSS value (defaults to "auto")
46713 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
46717 onRender : function(ct, position){
46718 //console.log('row render');
46720 var t = new Roo.Template(
46721 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
46722 '<label for="{0}" style="{2}">{1}{4}</label>',
46723 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46727 t.disableFormats = true;
46729 Roo.form.Layout.prototype.rowTpl = t;
46731 this.fieldTpl = this.rowTpl;
46733 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46734 var labelWidth = 100;
46736 if ((this.labelAlign != 'top')) {
46737 if (typeof this.labelWidth == 'number') {
46738 labelWidth = this.labelWidth
46740 this.padWidth = 20 + labelWidth;
46744 Roo.form.Column.superclass.onRender.call(this, ct, position);
46746 this.el.setWidth(this.width);
46749 this.el.setHeight(this.height);
46754 renderField : function(f){
46755 f.fieldEl = this.fieldTpl.append(this.el, [
46756 f.id, f.fieldLabel,
46757 f.labelStyle||this.labelStyle||'',
46758 this.elementStyle||'',
46759 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46760 f.itemCls||this.itemCls||'',
46761 f.width ? f.width + this.padWidth : 160 + this.padWidth
46768 * @class Roo.form.FieldSet
46769 * @extends Roo.form.Layout
46770 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46772 * @param {Object} config Configuration options
46774 Roo.form.FieldSet = function(config){
46775 Roo.form.FieldSet.superclass.constructor.call(this, config);
46778 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46780 * @cfg {String} legend
46781 * The text to display as the legend for the FieldSet (defaults to '')
46784 * @cfg {String/Object} autoCreate
46785 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46789 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46792 onRender : function(ct, position){
46793 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46795 this.setLegend(this.legend);
46800 setLegend : function(text){
46802 this.el.child('legend').update(text);
46807 * Ext JS Library 1.1.1
46808 * Copyright(c) 2006-2007, Ext JS, LLC.
46810 * Originally Released Under LGPL - original licence link has changed is not relivant.
46813 * <script type="text/javascript">
46816 * @class Roo.form.VTypes
46817 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46820 Roo.form.VTypes = function(){
46821 // closure these in so they are only created once.
46822 var alpha = /^[a-zA-Z_]+$/;
46823 var alphanum = /^[a-zA-Z0-9_]+$/;
46824 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
46825 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46827 // All these messages and functions are configurable
46830 * The function used to validate email addresses
46831 * @param {String} value The email address
46833 'email' : function(v){
46834 return email.test(v);
46837 * The error text to display when the email validation function returns false
46840 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46842 * The keystroke filter mask to be applied on email input
46845 'emailMask' : /[a-z0-9_\.\-@]/i,
46848 * The function used to validate URLs
46849 * @param {String} value The URL
46851 'url' : function(v){
46852 return url.test(v);
46855 * The error text to display when the url validation function returns false
46858 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46861 * The function used to validate alpha values
46862 * @param {String} value The value
46864 'alpha' : function(v){
46865 return alpha.test(v);
46868 * The error text to display when the alpha validation function returns false
46871 'alphaText' : 'This field should only contain letters and _',
46873 * The keystroke filter mask to be applied on alpha input
46876 'alphaMask' : /[a-z_]/i,
46879 * The function used to validate alphanumeric values
46880 * @param {String} value The value
46882 'alphanum' : function(v){
46883 return alphanum.test(v);
46886 * The error text to display when the alphanumeric validation function returns false
46889 'alphanumText' : 'This field should only contain letters, numbers and _',
46891 * The keystroke filter mask to be applied on alphanumeric input
46894 'alphanumMask' : /[a-z0-9_]/i
46896 }();//<script type="text/javascript">
46899 * @class Roo.form.FCKeditor
46900 * @extends Roo.form.TextArea
46901 * Wrapper around the FCKEditor http://www.fckeditor.net
46903 * Creates a new FCKeditor
46904 * @param {Object} config Configuration options
46906 Roo.form.FCKeditor = function(config){
46907 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46910 * @event editorinit
46911 * Fired when the editor is initialized - you can add extra handlers here..
46912 * @param {FCKeditor} this
46913 * @param {Object} the FCK object.
46920 Roo.form.FCKeditor.editors = { };
46921 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46923 //defaultAutoCreate : {
46924 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46928 * @cfg {Object} fck options - see fck manual for details.
46933 * @cfg {Object} fck toolbar set (Basic or Default)
46935 toolbarSet : 'Basic',
46937 * @cfg {Object} fck BasePath
46939 basePath : '/fckeditor/',
46947 onRender : function(ct, position)
46950 this.defaultAutoCreate = {
46952 style:"width:300px;height:60px;",
46953 autocomplete: "new-password"
46956 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46959 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46960 if(this.preventScrollbars){
46961 this.el.setStyle("overflow", "hidden");
46963 this.el.setHeight(this.growMin);
46966 //console.log('onrender' + this.getId() );
46967 Roo.form.FCKeditor.editors[this.getId()] = this;
46970 this.replaceTextarea() ;
46974 getEditor : function() {
46975 return this.fckEditor;
46978 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46979 * @param {Mixed} value The value to set
46983 setValue : function(value)
46985 //console.log('setValue: ' + value);
46987 if(typeof(value) == 'undefined') { // not sure why this is happending...
46990 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46992 //if(!this.el || !this.getEditor()) {
46993 // this.value = value;
46994 //this.setValue.defer(100,this,[value]);
46998 if(!this.getEditor()) {
47002 this.getEditor().SetData(value);
47009 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
47010 * @return {Mixed} value The field value
47012 getValue : function()
47015 if (this.frame && this.frame.dom.style.display == 'none') {
47016 return Roo.form.FCKeditor.superclass.getValue.call(this);
47019 if(!this.el || !this.getEditor()) {
47021 // this.getValue.defer(100,this);
47026 var value=this.getEditor().GetData();
47027 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
47028 return Roo.form.FCKeditor.superclass.getValue.call(this);
47034 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
47035 * @return {Mixed} value The field value
47037 getRawValue : function()
47039 if (this.frame && this.frame.dom.style.display == 'none') {
47040 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
47043 if(!this.el || !this.getEditor()) {
47044 //this.getRawValue.defer(100,this);
47051 var value=this.getEditor().GetData();
47052 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
47053 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
47057 setSize : function(w,h) {
47061 //if (this.frame && this.frame.dom.style.display == 'none') {
47062 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
47065 //if(!this.el || !this.getEditor()) {
47066 // this.setSize.defer(100,this, [w,h]);
47072 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
47074 this.frame.dom.setAttribute('width', w);
47075 this.frame.dom.setAttribute('height', h);
47076 this.frame.setSize(w,h);
47080 toggleSourceEdit : function(value) {
47084 this.el.dom.style.display = value ? '' : 'none';
47085 this.frame.dom.style.display = value ? 'none' : '';
47090 focus: function(tag)
47092 if (this.frame.dom.style.display == 'none') {
47093 return Roo.form.FCKeditor.superclass.focus.call(this);
47095 if(!this.el || !this.getEditor()) {
47096 this.focus.defer(100,this, [tag]);
47103 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
47104 this.getEditor().Focus();
47106 if (!this.getEditor().Selection.GetSelection()) {
47107 this.focus.defer(100,this, [tag]);
47112 var r = this.getEditor().EditorDocument.createRange();
47113 r.setStart(tgs[0],0);
47114 r.setEnd(tgs[0],0);
47115 this.getEditor().Selection.GetSelection().removeAllRanges();
47116 this.getEditor().Selection.GetSelection().addRange(r);
47117 this.getEditor().Focus();
47124 replaceTextarea : function()
47126 if ( document.getElementById( this.getId() + '___Frame' ) ) {
47129 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
47131 // We must check the elements firstly using the Id and then the name.
47132 var oTextarea = document.getElementById( this.getId() );
47134 var colElementsByName = document.getElementsByName( this.getId() ) ;
47136 oTextarea.style.display = 'none' ;
47138 if ( oTextarea.tabIndex ) {
47139 this.TabIndex = oTextarea.tabIndex ;
47142 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
47143 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
47144 this.frame = Roo.get(this.getId() + '___Frame')
47147 _getConfigHtml : function()
47151 for ( var o in this.fckconfig ) {
47152 sConfig += sConfig.length > 0 ? '&' : '';
47153 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
47156 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
47160 _getIFrameHtml : function()
47162 var sFile = 'fckeditor.html' ;
47163 /* no idea what this is about..
47166 if ( (/fcksource=true/i).test( window.top.location.search ) )
47167 sFile = 'fckeditor.original.html' ;
47172 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
47173 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
47176 var html = '<iframe id="' + this.getId() +
47177 '___Frame" src="' + sLink +
47178 '" width="' + this.width +
47179 '" height="' + this.height + '"' +
47180 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
47181 ' frameborder="0" scrolling="no"></iframe>' ;
47186 _insertHtmlBefore : function( html, element )
47188 if ( element.insertAdjacentHTML ) {
47190 element.insertAdjacentHTML( 'beforeBegin', html ) ;
47192 var oRange = document.createRange() ;
47193 oRange.setStartBefore( element ) ;
47194 var oFragment = oRange.createContextualFragment( html );
47195 element.parentNode.insertBefore( oFragment, element ) ;
47208 //Roo.reg('fckeditor', Roo.form.FCKeditor);
47210 function FCKeditor_OnComplete(editorInstance){
47211 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
47212 f.fckEditor = editorInstance;
47213 //console.log("loaded");
47214 f.fireEvent('editorinit', f, editorInstance);
47234 //<script type="text/javascript">
47236 * @class Roo.form.GridField
47237 * @extends Roo.form.Field
47238 * Embed a grid (or editable grid into a form)
47241 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
47243 * xgrid.store = Roo.data.Store
47244 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
47245 * xgrid.store.reader = Roo.data.JsonReader
47249 * Creates a new GridField
47250 * @param {Object} config Configuration options
47252 Roo.form.GridField = function(config){
47253 Roo.form.GridField.superclass.constructor.call(this, config);
47257 Roo.extend(Roo.form.GridField, Roo.form.Field, {
47259 * @cfg {Number} width - used to restrict width of grid..
47263 * @cfg {Number} height - used to restrict height of grid..
47267 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
47273 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47274 * {tag: "input", type: "checkbox", autocomplete: "off"})
47276 // defaultAutoCreate : { tag: 'div' },
47277 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
47279 * @cfg {String} addTitle Text to include for adding a title.
47283 onResize : function(){
47284 Roo.form.Field.superclass.onResize.apply(this, arguments);
47287 initEvents : function(){
47288 // Roo.form.Checkbox.superclass.initEvents.call(this);
47289 // has no events...
47294 getResizeEl : function(){
47298 getPositionEl : function(){
47303 onRender : function(ct, position){
47305 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
47306 var style = this.style;
47309 Roo.form.GridField.superclass.onRender.call(this, ct, position);
47310 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
47311 this.viewEl = this.wrap.createChild({ tag: 'div' });
47313 this.viewEl.applyStyles(style);
47316 this.viewEl.setWidth(this.width);
47319 this.viewEl.setHeight(this.height);
47321 //if(this.inputValue !== undefined){
47322 //this.setValue(this.value);
47325 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
47328 this.grid.render();
47329 this.grid.getDataSource().on('remove', this.refreshValue, this);
47330 this.grid.getDataSource().on('update', this.refreshValue, this);
47331 this.grid.on('afteredit', this.refreshValue, this);
47337 * Sets the value of the item.
47338 * @param {String} either an object or a string..
47340 setValue : function(v){
47342 v = v || []; // empty set..
47343 // this does not seem smart - it really only affects memoryproxy grids..
47344 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
47345 var ds = this.grid.getDataSource();
47346 // assumes a json reader..
47348 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
47349 ds.loadData( data);
47351 // clear selection so it does not get stale.
47352 if (this.grid.sm) {
47353 this.grid.sm.clearSelections();
47356 Roo.form.GridField.superclass.setValue.call(this, v);
47357 this.refreshValue();
47358 // should load data in the grid really....
47362 refreshValue: function() {
47364 this.grid.getDataSource().each(function(r) {
47367 this.el.dom.value = Roo.encode(val);
47375 * Ext JS Library 1.1.1
47376 * Copyright(c) 2006-2007, Ext JS, LLC.
47378 * Originally Released Under LGPL - original licence link has changed is not relivant.
47381 * <script type="text/javascript">
47384 * @class Roo.form.DisplayField
47385 * @extends Roo.form.Field
47386 * A generic Field to display non-editable data.
47387 * @cfg {Boolean} closable (true|false) default false
47389 * Creates a new Display Field item.
47390 * @param {Object} config Configuration options
47392 Roo.form.DisplayField = function(config){
47393 Roo.form.DisplayField.superclass.constructor.call(this, config);
47398 * Fires after the click the close btn
47399 * @param {Roo.form.DisplayField} this
47405 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
47406 inputType: 'hidden',
47412 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47414 focusClass : undefined,
47416 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47418 fieldClass: 'x-form-field',
47421 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
47423 valueRenderer: undefined,
47427 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47428 * {tag: "input", type: "checkbox", autocomplete: "off"})
47431 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
47435 onResize : function(){
47436 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
47440 initEvents : function(){
47441 // Roo.form.Checkbox.superclass.initEvents.call(this);
47442 // has no events...
47445 this.closeEl.on('click', this.onClose, this);
47451 getResizeEl : function(){
47455 getPositionEl : function(){
47460 onRender : function(ct, position){
47462 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
47463 //if(this.inputValue !== undefined){
47464 this.wrap = this.el.wrap();
47466 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
47469 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
47472 if (this.bodyStyle) {
47473 this.viewEl.applyStyles(this.bodyStyle);
47475 //this.viewEl.setStyle('padding', '2px');
47477 this.setValue(this.value);
47482 initValue : Roo.emptyFn,
47487 onClick : function(){
47492 * Sets the checked state of the checkbox.
47493 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
47495 setValue : function(v){
47497 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
47498 // this might be called before we have a dom element..
47499 if (!this.viewEl) {
47502 this.viewEl.dom.innerHTML = html;
47503 Roo.form.DisplayField.superclass.setValue.call(this, v);
47507 onClose : function(e)
47509 e.preventDefault();
47511 this.fireEvent('close', this);
47520 * @class Roo.form.DayPicker
47521 * @extends Roo.form.Field
47522 * A Day picker show [M] [T] [W] ....
47524 * Creates a new Day Picker
47525 * @param {Object} config Configuration options
47527 Roo.form.DayPicker= function(config){
47528 Roo.form.DayPicker.superclass.constructor.call(this, config);
47532 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
47534 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47536 focusClass : undefined,
47538 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47540 fieldClass: "x-form-field",
47543 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47544 * {tag: "input", type: "checkbox", autocomplete: "off"})
47546 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
47549 actionMode : 'viewEl',
47553 inputType : 'hidden',
47556 inputElement: false, // real input element?
47557 basedOn: false, // ????
47559 isFormField: true, // not sure where this is needed!!!!
47561 onResize : function(){
47562 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
47563 if(!this.boxLabel){
47564 this.el.alignTo(this.wrap, 'c-c');
47568 initEvents : function(){
47569 Roo.form.Checkbox.superclass.initEvents.call(this);
47570 this.el.on("click", this.onClick, this);
47571 this.el.on("change", this.onClick, this);
47575 getResizeEl : function(){
47579 getPositionEl : function(){
47585 onRender : function(ct, position){
47586 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
47588 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
47590 var r1 = '<table><tr>';
47591 var r2 = '<tr class="x-form-daypick-icons">';
47592 for (var i=0; i < 7; i++) {
47593 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
47594 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
47597 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
47598 viewEl.select('img').on('click', this.onClick, this);
47599 this.viewEl = viewEl;
47602 // this will not work on Chrome!!!
47603 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
47604 this.el.on('propertychange', this.setFromHidden, this); //ie
47612 initValue : Roo.emptyFn,
47615 * Returns the checked state of the checkbox.
47616 * @return {Boolean} True if checked, else false
47618 getValue : function(){
47619 return this.el.dom.value;
47624 onClick : function(e){
47625 //this.setChecked(!this.checked);
47626 Roo.get(e.target).toggleClass('x-menu-item-checked');
47627 this.refreshValue();
47628 //if(this.el.dom.checked != this.checked){
47629 // this.setValue(this.el.dom.checked);
47634 refreshValue : function()
47637 this.viewEl.select('img',true).each(function(e,i,n) {
47638 val += e.is(".x-menu-item-checked") ? String(n) : '';
47640 this.setValue(val, true);
47644 * Sets the checked state of the checkbox.
47645 * On is always based on a string comparison between inputValue and the param.
47646 * @param {Boolean/String} value - the value to set
47647 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
47649 setValue : function(v,suppressEvent){
47650 if (!this.el.dom) {
47653 var old = this.el.dom.value ;
47654 this.el.dom.value = v;
47655 if (suppressEvent) {
47659 // update display..
47660 this.viewEl.select('img',true).each(function(e,i,n) {
47662 var on = e.is(".x-menu-item-checked");
47663 var newv = v.indexOf(String(n)) > -1;
47665 e.toggleClass('x-menu-item-checked');
47671 this.fireEvent('change', this, v, old);
47676 // handle setting of hidden value by some other method!!?!?
47677 setFromHidden: function()
47682 //console.log("SET FROM HIDDEN");
47683 //alert('setFrom hidden');
47684 this.setValue(this.el.dom.value);
47687 onDestroy : function()
47690 Roo.get(this.viewEl).remove();
47693 Roo.form.DayPicker.superclass.onDestroy.call(this);
47697 * RooJS Library 1.1.1
47698 * Copyright(c) 2008-2011 Alan Knowles
47705 * @class Roo.form.ComboCheck
47706 * @extends Roo.form.ComboBox
47707 * A combobox for multiple select items.
47709 * FIXME - could do with a reset button..
47712 * Create a new ComboCheck
47713 * @param {Object} config Configuration options
47715 Roo.form.ComboCheck = function(config){
47716 Roo.form.ComboCheck.superclass.constructor.call(this, config);
47717 // should verify some data...
47719 // hiddenName = required..
47720 // displayField = required
47721 // valudField == required
47722 var req= [ 'hiddenName', 'displayField', 'valueField' ];
47724 Roo.each(req, function(e) {
47725 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
47726 throw "Roo.form.ComboCheck : missing value for: " + e;
47733 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
47738 selectedClass: 'x-menu-item-checked',
47741 onRender : function(ct, position){
47747 var cls = 'x-combo-list';
47750 this.tpl = new Roo.Template({
47751 html : '<div class="'+cls+'-item x-menu-check-item">' +
47752 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47753 '<span>{' + this.displayField + '}</span>' +
47760 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47761 this.view.singleSelect = false;
47762 this.view.multiSelect = true;
47763 this.view.toggleSelect = true;
47764 this.pageTb.add(new Roo.Toolbar.Fill(), {
47767 handler: function()
47774 onViewOver : function(e, t){
47780 onViewClick : function(doFocus,index){
47784 select: function () {
47785 //Roo.log("SELECT CALLED");
47788 selectByValue : function(xv, scrollIntoView){
47789 var ar = this.getValueArray();
47792 Roo.each(ar, function(v) {
47793 if(v === undefined || v === null){
47796 var r = this.findRecord(this.valueField, v);
47798 sels.push(this.store.indexOf(r))
47802 this.view.select(sels);
47808 onSelect : function(record, index){
47809 // Roo.log("onselect Called");
47810 // this is only called by the clear button now..
47811 this.view.clearSelections();
47812 this.setValue('[]');
47813 if (this.value != this.valueBefore) {
47814 this.fireEvent('change', this, this.value, this.valueBefore);
47815 this.valueBefore = this.value;
47818 getValueArray : function()
47823 //Roo.log(this.value);
47824 if (typeof(this.value) == 'undefined') {
47827 var ar = Roo.decode(this.value);
47828 return ar instanceof Array ? ar : []; //?? valid?
47831 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47836 expand : function ()
47839 Roo.form.ComboCheck.superclass.expand.call(this);
47840 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47841 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47846 collapse : function(){
47847 Roo.form.ComboCheck.superclass.collapse.call(this);
47848 var sl = this.view.getSelectedIndexes();
47849 var st = this.store;
47853 Roo.each(sl, function(i) {
47855 nv.push(r.get(this.valueField));
47857 this.setValue(Roo.encode(nv));
47858 if (this.value != this.valueBefore) {
47860 this.fireEvent('change', this, this.value, this.valueBefore);
47861 this.valueBefore = this.value;
47866 setValue : function(v){
47870 var vals = this.getValueArray();
47872 Roo.each(vals, function(k) {
47873 var r = this.findRecord(this.valueField, k);
47875 tv.push(r.data[this.displayField]);
47876 }else if(this.valueNotFoundText !== undefined){
47877 tv.push( this.valueNotFoundText );
47882 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47883 this.hiddenField.value = v;
47889 * Ext JS Library 1.1.1
47890 * Copyright(c) 2006-2007, Ext JS, LLC.
47892 * Originally Released Under LGPL - original licence link has changed is not relivant.
47895 * <script type="text/javascript">
47899 * @class Roo.form.Signature
47900 * @extends Roo.form.Field
47904 * @param {Object} config Configuration options
47907 Roo.form.Signature = function(config){
47908 Roo.form.Signature.superclass.constructor.call(this, config);
47910 this.addEvents({// not in used??
47913 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47914 * @param {Roo.form.Signature} combo This combo box
47919 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47920 * @param {Roo.form.ComboBox} combo This combo box
47921 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47927 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47929 * @cfg {Object} labels Label to use when rendering a form.
47933 * confirm : "Confirm"
47938 confirm : "Confirm"
47941 * @cfg {Number} width The signature panel width (defaults to 300)
47945 * @cfg {Number} height The signature panel height (defaults to 100)
47949 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47951 allowBlank : false,
47954 // {Object} signPanel The signature SVG panel element (defaults to {})
47956 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47957 isMouseDown : false,
47958 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47959 isConfirmed : false,
47960 // {String} signatureTmp SVG mapping string (defaults to empty string)
47964 defaultAutoCreate : { // modified by initCompnoent..
47970 onRender : function(ct, position){
47972 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47974 this.wrap = this.el.wrap({
47975 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47978 this.createToolbar(this);
47979 this.signPanel = this.wrap.createChild({
47981 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47985 this.svgID = Roo.id();
47986 this.svgEl = this.signPanel.createChild({
47987 xmlns : 'http://www.w3.org/2000/svg',
47989 id : this.svgID + "-svg",
47991 height: this.height,
47992 viewBox: '0 0 '+this.width+' '+this.height,
47996 id: this.svgID + "-svg-r",
47998 height: this.height,
48003 id: this.svgID + "-svg-l",
48005 y1: (this.height*0.8), // start set the line in 80% of height
48006 x2: this.width, // end
48007 y2: (this.height*0.8), // end set the line in 80% of height
48009 'stroke-width': "1",
48010 'stroke-dasharray': "3",
48011 'shape-rendering': "crispEdges",
48012 'pointer-events': "none"
48016 id: this.svgID + "-svg-p",
48018 'stroke-width': "3",
48020 'pointer-events': 'none'
48025 this.svgBox = this.svgEl.dom.getScreenCTM();
48027 createSVG : function(){
48028 var svg = this.signPanel;
48029 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
48032 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
48033 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
48034 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
48035 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
48036 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
48037 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
48038 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
48041 isTouchEvent : function(e){
48042 return e.type.match(/^touch/);
48044 getCoords : function (e) {
48045 var pt = this.svgEl.dom.createSVGPoint();
48048 if (this.isTouchEvent(e)) {
48049 pt.x = e.targetTouches[0].clientX;
48050 pt.y = e.targetTouches[0].clientY;
48052 var a = this.svgEl.dom.getScreenCTM();
48053 var b = a.inverse();
48054 var mx = pt.matrixTransform(b);
48055 return mx.x + ',' + mx.y;
48057 //mouse event headler
48058 down : function (e) {
48059 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
48060 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
48062 this.isMouseDown = true;
48064 e.preventDefault();
48066 move : function (e) {
48067 if (this.isMouseDown) {
48068 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
48069 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
48072 e.preventDefault();
48074 up : function (e) {
48075 this.isMouseDown = false;
48076 var sp = this.signatureTmp.split(' ');
48079 if(!sp[sp.length-2].match(/^L/)){
48083 this.signatureTmp = sp.join(" ");
48086 if(this.getValue() != this.signatureTmp){
48087 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48088 this.isConfirmed = false;
48090 e.preventDefault();
48094 * Protected method that will not generally be called directly. It
48095 * is called when the editor creates its toolbar. Override this method if you need to
48096 * add custom toolbar buttons.
48097 * @param {HtmlEditor} editor
48099 createToolbar : function(editor){
48100 function btn(id, toggle, handler){
48101 var xid = fid + '-'+ id ;
48105 cls : 'x-btn-icon x-edit-'+id,
48106 enableToggle:toggle !== false,
48107 scope: editor, // was editor...
48108 handler:handler||editor.relayBtnCmd,
48109 clickEvent:'mousedown',
48110 tooltip: etb.buttonTips[id] || undefined, ///tips ???
48116 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
48120 cls : ' x-signature-btn x-signature-'+id,
48121 scope: editor, // was editor...
48122 handler: this.reset,
48123 clickEvent:'mousedown',
48124 text: this.labels.clear
48131 cls : ' x-signature-btn x-signature-'+id,
48132 scope: editor, // was editor...
48133 handler: this.confirmHandler,
48134 clickEvent:'mousedown',
48135 text: this.labels.confirm
48142 * when user is clicked confirm then show this image.....
48144 * @return {String} Image Data URI
48146 getImageDataURI : function(){
48147 var svg = this.svgEl.dom.parentNode.innerHTML;
48148 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
48153 * @return {Boolean} this.isConfirmed
48155 getConfirmed : function(){
48156 return this.isConfirmed;
48160 * @return {Number} this.width
48162 getWidth : function(){
48167 * @return {Number} this.height
48169 getHeight : function(){
48170 return this.height;
48173 getSignature : function(){
48174 return this.signatureTmp;
48177 reset : function(){
48178 this.signatureTmp = '';
48179 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48180 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
48181 this.isConfirmed = false;
48182 Roo.form.Signature.superclass.reset.call(this);
48184 setSignature : function(s){
48185 this.signatureTmp = s;
48186 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48187 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
48189 this.isConfirmed = false;
48190 Roo.form.Signature.superclass.reset.call(this);
48193 // Roo.log(this.signPanel.dom.contentWindow.up())
48196 setConfirmed : function(){
48200 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
48203 confirmHandler : function(){
48204 if(!this.getSignature()){
48208 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
48209 this.setValue(this.getSignature());
48210 this.isConfirmed = true;
48212 this.fireEvent('confirm', this);
48215 // Subclasses should provide the validation implementation by overriding this
48216 validateValue : function(value){
48217 if(this.allowBlank){
48221 if(this.isConfirmed){
48228 * Ext JS Library 1.1.1
48229 * Copyright(c) 2006-2007, Ext JS, LLC.
48231 * Originally Released Under LGPL - original licence link has changed is not relivant.
48234 * <script type="text/javascript">
48239 * @class Roo.form.ComboBox
48240 * @extends Roo.form.TriggerField
48241 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
48243 * Create a new ComboBox.
48244 * @param {Object} config Configuration options
48246 Roo.form.Select = function(config){
48247 Roo.form.Select.superclass.constructor.call(this, config);
48251 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
48253 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
48256 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
48257 * rendering into an Roo.Editor, defaults to false)
48260 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
48261 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
48264 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
48267 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
48268 * the dropdown list (defaults to undefined, with no header element)
48272 * @cfg {String/Roo.Template} tpl The template to use to render the output
48276 defaultAutoCreate : {tag: "select" },
48278 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
48280 listWidth: undefined,
48282 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
48283 * mode = 'remote' or 'text' if mode = 'local')
48285 displayField: undefined,
48287 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
48288 * mode = 'remote' or 'value' if mode = 'local').
48289 * Note: use of a valueField requires the user make a selection
48290 * in order for a value to be mapped.
48292 valueField: undefined,
48296 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
48297 * field's data value (defaults to the underlying DOM element's name)
48299 hiddenName: undefined,
48301 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
48305 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
48307 selectedClass: 'x-combo-selected',
48309 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
48310 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
48311 * which displays a downward arrow icon).
48313 triggerClass : 'x-form-arrow-trigger',
48315 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
48319 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
48320 * anchor positions (defaults to 'tl-bl')
48322 listAlign: 'tl-bl?',
48324 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
48328 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
48329 * query specified by the allQuery config option (defaults to 'query')
48331 triggerAction: 'query',
48333 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
48334 * (defaults to 4, does not apply if editable = false)
48338 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
48339 * delay (typeAheadDelay) if it matches a known value (defaults to false)
48343 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
48344 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
48348 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
48349 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
48353 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
48354 * when editable = true (defaults to false)
48356 selectOnFocus:false,
48358 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
48360 queryParam: 'query',
48362 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
48363 * when mode = 'remote' (defaults to 'Loading...')
48365 loadingText: 'Loading...',
48367 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
48371 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
48375 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
48376 * traditional select (defaults to true)
48380 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
48384 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
48388 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
48389 * listWidth has a higher value)
48393 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
48394 * allow the user to set arbitrary text into the field (defaults to false)
48396 forceSelection:false,
48398 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
48399 * if typeAhead = true (defaults to 250)
48401 typeAheadDelay : 250,
48403 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
48404 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
48406 valueNotFoundText : undefined,
48409 * @cfg {String} defaultValue The value displayed after loading the store.
48414 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
48416 blockFocus : false,
48419 * @cfg {Boolean} disableClear Disable showing of clear button.
48421 disableClear : false,
48423 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
48425 alwaysQuery : false,
48431 // element that contains real text value.. (when hidden is used..)
48434 onRender : function(ct, position){
48435 Roo.form.Field.prototype.onRender.call(this, ct, position);
48438 this.store.on('beforeload', this.onBeforeLoad, this);
48439 this.store.on('load', this.onLoad, this);
48440 this.store.on('loadexception', this.onLoadException, this);
48441 this.store.load({});
48449 initEvents : function(){
48450 //Roo.form.ComboBox.superclass.initEvents.call(this);
48454 onDestroy : function(){
48457 this.store.un('beforeload', this.onBeforeLoad, this);
48458 this.store.un('load', this.onLoad, this);
48459 this.store.un('loadexception', this.onLoadException, this);
48461 //Roo.form.ComboBox.superclass.onDestroy.call(this);
48465 fireKey : function(e){
48466 if(e.isNavKeyPress() && !this.list.isVisible()){
48467 this.fireEvent("specialkey", this, e);
48472 onResize: function(w, h){
48480 * Allow or prevent the user from directly editing the field text. If false is passed,
48481 * the user will only be able to select from the items defined in the dropdown list. This method
48482 * is the runtime equivalent of setting the 'editable' config option at config time.
48483 * @param {Boolean} value True to allow the user to directly edit the field text
48485 setEditable : function(value){
48490 onBeforeLoad : function(){
48492 Roo.log("Select before load");
48495 this.innerList.update(this.loadingText ?
48496 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
48497 //this.restrictHeight();
48498 this.selectedIndex = -1;
48502 onLoad : function(){
48505 var dom = this.el.dom;
48506 dom.innerHTML = '';
48507 var od = dom.ownerDocument;
48509 if (this.emptyText) {
48510 var op = od.createElement('option');
48511 op.setAttribute('value', '');
48512 op.innerHTML = String.format('{0}', this.emptyText);
48513 dom.appendChild(op);
48515 if(this.store.getCount() > 0){
48517 var vf = this.valueField;
48518 var df = this.displayField;
48519 this.store.data.each(function(r) {
48520 // which colmsn to use... testing - cdoe / title..
48521 var op = od.createElement('option');
48522 op.setAttribute('value', r.data[vf]);
48523 op.innerHTML = String.format('{0}', r.data[df]);
48524 dom.appendChild(op);
48526 if (typeof(this.defaultValue != 'undefined')) {
48527 this.setValue(this.defaultValue);
48532 //this.onEmptyResults();
48537 onLoadException : function()
48539 dom.innerHTML = '';
48541 Roo.log("Select on load exception");
48545 Roo.log(this.store.reader.jsonData);
48546 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
48547 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
48553 onTypeAhead : function(){
48558 onSelect : function(record, index){
48559 Roo.log('on select?');
48561 if(this.fireEvent('beforeselect', this, record, index) !== false){
48562 this.setFromData(index > -1 ? record.data : false);
48564 this.fireEvent('select', this, record, index);
48569 * Returns the currently selected field value or empty string if no value is set.
48570 * @return {String} value The selected value
48572 getValue : function(){
48573 var dom = this.el.dom;
48574 this.value = dom.options[dom.selectedIndex].value;
48580 * Clears any text/value currently set in the field
48582 clearValue : function(){
48584 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
48589 * Sets the specified value into the field. If the value finds a match, the corresponding record text
48590 * will be displayed in the field. If the value does not match the data value of an existing item,
48591 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
48592 * Otherwise the field will be blank (although the value will still be set).
48593 * @param {String} value The value to match
48595 setValue : function(v){
48596 var d = this.el.dom;
48597 for (var i =0; i < d.options.length;i++) {
48598 if (v == d.options[i].value) {
48599 d.selectedIndex = i;
48607 * @property {Object} the last set data for the element
48612 * Sets the value of the field based on a object which is related to the record format for the store.
48613 * @param {Object} value the value to set as. or false on reset?
48615 setFromData : function(o){
48616 Roo.log('setfrom data?');
48622 reset : function(){
48626 findRecord : function(prop, value){
48631 if(this.store.getCount() > 0){
48632 this.store.each(function(r){
48633 if(r.data[prop] == value){
48643 getName: function()
48645 // returns hidden if it's set..
48646 if (!this.rendered) {return ''};
48647 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
48655 onEmptyResults : function(){
48656 Roo.log('empty results');
48661 * Returns true if the dropdown list is expanded, else false.
48663 isExpanded : function(){
48668 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
48669 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48670 * @param {String} value The data value of the item to select
48671 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48672 * selected item if it is not currently in view (defaults to true)
48673 * @return {Boolean} True if the value matched an item in the list, else false
48675 selectByValue : function(v, scrollIntoView){
48676 Roo.log('select By Value');
48679 if(v !== undefined && v !== null){
48680 var r = this.findRecord(this.valueField || this.displayField, v);
48682 this.select(this.store.indexOf(r), scrollIntoView);
48690 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
48691 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48692 * @param {Number} index The zero-based index of the list item to select
48693 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48694 * selected item if it is not currently in view (defaults to true)
48696 select : function(index, scrollIntoView){
48697 Roo.log('select ');
48700 this.selectedIndex = index;
48701 this.view.select(index);
48702 if(scrollIntoView !== false){
48703 var el = this.view.getNode(index);
48705 this.innerList.scrollChildIntoView(el, false);
48713 validateBlur : function(){
48720 initQuery : function(){
48721 this.doQuery(this.getRawValue());
48725 doForce : function(){
48726 if(this.el.dom.value.length > 0){
48727 this.el.dom.value =
48728 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
48734 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
48735 * query allowing the query action to be canceled if needed.
48736 * @param {String} query The SQL query to execute
48737 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
48738 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
48739 * saved in the current store (defaults to false)
48741 doQuery : function(q, forceAll){
48743 Roo.log('doQuery?');
48744 if(q === undefined || q === null){
48749 forceAll: forceAll,
48753 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48757 forceAll = qe.forceAll;
48758 if(forceAll === true || (q.length >= this.minChars)){
48759 if(this.lastQuery != q || this.alwaysQuery){
48760 this.lastQuery = q;
48761 if(this.mode == 'local'){
48762 this.selectedIndex = -1;
48764 this.store.clearFilter();
48766 this.store.filter(this.displayField, q);
48770 this.store.baseParams[this.queryParam] = q;
48772 params: this.getParams(q)
48777 this.selectedIndex = -1;
48784 getParams : function(q){
48786 //p[this.queryParam] = q;
48789 p.limit = this.pageSize;
48795 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48797 collapse : function(){
48802 collapseIf : function(e){
48807 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48809 expand : function(){
48817 * @cfg {Boolean} grow
48821 * @cfg {Number} growMin
48825 * @cfg {Number} growMax
48833 setWidth : function()
48837 getResizeEl : function(){
48840 });//<script type="text/javasscript">
48844 * @class Roo.DDView
48845 * A DnD enabled version of Roo.View.
48846 * @param {Element/String} container The Element in which to create the View.
48847 * @param {String} tpl The template string used to create the markup for each element of the View
48848 * @param {Object} config The configuration properties. These include all the config options of
48849 * {@link Roo.View} plus some specific to this class.<br>
48851 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48852 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48854 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48855 .x-view-drag-insert-above {
48856 border-top:1px dotted #3366cc;
48858 .x-view-drag-insert-below {
48859 border-bottom:1px dotted #3366cc;
48865 Roo.DDView = function(container, tpl, config) {
48866 Roo.DDView.superclass.constructor.apply(this, arguments);
48867 this.getEl().setStyle("outline", "0px none");
48868 this.getEl().unselectable();
48869 if (this.dragGroup) {
48870 this.setDraggable(this.dragGroup.split(","));
48872 if (this.dropGroup) {
48873 this.setDroppable(this.dropGroup.split(","));
48875 if (this.deletable) {
48876 this.setDeletable();
48878 this.isDirtyFlag = false;
48884 Roo.extend(Roo.DDView, Roo.View, {
48885 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48886 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48887 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48888 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48892 reset: Roo.emptyFn,
48894 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48896 validate: function() {
48900 destroy: function() {
48901 this.purgeListeners();
48902 this.getEl.removeAllListeners();
48903 this.getEl().remove();
48904 if (this.dragZone) {
48905 if (this.dragZone.destroy) {
48906 this.dragZone.destroy();
48909 if (this.dropZone) {
48910 if (this.dropZone.destroy) {
48911 this.dropZone.destroy();
48916 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48917 getName: function() {
48921 /** Loads the View from a JSON string representing the Records to put into the Store. */
48922 setValue: function(v) {
48924 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48927 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48928 this.store.proxy = new Roo.data.MemoryProxy(data);
48932 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48933 getValue: function() {
48935 this.store.each(function(rec) {
48936 result += rec.id + ',';
48938 return result.substr(0, result.length - 1) + ')';
48941 getIds: function() {
48942 var i = 0, result = new Array(this.store.getCount());
48943 this.store.each(function(rec) {
48944 result[i++] = rec.id;
48949 isDirty: function() {
48950 return this.isDirtyFlag;
48954 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48955 * whole Element becomes the target, and this causes the drop gesture to append.
48957 getTargetFromEvent : function(e) {
48958 var target = e.getTarget();
48959 while ((target !== null) && (target.parentNode != this.el.dom)) {
48960 target = target.parentNode;
48963 target = this.el.dom.lastChild || this.el.dom;
48969 * Create the drag data which consists of an object which has the property "ddel" as
48970 * the drag proxy element.
48972 getDragData : function(e) {
48973 var target = this.findItemFromChild(e.getTarget());
48975 this.handleSelection(e);
48976 var selNodes = this.getSelectedNodes();
48979 copy: this.copy || (this.allowCopy && e.ctrlKey),
48983 var selectedIndices = this.getSelectedIndexes();
48984 for (var i = 0; i < selectedIndices.length; i++) {
48985 dragData.records.push(this.store.getAt(selectedIndices[i]));
48987 if (selNodes.length == 1) {
48988 dragData.ddel = target.cloneNode(true); // the div element
48990 var div = document.createElement('div'); // create the multi element drag "ghost"
48991 div.className = 'multi-proxy';
48992 for (var i = 0, len = selNodes.length; i < len; i++) {
48993 div.appendChild(selNodes[i].cloneNode(true));
48995 dragData.ddel = div;
48997 //console.log(dragData)
48998 //console.log(dragData.ddel.innerHTML)
49001 //console.log('nodragData')
49005 /** Specify to which ddGroup items in this DDView may be dragged. */
49006 setDraggable: function(ddGroup) {
49007 if (ddGroup instanceof Array) {
49008 Roo.each(ddGroup, this.setDraggable, this);
49011 if (this.dragZone) {
49012 this.dragZone.addToGroup(ddGroup);
49014 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
49015 containerScroll: true,
49019 // Draggability implies selection. DragZone's mousedown selects the element.
49020 if (!this.multiSelect) { this.singleSelect = true; }
49022 // Wire the DragZone's handlers up to methods in *this*
49023 this.dragZone.getDragData = this.getDragData.createDelegate(this);
49027 /** Specify from which ddGroup this DDView accepts drops. */
49028 setDroppable: function(ddGroup) {
49029 if (ddGroup instanceof Array) {
49030 Roo.each(ddGroup, this.setDroppable, this);
49033 if (this.dropZone) {
49034 this.dropZone.addToGroup(ddGroup);
49036 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
49037 containerScroll: true,
49041 // Wire the DropZone's handlers up to methods in *this*
49042 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
49043 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
49044 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
49045 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
49046 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
49050 /** Decide whether to drop above or below a View node. */
49051 getDropPoint : function(e, n, dd){
49052 if (n == this.el.dom) { return "above"; }
49053 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
49054 var c = t + (b - t) / 2;
49055 var y = Roo.lib.Event.getPageY(e);
49063 onNodeEnter : function(n, dd, e, data){
49067 onNodeOver : function(n, dd, e, data){
49068 var pt = this.getDropPoint(e, n, dd);
49069 // set the insert point style on the target node
49070 var dragElClass = this.dropNotAllowed;
49073 if (pt == "above"){
49074 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
49075 targetElClass = "x-view-drag-insert-above";
49077 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
49078 targetElClass = "x-view-drag-insert-below";
49080 if (this.lastInsertClass != targetElClass){
49081 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
49082 this.lastInsertClass = targetElClass;
49085 return dragElClass;
49088 onNodeOut : function(n, dd, e, data){
49089 this.removeDropIndicators(n);
49092 onNodeDrop : function(n, dd, e, data){
49093 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
49096 var pt = this.getDropPoint(e, n, dd);
49097 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
49098 if (pt == "below") { insertAt++; }
49099 for (var i = 0; i < data.records.length; i++) {
49100 var r = data.records[i];
49101 var dup = this.store.getById(r.id);
49102 if (dup && (dd != this.dragZone)) {
49103 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
49106 this.store.insert(insertAt++, r.copy());
49108 data.source.isDirtyFlag = true;
49110 this.store.insert(insertAt++, r);
49112 this.isDirtyFlag = true;
49115 this.dragZone.cachedTarget = null;
49119 removeDropIndicators : function(n){
49121 Roo.fly(n).removeClass([
49122 "x-view-drag-insert-above",
49123 "x-view-drag-insert-below"]);
49124 this.lastInsertClass = "_noclass";
49129 * Utility method. Add a delete option to the DDView's context menu.
49130 * @param {String} imageUrl The URL of the "delete" icon image.
49132 setDeletable: function(imageUrl) {
49133 if (!this.singleSelect && !this.multiSelect) {
49134 this.singleSelect = true;
49136 var c = this.getContextMenu();
49137 this.contextMenu.on("itemclick", function(item) {
49140 this.remove(this.getSelectedIndexes());
49144 this.contextMenu.add({
49151 /** Return the context menu for this DDView. */
49152 getContextMenu: function() {
49153 if (!this.contextMenu) {
49154 // Create the View's context menu
49155 this.contextMenu = new Roo.menu.Menu({
49156 id: this.id + "-contextmenu"
49158 this.el.on("contextmenu", this.showContextMenu, this);
49160 return this.contextMenu;
49163 disableContextMenu: function() {
49164 if (this.contextMenu) {
49165 this.el.un("contextmenu", this.showContextMenu, this);
49169 showContextMenu: function(e, item) {
49170 item = this.findItemFromChild(e.getTarget());
49173 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
49174 this.contextMenu.showAt(e.getXY());
49179 * Remove {@link Roo.data.Record}s at the specified indices.
49180 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
49182 remove: function(selectedIndices) {
49183 selectedIndices = [].concat(selectedIndices);
49184 for (var i = 0; i < selectedIndices.length; i++) {
49185 var rec = this.store.getAt(selectedIndices[i]);
49186 this.store.remove(rec);
49191 * Double click fires the event, but also, if this is draggable, and there is only one other
49192 * related DropZone, it transfers the selected node.
49194 onDblClick : function(e){
49195 var item = this.findItemFromChild(e.getTarget());
49197 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
49200 if (this.dragGroup) {
49201 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
49202 while (targets.indexOf(this.dropZone) > -1) {
49203 targets.remove(this.dropZone);
49205 if (targets.length == 1) {
49206 this.dragZone.cachedTarget = null;
49207 var el = Roo.get(targets[0].getEl());
49208 var box = el.getBox(true);
49209 targets[0].onNodeDrop(el.dom, {
49211 xy: [box.x, box.y + box.height - 1]
49212 }, null, this.getDragData(e));
49218 handleSelection: function(e) {
49219 this.dragZone.cachedTarget = null;
49220 var item = this.findItemFromChild(e.getTarget());
49222 this.clearSelections(true);
49225 if (item && (this.multiSelect || this.singleSelect)){
49226 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
49227 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
49228 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
49229 this.unselect(item);
49231 this.select(item, this.multiSelect && e.ctrlKey);
49232 this.lastSelection = item;
49237 onItemClick : function(item, index, e){
49238 if(this.fireEvent("beforeclick", this, index, item, e) === false){
49244 unselect : function(nodeInfo, suppressEvent){
49245 var node = this.getNode(nodeInfo);
49246 if(node && this.isSelected(node)){
49247 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
49248 Roo.fly(node).removeClass(this.selectedClass);
49249 this.selections.remove(node);
49250 if(!suppressEvent){
49251 this.fireEvent("selectionchange", this, this.selections);
49259 * Ext JS Library 1.1.1
49260 * Copyright(c) 2006-2007, Ext JS, LLC.
49262 * Originally Released Under LGPL - original licence link has changed is not relivant.
49265 * <script type="text/javascript">
49269 * @class Roo.LayoutManager
49270 * @extends Roo.util.Observable
49271 * Base class for layout managers.
49273 Roo.LayoutManager = function(container, config){
49274 Roo.LayoutManager.superclass.constructor.call(this);
49275 this.el = Roo.get(container);
49276 // ie scrollbar fix
49277 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
49278 document.body.scroll = "no";
49279 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
49280 this.el.position('relative');
49282 this.id = this.el.id;
49283 this.el.addClass("x-layout-container");
49284 /** false to disable window resize monitoring @type Boolean */
49285 this.monitorWindowResize = true;
49290 * Fires when a layout is performed.
49291 * @param {Roo.LayoutManager} this
49295 * @event regionresized
49296 * Fires when the user resizes a region.
49297 * @param {Roo.LayoutRegion} region The resized region
49298 * @param {Number} newSize The new size (width for east/west, height for north/south)
49300 "regionresized" : true,
49302 * @event regioncollapsed
49303 * Fires when a region is collapsed.
49304 * @param {Roo.LayoutRegion} region The collapsed region
49306 "regioncollapsed" : true,
49308 * @event regionexpanded
49309 * Fires when a region is expanded.
49310 * @param {Roo.LayoutRegion} region The expanded region
49312 "regionexpanded" : true
49314 this.updating = false;
49315 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
49318 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
49320 * Returns true if this layout is currently being updated
49321 * @return {Boolean}
49323 isUpdating : function(){
49324 return this.updating;
49328 * Suspend the LayoutManager from doing auto-layouts while
49329 * making multiple add or remove calls
49331 beginUpdate : function(){
49332 this.updating = true;
49336 * Restore auto-layouts and optionally disable the manager from performing a layout
49337 * @param {Boolean} noLayout true to disable a layout update
49339 endUpdate : function(noLayout){
49340 this.updating = false;
49346 layout: function(){
49350 onRegionResized : function(region, newSize){
49351 this.fireEvent("regionresized", region, newSize);
49355 onRegionCollapsed : function(region){
49356 this.fireEvent("regioncollapsed", region);
49359 onRegionExpanded : function(region){
49360 this.fireEvent("regionexpanded", region);
49364 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
49365 * performs box-model adjustments.
49366 * @return {Object} The size as an object {width: (the width), height: (the height)}
49368 getViewSize : function(){
49370 if(this.el.dom != document.body){
49371 size = this.el.getSize();
49373 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
49375 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
49376 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
49381 * Returns the Element this layout is bound to.
49382 * @return {Roo.Element}
49384 getEl : function(){
49389 * Returns the specified region.
49390 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
49391 * @return {Roo.LayoutRegion}
49393 getRegion : function(target){
49394 return this.regions[target.toLowerCase()];
49397 onWindowResize : function(){
49398 if(this.monitorWindowResize){
49404 * Ext JS Library 1.1.1
49405 * Copyright(c) 2006-2007, Ext JS, LLC.
49407 * Originally Released Under LGPL - original licence link has changed is not relivant.
49410 * <script type="text/javascript">
49413 * @class Roo.BorderLayout
49414 * @extends Roo.LayoutManager
49415 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
49416 * please see: <br><br>
49417 * <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>
49418 * <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>
49421 var layout = new Roo.BorderLayout(document.body, {
49455 preferredTabWidth: 150
49460 var CP = Roo.ContentPanel;
49462 layout.beginUpdate();
49463 layout.add("north", new CP("north", "North"));
49464 layout.add("south", new CP("south", {title: "South", closable: true}));
49465 layout.add("west", new CP("west", {title: "West"}));
49466 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
49467 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
49468 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
49469 layout.getRegion("center").showPanel("center1");
49470 layout.endUpdate();
49473 <b>The container the layout is rendered into can be either the body element or any other element.
49474 If it is not the body element, the container needs to either be an absolute positioned element,
49475 or you will need to add "position:relative" to the css of the container. You will also need to specify
49476 the container size if it is not the body element.</b>
49479 * Create a new BorderLayout
49480 * @param {String/HTMLElement/Element} container The container this layout is bound to
49481 * @param {Object} config Configuration options
49483 Roo.BorderLayout = function(container, config){
49484 config = config || {};
49485 Roo.BorderLayout.superclass.constructor.call(this, container, config);
49486 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
49487 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
49488 var target = this.factory.validRegions[i];
49489 if(config[target]){
49490 this.addRegion(target, config[target]);
49495 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
49497 * Creates and adds a new region if it doesn't already exist.
49498 * @param {String} target The target region key (north, south, east, west or center).
49499 * @param {Object} config The regions config object
49500 * @return {BorderLayoutRegion} The new region
49502 addRegion : function(target, config){
49503 if(!this.regions[target]){
49504 var r = this.factory.create(target, this, config);
49505 this.bindRegion(target, r);
49507 return this.regions[target];
49511 bindRegion : function(name, r){
49512 this.regions[name] = r;
49513 r.on("visibilitychange", this.layout, this);
49514 r.on("paneladded", this.layout, this);
49515 r.on("panelremoved", this.layout, this);
49516 r.on("invalidated", this.layout, this);
49517 r.on("resized", this.onRegionResized, this);
49518 r.on("collapsed", this.onRegionCollapsed, this);
49519 r.on("expanded", this.onRegionExpanded, this);
49523 * Performs a layout update.
49525 layout : function(){
49526 if(this.updating) {
49529 var size = this.getViewSize();
49530 var w = size.width;
49531 var h = size.height;
49536 //var x = 0, y = 0;
49538 var rs = this.regions;
49539 var north = rs["north"];
49540 var south = rs["south"];
49541 var west = rs["west"];
49542 var east = rs["east"];
49543 var center = rs["center"];
49544 //if(this.hideOnLayout){ // not supported anymore
49545 //c.el.setStyle("display", "none");
49547 if(north && north.isVisible()){
49548 var b = north.getBox();
49549 var m = north.getMargins();
49550 b.width = w - (m.left+m.right);
49553 centerY = b.height + b.y + m.bottom;
49554 centerH -= centerY;
49555 north.updateBox(this.safeBox(b));
49557 if(south && south.isVisible()){
49558 var b = south.getBox();
49559 var m = south.getMargins();
49560 b.width = w - (m.left+m.right);
49562 var totalHeight = (b.height + m.top + m.bottom);
49563 b.y = h - totalHeight + m.top;
49564 centerH -= totalHeight;
49565 south.updateBox(this.safeBox(b));
49567 if(west && west.isVisible()){
49568 var b = west.getBox();
49569 var m = west.getMargins();
49570 b.height = centerH - (m.top+m.bottom);
49572 b.y = centerY + m.top;
49573 var totalWidth = (b.width + m.left + m.right);
49574 centerX += totalWidth;
49575 centerW -= totalWidth;
49576 west.updateBox(this.safeBox(b));
49578 if(east && east.isVisible()){
49579 var b = east.getBox();
49580 var m = east.getMargins();
49581 b.height = centerH - (m.top+m.bottom);
49582 var totalWidth = (b.width + m.left + m.right);
49583 b.x = w - totalWidth + m.left;
49584 b.y = centerY + m.top;
49585 centerW -= totalWidth;
49586 east.updateBox(this.safeBox(b));
49589 var m = center.getMargins();
49591 x: centerX + m.left,
49592 y: centerY + m.top,
49593 width: centerW - (m.left+m.right),
49594 height: centerH - (m.top+m.bottom)
49596 //if(this.hideOnLayout){
49597 //center.el.setStyle("display", "block");
49599 center.updateBox(this.safeBox(centerBox));
49602 this.fireEvent("layout", this);
49606 safeBox : function(box){
49607 box.width = Math.max(0, box.width);
49608 box.height = Math.max(0, box.height);
49613 * Adds a ContentPanel (or subclass) to this layout.
49614 * @param {String} target The target region key (north, south, east, west or center).
49615 * @param {Roo.ContentPanel} panel The panel to add
49616 * @return {Roo.ContentPanel} The added panel
49618 add : function(target, panel){
49620 target = target.toLowerCase();
49621 return this.regions[target].add(panel);
49625 * Remove a ContentPanel (or subclass) to this layout.
49626 * @param {String} target The target region key (north, south, east, west or center).
49627 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
49628 * @return {Roo.ContentPanel} The removed panel
49630 remove : function(target, panel){
49631 target = target.toLowerCase();
49632 return this.regions[target].remove(panel);
49636 * Searches all regions for a panel with the specified id
49637 * @param {String} panelId
49638 * @return {Roo.ContentPanel} The panel or null if it wasn't found
49640 findPanel : function(panelId){
49641 var rs = this.regions;
49642 for(var target in rs){
49643 if(typeof rs[target] != "function"){
49644 var p = rs[target].getPanel(panelId);
49654 * Searches all regions for a panel with the specified id and activates (shows) it.
49655 * @param {String/ContentPanel} panelId The panels id or the panel itself
49656 * @return {Roo.ContentPanel} The shown panel or null
49658 showPanel : function(panelId) {
49659 var rs = this.regions;
49660 for(var target in rs){
49661 var r = rs[target];
49662 if(typeof r != "function"){
49663 if(r.hasPanel(panelId)){
49664 return r.showPanel(panelId);
49672 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
49673 * @param {Roo.state.Provider} provider (optional) An alternate state provider
49675 restoreState : function(provider){
49677 provider = Roo.state.Manager;
49679 var sm = new Roo.LayoutStateManager();
49680 sm.init(this, provider);
49684 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
49685 * object should contain properties for each region to add ContentPanels to, and each property's value should be
49686 * a valid ContentPanel config object. Example:
49688 // Create the main layout
49689 var layout = new Roo.BorderLayout('main-ct', {
49700 // Create and add multiple ContentPanels at once via configs
49703 id: 'source-files',
49705 title:'Ext Source Files',
49718 * @param {Object} regions An object containing ContentPanel configs by region name
49720 batchAdd : function(regions){
49721 this.beginUpdate();
49722 for(var rname in regions){
49723 var lr = this.regions[rname];
49725 this.addTypedPanels(lr, regions[rname]);
49732 addTypedPanels : function(lr, ps){
49733 if(typeof ps == 'string'){
49734 lr.add(new Roo.ContentPanel(ps));
49736 else if(ps instanceof Array){
49737 for(var i =0, len = ps.length; i < len; i++){
49738 this.addTypedPanels(lr, ps[i]);
49741 else if(!ps.events){ // raw config?
49743 delete ps.el; // prevent conflict
49744 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
49746 else { // panel object assumed!
49751 * Adds a xtype elements to the layout.
49755 xtype : 'ContentPanel',
49762 xtype : 'NestedLayoutPanel',
49768 items : [ ... list of content panels or nested layout panels.. ]
49772 * @param {Object} cfg Xtype definition of item to add.
49774 addxtype : function(cfg)
49776 // basically accepts a pannel...
49777 // can accept a layout region..!?!?
49778 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49780 if (!cfg.xtype.match(/Panel$/)) {
49785 if (typeof(cfg.region) == 'undefined') {
49786 Roo.log("Failed to add Panel, region was not set");
49790 var region = cfg.region;
49796 xitems = cfg.items;
49803 case 'ContentPanel': // ContentPanel (el, cfg)
49804 case 'ScrollPanel': // ContentPanel (el, cfg)
49806 if(cfg.autoCreate) {
49807 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49809 var el = this.el.createChild();
49810 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49813 this.add(region, ret);
49817 case 'TreePanel': // our new panel!
49818 cfg.el = this.el.createChild();
49819 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49820 this.add(region, ret);
49823 case 'NestedLayoutPanel':
49824 // create a new Layout (which is a Border Layout...
49825 var el = this.el.createChild();
49826 var clayout = cfg.layout;
49828 clayout.items = clayout.items || [];
49829 // replace this exitems with the clayout ones..
49830 xitems = clayout.items;
49833 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49834 cfg.background = false;
49836 var layout = new Roo.BorderLayout(el, clayout);
49838 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49839 //console.log('adding nested layout panel ' + cfg.toSource());
49840 this.add(region, ret);
49841 nb = {}; /// find first...
49846 // needs grid and region
49848 //var el = this.getRegion(region).el.createChild();
49849 var el = this.el.createChild();
49850 // create the grid first...
49852 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49854 if (region == 'center' && this.active ) {
49855 cfg.background = false;
49857 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49859 this.add(region, ret);
49860 if (cfg.background) {
49861 ret.on('activate', function(gp) {
49862 if (!gp.grid.rendered) {
49877 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49879 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49880 this.add(region, ret);
49883 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49887 // GridPanel (grid, cfg)
49890 this.beginUpdate();
49894 Roo.each(xitems, function(i) {
49895 region = nb && i.region ? i.region : false;
49897 var add = ret.addxtype(i);
49900 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49901 if (!i.background) {
49902 abn[region] = nb[region] ;
49909 // make the last non-background panel active..
49910 //if (nb) { Roo.log(abn); }
49913 for(var r in abn) {
49914 region = this.getRegion(r);
49916 // tried using nb[r], but it does not work..
49918 region.showPanel(abn[r]);
49929 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49930 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49931 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49932 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49935 var CP = Roo.ContentPanel;
49937 var layout = Roo.BorderLayout.create({
49941 panels: [new CP("north", "North")]
49950 panels: [new CP("west", {title: "West"})]
49959 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49968 panels: [new CP("south", {title: "South", closable: true})]
49975 preferredTabWidth: 150,
49977 new CP("center1", {title: "Close Me", closable: true}),
49978 new CP("center2", {title: "Center Panel", closable: false})
49983 layout.getRegion("center").showPanel("center1");
49988 Roo.BorderLayout.create = function(config, targetEl){
49989 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49990 layout.beginUpdate();
49991 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49992 for(var j = 0, jlen = regions.length; j < jlen; j++){
49993 var lr = regions[j];
49994 if(layout.regions[lr] && config[lr].panels){
49995 var r = layout.regions[lr];
49996 var ps = config[lr].panels;
49997 layout.addTypedPanels(r, ps);
50000 layout.endUpdate();
50005 Roo.BorderLayout.RegionFactory = {
50007 validRegions : ["north","south","east","west","center"],
50010 create : function(target, mgr, config){
50011 target = target.toLowerCase();
50012 if(config.lightweight || config.basic){
50013 return new Roo.BasicLayoutRegion(mgr, config, target);
50017 return new Roo.NorthLayoutRegion(mgr, config);
50019 return new Roo.SouthLayoutRegion(mgr, config);
50021 return new Roo.EastLayoutRegion(mgr, config);
50023 return new Roo.WestLayoutRegion(mgr, config);
50025 return new Roo.CenterLayoutRegion(mgr, config);
50027 throw 'Layout region "'+target+'" not supported.';
50031 * Ext JS Library 1.1.1
50032 * Copyright(c) 2006-2007, Ext JS, LLC.
50034 * Originally Released Under LGPL - original licence link has changed is not relivant.
50037 * <script type="text/javascript">
50041 * @class Roo.BasicLayoutRegion
50042 * @extends Roo.util.Observable
50043 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
50044 * and does not have a titlebar, tabs or any other features. All it does is size and position
50045 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
50047 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
50049 this.position = pos;
50052 * @scope Roo.BasicLayoutRegion
50056 * @event beforeremove
50057 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
50058 * @param {Roo.LayoutRegion} this
50059 * @param {Roo.ContentPanel} panel The panel
50060 * @param {Object} e The cancel event object
50062 "beforeremove" : true,
50064 * @event invalidated
50065 * Fires when the layout for this region is changed.
50066 * @param {Roo.LayoutRegion} this
50068 "invalidated" : true,
50070 * @event visibilitychange
50071 * Fires when this region is shown or hidden
50072 * @param {Roo.LayoutRegion} this
50073 * @param {Boolean} visibility true or false
50075 "visibilitychange" : true,
50077 * @event paneladded
50078 * Fires when a panel is added.
50079 * @param {Roo.LayoutRegion} this
50080 * @param {Roo.ContentPanel} panel The panel
50082 "paneladded" : true,
50084 * @event panelremoved
50085 * Fires when a panel is removed.
50086 * @param {Roo.LayoutRegion} this
50087 * @param {Roo.ContentPanel} panel The panel
50089 "panelremoved" : true,
50092 * Fires when this region is collapsed.
50093 * @param {Roo.LayoutRegion} this
50095 "collapsed" : true,
50098 * Fires when this region is expanded.
50099 * @param {Roo.LayoutRegion} this
50104 * Fires when this region is slid into view.
50105 * @param {Roo.LayoutRegion} this
50107 "slideshow" : true,
50110 * Fires when this region slides out of view.
50111 * @param {Roo.LayoutRegion} this
50113 "slidehide" : true,
50115 * @event panelactivated
50116 * Fires when a panel is activated.
50117 * @param {Roo.LayoutRegion} this
50118 * @param {Roo.ContentPanel} panel The activated panel
50120 "panelactivated" : true,
50123 * Fires when the user resizes this region.
50124 * @param {Roo.LayoutRegion} this
50125 * @param {Number} newSize The new size (width for east/west, height for north/south)
50129 /** A collection of panels in this region. @type Roo.util.MixedCollection */
50130 this.panels = new Roo.util.MixedCollection();
50131 this.panels.getKey = this.getPanelId.createDelegate(this);
50133 this.activePanel = null;
50134 // ensure listeners are added...
50136 if (config.listeners || config.events) {
50137 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
50138 listeners : config.listeners || {},
50139 events : config.events || {}
50143 if(skipConfig !== true){
50144 this.applyConfig(config);
50148 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
50149 getPanelId : function(p){
50153 applyConfig : function(config){
50154 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50155 this.config = config;
50160 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
50161 * the width, for horizontal (north, south) the height.
50162 * @param {Number} newSize The new width or height
50164 resizeTo : function(newSize){
50165 var el = this.el ? this.el :
50166 (this.activePanel ? this.activePanel.getEl() : null);
50168 switch(this.position){
50171 el.setWidth(newSize);
50172 this.fireEvent("resized", this, newSize);
50176 el.setHeight(newSize);
50177 this.fireEvent("resized", this, newSize);
50183 getBox : function(){
50184 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
50187 getMargins : function(){
50188 return this.margins;
50191 updateBox : function(box){
50193 var el = this.activePanel.getEl();
50194 el.dom.style.left = box.x + "px";
50195 el.dom.style.top = box.y + "px";
50196 this.activePanel.setSize(box.width, box.height);
50200 * Returns the container element for this region.
50201 * @return {Roo.Element}
50203 getEl : function(){
50204 return this.activePanel;
50208 * Returns true if this region is currently visible.
50209 * @return {Boolean}
50211 isVisible : function(){
50212 return this.activePanel ? true : false;
50215 setActivePanel : function(panel){
50216 panel = this.getPanel(panel);
50217 if(this.activePanel && this.activePanel != panel){
50218 this.activePanel.setActiveState(false);
50219 this.activePanel.getEl().setLeftTop(-10000,-10000);
50221 this.activePanel = panel;
50222 panel.setActiveState(true);
50224 panel.setSize(this.box.width, this.box.height);
50226 this.fireEvent("panelactivated", this, panel);
50227 this.fireEvent("invalidated");
50231 * Show the specified panel.
50232 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
50233 * @return {Roo.ContentPanel} The shown panel or null
50235 showPanel : function(panel){
50236 if(panel = this.getPanel(panel)){
50237 this.setActivePanel(panel);
50243 * Get the active panel for this region.
50244 * @return {Roo.ContentPanel} The active panel or null
50246 getActivePanel : function(){
50247 return this.activePanel;
50251 * Add the passed ContentPanel(s)
50252 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50253 * @return {Roo.ContentPanel} The panel added (if only one was added)
50255 add : function(panel){
50256 if(arguments.length > 1){
50257 for(var i = 0, len = arguments.length; i < len; i++) {
50258 this.add(arguments[i]);
50262 if(this.hasPanel(panel)){
50263 this.showPanel(panel);
50266 var el = panel.getEl();
50267 if(el.dom.parentNode != this.mgr.el.dom){
50268 this.mgr.el.dom.appendChild(el.dom);
50270 if(panel.setRegion){
50271 panel.setRegion(this);
50273 this.panels.add(panel);
50274 el.setStyle("position", "absolute");
50275 if(!panel.background){
50276 this.setActivePanel(panel);
50277 if(this.config.initialSize && this.panels.getCount()==1){
50278 this.resizeTo(this.config.initialSize);
50281 this.fireEvent("paneladded", this, panel);
50286 * Returns true if the panel is in this region.
50287 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50288 * @return {Boolean}
50290 hasPanel : function(panel){
50291 if(typeof panel == "object"){ // must be panel obj
50292 panel = panel.getId();
50294 return this.getPanel(panel) ? true : false;
50298 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50299 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50300 * @param {Boolean} preservePanel Overrides the config preservePanel option
50301 * @return {Roo.ContentPanel} The panel that was removed
50303 remove : function(panel, preservePanel){
50304 panel = this.getPanel(panel);
50309 this.fireEvent("beforeremove", this, panel, e);
50310 if(e.cancel === true){
50313 var panelId = panel.getId();
50314 this.panels.removeKey(panelId);
50319 * Returns the panel specified or null if it's not in this region.
50320 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50321 * @return {Roo.ContentPanel}
50323 getPanel : function(id){
50324 if(typeof id == "object"){ // must be panel obj
50327 return this.panels.get(id);
50331 * Returns this regions position (north/south/east/west/center).
50334 getPosition: function(){
50335 return this.position;
50339 * Ext JS Library 1.1.1
50340 * Copyright(c) 2006-2007, Ext JS, LLC.
50342 * Originally Released Under LGPL - original licence link has changed is not relivant.
50345 * <script type="text/javascript">
50349 * @class Roo.LayoutRegion
50350 * @extends Roo.BasicLayoutRegion
50351 * This class represents a region in a layout manager.
50352 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
50353 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
50354 * @cfg {Boolean} floatable False to disable floating (defaults to true)
50355 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
50356 * @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})
50357 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
50358 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
50359 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
50360 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
50361 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
50362 * @cfg {String} title The title for the region (overrides panel titles)
50363 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
50364 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
50365 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
50366 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
50367 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
50368 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
50369 * the space available, similar to FireFox 1.5 tabs (defaults to false)
50370 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
50371 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
50372 * @cfg {Boolean} showPin True to show a pin button
50373 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
50374 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
50375 * @cfg {Boolean} disableTabTips True to disable tab tooltips
50376 * @cfg {Number} width For East/West panels
50377 * @cfg {Number} height For North/South panels
50378 * @cfg {Boolean} split To show the splitter
50379 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
50381 Roo.LayoutRegion = function(mgr, config, pos){
50382 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
50383 var dh = Roo.DomHelper;
50384 /** This region's container element
50385 * @type Roo.Element */
50386 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
50387 /** This region's title element
50388 * @type Roo.Element */
50390 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
50391 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
50392 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
50394 this.titleEl.enableDisplayMode();
50395 /** This region's title text element
50396 * @type HTMLElement */
50397 this.titleTextEl = this.titleEl.dom.firstChild;
50398 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
50399 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
50400 this.closeBtn.enableDisplayMode();
50401 this.closeBtn.on("click", this.closeClicked, this);
50402 this.closeBtn.hide();
50404 this.createBody(config);
50405 this.visible = true;
50406 this.collapsed = false;
50408 if(config.hideWhenEmpty){
50410 this.on("paneladded", this.validateVisibility, this);
50411 this.on("panelremoved", this.validateVisibility, this);
50413 this.applyConfig(config);
50416 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
50418 createBody : function(){
50419 /** This region's body element
50420 * @type Roo.Element */
50421 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
50424 applyConfig : function(c){
50425 if(c.collapsible && this.position != "center" && !this.collapsedEl){
50426 var dh = Roo.DomHelper;
50427 if(c.titlebar !== false){
50428 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
50429 this.collapseBtn.on("click", this.collapse, this);
50430 this.collapseBtn.enableDisplayMode();
50432 if(c.showPin === true || this.showPin){
50433 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
50434 this.stickBtn.enableDisplayMode();
50435 this.stickBtn.on("click", this.expand, this);
50436 this.stickBtn.hide();
50439 /** This region's collapsed element
50440 * @type Roo.Element */
50441 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
50442 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
50444 if(c.floatable !== false){
50445 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
50446 this.collapsedEl.on("click", this.collapseClick, this);
50449 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
50450 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
50451 id: "message", unselectable: "on", style:{"float":"left"}});
50452 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
50454 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
50455 this.expandBtn.on("click", this.expand, this);
50457 if(this.collapseBtn){
50458 this.collapseBtn.setVisible(c.collapsible == true);
50460 this.cmargins = c.cmargins || this.cmargins ||
50461 (this.position == "west" || this.position == "east" ?
50462 {top: 0, left: 2, right:2, bottom: 0} :
50463 {top: 2, left: 0, right:0, bottom: 2});
50464 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50465 this.bottomTabs = c.tabPosition != "top";
50466 this.autoScroll = c.autoScroll || false;
50467 if(this.autoScroll){
50468 this.bodyEl.setStyle("overflow", "auto");
50470 this.bodyEl.setStyle("overflow", "hidden");
50472 //if(c.titlebar !== false){
50473 if((!c.titlebar && !c.title) || c.titlebar === false){
50474 this.titleEl.hide();
50476 this.titleEl.show();
50478 this.titleTextEl.innerHTML = c.title;
50482 this.duration = c.duration || .30;
50483 this.slideDuration = c.slideDuration || .45;
50486 this.collapse(true);
50493 * Returns true if this region is currently visible.
50494 * @return {Boolean}
50496 isVisible : function(){
50497 return this.visible;
50501 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
50502 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
50504 setCollapsedTitle : function(title){
50505 title = title || " ";
50506 if(this.collapsedTitleTextEl){
50507 this.collapsedTitleTextEl.innerHTML = title;
50511 getBox : function(){
50513 if(!this.collapsed){
50514 b = this.el.getBox(false, true);
50516 b = this.collapsedEl.getBox(false, true);
50521 getMargins : function(){
50522 return this.collapsed ? this.cmargins : this.margins;
50525 highlight : function(){
50526 this.el.addClass("x-layout-panel-dragover");
50529 unhighlight : function(){
50530 this.el.removeClass("x-layout-panel-dragover");
50533 updateBox : function(box){
50535 if(!this.collapsed){
50536 this.el.dom.style.left = box.x + "px";
50537 this.el.dom.style.top = box.y + "px";
50538 this.updateBody(box.width, box.height);
50540 this.collapsedEl.dom.style.left = box.x + "px";
50541 this.collapsedEl.dom.style.top = box.y + "px";
50542 this.collapsedEl.setSize(box.width, box.height);
50545 this.tabs.autoSizeTabs();
50549 updateBody : function(w, h){
50551 this.el.setWidth(w);
50552 w -= this.el.getBorderWidth("rl");
50553 if(this.config.adjustments){
50554 w += this.config.adjustments[0];
50558 this.el.setHeight(h);
50559 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
50560 h -= this.el.getBorderWidth("tb");
50561 if(this.config.adjustments){
50562 h += this.config.adjustments[1];
50564 this.bodyEl.setHeight(h);
50566 h = this.tabs.syncHeight(h);
50569 if(this.panelSize){
50570 w = w !== null ? w : this.panelSize.width;
50571 h = h !== null ? h : this.panelSize.height;
50573 if(this.activePanel){
50574 var el = this.activePanel.getEl();
50575 w = w !== null ? w : el.getWidth();
50576 h = h !== null ? h : el.getHeight();
50577 this.panelSize = {width: w, height: h};
50578 this.activePanel.setSize(w, h);
50580 if(Roo.isIE && this.tabs){
50581 this.tabs.el.repaint();
50586 * Returns the container element for this region.
50587 * @return {Roo.Element}
50589 getEl : function(){
50594 * Hides this region.
50597 if(!this.collapsed){
50598 this.el.dom.style.left = "-2000px";
50601 this.collapsedEl.dom.style.left = "-2000px";
50602 this.collapsedEl.hide();
50604 this.visible = false;
50605 this.fireEvent("visibilitychange", this, false);
50609 * Shows this region if it was previously hidden.
50612 if(!this.collapsed){
50615 this.collapsedEl.show();
50617 this.visible = true;
50618 this.fireEvent("visibilitychange", this, true);
50621 closeClicked : function(){
50622 if(this.activePanel){
50623 this.remove(this.activePanel);
50627 collapseClick : function(e){
50629 e.stopPropagation();
50632 e.stopPropagation();
50638 * Collapses this region.
50639 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
50641 collapse : function(skipAnim){
50642 if(this.collapsed) {
50645 this.collapsed = true;
50647 this.split.el.hide();
50649 if(this.config.animate && skipAnim !== true){
50650 this.fireEvent("invalidated", this);
50651 this.animateCollapse();
50653 this.el.setLocation(-20000,-20000);
50655 this.collapsedEl.show();
50656 this.fireEvent("collapsed", this);
50657 this.fireEvent("invalidated", this);
50661 animateCollapse : function(){
50666 * Expands this region if it was previously collapsed.
50667 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
50668 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
50670 expand : function(e, skipAnim){
50672 e.stopPropagation();
50674 if(!this.collapsed || this.el.hasActiveFx()) {
50678 this.afterSlideIn();
50681 this.collapsed = false;
50682 if(this.config.animate && skipAnim !== true){
50683 this.animateExpand();
50687 this.split.el.show();
50689 this.collapsedEl.setLocation(-2000,-2000);
50690 this.collapsedEl.hide();
50691 this.fireEvent("invalidated", this);
50692 this.fireEvent("expanded", this);
50696 animateExpand : function(){
50700 initTabs : function()
50702 this.bodyEl.setStyle("overflow", "hidden");
50703 var ts = new Roo.TabPanel(
50706 tabPosition: this.bottomTabs ? 'bottom' : 'top',
50707 disableTooltips: this.config.disableTabTips,
50708 toolbar : this.config.toolbar
50711 if(this.config.hideTabs){
50712 ts.stripWrap.setDisplayed(false);
50715 ts.resizeTabs = this.config.resizeTabs === true;
50716 ts.minTabWidth = this.config.minTabWidth || 40;
50717 ts.maxTabWidth = this.config.maxTabWidth || 250;
50718 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
50719 ts.monitorResize = false;
50720 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50721 ts.bodyEl.addClass('x-layout-tabs-body');
50722 this.panels.each(this.initPanelAsTab, this);
50725 initPanelAsTab : function(panel){
50726 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
50727 this.config.closeOnTab && panel.isClosable());
50728 if(panel.tabTip !== undefined){
50729 ti.setTooltip(panel.tabTip);
50731 ti.on("activate", function(){
50732 this.setActivePanel(panel);
50734 if(this.config.closeOnTab){
50735 ti.on("beforeclose", function(t, e){
50737 this.remove(panel);
50743 updatePanelTitle : function(panel, title){
50744 if(this.activePanel == panel){
50745 this.updateTitle(title);
50748 var ti = this.tabs.getTab(panel.getEl().id);
50750 if(panel.tabTip !== undefined){
50751 ti.setTooltip(panel.tabTip);
50756 updateTitle : function(title){
50757 if(this.titleTextEl && !this.config.title){
50758 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50762 setActivePanel : function(panel){
50763 panel = this.getPanel(panel);
50764 if(this.activePanel && this.activePanel != panel){
50765 this.activePanel.setActiveState(false);
50767 this.activePanel = panel;
50768 panel.setActiveState(true);
50769 if(this.panelSize){
50770 panel.setSize(this.panelSize.width, this.panelSize.height);
50773 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50775 this.updateTitle(panel.getTitle());
50777 this.fireEvent("invalidated", this);
50779 this.fireEvent("panelactivated", this, panel);
50783 * Shows the specified panel.
50784 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50785 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50787 showPanel : function(panel)
50789 panel = this.getPanel(panel);
50792 var tab = this.tabs.getTab(panel.getEl().id);
50793 if(tab.isHidden()){
50794 this.tabs.unhideTab(tab.id);
50798 this.setActivePanel(panel);
50805 * Get the active panel for this region.
50806 * @return {Roo.ContentPanel} The active panel or null
50808 getActivePanel : function(){
50809 return this.activePanel;
50812 validateVisibility : function(){
50813 if(this.panels.getCount() < 1){
50814 this.updateTitle(" ");
50815 this.closeBtn.hide();
50818 if(!this.isVisible()){
50825 * Adds the passed ContentPanel(s) to this region.
50826 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50827 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50829 add : function(panel){
50830 if(arguments.length > 1){
50831 for(var i = 0, len = arguments.length; i < len; i++) {
50832 this.add(arguments[i]);
50836 if(this.hasPanel(panel)){
50837 this.showPanel(panel);
50840 panel.setRegion(this);
50841 this.panels.add(panel);
50842 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50843 this.bodyEl.dom.appendChild(panel.getEl().dom);
50844 if(panel.background !== true){
50845 this.setActivePanel(panel);
50847 this.fireEvent("paneladded", this, panel);
50853 this.initPanelAsTab(panel);
50855 if(panel.background !== true){
50856 this.tabs.activate(panel.getEl().id);
50858 this.fireEvent("paneladded", this, panel);
50863 * Hides the tab for the specified panel.
50864 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50866 hidePanel : function(panel){
50867 if(this.tabs && (panel = this.getPanel(panel))){
50868 this.tabs.hideTab(panel.getEl().id);
50873 * Unhides the tab for a previously hidden panel.
50874 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50876 unhidePanel : function(panel){
50877 if(this.tabs && (panel = this.getPanel(panel))){
50878 this.tabs.unhideTab(panel.getEl().id);
50882 clearPanels : function(){
50883 while(this.panels.getCount() > 0){
50884 this.remove(this.panels.first());
50889 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50890 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50891 * @param {Boolean} preservePanel Overrides the config preservePanel option
50892 * @return {Roo.ContentPanel} The panel that was removed
50894 remove : function(panel, preservePanel){
50895 panel = this.getPanel(panel);
50900 this.fireEvent("beforeremove", this, panel, e);
50901 if(e.cancel === true){
50904 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50905 var panelId = panel.getId();
50906 this.panels.removeKey(panelId);
50908 document.body.appendChild(panel.getEl().dom);
50911 this.tabs.removeTab(panel.getEl().id);
50912 }else if (!preservePanel){
50913 this.bodyEl.dom.removeChild(panel.getEl().dom);
50915 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50916 var p = this.panels.first();
50917 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50918 tempEl.appendChild(p.getEl().dom);
50919 this.bodyEl.update("");
50920 this.bodyEl.dom.appendChild(p.getEl().dom);
50922 this.updateTitle(p.getTitle());
50924 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50925 this.setActivePanel(p);
50927 panel.setRegion(null);
50928 if(this.activePanel == panel){
50929 this.activePanel = null;
50931 if(this.config.autoDestroy !== false && preservePanel !== true){
50932 try{panel.destroy();}catch(e){}
50934 this.fireEvent("panelremoved", this, panel);
50939 * Returns the TabPanel component used by this region
50940 * @return {Roo.TabPanel}
50942 getTabs : function(){
50946 createTool : function(parentEl, className){
50947 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50948 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50949 btn.addClassOnOver("x-layout-tools-button-over");
50954 * Ext JS Library 1.1.1
50955 * Copyright(c) 2006-2007, Ext JS, LLC.
50957 * Originally Released Under LGPL - original licence link has changed is not relivant.
50960 * <script type="text/javascript">
50966 * @class Roo.SplitLayoutRegion
50967 * @extends Roo.LayoutRegion
50968 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50970 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50971 this.cursor = cursor;
50972 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50975 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50976 splitTip : "Drag to resize.",
50977 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50978 useSplitTips : false,
50980 applyConfig : function(config){
50981 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50984 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50985 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50986 /** The SplitBar for this region
50987 * @type Roo.SplitBar */
50988 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50989 this.split.on("moved", this.onSplitMove, this);
50990 this.split.useShim = config.useShim === true;
50991 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50992 if(this.useSplitTips){
50993 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50995 if(config.collapsible){
50996 this.split.el.on("dblclick", this.collapse, this);
50999 if(typeof config.minSize != "undefined"){
51000 this.split.minSize = config.minSize;
51002 if(typeof config.maxSize != "undefined"){
51003 this.split.maxSize = config.maxSize;
51005 if(config.hideWhenEmpty || config.hidden || config.collapsed){
51006 this.hideSplitter();
51011 getHMaxSize : function(){
51012 var cmax = this.config.maxSize || 10000;
51013 var center = this.mgr.getRegion("center");
51014 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
51017 getVMaxSize : function(){
51018 var cmax = this.config.maxSize || 10000;
51019 var center = this.mgr.getRegion("center");
51020 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
51023 onSplitMove : function(split, newSize){
51024 this.fireEvent("resized", this, newSize);
51028 * Returns the {@link Roo.SplitBar} for this region.
51029 * @return {Roo.SplitBar}
51031 getSplitBar : function(){
51036 this.hideSplitter();
51037 Roo.SplitLayoutRegion.superclass.hide.call(this);
51040 hideSplitter : function(){
51042 this.split.el.setLocation(-2000,-2000);
51043 this.split.el.hide();
51049 this.split.el.show();
51051 Roo.SplitLayoutRegion.superclass.show.call(this);
51054 beforeSlide: function(){
51055 if(Roo.isGecko){// firefox overflow auto bug workaround
51056 this.bodyEl.clip();
51058 this.tabs.bodyEl.clip();
51060 if(this.activePanel){
51061 this.activePanel.getEl().clip();
51063 if(this.activePanel.beforeSlide){
51064 this.activePanel.beforeSlide();
51070 afterSlide : function(){
51071 if(Roo.isGecko){// firefox overflow auto bug workaround
51072 this.bodyEl.unclip();
51074 this.tabs.bodyEl.unclip();
51076 if(this.activePanel){
51077 this.activePanel.getEl().unclip();
51078 if(this.activePanel.afterSlide){
51079 this.activePanel.afterSlide();
51085 initAutoHide : function(){
51086 if(this.autoHide !== false){
51087 if(!this.autoHideHd){
51088 var st = new Roo.util.DelayedTask(this.slideIn, this);
51089 this.autoHideHd = {
51090 "mouseout": function(e){
51091 if(!e.within(this.el, true)){
51095 "mouseover" : function(e){
51101 this.el.on(this.autoHideHd);
51105 clearAutoHide : function(){
51106 if(this.autoHide !== false){
51107 this.el.un("mouseout", this.autoHideHd.mouseout);
51108 this.el.un("mouseover", this.autoHideHd.mouseover);
51112 clearMonitor : function(){
51113 Roo.get(document).un("click", this.slideInIf, this);
51116 // these names are backwards but not changed for compat
51117 slideOut : function(){
51118 if(this.isSlid || this.el.hasActiveFx()){
51121 this.isSlid = true;
51122 if(this.collapseBtn){
51123 this.collapseBtn.hide();
51125 this.closeBtnState = this.closeBtn.getStyle('display');
51126 this.closeBtn.hide();
51128 this.stickBtn.show();
51131 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
51132 this.beforeSlide();
51133 this.el.setStyle("z-index", 10001);
51134 this.el.slideIn(this.getSlideAnchor(), {
51135 callback: function(){
51137 this.initAutoHide();
51138 Roo.get(document).on("click", this.slideInIf, this);
51139 this.fireEvent("slideshow", this);
51146 afterSlideIn : function(){
51147 this.clearAutoHide();
51148 this.isSlid = false;
51149 this.clearMonitor();
51150 this.el.setStyle("z-index", "");
51151 if(this.collapseBtn){
51152 this.collapseBtn.show();
51154 this.closeBtn.setStyle('display', this.closeBtnState);
51156 this.stickBtn.hide();
51158 this.fireEvent("slidehide", this);
51161 slideIn : function(cb){
51162 if(!this.isSlid || this.el.hasActiveFx()){
51166 this.isSlid = false;
51167 this.beforeSlide();
51168 this.el.slideOut(this.getSlideAnchor(), {
51169 callback: function(){
51170 this.el.setLeftTop(-10000, -10000);
51172 this.afterSlideIn();
51180 slideInIf : function(e){
51181 if(!e.within(this.el)){
51186 animateCollapse : function(){
51187 this.beforeSlide();
51188 this.el.setStyle("z-index", 20000);
51189 var anchor = this.getSlideAnchor();
51190 this.el.slideOut(anchor, {
51191 callback : function(){
51192 this.el.setStyle("z-index", "");
51193 this.collapsedEl.slideIn(anchor, {duration:.3});
51195 this.el.setLocation(-10000,-10000);
51197 this.fireEvent("collapsed", this);
51204 animateExpand : function(){
51205 this.beforeSlide();
51206 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
51207 this.el.setStyle("z-index", 20000);
51208 this.collapsedEl.hide({
51211 this.el.slideIn(this.getSlideAnchor(), {
51212 callback : function(){
51213 this.el.setStyle("z-index", "");
51216 this.split.el.show();
51218 this.fireEvent("invalidated", this);
51219 this.fireEvent("expanded", this);
51247 getAnchor : function(){
51248 return this.anchors[this.position];
51251 getCollapseAnchor : function(){
51252 return this.canchors[this.position];
51255 getSlideAnchor : function(){
51256 return this.sanchors[this.position];
51259 getAlignAdj : function(){
51260 var cm = this.cmargins;
51261 switch(this.position){
51277 getExpandAdj : function(){
51278 var c = this.collapsedEl, cm = this.cmargins;
51279 switch(this.position){
51281 return [-(cm.right+c.getWidth()+cm.left), 0];
51284 return [cm.right+c.getWidth()+cm.left, 0];
51287 return [0, -(cm.top+cm.bottom+c.getHeight())];
51290 return [0, cm.top+cm.bottom+c.getHeight()];
51296 * Ext JS Library 1.1.1
51297 * Copyright(c) 2006-2007, Ext JS, LLC.
51299 * Originally Released Under LGPL - original licence link has changed is not relivant.
51302 * <script type="text/javascript">
51305 * These classes are private internal classes
51307 Roo.CenterLayoutRegion = function(mgr, config){
51308 Roo.LayoutRegion.call(this, mgr, config, "center");
51309 this.visible = true;
51310 this.minWidth = config.minWidth || 20;
51311 this.minHeight = config.minHeight || 20;
51314 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
51316 // center panel can't be hidden
51320 // center panel can't be hidden
51323 getMinWidth: function(){
51324 return this.minWidth;
51327 getMinHeight: function(){
51328 return this.minHeight;
51333 Roo.NorthLayoutRegion = function(mgr, config){
51334 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
51336 this.split.placement = Roo.SplitBar.TOP;
51337 this.split.orientation = Roo.SplitBar.VERTICAL;
51338 this.split.el.addClass("x-layout-split-v");
51340 var size = config.initialSize || config.height;
51341 if(typeof size != "undefined"){
51342 this.el.setHeight(size);
51345 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
51346 orientation: Roo.SplitBar.VERTICAL,
51347 getBox : function(){
51348 if(this.collapsed){
51349 return this.collapsedEl.getBox();
51351 var box = this.el.getBox();
51353 box.height += this.split.el.getHeight();
51358 updateBox : function(box){
51359 if(this.split && !this.collapsed){
51360 box.height -= this.split.el.getHeight();
51361 this.split.el.setLeft(box.x);
51362 this.split.el.setTop(box.y+box.height);
51363 this.split.el.setWidth(box.width);
51365 if(this.collapsed){
51366 this.updateBody(box.width, null);
51368 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51372 Roo.SouthLayoutRegion = function(mgr, config){
51373 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
51375 this.split.placement = Roo.SplitBar.BOTTOM;
51376 this.split.orientation = Roo.SplitBar.VERTICAL;
51377 this.split.el.addClass("x-layout-split-v");
51379 var size = config.initialSize || config.height;
51380 if(typeof size != "undefined"){
51381 this.el.setHeight(size);
51384 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
51385 orientation: Roo.SplitBar.VERTICAL,
51386 getBox : function(){
51387 if(this.collapsed){
51388 return this.collapsedEl.getBox();
51390 var box = this.el.getBox();
51392 var sh = this.split.el.getHeight();
51399 updateBox : function(box){
51400 if(this.split && !this.collapsed){
51401 var sh = this.split.el.getHeight();
51404 this.split.el.setLeft(box.x);
51405 this.split.el.setTop(box.y-sh);
51406 this.split.el.setWidth(box.width);
51408 if(this.collapsed){
51409 this.updateBody(box.width, null);
51411 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51415 Roo.EastLayoutRegion = function(mgr, config){
51416 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
51418 this.split.placement = Roo.SplitBar.RIGHT;
51419 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51420 this.split.el.addClass("x-layout-split-h");
51422 var size = config.initialSize || config.width;
51423 if(typeof size != "undefined"){
51424 this.el.setWidth(size);
51427 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
51428 orientation: Roo.SplitBar.HORIZONTAL,
51429 getBox : function(){
51430 if(this.collapsed){
51431 return this.collapsedEl.getBox();
51433 var box = this.el.getBox();
51435 var sw = this.split.el.getWidth();
51442 updateBox : function(box){
51443 if(this.split && !this.collapsed){
51444 var sw = this.split.el.getWidth();
51446 this.split.el.setLeft(box.x);
51447 this.split.el.setTop(box.y);
51448 this.split.el.setHeight(box.height);
51451 if(this.collapsed){
51452 this.updateBody(null, box.height);
51454 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51458 Roo.WestLayoutRegion = function(mgr, config){
51459 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
51461 this.split.placement = Roo.SplitBar.LEFT;
51462 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51463 this.split.el.addClass("x-layout-split-h");
51465 var size = config.initialSize || config.width;
51466 if(typeof size != "undefined"){
51467 this.el.setWidth(size);
51470 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
51471 orientation: Roo.SplitBar.HORIZONTAL,
51472 getBox : function(){
51473 if(this.collapsed){
51474 return this.collapsedEl.getBox();
51476 var box = this.el.getBox();
51478 box.width += this.split.el.getWidth();
51483 updateBox : function(box){
51484 if(this.split && !this.collapsed){
51485 var sw = this.split.el.getWidth();
51487 this.split.el.setLeft(box.x+box.width);
51488 this.split.el.setTop(box.y);
51489 this.split.el.setHeight(box.height);
51491 if(this.collapsed){
51492 this.updateBody(null, box.height);
51494 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51499 * Ext JS Library 1.1.1
51500 * Copyright(c) 2006-2007, Ext JS, LLC.
51502 * Originally Released Under LGPL - original licence link has changed is not relivant.
51505 * <script type="text/javascript">
51510 * Private internal class for reading and applying state
51512 Roo.LayoutStateManager = function(layout){
51513 // default empty state
51522 Roo.LayoutStateManager.prototype = {
51523 init : function(layout, provider){
51524 this.provider = provider;
51525 var state = provider.get(layout.id+"-layout-state");
51527 var wasUpdating = layout.isUpdating();
51529 layout.beginUpdate();
51531 for(var key in state){
51532 if(typeof state[key] != "function"){
51533 var rstate = state[key];
51534 var r = layout.getRegion(key);
51537 r.resizeTo(rstate.size);
51539 if(rstate.collapsed == true){
51542 r.expand(null, true);
51548 layout.endUpdate();
51550 this.state = state;
51552 this.layout = layout;
51553 layout.on("regionresized", this.onRegionResized, this);
51554 layout.on("regioncollapsed", this.onRegionCollapsed, this);
51555 layout.on("regionexpanded", this.onRegionExpanded, this);
51558 storeState : function(){
51559 this.provider.set(this.layout.id+"-layout-state", this.state);
51562 onRegionResized : function(region, newSize){
51563 this.state[region.getPosition()].size = newSize;
51567 onRegionCollapsed : function(region){
51568 this.state[region.getPosition()].collapsed = true;
51572 onRegionExpanded : function(region){
51573 this.state[region.getPosition()].collapsed = false;
51578 * Ext JS Library 1.1.1
51579 * Copyright(c) 2006-2007, Ext JS, LLC.
51581 * Originally Released Under LGPL - original licence link has changed is not relivant.
51584 * <script type="text/javascript">
51587 * @class Roo.ContentPanel
51588 * @extends Roo.util.Observable
51589 * A basic ContentPanel element.
51590 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
51591 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
51592 * @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
51593 * @cfg {Boolean} closable True if the panel can be closed/removed
51594 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
51595 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
51596 * @cfg {Toolbar} toolbar A toolbar for this panel
51597 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
51598 * @cfg {String} title The title for this panel
51599 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
51600 * @cfg {String} url Calls {@link #setUrl} with this value
51601 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
51602 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
51603 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
51604 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
51607 * Create a new ContentPanel.
51608 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
51609 * @param {String/Object} config A string to set only the title or a config object
51610 * @param {String} content (optional) Set the HTML content for this panel
51611 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
51613 Roo.ContentPanel = function(el, config, content){
51617 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
51621 if (config && config.parentLayout) {
51622 el = config.parentLayout.el.createChild();
51625 if(el.autoCreate){ // xtype is available if this is called from factory
51629 this.el = Roo.get(el);
51630 if(!this.el && config && config.autoCreate){
51631 if(typeof config.autoCreate == "object"){
51632 if(!config.autoCreate.id){
51633 config.autoCreate.id = config.id||el;
51635 this.el = Roo.DomHelper.append(document.body,
51636 config.autoCreate, true);
51638 this.el = Roo.DomHelper.append(document.body,
51639 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
51642 this.closable = false;
51643 this.loaded = false;
51644 this.active = false;
51645 if(typeof config == "string"){
51646 this.title = config;
51648 Roo.apply(this, config);
51651 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
51652 this.wrapEl = this.el.wrap();
51653 this.toolbar.container = this.el.insertSibling(false, 'before');
51654 this.toolbar = new Roo.Toolbar(this.toolbar);
51657 // xtype created footer. - not sure if will work as we normally have to render first..
51658 if (this.footer && !this.footer.el && this.footer.xtype) {
51659 if (!this.wrapEl) {
51660 this.wrapEl = this.el.wrap();
51663 this.footer.container = this.wrapEl.createChild();
51665 this.footer = Roo.factory(this.footer, Roo);
51670 this.resizeEl = Roo.get(this.resizeEl, true);
51672 this.resizeEl = this.el;
51674 // handle view.xtype
51682 * Fires when this panel is activated.
51683 * @param {Roo.ContentPanel} this
51687 * @event deactivate
51688 * Fires when this panel is activated.
51689 * @param {Roo.ContentPanel} this
51691 "deactivate" : true,
51695 * Fires when this panel is resized if fitToFrame is true.
51696 * @param {Roo.ContentPanel} this
51697 * @param {Number} width The width after any component adjustments
51698 * @param {Number} height The height after any component adjustments
51704 * Fires when this tab is created
51705 * @param {Roo.ContentPanel} this
51716 if(this.autoScroll){
51717 this.resizeEl.setStyle("overflow", "auto");
51719 // fix randome scrolling
51720 this.el.on('scroll', function() {
51721 Roo.log('fix random scolling');
51722 this.scrollTo('top',0);
51725 content = content || this.content;
51727 this.setContent(content);
51729 if(config && config.url){
51730 this.setUrl(this.url, this.params, this.loadOnce);
51735 Roo.ContentPanel.superclass.constructor.call(this);
51737 if (this.view && typeof(this.view.xtype) != 'undefined') {
51738 this.view.el = this.el.appendChild(document.createElement("div"));
51739 this.view = Roo.factory(this.view);
51740 this.view.render && this.view.render(false, '');
51744 this.fireEvent('render', this);
51747 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
51749 setRegion : function(region){
51750 this.region = region;
51752 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
51754 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
51759 * Returns the toolbar for this Panel if one was configured.
51760 * @return {Roo.Toolbar}
51762 getToolbar : function(){
51763 return this.toolbar;
51766 setActiveState : function(active){
51767 this.active = active;
51769 this.fireEvent("deactivate", this);
51771 this.fireEvent("activate", this);
51775 * Updates this panel's element
51776 * @param {String} content The new content
51777 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51779 setContent : function(content, loadScripts){
51780 this.el.update(content, loadScripts);
51783 ignoreResize : function(w, h){
51784 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51787 this.lastSize = {width: w, height: h};
51792 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51793 * @return {Roo.UpdateManager} The UpdateManager
51795 getUpdateManager : function(){
51796 return this.el.getUpdateManager();
51799 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51800 * @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:
51803 url: "your-url.php",
51804 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51805 callback: yourFunction,
51806 scope: yourObject, //(optional scope)
51809 text: "Loading...",
51814 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51815 * 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.
51816 * @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}
51817 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51818 * @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.
51819 * @return {Roo.ContentPanel} this
51822 var um = this.el.getUpdateManager();
51823 um.update.apply(um, arguments);
51829 * 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.
51830 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51831 * @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)
51832 * @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)
51833 * @return {Roo.UpdateManager} The UpdateManager
51835 setUrl : function(url, params, loadOnce){
51836 if(this.refreshDelegate){
51837 this.removeListener("activate", this.refreshDelegate);
51839 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51840 this.on("activate", this.refreshDelegate);
51841 return this.el.getUpdateManager();
51844 _handleRefresh : function(url, params, loadOnce){
51845 if(!loadOnce || !this.loaded){
51846 var updater = this.el.getUpdateManager();
51847 updater.update(url, params, this._setLoaded.createDelegate(this));
51851 _setLoaded : function(){
51852 this.loaded = true;
51856 * Returns this panel's id
51859 getId : function(){
51864 * Returns this panel's element - used by regiosn to add.
51865 * @return {Roo.Element}
51867 getEl : function(){
51868 return this.wrapEl || this.el;
51871 adjustForComponents : function(width, height)
51873 //Roo.log('adjustForComponents ');
51874 if(this.resizeEl != this.el){
51875 width -= this.el.getFrameWidth('lr');
51876 height -= this.el.getFrameWidth('tb');
51879 var te = this.toolbar.getEl();
51880 height -= te.getHeight();
51881 te.setWidth(width);
51884 var te = this.footer.getEl();
51885 Roo.log("footer:" + te.getHeight());
51887 height -= te.getHeight();
51888 te.setWidth(width);
51892 if(this.adjustments){
51893 width += this.adjustments[0];
51894 height += this.adjustments[1];
51896 return {"width": width, "height": height};
51899 setSize : function(width, height){
51900 if(this.fitToFrame && !this.ignoreResize(width, height)){
51901 if(this.fitContainer && this.resizeEl != this.el){
51902 this.el.setSize(width, height);
51904 var size = this.adjustForComponents(width, height);
51905 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51906 this.fireEvent('resize', this, size.width, size.height);
51911 * Returns this panel's title
51914 getTitle : function(){
51919 * Set this panel's title
51920 * @param {String} title
51922 setTitle : function(title){
51923 this.title = title;
51925 this.region.updatePanelTitle(this, title);
51930 * Returns true is this panel was configured to be closable
51931 * @return {Boolean}
51933 isClosable : function(){
51934 return this.closable;
51937 beforeSlide : function(){
51939 this.resizeEl.clip();
51942 afterSlide : function(){
51944 this.resizeEl.unclip();
51948 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51949 * Will fail silently if the {@link #setUrl} method has not been called.
51950 * This does not activate the panel, just updates its content.
51952 refresh : function(){
51953 if(this.refreshDelegate){
51954 this.loaded = false;
51955 this.refreshDelegate();
51960 * Destroys this panel
51962 destroy : function(){
51963 this.el.removeAllListeners();
51964 var tempEl = document.createElement("span");
51965 tempEl.appendChild(this.el.dom);
51966 tempEl.innerHTML = "";
51972 * form - if the content panel contains a form - this is a reference to it.
51973 * @type {Roo.form.Form}
51977 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51978 * This contains a reference to it.
51984 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51994 * @param {Object} cfg Xtype definition of item to add.
51997 addxtype : function(cfg) {
51999 if (cfg.xtype.match(/^Form$/)) {
52002 //if (this.footer) {
52003 // el = this.footer.container.insertSibling(false, 'before');
52005 el = this.el.createChild();
52008 this.form = new Roo.form.Form(cfg);
52011 if ( this.form.allItems.length) {
52012 this.form.render(el.dom);
52016 // should only have one of theses..
52017 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
52018 // views.. should not be just added - used named prop 'view''
52020 cfg.el = this.el.appendChild(document.createElement("div"));
52023 var ret = new Roo.factory(cfg);
52025 ret.render && ret.render(false, ''); // render blank..
52034 * @class Roo.GridPanel
52035 * @extends Roo.ContentPanel
52037 * Create a new GridPanel.
52038 * @param {Roo.grid.Grid} grid The grid for this panel
52039 * @param {String/Object} config A string to set only the panel's title, or a config object
52041 Roo.GridPanel = function(grid, config){
52044 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
52045 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
52047 this.wrapper.dom.appendChild(grid.getGridEl().dom);
52049 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
52052 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
52054 // xtype created footer. - not sure if will work as we normally have to render first..
52055 if (this.footer && !this.footer.el && this.footer.xtype) {
52057 this.footer.container = this.grid.getView().getFooterPanel(true);
52058 this.footer.dataSource = this.grid.dataSource;
52059 this.footer = Roo.factory(this.footer, Roo);
52063 grid.monitorWindowResize = false; // turn off autosizing
52064 grid.autoHeight = false;
52065 grid.autoWidth = false;
52067 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
52070 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
52071 getId : function(){
52072 return this.grid.id;
52076 * Returns the grid for this panel
52077 * @return {Roo.grid.Grid}
52079 getGrid : function(){
52083 setSize : function(width, height){
52084 if(!this.ignoreResize(width, height)){
52085 var grid = this.grid;
52086 var size = this.adjustForComponents(width, height);
52087 grid.getGridEl().setSize(size.width, size.height);
52092 beforeSlide : function(){
52093 this.grid.getView().scroller.clip();
52096 afterSlide : function(){
52097 this.grid.getView().scroller.unclip();
52100 destroy : function(){
52101 this.grid.destroy();
52103 Roo.GridPanel.superclass.destroy.call(this);
52109 * @class Roo.NestedLayoutPanel
52110 * @extends Roo.ContentPanel
52112 * Create a new NestedLayoutPanel.
52115 * @param {Roo.BorderLayout} layout The layout for this panel
52116 * @param {String/Object} config A string to set only the title or a config object
52118 Roo.NestedLayoutPanel = function(layout, config)
52120 // construct with only one argument..
52121 /* FIXME - implement nicer consturctors
52122 if (layout.layout) {
52124 layout = config.layout;
52125 delete config.layout;
52127 if (layout.xtype && !layout.getEl) {
52128 // then layout needs constructing..
52129 layout = Roo.factory(layout, Roo);
52134 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
52136 layout.monitorWindowResize = false; // turn off autosizing
52137 this.layout = layout;
52138 this.layout.getEl().addClass("x-layout-nested-layout");
52145 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
52147 setSize : function(width, height){
52148 if(!this.ignoreResize(width, height)){
52149 var size = this.adjustForComponents(width, height);
52150 var el = this.layout.getEl();
52151 el.setSize(size.width, size.height);
52152 var touch = el.dom.offsetWidth;
52153 this.layout.layout();
52154 // ie requires a double layout on the first pass
52155 if(Roo.isIE && !this.initialized){
52156 this.initialized = true;
52157 this.layout.layout();
52162 // activate all subpanels if not currently active..
52164 setActiveState : function(active){
52165 this.active = active;
52167 this.fireEvent("deactivate", this);
52171 this.fireEvent("activate", this);
52172 // not sure if this should happen before or after..
52173 if (!this.layout) {
52174 return; // should not happen..
52177 for (var r in this.layout.regions) {
52178 reg = this.layout.getRegion(r);
52179 if (reg.getActivePanel()) {
52180 //reg.showPanel(reg.getActivePanel()); // force it to activate..
52181 reg.setActivePanel(reg.getActivePanel());
52184 if (!reg.panels.length) {
52187 reg.showPanel(reg.getPanel(0));
52196 * Returns the nested BorderLayout for this panel
52197 * @return {Roo.BorderLayout}
52199 getLayout : function(){
52200 return this.layout;
52204 * Adds a xtype elements to the layout of the nested panel
52208 xtype : 'ContentPanel',
52215 xtype : 'NestedLayoutPanel',
52221 items : [ ... list of content panels or nested layout panels.. ]
52225 * @param {Object} cfg Xtype definition of item to add.
52227 addxtype : function(cfg) {
52228 return this.layout.addxtype(cfg);
52233 Roo.ScrollPanel = function(el, config, content){
52234 config = config || {};
52235 config.fitToFrame = true;
52236 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
52238 this.el.dom.style.overflow = "hidden";
52239 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
52240 this.el.removeClass("x-layout-inactive-content");
52241 this.el.on("mousewheel", this.onWheel, this);
52243 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
52244 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
52245 up.unselectable(); down.unselectable();
52246 up.on("click", this.scrollUp, this);
52247 down.on("click", this.scrollDown, this);
52248 up.addClassOnOver("x-scroller-btn-over");
52249 down.addClassOnOver("x-scroller-btn-over");
52250 up.addClassOnClick("x-scroller-btn-click");
52251 down.addClassOnClick("x-scroller-btn-click");
52252 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
52254 this.resizeEl = this.el;
52255 this.el = wrap; this.up = up; this.down = down;
52258 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
52260 wheelIncrement : 5,
52261 scrollUp : function(){
52262 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
52265 scrollDown : function(){
52266 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
52269 afterScroll : function(){
52270 var el = this.resizeEl;
52271 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
52272 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52273 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52276 setSize : function(){
52277 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
52278 this.afterScroll();
52281 onWheel : function(e){
52282 var d = e.getWheelDelta();
52283 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
52284 this.afterScroll();
52288 setContent : function(content, loadScripts){
52289 this.resizeEl.update(content, loadScripts);
52303 * @class Roo.TreePanel
52304 * @extends Roo.ContentPanel
52306 * Create a new TreePanel. - defaults to fit/scoll contents.
52307 * @param {String/Object} config A string to set only the panel's title, or a config object
52308 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
52310 Roo.TreePanel = function(config){
52311 var el = config.el;
52312 var tree = config.tree;
52313 delete config.tree;
52314 delete config.el; // hopefull!
52316 // wrapper for IE7 strict & safari scroll issue
52318 var treeEl = el.createChild();
52319 config.resizeEl = treeEl;
52323 Roo.TreePanel.superclass.constructor.call(this, el, config);
52326 this.tree = new Roo.tree.TreePanel(treeEl , tree);
52327 //console.log(tree);
52328 this.on('activate', function()
52330 if (this.tree.rendered) {
52333 //console.log('render tree');
52334 this.tree.render();
52336 // this should not be needed.. - it's actually the 'el' that resizes?
52337 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
52339 //this.on('resize', function (cp, w, h) {
52340 // this.tree.innerCt.setWidth(w);
52341 // this.tree.innerCt.setHeight(h);
52342 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
52349 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
52366 * Ext JS Library 1.1.1
52367 * Copyright(c) 2006-2007, Ext JS, LLC.
52369 * Originally Released Under LGPL - original licence link has changed is not relivant.
52372 * <script type="text/javascript">
52377 * @class Roo.ReaderLayout
52378 * @extends Roo.BorderLayout
52379 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
52380 * center region containing two nested regions (a top one for a list view and one for item preview below),
52381 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
52382 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
52383 * expedites the setup of the overall layout and regions for this common application style.
52386 var reader = new Roo.ReaderLayout();
52387 var CP = Roo.ContentPanel; // shortcut for adding
52389 reader.beginUpdate();
52390 reader.add("north", new CP("north", "North"));
52391 reader.add("west", new CP("west", {title: "West"}));
52392 reader.add("east", new CP("east", {title: "East"}));
52394 reader.regions.listView.add(new CP("listView", "List"));
52395 reader.regions.preview.add(new CP("preview", "Preview"));
52396 reader.endUpdate();
52399 * Create a new ReaderLayout
52400 * @param {Object} config Configuration options
52401 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
52402 * document.body if omitted)
52404 Roo.ReaderLayout = function(config, renderTo){
52405 var c = config || {size:{}};
52406 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
52407 north: c.north !== false ? Roo.apply({
52411 }, c.north) : false,
52412 west: c.west !== false ? Roo.apply({
52420 margins:{left:5,right:0,bottom:5,top:5},
52421 cmargins:{left:5,right:5,bottom:5,top:5}
52422 }, c.west) : false,
52423 east: c.east !== false ? Roo.apply({
52431 margins:{left:0,right:5,bottom:5,top:5},
52432 cmargins:{left:5,right:5,bottom:5,top:5}
52433 }, c.east) : false,
52434 center: Roo.apply({
52435 tabPosition: 'top',
52439 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
52443 this.el.addClass('x-reader');
52445 this.beginUpdate();
52447 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
52448 south: c.preview !== false ? Roo.apply({
52455 cmargins:{top:5,left:0, right:0, bottom:0}
52456 }, c.preview) : false,
52457 center: Roo.apply({
52463 this.add('center', new Roo.NestedLayoutPanel(inner,
52464 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
52468 this.regions.preview = inner.getRegion('south');
52469 this.regions.listView = inner.getRegion('center');
52472 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
52474 * Ext JS Library 1.1.1
52475 * Copyright(c) 2006-2007, Ext JS, LLC.
52477 * Originally Released Under LGPL - original licence link has changed is not relivant.
52480 * <script type="text/javascript">
52484 * @class Roo.grid.Grid
52485 * @extends Roo.util.Observable
52486 * This class represents the primary interface of a component based grid control.
52487 * <br><br>Usage:<pre><code>
52488 var grid = new Roo.grid.Grid("my-container-id", {
52491 selModel: mySelectionModel,
52492 autoSizeColumns: true,
52493 monitorWindowResize: false,
52494 trackMouseOver: true
52499 * <b>Common Problems:</b><br/>
52500 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
52501 * element will correct this<br/>
52502 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
52503 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
52504 * are unpredictable.<br/>
52505 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
52506 * grid to calculate dimensions/offsets.<br/>
52508 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
52509 * The container MUST have some type of size defined for the grid to fill. The container will be
52510 * automatically set to position relative if it isn't already.
52511 * @param {Object} config A config object that sets properties on this grid.
52513 Roo.grid.Grid = function(container, config){
52514 // initialize the container
52515 this.container = Roo.get(container);
52516 this.container.update("");
52517 this.container.setStyle("overflow", "hidden");
52518 this.container.addClass('x-grid-container');
52520 this.id = this.container.id;
52522 Roo.apply(this, config);
52523 // check and correct shorthanded configs
52525 this.dataSource = this.ds;
52529 this.colModel = this.cm;
52533 this.selModel = this.sm;
52537 if (this.selModel) {
52538 this.selModel = Roo.factory(this.selModel, Roo.grid);
52539 this.sm = this.selModel;
52540 this.sm.xmodule = this.xmodule || false;
52542 if (typeof(this.colModel.config) == 'undefined') {
52543 this.colModel = new Roo.grid.ColumnModel(this.colModel);
52544 this.cm = this.colModel;
52545 this.cm.xmodule = this.xmodule || false;
52547 if (this.dataSource) {
52548 this.dataSource= Roo.factory(this.dataSource, Roo.data);
52549 this.ds = this.dataSource;
52550 this.ds.xmodule = this.xmodule || false;
52557 this.container.setWidth(this.width);
52561 this.container.setHeight(this.height);
52568 * The raw click event for the entire grid.
52569 * @param {Roo.EventObject} e
52574 * The raw dblclick event for the entire grid.
52575 * @param {Roo.EventObject} e
52579 * @event contextmenu
52580 * The raw contextmenu event for the entire grid.
52581 * @param {Roo.EventObject} e
52583 "contextmenu" : true,
52586 * The raw mousedown event for the entire grid.
52587 * @param {Roo.EventObject} e
52589 "mousedown" : true,
52592 * The raw mouseup event for the entire grid.
52593 * @param {Roo.EventObject} e
52598 * The raw mouseover event for the entire grid.
52599 * @param {Roo.EventObject} e
52601 "mouseover" : true,
52604 * The raw mouseout event for the entire grid.
52605 * @param {Roo.EventObject} e
52610 * The raw keypress event for the entire grid.
52611 * @param {Roo.EventObject} e
52616 * The raw keydown event for the entire grid.
52617 * @param {Roo.EventObject} e
52625 * Fires when a cell is clicked
52626 * @param {Grid} this
52627 * @param {Number} rowIndex
52628 * @param {Number} columnIndex
52629 * @param {Roo.EventObject} e
52631 "cellclick" : true,
52633 * @event celldblclick
52634 * Fires when a cell is double clicked
52635 * @param {Grid} this
52636 * @param {Number} rowIndex
52637 * @param {Number} columnIndex
52638 * @param {Roo.EventObject} e
52640 "celldblclick" : true,
52643 * Fires when a row is clicked
52644 * @param {Grid} this
52645 * @param {Number} rowIndex
52646 * @param {Roo.EventObject} e
52650 * @event rowdblclick
52651 * Fires when a row is double clicked
52652 * @param {Grid} this
52653 * @param {Number} rowIndex
52654 * @param {Roo.EventObject} e
52656 "rowdblclick" : true,
52658 * @event headerclick
52659 * Fires when a header is clicked
52660 * @param {Grid} this
52661 * @param {Number} columnIndex
52662 * @param {Roo.EventObject} e
52664 "headerclick" : true,
52666 * @event headerdblclick
52667 * Fires when a header cell is double clicked
52668 * @param {Grid} this
52669 * @param {Number} columnIndex
52670 * @param {Roo.EventObject} e
52672 "headerdblclick" : true,
52674 * @event rowcontextmenu
52675 * Fires when a row is right clicked
52676 * @param {Grid} this
52677 * @param {Number} rowIndex
52678 * @param {Roo.EventObject} e
52680 "rowcontextmenu" : true,
52682 * @event cellcontextmenu
52683 * Fires when a cell is right clicked
52684 * @param {Grid} this
52685 * @param {Number} rowIndex
52686 * @param {Number} cellIndex
52687 * @param {Roo.EventObject} e
52689 "cellcontextmenu" : true,
52691 * @event headercontextmenu
52692 * Fires when a header is right clicked
52693 * @param {Grid} this
52694 * @param {Number} columnIndex
52695 * @param {Roo.EventObject} e
52697 "headercontextmenu" : true,
52699 * @event bodyscroll
52700 * Fires when the body element is scrolled
52701 * @param {Number} scrollLeft
52702 * @param {Number} scrollTop
52704 "bodyscroll" : true,
52706 * @event columnresize
52707 * Fires when the user resizes a column
52708 * @param {Number} columnIndex
52709 * @param {Number} newSize
52711 "columnresize" : true,
52713 * @event columnmove
52714 * Fires when the user moves a column
52715 * @param {Number} oldIndex
52716 * @param {Number} newIndex
52718 "columnmove" : true,
52721 * Fires when row(s) start being dragged
52722 * @param {Grid} this
52723 * @param {Roo.GridDD} dd The drag drop object
52724 * @param {event} e The raw browser event
52726 "startdrag" : true,
52729 * Fires when a drag operation is complete
52730 * @param {Grid} this
52731 * @param {Roo.GridDD} dd The drag drop object
52732 * @param {event} e The raw browser event
52737 * Fires when dragged row(s) are dropped on a valid DD target
52738 * @param {Grid} this
52739 * @param {Roo.GridDD} dd The drag drop object
52740 * @param {String} targetId The target drag drop object
52741 * @param {event} e The raw browser event
52746 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
52747 * @param {Grid} this
52748 * @param {Roo.GridDD} dd The drag drop object
52749 * @param {String} targetId The target drag drop object
52750 * @param {event} e The raw browser event
52755 * Fires when the dragged row(s) first cross another DD target while being dragged
52756 * @param {Grid} this
52757 * @param {Roo.GridDD} dd The drag drop object
52758 * @param {String} targetId The target drag drop object
52759 * @param {event} e The raw browser event
52761 "dragenter" : true,
52764 * Fires when the dragged row(s) leave another DD target while being dragged
52765 * @param {Grid} this
52766 * @param {Roo.GridDD} dd The drag drop object
52767 * @param {String} targetId The target drag drop object
52768 * @param {event} e The raw browser event
52773 * Fires when a row is rendered, so you can change add a style to it.
52774 * @param {GridView} gridview The grid view
52775 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52781 * Fires when the grid is rendered
52782 * @param {Grid} grid
52787 Roo.grid.Grid.superclass.constructor.call(this);
52789 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52792 * @cfg {String} ddGroup - drag drop group.
52796 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52798 minColumnWidth : 25,
52801 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52802 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52803 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52805 autoSizeColumns : false,
52808 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52810 autoSizeHeaders : true,
52813 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52815 monitorWindowResize : true,
52818 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52819 * rows measured to get a columns size. Default is 0 (all rows).
52821 maxRowsToMeasure : 0,
52824 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52826 trackMouseOver : true,
52829 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52833 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52835 enableDragDrop : false,
52838 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52840 enableColumnMove : true,
52843 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52845 enableColumnHide : true,
52848 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52850 enableRowHeightSync : false,
52853 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52858 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52860 autoHeight : false,
52863 * @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.
52865 autoExpandColumn : false,
52868 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52871 autoExpandMin : 50,
52874 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52876 autoExpandMax : 1000,
52879 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52884 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52888 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52898 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52899 * of a fixed width. Default is false.
52902 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52905 * Called once after all setup has been completed and the grid is ready to be rendered.
52906 * @return {Roo.grid.Grid} this
52908 render : function()
52910 var c = this.container;
52911 // try to detect autoHeight/width mode
52912 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52913 this.autoHeight = true;
52915 var view = this.getView();
52918 c.on("click", this.onClick, this);
52919 c.on("dblclick", this.onDblClick, this);
52920 c.on("contextmenu", this.onContextMenu, this);
52921 c.on("keydown", this.onKeyDown, this);
52923 c.on("touchstart", this.onTouchStart, this);
52926 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52928 this.getSelectionModel().init(this);
52933 this.loadMask = new Roo.LoadMask(this.container,
52934 Roo.apply({store:this.dataSource}, this.loadMask));
52938 if (this.toolbar && this.toolbar.xtype) {
52939 this.toolbar.container = this.getView().getHeaderPanel(true);
52940 this.toolbar = new Roo.Toolbar(this.toolbar);
52942 if (this.footer && this.footer.xtype) {
52943 this.footer.dataSource = this.getDataSource();
52944 this.footer.container = this.getView().getFooterPanel(true);
52945 this.footer = Roo.factory(this.footer, Roo);
52947 if (this.dropTarget && this.dropTarget.xtype) {
52948 delete this.dropTarget.xtype;
52949 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52953 this.rendered = true;
52954 this.fireEvent('render', this);
52959 * Reconfigures the grid to use a different Store and Column Model.
52960 * The View will be bound to the new objects and refreshed.
52961 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52962 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52964 reconfigure : function(dataSource, colModel){
52966 this.loadMask.destroy();
52967 this.loadMask = new Roo.LoadMask(this.container,
52968 Roo.apply({store:dataSource}, this.loadMask));
52970 this.view.bind(dataSource, colModel);
52971 this.dataSource = dataSource;
52972 this.colModel = colModel;
52973 this.view.refresh(true);
52977 onKeyDown : function(e){
52978 this.fireEvent("keydown", e);
52982 * Destroy this grid.
52983 * @param {Boolean} removeEl True to remove the element
52985 destroy : function(removeEl, keepListeners){
52987 this.loadMask.destroy();
52989 var c = this.container;
52990 c.removeAllListeners();
52991 this.view.destroy();
52992 this.colModel.purgeListeners();
52993 if(!keepListeners){
52994 this.purgeListeners();
52997 if(removeEl === true){
53003 processEvent : function(name, e){
53004 // does this fire select???
53005 //Roo.log('grid:processEvent ' + name);
53007 if (name != 'touchstart' ) {
53008 this.fireEvent(name, e);
53011 var t = e.getTarget();
53013 var header = v.findHeaderIndex(t);
53014 if(header !== false){
53015 var ename = name == 'touchstart' ? 'click' : name;
53017 this.fireEvent("header" + ename, this, header, e);
53019 var row = v.findRowIndex(t);
53020 var cell = v.findCellIndex(t);
53021 if (name == 'touchstart') {
53022 // first touch is always a click.
53023 // hopefull this happens after selection is updated.?
53026 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
53027 var cs = this.selModel.getSelectedCell();
53028 if (row == cs[0] && cell == cs[1]){
53032 if (typeof(this.selModel.getSelections) != 'undefined') {
53033 var cs = this.selModel.getSelections();
53034 var ds = this.dataSource;
53035 if (cs.length == 1 && ds.getAt(row) == cs[0]){
53046 this.fireEvent("row" + name, this, row, e);
53047 if(cell !== false){
53048 this.fireEvent("cell" + name, this, row, cell, e);
53055 onClick : function(e){
53056 this.processEvent("click", e);
53059 onTouchStart : function(e){
53060 this.processEvent("touchstart", e);
53064 onContextMenu : function(e, t){
53065 this.processEvent("contextmenu", e);
53069 onDblClick : function(e){
53070 this.processEvent("dblclick", e);
53074 walkCells : function(row, col, step, fn, scope){
53075 var cm = this.colModel, clen = cm.getColumnCount();
53076 var ds = this.dataSource, rlen = ds.getCount(), first = true;
53088 if(fn.call(scope || this, row, col, cm) === true){
53106 if(fn.call(scope || this, row, col, cm) === true){
53118 getSelections : function(){
53119 return this.selModel.getSelections();
53123 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
53124 * but if manual update is required this method will initiate it.
53126 autoSize : function(){
53128 this.view.layout();
53129 if(this.view.adjustForScroll){
53130 this.view.adjustForScroll();
53136 * Returns the grid's underlying element.
53137 * @return {Element} The element
53139 getGridEl : function(){
53140 return this.container;
53143 // private for compatibility, overridden by editor grid
53144 stopEditing : function(){},
53147 * Returns the grid's SelectionModel.
53148 * @return {SelectionModel}
53150 getSelectionModel : function(){
53151 if(!this.selModel){
53152 this.selModel = new Roo.grid.RowSelectionModel();
53154 return this.selModel;
53158 * Returns the grid's DataSource.
53159 * @return {DataSource}
53161 getDataSource : function(){
53162 return this.dataSource;
53166 * Returns the grid's ColumnModel.
53167 * @return {ColumnModel}
53169 getColumnModel : function(){
53170 return this.colModel;
53174 * Returns the grid's GridView object.
53175 * @return {GridView}
53177 getView : function(){
53179 this.view = new Roo.grid.GridView(this.viewConfig);
53184 * Called to get grid's drag proxy text, by default returns this.ddText.
53187 getDragDropText : function(){
53188 var count = this.selModel.getCount();
53189 return String.format(this.ddText, count, count == 1 ? '' : 's');
53193 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
53194 * %0 is replaced with the number of selected rows.
53197 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
53199 * Ext JS Library 1.1.1
53200 * Copyright(c) 2006-2007, Ext JS, LLC.
53202 * Originally Released Under LGPL - original licence link has changed is not relivant.
53205 * <script type="text/javascript">
53208 Roo.grid.AbstractGridView = function(){
53212 "beforerowremoved" : true,
53213 "beforerowsinserted" : true,
53214 "beforerefresh" : true,
53215 "rowremoved" : true,
53216 "rowsinserted" : true,
53217 "rowupdated" : true,
53220 Roo.grid.AbstractGridView.superclass.constructor.call(this);
53223 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
53224 rowClass : "x-grid-row",
53225 cellClass : "x-grid-cell",
53226 tdClass : "x-grid-td",
53227 hdClass : "x-grid-hd",
53228 splitClass : "x-grid-hd-split",
53230 init: function(grid){
53232 var cid = this.grid.getGridEl().id;
53233 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
53234 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
53235 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
53236 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
53239 getColumnRenderers : function(){
53240 var renderers = [];
53241 var cm = this.grid.colModel;
53242 var colCount = cm.getColumnCount();
53243 for(var i = 0; i < colCount; i++){
53244 renderers[i] = cm.getRenderer(i);
53249 getColumnIds : function(){
53251 var cm = this.grid.colModel;
53252 var colCount = cm.getColumnCount();
53253 for(var i = 0; i < colCount; i++){
53254 ids[i] = cm.getColumnId(i);
53259 getDataIndexes : function(){
53260 if(!this.indexMap){
53261 this.indexMap = this.buildIndexMap();
53263 return this.indexMap.colToData;
53266 getColumnIndexByDataIndex : function(dataIndex){
53267 if(!this.indexMap){
53268 this.indexMap = this.buildIndexMap();
53270 return this.indexMap.dataToCol[dataIndex];
53274 * Set a css style for a column dynamically.
53275 * @param {Number} colIndex The index of the column
53276 * @param {String} name The css property name
53277 * @param {String} value The css value
53279 setCSSStyle : function(colIndex, name, value){
53280 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
53281 Roo.util.CSS.updateRule(selector, name, value);
53284 generateRules : function(cm){
53285 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
53286 Roo.util.CSS.removeStyleSheet(rulesId);
53287 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53288 var cid = cm.getColumnId(i);
53289 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
53290 this.tdSelector, cid, " {\n}\n",
53291 this.hdSelector, cid, " {\n}\n",
53292 this.splitSelector, cid, " {\n}\n");
53294 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53298 * Ext JS Library 1.1.1
53299 * Copyright(c) 2006-2007, Ext JS, LLC.
53301 * Originally Released Under LGPL - original licence link has changed is not relivant.
53304 * <script type="text/javascript">
53308 // This is a support class used internally by the Grid components
53309 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
53311 this.view = grid.getView();
53312 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53313 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
53315 this.setHandleElId(Roo.id(hd));
53316 this.setOuterHandleElId(Roo.id(hd2));
53318 this.scroll = false;
53320 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
53322 getDragData : function(e){
53323 var t = Roo.lib.Event.getTarget(e);
53324 var h = this.view.findHeaderCell(t);
53326 return {ddel: h.firstChild, header:h};
53331 onInitDrag : function(e){
53332 this.view.headersDisabled = true;
53333 var clone = this.dragData.ddel.cloneNode(true);
53334 clone.id = Roo.id();
53335 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
53336 this.proxy.update(clone);
53340 afterValidDrop : function(){
53342 setTimeout(function(){
53343 v.headersDisabled = false;
53347 afterInvalidDrop : function(){
53349 setTimeout(function(){
53350 v.headersDisabled = false;
53356 * Ext JS Library 1.1.1
53357 * Copyright(c) 2006-2007, Ext JS, LLC.
53359 * Originally Released Under LGPL - original licence link has changed is not relivant.
53362 * <script type="text/javascript">
53365 // This is a support class used internally by the Grid components
53366 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
53368 this.view = grid.getView();
53369 // split the proxies so they don't interfere with mouse events
53370 this.proxyTop = Roo.DomHelper.append(document.body, {
53371 cls:"col-move-top", html:" "
53373 this.proxyBottom = Roo.DomHelper.append(document.body, {
53374 cls:"col-move-bottom", html:" "
53376 this.proxyTop.hide = this.proxyBottom.hide = function(){
53377 this.setLeftTop(-100,-100);
53378 this.setStyle("visibility", "hidden");
53380 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53381 // temporarily disabled
53382 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
53383 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
53385 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
53386 proxyOffsets : [-4, -9],
53387 fly: Roo.Element.fly,
53389 getTargetFromEvent : function(e){
53390 var t = Roo.lib.Event.getTarget(e);
53391 var cindex = this.view.findCellIndex(t);
53392 if(cindex !== false){
53393 return this.view.getHeaderCell(cindex);
53398 nextVisible : function(h){
53399 var v = this.view, cm = this.grid.colModel;
53402 if(!cm.isHidden(v.getCellIndex(h))){
53410 prevVisible : function(h){
53411 var v = this.view, cm = this.grid.colModel;
53414 if(!cm.isHidden(v.getCellIndex(h))){
53422 positionIndicator : function(h, n, e){
53423 var x = Roo.lib.Event.getPageX(e);
53424 var r = Roo.lib.Dom.getRegion(n.firstChild);
53425 var px, pt, py = r.top + this.proxyOffsets[1];
53426 if((r.right - x) <= (r.right-r.left)/2){
53427 px = r.right+this.view.borderWidth;
53433 var oldIndex = this.view.getCellIndex(h);
53434 var newIndex = this.view.getCellIndex(n);
53436 if(this.grid.colModel.isFixed(newIndex)){
53440 var locked = this.grid.colModel.isLocked(newIndex);
53445 if(oldIndex < newIndex){
53448 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
53451 px += this.proxyOffsets[0];
53452 this.proxyTop.setLeftTop(px, py);
53453 this.proxyTop.show();
53454 if(!this.bottomOffset){
53455 this.bottomOffset = this.view.mainHd.getHeight();
53457 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
53458 this.proxyBottom.show();
53462 onNodeEnter : function(n, dd, e, data){
53463 if(data.header != n){
53464 this.positionIndicator(data.header, n, e);
53468 onNodeOver : function(n, dd, e, data){
53469 var result = false;
53470 if(data.header != n){
53471 result = this.positionIndicator(data.header, n, e);
53474 this.proxyTop.hide();
53475 this.proxyBottom.hide();
53477 return result ? this.dropAllowed : this.dropNotAllowed;
53480 onNodeOut : function(n, dd, e, data){
53481 this.proxyTop.hide();
53482 this.proxyBottom.hide();
53485 onNodeDrop : function(n, dd, e, data){
53486 var h = data.header;
53488 var cm = this.grid.colModel;
53489 var x = Roo.lib.Event.getPageX(e);
53490 var r = Roo.lib.Dom.getRegion(n.firstChild);
53491 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
53492 var oldIndex = this.view.getCellIndex(h);
53493 var newIndex = this.view.getCellIndex(n);
53494 var locked = cm.isLocked(newIndex);
53498 if(oldIndex < newIndex){
53501 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
53504 cm.setLocked(oldIndex, locked, true);
53505 cm.moveColumn(oldIndex, newIndex);
53506 this.grid.fireEvent("columnmove", oldIndex, newIndex);
53514 * Ext JS Library 1.1.1
53515 * Copyright(c) 2006-2007, Ext JS, LLC.
53517 * Originally Released Under LGPL - original licence link has changed is not relivant.
53520 * <script type="text/javascript">
53524 * @class Roo.grid.GridView
53525 * @extends Roo.util.Observable
53528 * @param {Object} config
53530 Roo.grid.GridView = function(config){
53531 Roo.grid.GridView.superclass.constructor.call(this);
53534 Roo.apply(this, config);
53537 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
53539 unselectable : 'unselectable="on"',
53540 unselectableCls : 'x-unselectable',
53543 rowClass : "x-grid-row",
53545 cellClass : "x-grid-col",
53547 tdClass : "x-grid-td",
53549 hdClass : "x-grid-hd",
53551 splitClass : "x-grid-split",
53553 sortClasses : ["sort-asc", "sort-desc"],
53555 enableMoveAnim : false,
53559 dh : Roo.DomHelper,
53561 fly : Roo.Element.fly,
53563 css : Roo.util.CSS,
53569 scrollIncrement : 22,
53571 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
53573 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
53575 bind : function(ds, cm){
53577 this.ds.un("load", this.onLoad, this);
53578 this.ds.un("datachanged", this.onDataChange, this);
53579 this.ds.un("add", this.onAdd, this);
53580 this.ds.un("remove", this.onRemove, this);
53581 this.ds.un("update", this.onUpdate, this);
53582 this.ds.un("clear", this.onClear, this);
53585 ds.on("load", this.onLoad, this);
53586 ds.on("datachanged", this.onDataChange, this);
53587 ds.on("add", this.onAdd, this);
53588 ds.on("remove", this.onRemove, this);
53589 ds.on("update", this.onUpdate, this);
53590 ds.on("clear", this.onClear, this);
53595 this.cm.un("widthchange", this.onColWidthChange, this);
53596 this.cm.un("headerchange", this.onHeaderChange, this);
53597 this.cm.un("hiddenchange", this.onHiddenChange, this);
53598 this.cm.un("columnmoved", this.onColumnMove, this);
53599 this.cm.un("columnlockchange", this.onColumnLock, this);
53602 this.generateRules(cm);
53603 cm.on("widthchange", this.onColWidthChange, this);
53604 cm.on("headerchange", this.onHeaderChange, this);
53605 cm.on("hiddenchange", this.onHiddenChange, this);
53606 cm.on("columnmoved", this.onColumnMove, this);
53607 cm.on("columnlockchange", this.onColumnLock, this);
53612 init: function(grid){
53613 Roo.grid.GridView.superclass.init.call(this, grid);
53615 this.bind(grid.dataSource, grid.colModel);
53617 grid.on("headerclick", this.handleHeaderClick, this);
53619 if(grid.trackMouseOver){
53620 grid.on("mouseover", this.onRowOver, this);
53621 grid.on("mouseout", this.onRowOut, this);
53623 grid.cancelTextSelection = function(){};
53624 this.gridId = grid.id;
53626 var tpls = this.templates || {};
53629 tpls.master = new Roo.Template(
53630 '<div class="x-grid" hidefocus="true">',
53631 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
53632 '<div class="x-grid-topbar"></div>',
53633 '<div class="x-grid-scroller"><div></div></div>',
53634 '<div class="x-grid-locked">',
53635 '<div class="x-grid-header">{lockedHeader}</div>',
53636 '<div class="x-grid-body">{lockedBody}</div>',
53638 '<div class="x-grid-viewport">',
53639 '<div class="x-grid-header">{header}</div>',
53640 '<div class="x-grid-body">{body}</div>',
53642 '<div class="x-grid-bottombar"></div>',
53644 '<div class="x-grid-resize-proxy"> </div>',
53647 tpls.master.disableformats = true;
53651 tpls.header = new Roo.Template(
53652 '<table border="0" cellspacing="0" cellpadding="0">',
53653 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
53656 tpls.header.disableformats = true;
53658 tpls.header.compile();
53661 tpls.hcell = new Roo.Template(
53662 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
53663 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
53666 tpls.hcell.disableFormats = true;
53668 tpls.hcell.compile();
53671 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
53672 this.unselectableCls + '" ' + this.unselectable +'> </div>');
53673 tpls.hsplit.disableFormats = true;
53675 tpls.hsplit.compile();
53678 tpls.body = new Roo.Template(
53679 '<table border="0" cellspacing="0" cellpadding="0">',
53680 "<tbody>{rows}</tbody>",
53683 tpls.body.disableFormats = true;
53685 tpls.body.compile();
53688 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
53689 tpls.row.disableFormats = true;
53691 tpls.row.compile();
53694 tpls.cell = new Roo.Template(
53695 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
53696 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
53697 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
53700 tpls.cell.disableFormats = true;
53702 tpls.cell.compile();
53704 this.templates = tpls;
53707 // remap these for backwards compat
53708 onColWidthChange : function(){
53709 this.updateColumns.apply(this, arguments);
53711 onHeaderChange : function(){
53712 this.updateHeaders.apply(this, arguments);
53714 onHiddenChange : function(){
53715 this.handleHiddenChange.apply(this, arguments);
53717 onColumnMove : function(){
53718 this.handleColumnMove.apply(this, arguments);
53720 onColumnLock : function(){
53721 this.handleLockChange.apply(this, arguments);
53724 onDataChange : function(){
53726 this.updateHeaderSortState();
53729 onClear : function(){
53733 onUpdate : function(ds, record){
53734 this.refreshRow(record);
53737 refreshRow : function(record){
53738 var ds = this.ds, index;
53739 if(typeof record == 'number'){
53741 record = ds.getAt(index);
53743 index = ds.indexOf(record);
53745 this.insertRows(ds, index, index, true);
53746 this.onRemove(ds, record, index+1, true);
53747 this.syncRowHeights(index, index);
53749 this.fireEvent("rowupdated", this, index, record);
53752 onAdd : function(ds, records, index){
53753 this.insertRows(ds, index, index + (records.length-1));
53756 onRemove : function(ds, record, index, isUpdate){
53757 if(isUpdate !== true){
53758 this.fireEvent("beforerowremoved", this, index, record);
53760 var bt = this.getBodyTable(), lt = this.getLockedTable();
53761 if(bt.rows[index]){
53762 bt.firstChild.removeChild(bt.rows[index]);
53764 if(lt.rows[index]){
53765 lt.firstChild.removeChild(lt.rows[index]);
53767 if(isUpdate !== true){
53768 this.stripeRows(index);
53769 this.syncRowHeights(index, index);
53771 this.fireEvent("rowremoved", this, index, record);
53775 onLoad : function(){
53776 this.scrollToTop();
53780 * Scrolls the grid to the top
53782 scrollToTop : function(){
53784 this.scroller.dom.scrollTop = 0;
53790 * Gets a panel in the header of the grid that can be used for toolbars etc.
53791 * After modifying the contents of this panel a call to grid.autoSize() may be
53792 * required to register any changes in size.
53793 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
53794 * @return Roo.Element
53796 getHeaderPanel : function(doShow){
53798 this.headerPanel.show();
53800 return this.headerPanel;
53804 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53805 * After modifying the contents of this panel a call to grid.autoSize() may be
53806 * required to register any changes in size.
53807 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53808 * @return Roo.Element
53810 getFooterPanel : function(doShow){
53812 this.footerPanel.show();
53814 return this.footerPanel;
53817 initElements : function(){
53818 var E = Roo.Element;
53819 var el = this.grid.getGridEl().dom.firstChild;
53820 var cs = el.childNodes;
53822 this.el = new E(el);
53824 this.focusEl = new E(el.firstChild);
53825 this.focusEl.swallowEvent("click", true);
53827 this.headerPanel = new E(cs[1]);
53828 this.headerPanel.enableDisplayMode("block");
53830 this.scroller = new E(cs[2]);
53831 this.scrollSizer = new E(this.scroller.dom.firstChild);
53833 this.lockedWrap = new E(cs[3]);
53834 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53835 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53837 this.mainWrap = new E(cs[4]);
53838 this.mainHd = new E(this.mainWrap.dom.firstChild);
53839 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53841 this.footerPanel = new E(cs[5]);
53842 this.footerPanel.enableDisplayMode("block");
53844 this.resizeProxy = new E(cs[6]);
53846 this.headerSelector = String.format(
53847 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53848 this.lockedHd.id, this.mainHd.id
53851 this.splitterSelector = String.format(
53852 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53853 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53856 idToCssName : function(s)
53858 return s.replace(/[^a-z0-9]+/ig, '-');
53861 getHeaderCell : function(index){
53862 return Roo.DomQuery.select(this.headerSelector)[index];
53865 getHeaderCellMeasure : function(index){
53866 return this.getHeaderCell(index).firstChild;
53869 getHeaderCellText : function(index){
53870 return this.getHeaderCell(index).firstChild.firstChild;
53873 getLockedTable : function(){
53874 return this.lockedBody.dom.firstChild;
53877 getBodyTable : function(){
53878 return this.mainBody.dom.firstChild;
53881 getLockedRow : function(index){
53882 return this.getLockedTable().rows[index];
53885 getRow : function(index){
53886 return this.getBodyTable().rows[index];
53889 getRowComposite : function(index){
53891 this.rowEl = new Roo.CompositeElementLite();
53893 var els = [], lrow, mrow;
53894 if(lrow = this.getLockedRow(index)){
53897 if(mrow = this.getRow(index)){
53900 this.rowEl.elements = els;
53904 * Gets the 'td' of the cell
53906 * @param {Integer} rowIndex row to select
53907 * @param {Integer} colIndex column to select
53911 getCell : function(rowIndex, colIndex){
53912 var locked = this.cm.getLockedCount();
53914 if(colIndex < locked){
53915 source = this.lockedBody.dom.firstChild;
53917 source = this.mainBody.dom.firstChild;
53918 colIndex -= locked;
53920 return source.rows[rowIndex].childNodes[colIndex];
53923 getCellText : function(rowIndex, colIndex){
53924 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53927 getCellBox : function(cell){
53928 var b = this.fly(cell).getBox();
53929 if(Roo.isOpera){ // opera fails to report the Y
53930 b.y = cell.offsetTop + this.mainBody.getY();
53935 getCellIndex : function(cell){
53936 var id = String(cell.className).match(this.cellRE);
53938 return parseInt(id[1], 10);
53943 findHeaderIndex : function(n){
53944 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53945 return r ? this.getCellIndex(r) : false;
53948 findHeaderCell : function(n){
53949 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53950 return r ? r : false;
53953 findRowIndex : function(n){
53957 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53958 return r ? r.rowIndex : false;
53961 findCellIndex : function(node){
53962 var stop = this.el.dom;
53963 while(node && node != stop){
53964 if(this.findRE.test(node.className)){
53965 return this.getCellIndex(node);
53967 node = node.parentNode;
53972 getColumnId : function(index){
53973 return this.cm.getColumnId(index);
53976 getSplitters : function()
53978 if(this.splitterSelector){
53979 return Roo.DomQuery.select(this.splitterSelector);
53985 getSplitter : function(index){
53986 return this.getSplitters()[index];
53989 onRowOver : function(e, t){
53991 if((row = this.findRowIndex(t)) !== false){
53992 this.getRowComposite(row).addClass("x-grid-row-over");
53996 onRowOut : function(e, t){
53998 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53999 this.getRowComposite(row).removeClass("x-grid-row-over");
54003 renderHeaders : function(){
54005 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
54006 var cb = [], lb = [], sb = [], lsb = [], p = {};
54007 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54008 p.cellId = "x-grid-hd-0-" + i;
54009 p.splitId = "x-grid-csplit-0-" + i;
54010 p.id = cm.getColumnId(i);
54011 p.value = cm.getColumnHeader(i) || "";
54012 p.title = cm.getColumnTooltip(i) || p.value.match(/\</) ? '' : p.value || "";
54013 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
54014 if(!cm.isLocked(i)){
54015 cb[cb.length] = ct.apply(p);
54016 sb[sb.length] = st.apply(p);
54018 lb[lb.length] = ct.apply(p);
54019 lsb[lsb.length] = st.apply(p);
54022 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
54023 ht.apply({cells: cb.join(""), splits:sb.join("")})];
54026 updateHeaders : function(){
54027 var html = this.renderHeaders();
54028 this.lockedHd.update(html[0]);
54029 this.mainHd.update(html[1]);
54033 * Focuses the specified row.
54034 * @param {Number} row The row index
54036 focusRow : function(row)
54038 //Roo.log('GridView.focusRow');
54039 var x = this.scroller.dom.scrollLeft;
54040 this.focusCell(row, 0, false);
54041 this.scroller.dom.scrollLeft = x;
54045 * Focuses the specified cell.
54046 * @param {Number} row The row index
54047 * @param {Number} col The column index
54048 * @param {Boolean} hscroll false to disable horizontal scrolling
54050 focusCell : function(row, col, hscroll)
54052 //Roo.log('GridView.focusCell');
54053 var el = this.ensureVisible(row, col, hscroll);
54054 this.focusEl.alignTo(el, "tl-tl");
54056 this.focusEl.focus();
54058 this.focusEl.focus.defer(1, this.focusEl);
54063 * Scrolls the specified cell into view
54064 * @param {Number} row The row index
54065 * @param {Number} col The column index
54066 * @param {Boolean} hscroll false to disable horizontal scrolling
54068 ensureVisible : function(row, col, hscroll)
54070 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
54071 //return null; //disable for testing.
54072 if(typeof row != "number"){
54073 row = row.rowIndex;
54075 if(row < 0 && row >= this.ds.getCount()){
54078 col = (col !== undefined ? col : 0);
54079 var cm = this.grid.colModel;
54080 while(cm.isHidden(col)){
54084 var el = this.getCell(row, col);
54088 var c = this.scroller.dom;
54090 var ctop = parseInt(el.offsetTop, 10);
54091 var cleft = parseInt(el.offsetLeft, 10);
54092 var cbot = ctop + el.offsetHeight;
54093 var cright = cleft + el.offsetWidth;
54095 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
54096 var stop = parseInt(c.scrollTop, 10);
54097 var sleft = parseInt(c.scrollLeft, 10);
54098 var sbot = stop + ch;
54099 var sright = sleft + c.clientWidth;
54101 Roo.log('GridView.ensureVisible:' +
54103 ' c.clientHeight:' + c.clientHeight +
54104 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
54112 c.scrollTop = ctop;
54113 //Roo.log("set scrolltop to ctop DISABLE?");
54114 }else if(cbot > sbot){
54115 //Roo.log("set scrolltop to cbot-ch");
54116 c.scrollTop = cbot-ch;
54119 if(hscroll !== false){
54121 c.scrollLeft = cleft;
54122 }else if(cright > sright){
54123 c.scrollLeft = cright-c.clientWidth;
54130 updateColumns : function(){
54131 this.grid.stopEditing();
54132 var cm = this.grid.colModel, colIds = this.getColumnIds();
54133 //var totalWidth = cm.getTotalWidth();
54135 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54136 //if(cm.isHidden(i)) continue;
54137 var w = cm.getColumnWidth(i);
54138 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
54139 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
54141 this.updateSplitters();
54144 generateRules : function(cm){
54145 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
54146 Roo.util.CSS.removeStyleSheet(rulesId);
54147 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54148 var cid = cm.getColumnId(i);
54150 if(cm.config[i].align){
54151 align = 'text-align:'+cm.config[i].align+';';
54154 if(cm.isHidden(i)){
54155 hidden = 'display:none;';
54157 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
54159 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
54160 this.hdSelector, cid, " {\n", align, width, "}\n",
54161 this.tdSelector, cid, " {\n",hidden,"\n}\n",
54162 this.splitSelector, cid, " {\n", hidden , "\n}\n");
54164 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54167 updateSplitters : function(){
54168 var cm = this.cm, s = this.getSplitters();
54169 if(s){ // splitters not created yet
54170 var pos = 0, locked = true;
54171 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54172 if(cm.isHidden(i)) {
54175 var w = cm.getColumnWidth(i); // make sure it's a number
54176 if(!cm.isLocked(i) && locked){
54181 s[i].style.left = (pos-this.splitOffset) + "px";
54186 handleHiddenChange : function(colModel, colIndex, hidden){
54188 this.hideColumn(colIndex);
54190 this.unhideColumn(colIndex);
54194 hideColumn : function(colIndex){
54195 var cid = this.getColumnId(colIndex);
54196 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
54197 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
54199 this.updateHeaders();
54201 this.updateSplitters();
54205 unhideColumn : function(colIndex){
54206 var cid = this.getColumnId(colIndex);
54207 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
54208 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
54211 this.updateHeaders();
54213 this.updateSplitters();
54217 insertRows : function(dm, firstRow, lastRow, isUpdate){
54218 if(firstRow == 0 && lastRow == dm.getCount()-1){
54222 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
54224 var s = this.getScrollState();
54225 var markup = this.renderRows(firstRow, lastRow);
54226 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
54227 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
54228 this.restoreScroll(s);
54230 this.fireEvent("rowsinserted", this, firstRow, lastRow);
54231 this.syncRowHeights(firstRow, lastRow);
54232 this.stripeRows(firstRow);
54238 bufferRows : function(markup, target, index){
54239 var before = null, trows = target.rows, tbody = target.tBodies[0];
54240 if(index < trows.length){
54241 before = trows[index];
54243 var b = document.createElement("div");
54244 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
54245 var rows = b.firstChild.rows;
54246 for(var i = 0, len = rows.length; i < len; i++){
54248 tbody.insertBefore(rows[0], before);
54250 tbody.appendChild(rows[0]);
54257 deleteRows : function(dm, firstRow, lastRow){
54258 if(dm.getRowCount()<1){
54259 this.fireEvent("beforerefresh", this);
54260 this.mainBody.update("");
54261 this.lockedBody.update("");
54262 this.fireEvent("refresh", this);
54264 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
54265 var bt = this.getBodyTable();
54266 var tbody = bt.firstChild;
54267 var rows = bt.rows;
54268 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
54269 tbody.removeChild(rows[firstRow]);
54271 this.stripeRows(firstRow);
54272 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
54276 updateRows : function(dataSource, firstRow, lastRow){
54277 var s = this.getScrollState();
54279 this.restoreScroll(s);
54282 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
54286 this.updateHeaderSortState();
54289 getScrollState : function(){
54291 var sb = this.scroller.dom;
54292 return {left: sb.scrollLeft, top: sb.scrollTop};
54295 stripeRows : function(startRow){
54296 if(!this.grid.stripeRows || this.ds.getCount() < 1){
54299 startRow = startRow || 0;
54300 var rows = this.getBodyTable().rows;
54301 var lrows = this.getLockedTable().rows;
54302 var cls = ' x-grid-row-alt ';
54303 for(var i = startRow, len = rows.length; i < len; i++){
54304 var row = rows[i], lrow = lrows[i];
54305 var isAlt = ((i+1) % 2 == 0);
54306 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
54307 if(isAlt == hasAlt){
54311 row.className += " x-grid-row-alt";
54313 row.className = row.className.replace("x-grid-row-alt", "");
54316 lrow.className = row.className;
54321 restoreScroll : function(state){
54322 //Roo.log('GridView.restoreScroll');
54323 var sb = this.scroller.dom;
54324 sb.scrollLeft = state.left;
54325 sb.scrollTop = state.top;
54329 syncScroll : function(){
54330 //Roo.log('GridView.syncScroll');
54331 var sb = this.scroller.dom;
54332 var sh = this.mainHd.dom;
54333 var bs = this.mainBody.dom;
54334 var lv = this.lockedBody.dom;
54335 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
54336 lv.scrollTop = bs.scrollTop = sb.scrollTop;
54339 handleScroll : function(e){
54341 var sb = this.scroller.dom;
54342 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
54346 handleWheel : function(e){
54347 var d = e.getWheelDelta();
54348 this.scroller.dom.scrollTop -= d*22;
54349 // set this here to prevent jumpy scrolling on large tables
54350 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
54354 renderRows : function(startRow, endRow){
54355 // pull in all the crap needed to render rows
54356 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
54357 var colCount = cm.getColumnCount();
54359 if(ds.getCount() < 1){
54363 // build a map for all the columns
54365 for(var i = 0; i < colCount; i++){
54366 var name = cm.getDataIndex(i);
54368 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
54369 renderer : cm.getRenderer(i),
54370 id : cm.getColumnId(i),
54371 locked : cm.isLocked(i),
54372 has_editor : cm.isCellEditable(i)
54376 startRow = startRow || 0;
54377 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
54379 // records to render
54380 var rs = ds.getRange(startRow, endRow);
54382 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
54385 // As much as I hate to duplicate code, this was branched because FireFox really hates
54386 // [].join("") on strings. The performance difference was substantial enough to
54387 // branch this function
54388 doRender : Roo.isGecko ?
54389 function(cs, rs, ds, startRow, colCount, stripe){
54390 var ts = this.templates, ct = ts.cell, rt = ts.row;
54392 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54394 var hasListener = this.grid.hasListener('rowclass');
54396 for(var j = 0, len = rs.length; j < len; j++){
54397 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
54398 for(var i = 0; i < colCount; i++){
54400 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54402 p.css = p.attr = "";
54403 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54404 if(p.value == undefined || p.value === "") {
54405 p.value = " ";
54408 p.css += ' x-grid-editable-cell';
54410 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
54411 p.css += ' x-grid-dirty-cell';
54413 var markup = ct.apply(p);
54421 if(stripe && ((rowIndex+1) % 2 == 0)){
54422 alt.push("x-grid-row-alt")
54425 alt.push( " x-grid-dirty-row");
54428 if(this.getRowClass){
54429 alt.push(this.getRowClass(r, rowIndex));
54435 rowIndex : rowIndex,
54438 this.grid.fireEvent('rowclass', this, rowcfg);
54439 alt.push(rowcfg.rowClass);
54441 rp.alt = alt.join(" ");
54442 lbuf+= rt.apply(rp);
54444 buf+= rt.apply(rp);
54446 return [lbuf, buf];
54448 function(cs, rs, ds, startRow, colCount, stripe){
54449 var ts = this.templates, ct = ts.cell, rt = ts.row;
54451 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54452 var hasListener = this.grid.hasListener('rowclass');
54455 for(var j = 0, len = rs.length; j < len; j++){
54456 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
54457 for(var i = 0; i < colCount; i++){
54459 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54461 p.css = p.attr = "";
54462 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54463 if(p.value == undefined || p.value === "") {
54464 p.value = " ";
54468 p.css += ' x-grid-editable-cell';
54470 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54471 p.css += ' x-grid-dirty-cell'
54474 var markup = ct.apply(p);
54476 cb[cb.length] = markup;
54478 lcb[lcb.length] = markup;
54482 if(stripe && ((rowIndex+1) % 2 == 0)){
54483 alt.push( "x-grid-row-alt");
54486 alt.push(" x-grid-dirty-row");
54489 if(this.getRowClass){
54490 alt.push( this.getRowClass(r, rowIndex));
54496 rowIndex : rowIndex,
54499 this.grid.fireEvent('rowclass', this, rowcfg);
54500 alt.push(rowcfg.rowClass);
54503 rp.alt = alt.join(" ");
54504 rp.cells = lcb.join("");
54505 lbuf[lbuf.length] = rt.apply(rp);
54506 rp.cells = cb.join("");
54507 buf[buf.length] = rt.apply(rp);
54509 return [lbuf.join(""), buf.join("")];
54512 renderBody : function(){
54513 var markup = this.renderRows();
54514 var bt = this.templates.body;
54515 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
54519 * Refreshes the grid
54520 * @param {Boolean} headersToo
54522 refresh : function(headersToo){
54523 this.fireEvent("beforerefresh", this);
54524 this.grid.stopEditing();
54525 var result = this.renderBody();
54526 this.lockedBody.update(result[0]);
54527 this.mainBody.update(result[1]);
54528 if(headersToo === true){
54529 this.updateHeaders();
54530 this.updateColumns();
54531 this.updateSplitters();
54532 this.updateHeaderSortState();
54534 this.syncRowHeights();
54536 this.fireEvent("refresh", this);
54539 handleColumnMove : function(cm, oldIndex, newIndex){
54540 this.indexMap = null;
54541 var s = this.getScrollState();
54542 this.refresh(true);
54543 this.restoreScroll(s);
54544 this.afterMove(newIndex);
54547 afterMove : function(colIndex){
54548 if(this.enableMoveAnim && Roo.enableFx){
54549 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
54551 // if multisort - fix sortOrder, and reload..
54552 if (this.grid.dataSource.multiSort) {
54553 // the we can call sort again..
54554 var dm = this.grid.dataSource;
54555 var cm = this.grid.colModel;
54557 for(var i = 0; i < cm.config.length; i++ ) {
54559 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
54560 continue; // dont' bother, it's not in sort list or being set.
54563 so.push(cm.config[i].dataIndex);
54566 dm.load(dm.lastOptions);
54573 updateCell : function(dm, rowIndex, dataIndex){
54574 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
54575 if(typeof colIndex == "undefined"){ // not present in grid
54578 var cm = this.grid.colModel;
54579 var cell = this.getCell(rowIndex, colIndex);
54580 var cellText = this.getCellText(rowIndex, colIndex);
54583 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
54584 id : cm.getColumnId(colIndex),
54585 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
54587 var renderer = cm.getRenderer(colIndex);
54588 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
54589 if(typeof val == "undefined" || val === "") {
54592 cellText.innerHTML = val;
54593 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
54594 this.syncRowHeights(rowIndex, rowIndex);
54597 calcColumnWidth : function(colIndex, maxRowsToMeasure){
54599 if(this.grid.autoSizeHeaders){
54600 var h = this.getHeaderCellMeasure(colIndex);
54601 maxWidth = Math.max(maxWidth, h.scrollWidth);
54604 if(this.cm.isLocked(colIndex)){
54605 tb = this.getLockedTable();
54608 tb = this.getBodyTable();
54609 index = colIndex - this.cm.getLockedCount();
54612 var rows = tb.rows;
54613 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
54614 for(var i = 0; i < stopIndex; i++){
54615 var cell = rows[i].childNodes[index].firstChild;
54616 maxWidth = Math.max(maxWidth, cell.scrollWidth);
54619 return maxWidth + /*margin for error in IE*/ 5;
54622 * Autofit a column to its content.
54623 * @param {Number} colIndex
54624 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
54626 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
54627 if(this.cm.isHidden(colIndex)){
54628 return; // can't calc a hidden column
54631 var cid = this.cm.getColumnId(colIndex);
54632 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
54633 if(this.grid.autoSizeHeaders){
54634 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
54637 var newWidth = this.calcColumnWidth(colIndex);
54638 this.cm.setColumnWidth(colIndex,
54639 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
54640 if(!suppressEvent){
54641 this.grid.fireEvent("columnresize", colIndex, newWidth);
54646 * Autofits all columns to their content and then expands to fit any extra space in the grid
54648 autoSizeColumns : function(){
54649 var cm = this.grid.colModel;
54650 var colCount = cm.getColumnCount();
54651 for(var i = 0; i < colCount; i++){
54652 this.autoSizeColumn(i, true, true);
54654 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
54657 this.updateColumns();
54663 * Autofits all columns to the grid's width proportionate with their current size
54664 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
54666 fitColumns : function(reserveScrollSpace){
54667 var cm = this.grid.colModel;
54668 var colCount = cm.getColumnCount();
54672 for (i = 0; i < colCount; i++){
54673 if(!cm.isHidden(i) && !cm.isFixed(i)){
54674 w = cm.getColumnWidth(i);
54680 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
54681 if(reserveScrollSpace){
54684 var frac = (avail - cm.getTotalWidth())/width;
54685 while (cols.length){
54688 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
54690 this.updateColumns();
54694 onRowSelect : function(rowIndex){
54695 var row = this.getRowComposite(rowIndex);
54696 row.addClass("x-grid-row-selected");
54699 onRowDeselect : function(rowIndex){
54700 var row = this.getRowComposite(rowIndex);
54701 row.removeClass("x-grid-row-selected");
54704 onCellSelect : function(row, col){
54705 var cell = this.getCell(row, col);
54707 Roo.fly(cell).addClass("x-grid-cell-selected");
54711 onCellDeselect : function(row, col){
54712 var cell = this.getCell(row, col);
54714 Roo.fly(cell).removeClass("x-grid-cell-selected");
54718 updateHeaderSortState : function(){
54720 // sort state can be single { field: xxx, direction : yyy}
54721 // or { xxx=>ASC , yyy : DESC ..... }
54724 if (!this.ds.multiSort) {
54725 var state = this.ds.getSortState();
54729 mstate[state.field] = state.direction;
54730 // FIXME... - this is not used here.. but might be elsewhere..
54731 this.sortState = state;
54734 mstate = this.ds.sortToggle;
54736 //remove existing sort classes..
54738 var sc = this.sortClasses;
54739 var hds = this.el.select(this.headerSelector).removeClass(sc);
54741 for(var f in mstate) {
54743 var sortColumn = this.cm.findColumnIndex(f);
54745 if(sortColumn != -1){
54746 var sortDir = mstate[f];
54747 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
54756 handleHeaderClick : function(g, index,e){
54758 Roo.log("header click");
54761 // touch events on header are handled by context
54762 this.handleHdCtx(g,index,e);
54767 if(this.headersDisabled){
54770 var dm = g.dataSource, cm = g.colModel;
54771 if(!cm.isSortable(index)){
54776 if (dm.multiSort) {
54777 // update the sortOrder
54779 for(var i = 0; i < cm.config.length; i++ ) {
54781 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
54782 continue; // dont' bother, it's not in sort list or being set.
54785 so.push(cm.config[i].dataIndex);
54791 dm.sort(cm.getDataIndex(index));
54795 destroy : function(){
54797 this.colMenu.removeAll();
54798 Roo.menu.MenuMgr.unregister(this.colMenu);
54799 this.colMenu.getEl().remove();
54800 delete this.colMenu;
54803 this.hmenu.removeAll();
54804 Roo.menu.MenuMgr.unregister(this.hmenu);
54805 this.hmenu.getEl().remove();
54808 if(this.grid.enableColumnMove){
54809 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54811 for(var dd in dds){
54812 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54813 var elid = dds[dd].dragElId;
54815 Roo.get(elid).remove();
54816 } else if(dds[dd].config.isTarget){
54817 dds[dd].proxyTop.remove();
54818 dds[dd].proxyBottom.remove();
54821 if(Roo.dd.DDM.locationCache[dd]){
54822 delete Roo.dd.DDM.locationCache[dd];
54825 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54828 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54829 this.bind(null, null);
54830 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54833 handleLockChange : function(){
54834 this.refresh(true);
54837 onDenyColumnLock : function(){
54841 onDenyColumnHide : function(){
54845 handleHdMenuClick : function(item){
54846 var index = this.hdCtxIndex;
54847 var cm = this.cm, ds = this.ds;
54850 ds.sort(cm.getDataIndex(index), "ASC");
54853 ds.sort(cm.getDataIndex(index), "DESC");
54856 var lc = cm.getLockedCount();
54857 if(cm.getColumnCount(true) <= lc+1){
54858 this.onDenyColumnLock();
54862 cm.setLocked(index, true, true);
54863 cm.moveColumn(index, lc);
54864 this.grid.fireEvent("columnmove", index, lc);
54866 cm.setLocked(index, true);
54870 var lc = cm.getLockedCount();
54871 if((lc-1) != index){
54872 cm.setLocked(index, false, true);
54873 cm.moveColumn(index, lc-1);
54874 this.grid.fireEvent("columnmove", index, lc-1);
54876 cm.setLocked(index, false);
54879 case 'wider': // used to expand cols on touch..
54881 var cw = cm.getColumnWidth(index);
54882 cw += (item.id == 'wider' ? 1 : -1) * 50;
54883 cw = Math.max(0, cw);
54884 cw = Math.min(cw,4000);
54885 cm.setColumnWidth(index, cw);
54889 index = cm.getIndexById(item.id.substr(4));
54891 if(item.checked && cm.getColumnCount(true) <= 1){
54892 this.onDenyColumnHide();
54895 cm.setHidden(index, item.checked);
54901 beforeColMenuShow : function(){
54902 var cm = this.cm, colCount = cm.getColumnCount();
54903 this.colMenu.removeAll();
54904 for(var i = 0; i < colCount; i++){
54905 this.colMenu.add(new Roo.menu.CheckItem({
54906 id: "col-"+cm.getColumnId(i),
54907 text: cm.getColumnHeader(i),
54908 checked: !cm.isHidden(i),
54914 handleHdCtx : function(g, index, e){
54916 var hd = this.getHeaderCell(index);
54917 this.hdCtxIndex = index;
54918 var ms = this.hmenu.items, cm = this.cm;
54919 ms.get("asc").setDisabled(!cm.isSortable(index));
54920 ms.get("desc").setDisabled(!cm.isSortable(index));
54921 if(this.grid.enableColLock !== false){
54922 ms.get("lock").setDisabled(cm.isLocked(index));
54923 ms.get("unlock").setDisabled(!cm.isLocked(index));
54925 this.hmenu.show(hd, "tl-bl");
54928 handleHdOver : function(e){
54929 var hd = this.findHeaderCell(e.getTarget());
54930 if(hd && !this.headersDisabled){
54931 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54932 this.fly(hd).addClass("x-grid-hd-over");
54937 handleHdOut : function(e){
54938 var hd = this.findHeaderCell(e.getTarget());
54940 this.fly(hd).removeClass("x-grid-hd-over");
54944 handleSplitDblClick : function(e, t){
54945 var i = this.getCellIndex(t);
54946 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54947 this.autoSizeColumn(i, true);
54952 render : function(){
54955 var colCount = cm.getColumnCount();
54957 if(this.grid.monitorWindowResize === true){
54958 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54960 var header = this.renderHeaders();
54961 var body = this.templates.body.apply({rows:""});
54962 var html = this.templates.master.apply({
54965 lockedHeader: header[0],
54969 //this.updateColumns();
54971 this.grid.getGridEl().dom.innerHTML = html;
54973 this.initElements();
54975 // a kludge to fix the random scolling effect in webkit
54976 this.el.on("scroll", function() {
54977 this.el.dom.scrollTop=0; // hopefully not recursive..
54980 this.scroller.on("scroll", this.handleScroll, this);
54981 this.lockedBody.on("mousewheel", this.handleWheel, this);
54982 this.mainBody.on("mousewheel", this.handleWheel, this);
54984 this.mainHd.on("mouseover", this.handleHdOver, this);
54985 this.mainHd.on("mouseout", this.handleHdOut, this);
54986 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54987 {delegate: "."+this.splitClass});
54989 this.lockedHd.on("mouseover", this.handleHdOver, this);
54990 this.lockedHd.on("mouseout", this.handleHdOut, this);
54991 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54992 {delegate: "."+this.splitClass});
54994 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54995 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54998 this.updateSplitters();
55000 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
55001 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
55002 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
55005 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
55006 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
55008 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
55009 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
55011 if(this.grid.enableColLock !== false){
55012 this.hmenu.add('-',
55013 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
55014 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
55018 this.hmenu.add('-',
55019 {id:"wider", text: this.columnsWiderText},
55020 {id:"narrow", text: this.columnsNarrowText }
55026 if(this.grid.enableColumnHide !== false){
55028 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
55029 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
55030 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
55032 this.hmenu.add('-',
55033 {id:"columns", text: this.columnsText, menu: this.colMenu}
55036 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
55038 this.grid.on("headercontextmenu", this.handleHdCtx, this);
55041 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
55042 this.dd = new Roo.grid.GridDragZone(this.grid, {
55043 ddGroup : this.grid.ddGroup || 'GridDD'
55049 for(var i = 0; i < colCount; i++){
55050 if(cm.isHidden(i)){
55051 this.hideColumn(i);
55053 if(cm.config[i].align){
55054 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
55055 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
55059 this.updateHeaderSortState();
55061 this.beforeInitialResize();
55064 // two part rendering gives faster view to the user
55065 this.renderPhase2.defer(1, this);
55068 renderPhase2 : function(){
55069 // render the rows now
55071 if(this.grid.autoSizeColumns){
55072 this.autoSizeColumns();
55076 beforeInitialResize : function(){
55080 onColumnSplitterMoved : function(i, w){
55081 this.userResized = true;
55082 var cm = this.grid.colModel;
55083 cm.setColumnWidth(i, w, true);
55084 var cid = cm.getColumnId(i);
55085 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
55086 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
55087 this.updateSplitters();
55089 this.grid.fireEvent("columnresize", i, w);
55092 syncRowHeights : function(startIndex, endIndex){
55093 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
55094 startIndex = startIndex || 0;
55095 var mrows = this.getBodyTable().rows;
55096 var lrows = this.getLockedTable().rows;
55097 var len = mrows.length-1;
55098 endIndex = Math.min(endIndex || len, len);
55099 for(var i = startIndex; i <= endIndex; i++){
55100 var m = mrows[i], l = lrows[i];
55101 var h = Math.max(m.offsetHeight, l.offsetHeight);
55102 m.style.height = l.style.height = h + "px";
55107 layout : function(initialRender, is2ndPass){
55109 var auto = g.autoHeight;
55110 var scrollOffset = 16;
55111 var c = g.getGridEl(), cm = this.cm,
55112 expandCol = g.autoExpandColumn,
55114 //c.beginMeasure();
55116 if(!c.dom.offsetWidth){ // display:none?
55118 this.lockedWrap.show();
55119 this.mainWrap.show();
55124 var hasLock = this.cm.isLocked(0);
55126 var tbh = this.headerPanel.getHeight();
55127 var bbh = this.footerPanel.getHeight();
55130 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
55131 var newHeight = ch + c.getBorderWidth("tb");
55133 newHeight = Math.min(g.maxHeight, newHeight);
55135 c.setHeight(newHeight);
55139 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
55142 var s = this.scroller;
55144 var csize = c.getSize(true);
55146 this.el.setSize(csize.width, csize.height);
55148 this.headerPanel.setWidth(csize.width);
55149 this.footerPanel.setWidth(csize.width);
55151 var hdHeight = this.mainHd.getHeight();
55152 var vw = csize.width;
55153 var vh = csize.height - (tbh + bbh);
55157 var bt = this.getBodyTable();
55159 if(cm.getLockedCount() == cm.config.length){
55160 bt = this.getLockedTable();
55163 var ltWidth = hasLock ?
55164 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
55166 var scrollHeight = bt.offsetHeight;
55167 var scrollWidth = ltWidth + bt.offsetWidth;
55168 var vscroll = false, hscroll = false;
55170 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
55172 var lw = this.lockedWrap, mw = this.mainWrap;
55173 var lb = this.lockedBody, mb = this.mainBody;
55175 setTimeout(function(){
55176 var t = s.dom.offsetTop;
55177 var w = s.dom.clientWidth,
55178 h = s.dom.clientHeight;
55181 lw.setSize(ltWidth, h);
55183 mw.setLeftTop(ltWidth, t);
55184 mw.setSize(w-ltWidth, h);
55186 lb.setHeight(h-hdHeight);
55187 mb.setHeight(h-hdHeight);
55189 if(is2ndPass !== true && !gv.userResized && expandCol){
55190 // high speed resize without full column calculation
55192 var ci = cm.getIndexById(expandCol);
55194 ci = cm.findColumnIndex(expandCol);
55196 ci = Math.max(0, ci); // make sure it's got at least the first col.
55197 var expandId = cm.getColumnId(ci);
55198 var tw = cm.getTotalWidth(false);
55199 var currentWidth = cm.getColumnWidth(ci);
55200 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
55201 if(currentWidth != cw){
55202 cm.setColumnWidth(ci, cw, true);
55203 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
55204 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
55205 gv.updateSplitters();
55206 gv.layout(false, true);
55218 onWindowResize : function(){
55219 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
55225 appendFooter : function(parentEl){
55229 sortAscText : "Sort Ascending",
55230 sortDescText : "Sort Descending",
55231 lockText : "Lock Column",
55232 unlockText : "Unlock Column",
55233 columnsText : "Columns",
55235 columnsWiderText : "Wider",
55236 columnsNarrowText : "Thinner"
55240 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
55241 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
55242 this.proxy.el.addClass('x-grid3-col-dd');
55245 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
55246 handleMouseDown : function(e){
55250 callHandleMouseDown : function(e){
55251 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
55256 * Ext JS Library 1.1.1
55257 * Copyright(c) 2006-2007, Ext JS, LLC.
55259 * Originally Released Under LGPL - original licence link has changed is not relivant.
55262 * <script type="text/javascript">
55266 // This is a support class used internally by the Grid components
55267 Roo.grid.SplitDragZone = function(grid, hd, hd2){
55269 this.view = grid.getView();
55270 this.proxy = this.view.resizeProxy;
55271 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
55272 "gridSplitters" + this.grid.getGridEl().id, {
55273 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
55275 this.setHandleElId(Roo.id(hd));
55276 this.setOuterHandleElId(Roo.id(hd2));
55277 this.scroll = false;
55279 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
55280 fly: Roo.Element.fly,
55282 b4StartDrag : function(x, y){
55283 this.view.headersDisabled = true;
55284 this.proxy.setHeight(this.view.mainWrap.getHeight());
55285 var w = this.cm.getColumnWidth(this.cellIndex);
55286 var minw = Math.max(w-this.grid.minColumnWidth, 0);
55287 this.resetConstraints();
55288 this.setXConstraint(minw, 1000);
55289 this.setYConstraint(0, 0);
55290 this.minX = x - minw;
55291 this.maxX = x + 1000;
55293 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
55297 handleMouseDown : function(e){
55298 ev = Roo.EventObject.setEvent(e);
55299 var t = this.fly(ev.getTarget());
55300 if(t.hasClass("x-grid-split")){
55301 this.cellIndex = this.view.getCellIndex(t.dom);
55302 this.split = t.dom;
55303 this.cm = this.grid.colModel;
55304 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
55305 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
55310 endDrag : function(e){
55311 this.view.headersDisabled = false;
55312 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
55313 var diff = endX - this.startPos;
55314 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
55317 autoOffset : function(){
55318 this.setDelta(0,0);
55322 * Ext JS Library 1.1.1
55323 * Copyright(c) 2006-2007, Ext JS, LLC.
55325 * Originally Released Under LGPL - original licence link has changed is not relivant.
55328 * <script type="text/javascript">
55332 // This is a support class used internally by the Grid components
55333 Roo.grid.GridDragZone = function(grid, config){
55334 this.view = grid.getView();
55335 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
55336 if(this.view.lockedBody){
55337 this.setHandleElId(Roo.id(this.view.mainBody.dom));
55338 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
55340 this.scroll = false;
55342 this.ddel = document.createElement('div');
55343 this.ddel.className = 'x-grid-dd-wrap';
55346 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
55347 ddGroup : "GridDD",
55349 getDragData : function(e){
55350 var t = Roo.lib.Event.getTarget(e);
55351 var rowIndex = this.view.findRowIndex(t);
55352 var sm = this.grid.selModel;
55354 //Roo.log(rowIndex);
55356 if (sm.getSelectedCell) {
55357 // cell selection..
55358 if (!sm.getSelectedCell()) {
55361 if (rowIndex != sm.getSelectedCell()[0]) {
55367 if(rowIndex !== false){
55372 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
55374 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
55377 if (e.hasModifier()){
55378 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
55381 Roo.log("getDragData");
55386 rowIndex: rowIndex,
55387 selections:sm.getSelections ? sm.getSelections() : (
55388 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
55395 onInitDrag : function(e){
55396 var data = this.dragData;
55397 this.ddel.innerHTML = this.grid.getDragDropText();
55398 this.proxy.update(this.ddel);
55399 // fire start drag?
55402 afterRepair : function(){
55403 this.dragging = false;
55406 getRepairXY : function(e, data){
55410 onEndDrag : function(data, e){
55414 onValidDrop : function(dd, e, id){
55419 beforeInvalidDrop : function(e, id){
55424 * Ext JS Library 1.1.1
55425 * Copyright(c) 2006-2007, Ext JS, LLC.
55427 * Originally Released Under LGPL - original licence link has changed is not relivant.
55430 * <script type="text/javascript">
55435 * @class Roo.grid.ColumnModel
55436 * @extends Roo.util.Observable
55437 * This is the default implementation of a ColumnModel used by the Grid. It defines
55438 * the columns in the grid.
55441 var colModel = new Roo.grid.ColumnModel([
55442 {header: "Ticker", width: 60, sortable: true, locked: true},
55443 {header: "Company Name", width: 150, sortable: true},
55444 {header: "Market Cap.", width: 100, sortable: true},
55445 {header: "$ Sales", width: 100, sortable: true, renderer: money},
55446 {header: "Employees", width: 100, sortable: true, resizable: false}
55451 * The config options listed for this class are options which may appear in each
55452 * individual column definition.
55453 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
55455 * @param {Object} config An Array of column config objects. See this class's
55456 * config objects for details.
55458 Roo.grid.ColumnModel = function(config){
55460 * The config passed into the constructor
55462 this.config = config;
55465 // if no id, create one
55466 // if the column does not have a dataIndex mapping,
55467 // map it to the order it is in the config
55468 for(var i = 0, len = config.length; i < len; i++){
55470 if(typeof c.dataIndex == "undefined"){
55473 if(typeof c.renderer == "string"){
55474 c.renderer = Roo.util.Format[c.renderer];
55476 if(typeof c.id == "undefined"){
55479 if(c.editor && c.editor.xtype){
55480 c.editor = Roo.factory(c.editor, Roo.grid);
55482 if(c.editor && c.editor.isFormField){
55483 c.editor = new Roo.grid.GridEditor(c.editor);
55485 this.lookup[c.id] = c;
55489 * The width of columns which have no width specified (defaults to 100)
55492 this.defaultWidth = 100;
55495 * Default sortable of columns which have no sortable specified (defaults to false)
55498 this.defaultSortable = false;
55502 * @event widthchange
55503 * Fires when the width of a column changes.
55504 * @param {ColumnModel} this
55505 * @param {Number} columnIndex The column index
55506 * @param {Number} newWidth The new width
55508 "widthchange": true,
55510 * @event headerchange
55511 * Fires when the text of a header changes.
55512 * @param {ColumnModel} this
55513 * @param {Number} columnIndex The column index
55514 * @param {Number} newText The new header text
55516 "headerchange": true,
55518 * @event hiddenchange
55519 * Fires when a column is hidden or "unhidden".
55520 * @param {ColumnModel} this
55521 * @param {Number} columnIndex The column index
55522 * @param {Boolean} hidden true if hidden, false otherwise
55524 "hiddenchange": true,
55526 * @event columnmoved
55527 * Fires when a column is moved.
55528 * @param {ColumnModel} this
55529 * @param {Number} oldIndex
55530 * @param {Number} newIndex
55532 "columnmoved" : true,
55534 * @event columlockchange
55535 * Fires when a column's locked state is changed
55536 * @param {ColumnModel} this
55537 * @param {Number} colIndex
55538 * @param {Boolean} locked true if locked
55540 "columnlockchange" : true
55542 Roo.grid.ColumnModel.superclass.constructor.call(this);
55544 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
55546 * @cfg {String} header The header text to display in the Grid view.
55549 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
55550 * {@link Roo.data.Record} definition from which to draw the column's value. If not
55551 * specified, the column's index is used as an index into the Record's data Array.
55554 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
55555 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
55558 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
55559 * Defaults to the value of the {@link #defaultSortable} property.
55560 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
55563 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
55566 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
55569 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
55572 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
55575 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
55576 * given the cell's data value. See {@link #setRenderer}. If not specified, the
55577 * default renderer uses the raw data value. If an object is returned (bootstrap only)
55578 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
55581 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
55584 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
55587 * @cfg {String} cursor (Optional)
55590 * @cfg {String} tooltip (Optional)
55593 * @cfg {Number} xs (Optional)
55596 * @cfg {Number} sm (Optional)
55599 * @cfg {Number} md (Optional)
55602 * @cfg {Number} lg (Optional)
55605 * Returns the id of the column at the specified index.
55606 * @param {Number} index The column index
55607 * @return {String} the id
55609 getColumnId : function(index){
55610 return this.config[index].id;
55614 * Returns the column for a specified id.
55615 * @param {String} id The column id
55616 * @return {Object} the column
55618 getColumnById : function(id){
55619 return this.lookup[id];
55624 * Returns the column for a specified dataIndex.
55625 * @param {String} dataIndex The column dataIndex
55626 * @return {Object|Boolean} the column or false if not found
55628 getColumnByDataIndex: function(dataIndex){
55629 var index = this.findColumnIndex(dataIndex);
55630 return index > -1 ? this.config[index] : false;
55634 * Returns the index for a specified column id.
55635 * @param {String} id The column id
55636 * @return {Number} the index, or -1 if not found
55638 getIndexById : function(id){
55639 for(var i = 0, len = this.config.length; i < len; i++){
55640 if(this.config[i].id == id){
55648 * Returns the index for a specified column dataIndex.
55649 * @param {String} dataIndex The column dataIndex
55650 * @return {Number} the index, or -1 if not found
55653 findColumnIndex : function(dataIndex){
55654 for(var i = 0, len = this.config.length; i < len; i++){
55655 if(this.config[i].dataIndex == dataIndex){
55663 moveColumn : function(oldIndex, newIndex){
55664 var c = this.config[oldIndex];
55665 this.config.splice(oldIndex, 1);
55666 this.config.splice(newIndex, 0, c);
55667 this.dataMap = null;
55668 this.fireEvent("columnmoved", this, oldIndex, newIndex);
55671 isLocked : function(colIndex){
55672 return this.config[colIndex].locked === true;
55675 setLocked : function(colIndex, value, suppressEvent){
55676 if(this.isLocked(colIndex) == value){
55679 this.config[colIndex].locked = value;
55680 if(!suppressEvent){
55681 this.fireEvent("columnlockchange", this, colIndex, value);
55685 getTotalLockedWidth : function(){
55686 var totalWidth = 0;
55687 for(var i = 0; i < this.config.length; i++){
55688 if(this.isLocked(i) && !this.isHidden(i)){
55689 this.totalWidth += this.getColumnWidth(i);
55695 getLockedCount : function(){
55696 for(var i = 0, len = this.config.length; i < len; i++){
55697 if(!this.isLocked(i)){
55702 return this.config.length;
55706 * Returns the number of columns.
55709 getColumnCount : function(visibleOnly){
55710 if(visibleOnly === true){
55712 for(var i = 0, len = this.config.length; i < len; i++){
55713 if(!this.isHidden(i)){
55719 return this.config.length;
55723 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
55724 * @param {Function} fn
55725 * @param {Object} scope (optional)
55726 * @return {Array} result
55728 getColumnsBy : function(fn, scope){
55730 for(var i = 0, len = this.config.length; i < len; i++){
55731 var c = this.config[i];
55732 if(fn.call(scope||this, c, i) === true){
55740 * Returns true if the specified column is sortable.
55741 * @param {Number} col The column index
55742 * @return {Boolean}
55744 isSortable : function(col){
55745 if(typeof this.config[col].sortable == "undefined"){
55746 return this.defaultSortable;
55748 return this.config[col].sortable;
55752 * Returns the rendering (formatting) function defined for the column.
55753 * @param {Number} col The column index.
55754 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
55756 getRenderer : function(col){
55757 if(!this.config[col].renderer){
55758 return Roo.grid.ColumnModel.defaultRenderer;
55760 return this.config[col].renderer;
55764 * Sets the rendering (formatting) function for a column.
55765 * @param {Number} col The column index
55766 * @param {Function} fn The function to use to process the cell's raw data
55767 * to return HTML markup for the grid view. The render function is called with
55768 * the following parameters:<ul>
55769 * <li>Data value.</li>
55770 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
55771 * <li>css A CSS style string to apply to the table cell.</li>
55772 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
55773 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
55774 * <li>Row index</li>
55775 * <li>Column index</li>
55776 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
55778 setRenderer : function(col, fn){
55779 this.config[col].renderer = fn;
55783 * Returns the width for the specified column.
55784 * @param {Number} col The column index
55787 getColumnWidth : function(col){
55788 return this.config[col].width * 1 || this.defaultWidth;
55792 * Sets the width for a column.
55793 * @param {Number} col The column index
55794 * @param {Number} width The new width
55796 setColumnWidth : function(col, width, suppressEvent){
55797 this.config[col].width = width;
55798 this.totalWidth = null;
55799 if(!suppressEvent){
55800 this.fireEvent("widthchange", this, col, width);
55805 * Returns the total width of all columns.
55806 * @param {Boolean} includeHidden True to include hidden column widths
55809 getTotalWidth : function(includeHidden){
55810 if(!this.totalWidth){
55811 this.totalWidth = 0;
55812 for(var i = 0, len = this.config.length; i < len; i++){
55813 if(includeHidden || !this.isHidden(i)){
55814 this.totalWidth += this.getColumnWidth(i);
55818 return this.totalWidth;
55822 * Returns the header for the specified column.
55823 * @param {Number} col The column index
55826 getColumnHeader : function(col){
55827 return this.config[col].header;
55831 * Sets the header for a column.
55832 * @param {Number} col The column index
55833 * @param {String} header The new header
55835 setColumnHeader : function(col, header){
55836 this.config[col].header = header;
55837 this.fireEvent("headerchange", this, col, header);
55841 * Returns the tooltip for the specified column.
55842 * @param {Number} col The column index
55845 getColumnTooltip : function(col){
55846 return this.config[col].tooltip;
55849 * Sets the tooltip for a column.
55850 * @param {Number} col The column index
55851 * @param {String} tooltip The new tooltip
55853 setColumnTooltip : function(col, tooltip){
55854 this.config[col].tooltip = tooltip;
55858 * Returns the dataIndex for the specified column.
55859 * @param {Number} col The column index
55862 getDataIndex : function(col){
55863 return this.config[col].dataIndex;
55867 * Sets the dataIndex for a column.
55868 * @param {Number} col The column index
55869 * @param {Number} dataIndex The new dataIndex
55871 setDataIndex : function(col, dataIndex){
55872 this.config[col].dataIndex = dataIndex;
55878 * Returns true if the cell is editable.
55879 * @param {Number} colIndex The column index
55880 * @param {Number} rowIndex The row index - this is nto actually used..?
55881 * @return {Boolean}
55883 isCellEditable : function(colIndex, rowIndex){
55884 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55888 * Returns the editor defined for the cell/column.
55889 * return false or null to disable editing.
55890 * @param {Number} colIndex The column index
55891 * @param {Number} rowIndex The row index
55894 getCellEditor : function(colIndex, rowIndex){
55895 return this.config[colIndex].editor;
55899 * Sets if a column is editable.
55900 * @param {Number} col The column index
55901 * @param {Boolean} editable True if the column is editable
55903 setEditable : function(col, editable){
55904 this.config[col].editable = editable;
55909 * Returns true if the column is hidden.
55910 * @param {Number} colIndex The column index
55911 * @return {Boolean}
55913 isHidden : function(colIndex){
55914 return this.config[colIndex].hidden;
55919 * Returns true if the column width cannot be changed
55921 isFixed : function(colIndex){
55922 return this.config[colIndex].fixed;
55926 * Returns true if the column can be resized
55927 * @return {Boolean}
55929 isResizable : function(colIndex){
55930 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55933 * Sets if a column is hidden.
55934 * @param {Number} colIndex The column index
55935 * @param {Boolean} hidden True if the column is hidden
55937 setHidden : function(colIndex, hidden){
55938 this.config[colIndex].hidden = hidden;
55939 this.totalWidth = null;
55940 this.fireEvent("hiddenchange", this, colIndex, hidden);
55944 * Sets the editor for a column.
55945 * @param {Number} col The column index
55946 * @param {Object} editor The editor object
55948 setEditor : function(col, editor){
55949 this.config[col].editor = editor;
55953 Roo.grid.ColumnModel.defaultRenderer = function(value){
55954 if(typeof value == "string" && value.length < 1){
55960 // Alias for backwards compatibility
55961 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55964 * Ext JS Library 1.1.1
55965 * Copyright(c) 2006-2007, Ext JS, LLC.
55967 * Originally Released Under LGPL - original licence link has changed is not relivant.
55970 * <script type="text/javascript">
55974 * @class Roo.grid.AbstractSelectionModel
55975 * @extends Roo.util.Observable
55976 * Abstract base class for grid SelectionModels. It provides the interface that should be
55977 * implemented by descendant classes. This class should not be directly instantiated.
55980 Roo.grid.AbstractSelectionModel = function(){
55981 this.locked = false;
55982 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55985 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55986 /** @ignore Called by the grid automatically. Do not call directly. */
55987 init : function(grid){
55993 * Locks the selections.
55996 this.locked = true;
56000 * Unlocks the selections.
56002 unlock : function(){
56003 this.locked = false;
56007 * Returns true if the selections are locked.
56008 * @return {Boolean}
56010 isLocked : function(){
56011 return this.locked;
56015 * Ext JS Library 1.1.1
56016 * Copyright(c) 2006-2007, Ext JS, LLC.
56018 * Originally Released Under LGPL - original licence link has changed is not relivant.
56021 * <script type="text/javascript">
56024 * @extends Roo.grid.AbstractSelectionModel
56025 * @class Roo.grid.RowSelectionModel
56026 * The default SelectionModel used by {@link Roo.grid.Grid}.
56027 * It supports multiple selections and keyboard selection/navigation.
56029 * @param {Object} config
56031 Roo.grid.RowSelectionModel = function(config){
56032 Roo.apply(this, config);
56033 this.selections = new Roo.util.MixedCollection(false, function(o){
56038 this.lastActive = false;
56042 * @event selectionchange
56043 * Fires when the selection changes
56044 * @param {SelectionModel} this
56046 "selectionchange" : true,
56048 * @event afterselectionchange
56049 * Fires after the selection changes (eg. by key press or clicking)
56050 * @param {SelectionModel} this
56052 "afterselectionchange" : true,
56054 * @event beforerowselect
56055 * Fires when a row is selected being selected, return false to cancel.
56056 * @param {SelectionModel} this
56057 * @param {Number} rowIndex The selected index
56058 * @param {Boolean} keepExisting False if other selections will be cleared
56060 "beforerowselect" : true,
56063 * Fires when a row is selected.
56064 * @param {SelectionModel} this
56065 * @param {Number} rowIndex The selected index
56066 * @param {Roo.data.Record} r The record
56068 "rowselect" : true,
56070 * @event rowdeselect
56071 * Fires when a row is deselected.
56072 * @param {SelectionModel} this
56073 * @param {Number} rowIndex The selected index
56075 "rowdeselect" : true
56077 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
56078 this.locked = false;
56081 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
56083 * @cfg {Boolean} singleSelect
56084 * True to allow selection of only one row at a time (defaults to false)
56086 singleSelect : false,
56089 initEvents : function(){
56091 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
56092 this.grid.on("mousedown", this.handleMouseDown, this);
56093 }else{ // allow click to work like normal
56094 this.grid.on("rowclick", this.handleDragableRowClick, this);
56097 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
56098 "up" : function(e){
56100 this.selectPrevious(e.shiftKey);
56101 }else if(this.last !== false && this.lastActive !== false){
56102 var last = this.last;
56103 this.selectRange(this.last, this.lastActive-1);
56104 this.grid.getView().focusRow(this.lastActive);
56105 if(last !== false){
56109 this.selectFirstRow();
56111 this.fireEvent("afterselectionchange", this);
56113 "down" : function(e){
56115 this.selectNext(e.shiftKey);
56116 }else if(this.last !== false && this.lastActive !== false){
56117 var last = this.last;
56118 this.selectRange(this.last, this.lastActive+1);
56119 this.grid.getView().focusRow(this.lastActive);
56120 if(last !== false){
56124 this.selectFirstRow();
56126 this.fireEvent("afterselectionchange", this);
56131 var view = this.grid.view;
56132 view.on("refresh", this.onRefresh, this);
56133 view.on("rowupdated", this.onRowUpdated, this);
56134 view.on("rowremoved", this.onRemove, this);
56138 onRefresh : function(){
56139 var ds = this.grid.dataSource, i, v = this.grid.view;
56140 var s = this.selections;
56141 s.each(function(r){
56142 if((i = ds.indexOfId(r.id)) != -1){
56144 s.add(ds.getAt(i)); // updating the selection relate data
56152 onRemove : function(v, index, r){
56153 this.selections.remove(r);
56157 onRowUpdated : function(v, index, r){
56158 if(this.isSelected(r)){
56159 v.onRowSelect(index);
56165 * @param {Array} records The records to select
56166 * @param {Boolean} keepExisting (optional) True to keep existing selections
56168 selectRecords : function(records, keepExisting){
56170 this.clearSelections();
56172 var ds = this.grid.dataSource;
56173 for(var i = 0, len = records.length; i < len; i++){
56174 this.selectRow(ds.indexOf(records[i]), true);
56179 * Gets the number of selected rows.
56182 getCount : function(){
56183 return this.selections.length;
56187 * Selects the first row in the grid.
56189 selectFirstRow : function(){
56194 * Select the last row.
56195 * @param {Boolean} keepExisting (optional) True to keep existing selections
56197 selectLastRow : function(keepExisting){
56198 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
56202 * Selects the row immediately following the last selected row.
56203 * @param {Boolean} keepExisting (optional) True to keep existing selections
56205 selectNext : function(keepExisting){
56206 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
56207 this.selectRow(this.last+1, keepExisting);
56208 this.grid.getView().focusRow(this.last);
56213 * Selects the row that precedes the last selected row.
56214 * @param {Boolean} keepExisting (optional) True to keep existing selections
56216 selectPrevious : function(keepExisting){
56218 this.selectRow(this.last-1, keepExisting);
56219 this.grid.getView().focusRow(this.last);
56224 * Returns the selected records
56225 * @return {Array} Array of selected records
56227 getSelections : function(){
56228 return [].concat(this.selections.items);
56232 * Returns the first selected record.
56235 getSelected : function(){
56236 return this.selections.itemAt(0);
56241 * Clears all selections.
56243 clearSelections : function(fast){
56248 var ds = this.grid.dataSource;
56249 var s = this.selections;
56250 s.each(function(r){
56251 this.deselectRow(ds.indexOfId(r.id));
56255 this.selections.clear();
56262 * Selects all rows.
56264 selectAll : function(){
56268 this.selections.clear();
56269 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
56270 this.selectRow(i, true);
56275 * Returns True if there is a selection.
56276 * @return {Boolean}
56278 hasSelection : function(){
56279 return this.selections.length > 0;
56283 * Returns True if the specified row is selected.
56284 * @param {Number/Record} record The record or index of the record to check
56285 * @return {Boolean}
56287 isSelected : function(index){
56288 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
56289 return (r && this.selections.key(r.id) ? true : false);
56293 * Returns True if the specified record id is selected.
56294 * @param {String} id The id of record to check
56295 * @return {Boolean}
56297 isIdSelected : function(id){
56298 return (this.selections.key(id) ? true : false);
56302 handleMouseDown : function(e, t){
56303 var view = this.grid.getView(), rowIndex;
56304 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
56307 if(e.shiftKey && this.last !== false){
56308 var last = this.last;
56309 this.selectRange(last, rowIndex, e.ctrlKey);
56310 this.last = last; // reset the last
56311 view.focusRow(rowIndex);
56313 var isSelected = this.isSelected(rowIndex);
56314 if(e.button !== 0 && isSelected){
56315 view.focusRow(rowIndex);
56316 }else if(e.ctrlKey && isSelected){
56317 this.deselectRow(rowIndex);
56318 }else if(!isSelected){
56319 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
56320 view.focusRow(rowIndex);
56323 this.fireEvent("afterselectionchange", this);
56326 handleDragableRowClick : function(grid, rowIndex, e)
56328 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
56329 this.selectRow(rowIndex, false);
56330 grid.view.focusRow(rowIndex);
56331 this.fireEvent("afterselectionchange", this);
56336 * Selects multiple rows.
56337 * @param {Array} rows Array of the indexes of the row to select
56338 * @param {Boolean} keepExisting (optional) True to keep existing selections
56340 selectRows : function(rows, keepExisting){
56342 this.clearSelections();
56344 for(var i = 0, len = rows.length; i < len; i++){
56345 this.selectRow(rows[i], true);
56350 * Selects a range of rows. All rows in between startRow and endRow are also selected.
56351 * @param {Number} startRow The index of the first row in the range
56352 * @param {Number} endRow The index of the last row in the range
56353 * @param {Boolean} keepExisting (optional) True to retain existing selections
56355 selectRange : function(startRow, endRow, keepExisting){
56360 this.clearSelections();
56362 if(startRow <= endRow){
56363 for(var i = startRow; i <= endRow; i++){
56364 this.selectRow(i, true);
56367 for(var i = startRow; i >= endRow; i--){
56368 this.selectRow(i, true);
56374 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
56375 * @param {Number} startRow The index of the first row in the range
56376 * @param {Number} endRow The index of the last row in the range
56378 deselectRange : function(startRow, endRow, preventViewNotify){
56382 for(var i = startRow; i <= endRow; i++){
56383 this.deselectRow(i, preventViewNotify);
56389 * @param {Number} row The index of the row to select
56390 * @param {Boolean} keepExisting (optional) True to keep existing selections
56392 selectRow : function(index, keepExisting, preventViewNotify){
56393 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
56396 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
56397 if(!keepExisting || this.singleSelect){
56398 this.clearSelections();
56400 var r = this.grid.dataSource.getAt(index);
56401 this.selections.add(r);
56402 this.last = this.lastActive = index;
56403 if(!preventViewNotify){
56404 this.grid.getView().onRowSelect(index);
56406 this.fireEvent("rowselect", this, index, r);
56407 this.fireEvent("selectionchange", this);
56413 * @param {Number} row The index of the row to deselect
56415 deselectRow : function(index, preventViewNotify){
56419 if(this.last == index){
56422 if(this.lastActive == index){
56423 this.lastActive = false;
56425 var r = this.grid.dataSource.getAt(index);
56426 this.selections.remove(r);
56427 if(!preventViewNotify){
56428 this.grid.getView().onRowDeselect(index);
56430 this.fireEvent("rowdeselect", this, index);
56431 this.fireEvent("selectionchange", this);
56435 restoreLast : function(){
56437 this.last = this._last;
56442 acceptsNav : function(row, col, cm){
56443 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56447 onEditorKey : function(field, e){
56448 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
56453 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56455 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56457 }else if(k == e.ENTER && !e.ctrlKey){
56461 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
56463 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
56465 }else if(k == e.ESC){
56469 g.startEditing(newCell[0], newCell[1]);
56474 * Ext JS Library 1.1.1
56475 * Copyright(c) 2006-2007, Ext JS, LLC.
56477 * Originally Released Under LGPL - original licence link has changed is not relivant.
56480 * <script type="text/javascript">
56483 * @class Roo.grid.CellSelectionModel
56484 * @extends Roo.grid.AbstractSelectionModel
56485 * This class provides the basic implementation for cell selection in a grid.
56487 * @param {Object} config The object containing the configuration of this model.
56488 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
56490 Roo.grid.CellSelectionModel = function(config){
56491 Roo.apply(this, config);
56493 this.selection = null;
56497 * @event beforerowselect
56498 * Fires before a cell is selected.
56499 * @param {SelectionModel} this
56500 * @param {Number} rowIndex The selected row index
56501 * @param {Number} colIndex The selected cell index
56503 "beforecellselect" : true,
56505 * @event cellselect
56506 * Fires when a cell is selected.
56507 * @param {SelectionModel} this
56508 * @param {Number} rowIndex The selected row index
56509 * @param {Number} colIndex The selected cell index
56511 "cellselect" : true,
56513 * @event selectionchange
56514 * Fires when the active selection changes.
56515 * @param {SelectionModel} this
56516 * @param {Object} selection null for no selection or an object (o) with two properties
56518 <li>o.record: the record object for the row the selection is in</li>
56519 <li>o.cell: An array of [rowIndex, columnIndex]</li>
56522 "selectionchange" : true,
56525 * Fires when the tab (or enter) was pressed on the last editable cell
56526 * You can use this to trigger add new row.
56527 * @param {SelectionModel} this
56531 * @event beforeeditnext
56532 * Fires before the next editable sell is made active
56533 * You can use this to skip to another cell or fire the tabend
56534 * if you set cell to false
56535 * @param {Object} eventdata object : { cell : [ row, col ] }
56537 "beforeeditnext" : true
56539 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
56542 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
56544 enter_is_tab: false,
56547 initEvents : function(){
56548 this.grid.on("mousedown", this.handleMouseDown, this);
56549 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
56550 var view = this.grid.view;
56551 view.on("refresh", this.onViewChange, this);
56552 view.on("rowupdated", this.onRowUpdated, this);
56553 view.on("beforerowremoved", this.clearSelections, this);
56554 view.on("beforerowsinserted", this.clearSelections, this);
56555 if(this.grid.isEditor){
56556 this.grid.on("beforeedit", this.beforeEdit, this);
56561 beforeEdit : function(e){
56562 this.select(e.row, e.column, false, true, e.record);
56566 onRowUpdated : function(v, index, r){
56567 if(this.selection && this.selection.record == r){
56568 v.onCellSelect(index, this.selection.cell[1]);
56573 onViewChange : function(){
56574 this.clearSelections(true);
56578 * Returns the currently selected cell,.
56579 * @return {Array} The selected cell (row, column) or null if none selected.
56581 getSelectedCell : function(){
56582 return this.selection ? this.selection.cell : null;
56586 * Clears all selections.
56587 * @param {Boolean} true to prevent the gridview from being notified about the change.
56589 clearSelections : function(preventNotify){
56590 var s = this.selection;
56592 if(preventNotify !== true){
56593 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
56595 this.selection = null;
56596 this.fireEvent("selectionchange", this, null);
56601 * Returns true if there is a selection.
56602 * @return {Boolean}
56604 hasSelection : function(){
56605 return this.selection ? true : false;
56609 handleMouseDown : function(e, t){
56610 var v = this.grid.getView();
56611 if(this.isLocked()){
56614 var row = v.findRowIndex(t);
56615 var cell = v.findCellIndex(t);
56616 if(row !== false && cell !== false){
56617 this.select(row, cell);
56623 * @param {Number} rowIndex
56624 * @param {Number} collIndex
56626 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
56627 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
56628 this.clearSelections();
56629 r = r || this.grid.dataSource.getAt(rowIndex);
56632 cell : [rowIndex, colIndex]
56634 if(!preventViewNotify){
56635 var v = this.grid.getView();
56636 v.onCellSelect(rowIndex, colIndex);
56637 if(preventFocus !== true){
56638 v.focusCell(rowIndex, colIndex);
56641 this.fireEvent("cellselect", this, rowIndex, colIndex);
56642 this.fireEvent("selectionchange", this, this.selection);
56647 isSelectable : function(rowIndex, colIndex, cm){
56648 return !cm.isHidden(colIndex);
56652 handleKeyDown : function(e){
56653 //Roo.log('Cell Sel Model handleKeyDown');
56654 if(!e.isNavKeyPress()){
56657 var g = this.grid, s = this.selection;
56660 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
56662 this.select(cell[0], cell[1]);
56667 var walk = function(row, col, step){
56668 return g.walkCells(row, col, step, sm.isSelectable, sm);
56670 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
56677 // handled by onEditorKey
56678 if (g.isEditor && g.editing) {
56682 newCell = walk(r, c-1, -1);
56684 newCell = walk(r, c+1, 1);
56689 newCell = walk(r+1, c, 1);
56693 newCell = walk(r-1, c, -1);
56697 newCell = walk(r, c+1, 1);
56701 newCell = walk(r, c-1, -1);
56706 if(g.isEditor && !g.editing){
56707 g.startEditing(r, c);
56716 this.select(newCell[0], newCell[1]);
56722 acceptsNav : function(row, col, cm){
56723 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56727 * @param {Number} field (not used) - as it's normally used as a listener
56728 * @param {Number} e - event - fake it by using
56730 * var e = Roo.EventObjectImpl.prototype;
56731 * e.keyCode = e.TAB
56735 onEditorKey : function(field, e){
56737 var k = e.getKey(),
56740 ed = g.activeEditor,
56742 ///Roo.log('onEditorKey' + k);
56745 if (this.enter_is_tab && k == e.ENTER) {
56751 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56753 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56759 } else if(k == e.ENTER && !e.ctrlKey){
56762 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56764 } else if(k == e.ESC){
56769 var ecall = { cell : newCell, forward : forward };
56770 this.fireEvent('beforeeditnext', ecall );
56771 newCell = ecall.cell;
56772 forward = ecall.forward;
56776 //Roo.log('next cell after edit');
56777 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
56778 } else if (forward) {
56779 // tabbed past last
56780 this.fireEvent.defer(100, this, ['tabend',this]);
56785 * Ext JS Library 1.1.1
56786 * Copyright(c) 2006-2007, Ext JS, LLC.
56788 * Originally Released Under LGPL - original licence link has changed is not relivant.
56791 * <script type="text/javascript">
56795 * @class Roo.grid.EditorGrid
56796 * @extends Roo.grid.Grid
56797 * Class for creating and editable grid.
56798 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56799 * The container MUST have some type of size defined for the grid to fill. The container will be
56800 * automatically set to position relative if it isn't already.
56801 * @param {Object} dataSource The data model to bind to
56802 * @param {Object} colModel The column model with info about this grid's columns
56804 Roo.grid.EditorGrid = function(container, config){
56805 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
56806 this.getGridEl().addClass("xedit-grid");
56808 if(!this.selModel){
56809 this.selModel = new Roo.grid.CellSelectionModel();
56812 this.activeEditor = null;
56816 * @event beforeedit
56817 * Fires before cell editing is triggered. The edit event object has the following properties <br />
56818 * <ul style="padding:5px;padding-left:16px;">
56819 * <li>grid - This grid</li>
56820 * <li>record - The record being edited</li>
56821 * <li>field - The field name being edited</li>
56822 * <li>value - The value for the field being edited.</li>
56823 * <li>row - The grid row index</li>
56824 * <li>column - The grid column index</li>
56825 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56827 * @param {Object} e An edit event (see above for description)
56829 "beforeedit" : true,
56832 * Fires after a cell is edited. <br />
56833 * <ul style="padding:5px;padding-left:16px;">
56834 * <li>grid - This grid</li>
56835 * <li>record - The record being edited</li>
56836 * <li>field - The field name being edited</li>
56837 * <li>value - The value being set</li>
56838 * <li>originalValue - The original value for the field, before the edit.</li>
56839 * <li>row - The grid row index</li>
56840 * <li>column - The grid column index</li>
56842 * @param {Object} e An edit event (see above for description)
56844 "afteredit" : true,
56846 * @event validateedit
56847 * Fires after a cell is edited, but before the value is set in the record.
56848 * You can use this to modify the value being set in the field, Return false
56849 * to cancel the change. The edit event object has the following properties <br />
56850 * <ul style="padding:5px;padding-left:16px;">
56851 * <li>editor - This editor</li>
56852 * <li>grid - This grid</li>
56853 * <li>record - The record being edited</li>
56854 * <li>field - The field name being edited</li>
56855 * <li>value - The value being set</li>
56856 * <li>originalValue - The original value for the field, before the edit.</li>
56857 * <li>row - The grid row index</li>
56858 * <li>column - The grid column index</li>
56859 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56861 * @param {Object} e An edit event (see above for description)
56863 "validateedit" : true
56865 this.on("bodyscroll", this.stopEditing, this);
56866 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56869 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56871 * @cfg {Number} clicksToEdit
56872 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56879 trackMouseOver: false, // causes very odd FF errors
56881 onCellDblClick : function(g, row, col){
56882 this.startEditing(row, col);
56885 onEditComplete : function(ed, value, startValue){
56886 this.editing = false;
56887 this.activeEditor = null;
56888 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56890 var field = this.colModel.getDataIndex(ed.col);
56895 originalValue: startValue,
56902 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
56905 if(String(value) !== String(startValue)){
56907 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56908 r.set(field, e.value);
56909 // if we are dealing with a combo box..
56910 // then we also set the 'name' colum to be the displayField
56911 if (ed.field.displayField && ed.field.name) {
56912 r.set(ed.field.name, ed.field.el.dom.value);
56915 delete e.cancel; //?? why!!!
56916 this.fireEvent("afteredit", e);
56919 this.fireEvent("afteredit", e); // always fire it!
56921 this.view.focusCell(ed.row, ed.col);
56925 * Starts editing the specified for the specified row/column
56926 * @param {Number} rowIndex
56927 * @param {Number} colIndex
56929 startEditing : function(row, col){
56930 this.stopEditing();
56931 if(this.colModel.isCellEditable(col, row)){
56932 this.view.ensureVisible(row, col, true);
56934 var r = this.dataSource.getAt(row);
56935 var field = this.colModel.getDataIndex(col);
56936 var cell = Roo.get(this.view.getCell(row,col));
56941 value: r.data[field],
56946 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56947 this.editing = true;
56948 var ed = this.colModel.getCellEditor(col, row);
56954 ed.render(ed.parentEl || document.body);
56960 (function(){ // complex but required for focus issues in safari, ie and opera
56964 ed.on("complete", this.onEditComplete, this, {single: true});
56965 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56966 this.activeEditor = ed;
56967 var v = r.data[field];
56968 ed.startEdit(this.view.getCell(row, col), v);
56969 // combo's with 'displayField and name set
56970 if (ed.field.displayField && ed.field.name) {
56971 ed.field.el.dom.value = r.data[ed.field.name];
56975 }).defer(50, this);
56981 * Stops any active editing
56983 stopEditing : function(){
56984 if(this.activeEditor){
56985 this.activeEditor.completeEdit();
56987 this.activeEditor = null;
56991 * Called to get grid's drag proxy text, by default returns this.ddText.
56994 getDragDropText : function(){
56995 var count = this.selModel.getSelectedCell() ? 1 : 0;
56996 return String.format(this.ddText, count, count == 1 ? '' : 's');
57001 * Ext JS Library 1.1.1
57002 * Copyright(c) 2006-2007, Ext JS, LLC.
57004 * Originally Released Under LGPL - original licence link has changed is not relivant.
57007 * <script type="text/javascript">
57010 // private - not really -- you end up using it !
57011 // This is a support class used internally by the Grid components
57014 * @class Roo.grid.GridEditor
57015 * @extends Roo.Editor
57016 * Class for creating and editable grid elements.
57017 * @param {Object} config any settings (must include field)
57019 Roo.grid.GridEditor = function(field, config){
57020 if (!config && field.field) {
57022 field = Roo.factory(config.field, Roo.form);
57024 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
57025 field.monitorTab = false;
57028 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
57031 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
57034 alignment: "tl-tl",
57037 cls: "x-small-editor x-grid-editor",
57042 * Ext JS Library 1.1.1
57043 * Copyright(c) 2006-2007, Ext JS, LLC.
57045 * Originally Released Under LGPL - original licence link has changed is not relivant.
57048 * <script type="text/javascript">
57053 Roo.grid.PropertyRecord = Roo.data.Record.create([
57054 {name:'name',type:'string'}, 'value'
57058 Roo.grid.PropertyStore = function(grid, source){
57060 this.store = new Roo.data.Store({
57061 recordType : Roo.grid.PropertyRecord
57063 this.store.on('update', this.onUpdate, this);
57065 this.setSource(source);
57067 Roo.grid.PropertyStore.superclass.constructor.call(this);
57072 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
57073 setSource : function(o){
57075 this.store.removeAll();
57078 if(this.isEditableValue(o[k])){
57079 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
57082 this.store.loadRecords({records: data}, {}, true);
57085 onUpdate : function(ds, record, type){
57086 if(type == Roo.data.Record.EDIT){
57087 var v = record.data['value'];
57088 var oldValue = record.modified['value'];
57089 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
57090 this.source[record.id] = v;
57092 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
57099 getProperty : function(row){
57100 return this.store.getAt(row);
57103 isEditableValue: function(val){
57104 if(val && val instanceof Date){
57106 }else if(typeof val == 'object' || typeof val == 'function'){
57112 setValue : function(prop, value){
57113 this.source[prop] = value;
57114 this.store.getById(prop).set('value', value);
57117 getSource : function(){
57118 return this.source;
57122 Roo.grid.PropertyColumnModel = function(grid, store){
57125 g.PropertyColumnModel.superclass.constructor.call(this, [
57126 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
57127 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
57129 this.store = store;
57130 this.bselect = Roo.DomHelper.append(document.body, {
57131 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
57132 {tag: 'option', value: 'true', html: 'true'},
57133 {tag: 'option', value: 'false', html: 'false'}
57136 Roo.id(this.bselect);
57139 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
57140 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
57141 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
57142 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
57143 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
57145 this.renderCellDelegate = this.renderCell.createDelegate(this);
57146 this.renderPropDelegate = this.renderProp.createDelegate(this);
57149 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
57153 valueText : 'Value',
57155 dateFormat : 'm/j/Y',
57158 renderDate : function(dateVal){
57159 return dateVal.dateFormat(this.dateFormat);
57162 renderBool : function(bVal){
57163 return bVal ? 'true' : 'false';
57166 isCellEditable : function(colIndex, rowIndex){
57167 return colIndex == 1;
57170 getRenderer : function(col){
57172 this.renderCellDelegate : this.renderPropDelegate;
57175 renderProp : function(v){
57176 return this.getPropertyName(v);
57179 renderCell : function(val){
57181 if(val instanceof Date){
57182 rv = this.renderDate(val);
57183 }else if(typeof val == 'boolean'){
57184 rv = this.renderBool(val);
57186 return Roo.util.Format.htmlEncode(rv);
57189 getPropertyName : function(name){
57190 var pn = this.grid.propertyNames;
57191 return pn && pn[name] ? pn[name] : name;
57194 getCellEditor : function(colIndex, rowIndex){
57195 var p = this.store.getProperty(rowIndex);
57196 var n = p.data['name'], val = p.data['value'];
57198 if(typeof(this.grid.customEditors[n]) == 'string'){
57199 return this.editors[this.grid.customEditors[n]];
57201 if(typeof(this.grid.customEditors[n]) != 'undefined'){
57202 return this.grid.customEditors[n];
57204 if(val instanceof Date){
57205 return this.editors['date'];
57206 }else if(typeof val == 'number'){
57207 return this.editors['number'];
57208 }else if(typeof val == 'boolean'){
57209 return this.editors['boolean'];
57211 return this.editors['string'];
57217 * @class Roo.grid.PropertyGrid
57218 * @extends Roo.grid.EditorGrid
57219 * This class represents the interface of a component based property grid control.
57220 * <br><br>Usage:<pre><code>
57221 var grid = new Roo.grid.PropertyGrid("my-container-id", {
57229 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57230 * The container MUST have some type of size defined for the grid to fill. The container will be
57231 * automatically set to position relative if it isn't already.
57232 * @param {Object} config A config object that sets properties on this grid.
57234 Roo.grid.PropertyGrid = function(container, config){
57235 config = config || {};
57236 var store = new Roo.grid.PropertyStore(this);
57237 this.store = store;
57238 var cm = new Roo.grid.PropertyColumnModel(this, store);
57239 store.store.sort('name', 'ASC');
57240 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
57243 enableColLock:false,
57244 enableColumnMove:false,
57246 trackMouseOver: false,
57249 this.getGridEl().addClass('x-props-grid');
57250 this.lastEditRow = null;
57251 this.on('columnresize', this.onColumnResize, this);
57254 * @event beforepropertychange
57255 * Fires before a property changes (return false to stop?)
57256 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57257 * @param {String} id Record Id
57258 * @param {String} newval New Value
57259 * @param {String} oldval Old Value
57261 "beforepropertychange": true,
57263 * @event propertychange
57264 * Fires after a property changes
57265 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57266 * @param {String} id Record Id
57267 * @param {String} newval New Value
57268 * @param {String} oldval Old Value
57270 "propertychange": true
57272 this.customEditors = this.customEditors || {};
57274 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
57277 * @cfg {Object} customEditors map of colnames=> custom editors.
57278 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
57279 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
57280 * false disables editing of the field.
57284 * @cfg {Object} propertyNames map of property Names to their displayed value
57287 render : function(){
57288 Roo.grid.PropertyGrid.superclass.render.call(this);
57289 this.autoSize.defer(100, this);
57292 autoSize : function(){
57293 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
57295 this.view.fitColumns();
57299 onColumnResize : function(){
57300 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
57304 * Sets the data for the Grid
57305 * accepts a Key => Value object of all the elements avaiable.
57306 * @param {Object} data to appear in grid.
57308 setSource : function(source){
57309 this.store.setSource(source);
57313 * Gets all the data from the grid.
57314 * @return {Object} data data stored in grid
57316 getSource : function(){
57317 return this.store.getSource();
57326 * @class Roo.grid.Calendar
57327 * @extends Roo.util.Grid
57328 * This class extends the Grid to provide a calendar widget
57329 * <br><br>Usage:<pre><code>
57330 var grid = new Roo.grid.Calendar("my-container-id", {
57333 selModel: mySelectionModel,
57334 autoSizeColumns: true,
57335 monitorWindowResize: false,
57336 trackMouseOver: true
57337 eventstore : real data store..
57343 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57344 * The container MUST have some type of size defined for the grid to fill. The container will be
57345 * automatically set to position relative if it isn't already.
57346 * @param {Object} config A config object that sets properties on this grid.
57348 Roo.grid.Calendar = function(container, config){
57349 // initialize the container
57350 this.container = Roo.get(container);
57351 this.container.update("");
57352 this.container.setStyle("overflow", "hidden");
57353 this.container.addClass('x-grid-container');
57355 this.id = this.container.id;
57357 Roo.apply(this, config);
57358 // check and correct shorthanded configs
57362 for (var r = 0;r < 6;r++) {
57365 for (var c =0;c < 7;c++) {
57369 if (this.eventStore) {
57370 this.eventStore= Roo.factory(this.eventStore, Roo.data);
57371 this.eventStore.on('load',this.onLoad, this);
57372 this.eventStore.on('beforeload',this.clearEvents, this);
57376 this.dataSource = new Roo.data.Store({
57377 proxy: new Roo.data.MemoryProxy(rows),
57378 reader: new Roo.data.ArrayReader({}, [
57379 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
57382 this.dataSource.load();
57383 this.ds = this.dataSource;
57384 this.ds.xmodule = this.xmodule || false;
57387 var cellRender = function(v,x,r)
57389 return String.format(
57390 '<div class="fc-day fc-widget-content"><div>' +
57391 '<div class="fc-event-container"></div>' +
57392 '<div class="fc-day-number">{0}</div>'+
57394 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
57395 '</div></div>', v);
57400 this.colModel = new Roo.grid.ColumnModel( [
57402 xtype: 'ColumnModel',
57404 dataIndex : 'weekday0',
57406 renderer : cellRender
57409 xtype: 'ColumnModel',
57411 dataIndex : 'weekday1',
57413 renderer : cellRender
57416 xtype: 'ColumnModel',
57418 dataIndex : 'weekday2',
57419 header : 'Tuesday',
57420 renderer : cellRender
57423 xtype: 'ColumnModel',
57425 dataIndex : 'weekday3',
57426 header : 'Wednesday',
57427 renderer : cellRender
57430 xtype: 'ColumnModel',
57432 dataIndex : 'weekday4',
57433 header : 'Thursday',
57434 renderer : cellRender
57437 xtype: 'ColumnModel',
57439 dataIndex : 'weekday5',
57441 renderer : cellRender
57444 xtype: 'ColumnModel',
57446 dataIndex : 'weekday6',
57447 header : 'Saturday',
57448 renderer : cellRender
57451 this.cm = this.colModel;
57452 this.cm.xmodule = this.xmodule || false;
57456 //this.selModel = new Roo.grid.CellSelectionModel();
57457 //this.sm = this.selModel;
57458 //this.selModel.init(this);
57462 this.container.setWidth(this.width);
57466 this.container.setHeight(this.height);
57473 * The raw click event for the entire grid.
57474 * @param {Roo.EventObject} e
57479 * The raw dblclick event for the entire grid.
57480 * @param {Roo.EventObject} e
57484 * @event contextmenu
57485 * The raw contextmenu event for the entire grid.
57486 * @param {Roo.EventObject} e
57488 "contextmenu" : true,
57491 * The raw mousedown event for the entire grid.
57492 * @param {Roo.EventObject} e
57494 "mousedown" : true,
57497 * The raw mouseup event for the entire grid.
57498 * @param {Roo.EventObject} e
57503 * The raw mouseover event for the entire grid.
57504 * @param {Roo.EventObject} e
57506 "mouseover" : true,
57509 * The raw mouseout event for the entire grid.
57510 * @param {Roo.EventObject} e
57515 * The raw keypress event for the entire grid.
57516 * @param {Roo.EventObject} e
57521 * The raw keydown event for the entire grid.
57522 * @param {Roo.EventObject} e
57530 * Fires when a cell is clicked
57531 * @param {Grid} this
57532 * @param {Number} rowIndex
57533 * @param {Number} columnIndex
57534 * @param {Roo.EventObject} e
57536 "cellclick" : true,
57538 * @event celldblclick
57539 * Fires when a cell is double clicked
57540 * @param {Grid} this
57541 * @param {Number} rowIndex
57542 * @param {Number} columnIndex
57543 * @param {Roo.EventObject} e
57545 "celldblclick" : true,
57548 * Fires when a row is clicked
57549 * @param {Grid} this
57550 * @param {Number} rowIndex
57551 * @param {Roo.EventObject} e
57555 * @event rowdblclick
57556 * Fires when a row is double clicked
57557 * @param {Grid} this
57558 * @param {Number} rowIndex
57559 * @param {Roo.EventObject} e
57561 "rowdblclick" : true,
57563 * @event headerclick
57564 * Fires when a header is clicked
57565 * @param {Grid} this
57566 * @param {Number} columnIndex
57567 * @param {Roo.EventObject} e
57569 "headerclick" : true,
57571 * @event headerdblclick
57572 * Fires when a header cell is double clicked
57573 * @param {Grid} this
57574 * @param {Number} columnIndex
57575 * @param {Roo.EventObject} e
57577 "headerdblclick" : true,
57579 * @event rowcontextmenu
57580 * Fires when a row is right clicked
57581 * @param {Grid} this
57582 * @param {Number} rowIndex
57583 * @param {Roo.EventObject} e
57585 "rowcontextmenu" : true,
57587 * @event cellcontextmenu
57588 * Fires when a cell is right clicked
57589 * @param {Grid} this
57590 * @param {Number} rowIndex
57591 * @param {Number} cellIndex
57592 * @param {Roo.EventObject} e
57594 "cellcontextmenu" : true,
57596 * @event headercontextmenu
57597 * Fires when a header is right clicked
57598 * @param {Grid} this
57599 * @param {Number} columnIndex
57600 * @param {Roo.EventObject} e
57602 "headercontextmenu" : true,
57604 * @event bodyscroll
57605 * Fires when the body element is scrolled
57606 * @param {Number} scrollLeft
57607 * @param {Number} scrollTop
57609 "bodyscroll" : true,
57611 * @event columnresize
57612 * Fires when the user resizes a column
57613 * @param {Number} columnIndex
57614 * @param {Number} newSize
57616 "columnresize" : true,
57618 * @event columnmove
57619 * Fires when the user moves a column
57620 * @param {Number} oldIndex
57621 * @param {Number} newIndex
57623 "columnmove" : true,
57626 * Fires when row(s) start being dragged
57627 * @param {Grid} this
57628 * @param {Roo.GridDD} dd The drag drop object
57629 * @param {event} e The raw browser event
57631 "startdrag" : true,
57634 * Fires when a drag operation is complete
57635 * @param {Grid} this
57636 * @param {Roo.GridDD} dd The drag drop object
57637 * @param {event} e The raw browser event
57642 * Fires when dragged row(s) are dropped on a valid DD target
57643 * @param {Grid} this
57644 * @param {Roo.GridDD} dd The drag drop object
57645 * @param {String} targetId The target drag drop object
57646 * @param {event} e The raw browser event
57651 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
57652 * @param {Grid} this
57653 * @param {Roo.GridDD} dd The drag drop object
57654 * @param {String} targetId The target drag drop object
57655 * @param {event} e The raw browser event
57660 * Fires when the dragged row(s) first cross another DD target while being dragged
57661 * @param {Grid} this
57662 * @param {Roo.GridDD} dd The drag drop object
57663 * @param {String} targetId The target drag drop object
57664 * @param {event} e The raw browser event
57666 "dragenter" : true,
57669 * Fires when the dragged row(s) leave another DD target while being dragged
57670 * @param {Grid} this
57671 * @param {Roo.GridDD} dd The drag drop object
57672 * @param {String} targetId The target drag drop object
57673 * @param {event} e The raw browser event
57678 * Fires when a row is rendered, so you can change add a style to it.
57679 * @param {GridView} gridview The grid view
57680 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
57686 * Fires when the grid is rendered
57687 * @param {Grid} grid
57692 * Fires when a date is selected
57693 * @param {DatePicker} this
57694 * @param {Date} date The selected date
57698 * @event monthchange
57699 * Fires when the displayed month changes
57700 * @param {DatePicker} this
57701 * @param {Date} date The selected month
57703 'monthchange': true,
57705 * @event evententer
57706 * Fires when mouse over an event
57707 * @param {Calendar} this
57708 * @param {event} Event
57710 'evententer': true,
57712 * @event eventleave
57713 * Fires when the mouse leaves an
57714 * @param {Calendar} this
57717 'eventleave': true,
57719 * @event eventclick
57720 * Fires when the mouse click an
57721 * @param {Calendar} this
57724 'eventclick': true,
57726 * @event eventrender
57727 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
57728 * @param {Calendar} this
57729 * @param {data} data to be modified
57731 'eventrender': true
57735 Roo.grid.Grid.superclass.constructor.call(this);
57736 this.on('render', function() {
57737 this.view.el.addClass('x-grid-cal');
57739 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
57743 if (!Roo.grid.Calendar.style) {
57744 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
57747 '.x-grid-cal .x-grid-col' : {
57748 height: 'auto !important',
57749 'vertical-align': 'top'
57751 '.x-grid-cal .fc-event-hori' : {
57762 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
57764 * @cfg {Store} eventStore The store that loads events.
57769 activeDate : false,
57772 monitorWindowResize : false,
57775 resizeColumns : function() {
57776 var col = (this.view.el.getWidth() / 7) - 3;
57777 // loop through cols, and setWidth
57778 for(var i =0 ; i < 7 ; i++){
57779 this.cm.setColumnWidth(i, col);
57782 setDate :function(date) {
57784 Roo.log('setDate?');
57786 this.resizeColumns();
57787 var vd = this.activeDate;
57788 this.activeDate = date;
57789 // if(vd && this.el){
57790 // var t = date.getTime();
57791 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
57792 // Roo.log('using add remove');
57794 // this.fireEvent('monthchange', this, date);
57796 // this.cells.removeClass("fc-state-highlight");
57797 // this.cells.each(function(c){
57798 // if(c.dateValue == t){
57799 // c.addClass("fc-state-highlight");
57800 // setTimeout(function(){
57801 // try{c.dom.firstChild.focus();}catch(e){}
57811 var days = date.getDaysInMonth();
57813 var firstOfMonth = date.getFirstDateOfMonth();
57814 var startingPos = firstOfMonth.getDay()-this.startDay;
57816 if(startingPos < this.startDay){
57820 var pm = date.add(Date.MONTH, -1);
57821 var prevStart = pm.getDaysInMonth()-startingPos;
57825 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57827 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57828 //this.cells.addClassOnOver('fc-state-hover');
57830 var cells = this.cells.elements;
57831 var textEls = this.textNodes;
57833 //Roo.each(cells, function(cell){
57834 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57837 days += startingPos;
57839 // convert everything to numbers so it's fast
57840 var day = 86400000;
57841 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57844 //Roo.log(prevStart);
57846 var today = new Date().clearTime().getTime();
57847 var sel = date.clearTime().getTime();
57848 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57849 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57850 var ddMatch = this.disabledDatesRE;
57851 var ddText = this.disabledDatesText;
57852 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57853 var ddaysText = this.disabledDaysText;
57854 var format = this.format;
57856 var setCellClass = function(cal, cell){
57858 //Roo.log('set Cell Class');
57860 var t = d.getTime();
57865 cell.dateValue = t;
57867 cell.className += " fc-today";
57868 cell.className += " fc-state-highlight";
57869 cell.title = cal.todayText;
57872 // disable highlight in other month..
57873 cell.className += " fc-state-highlight";
57878 //cell.className = " fc-state-disabled";
57879 cell.title = cal.minText;
57883 //cell.className = " fc-state-disabled";
57884 cell.title = cal.maxText;
57888 if(ddays.indexOf(d.getDay()) != -1){
57889 // cell.title = ddaysText;
57890 // cell.className = " fc-state-disabled";
57893 if(ddMatch && format){
57894 var fvalue = d.dateFormat(format);
57895 if(ddMatch.test(fvalue)){
57896 cell.title = ddText.replace("%0", fvalue);
57897 cell.className = " fc-state-disabled";
57901 if (!cell.initialClassName) {
57902 cell.initialClassName = cell.dom.className;
57905 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57910 for(; i < startingPos; i++) {
57911 cells[i].dayName = (++prevStart);
57912 Roo.log(textEls[i]);
57913 d.setDate(d.getDate()+1);
57915 //cells[i].className = "fc-past fc-other-month";
57916 setCellClass(this, cells[i]);
57921 for(; i < days; i++){
57922 intDay = i - startingPos + 1;
57923 cells[i].dayName = (intDay);
57924 d.setDate(d.getDate()+1);
57926 cells[i].className = ''; // "x-date-active";
57927 setCellClass(this, cells[i]);
57931 for(; i < 42; i++) {
57932 //textEls[i].innerHTML = (++extraDays);
57934 d.setDate(d.getDate()+1);
57935 cells[i].dayName = (++extraDays);
57936 cells[i].className = "fc-future fc-other-month";
57937 setCellClass(this, cells[i]);
57940 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57942 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57944 // this will cause all the cells to mis
57947 for (var r = 0;r < 6;r++) {
57948 for (var c =0;c < 7;c++) {
57949 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57953 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57954 for(i=0;i<cells.length;i++) {
57956 this.cells.elements[i].dayName = cells[i].dayName ;
57957 this.cells.elements[i].className = cells[i].className;
57958 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57959 this.cells.elements[i].title = cells[i].title ;
57960 this.cells.elements[i].dateValue = cells[i].dateValue ;
57966 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57967 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57969 ////if(totalRows != 6){
57970 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57971 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57974 this.fireEvent('monthchange', this, date);
57979 * Returns the grid's SelectionModel.
57980 * @return {SelectionModel}
57982 getSelectionModel : function(){
57983 if(!this.selModel){
57984 this.selModel = new Roo.grid.CellSelectionModel();
57986 return this.selModel;
57990 this.eventStore.load()
57996 findCell : function(dt) {
57997 dt = dt.clearTime().getTime();
57999 this.cells.each(function(c){
58000 //Roo.log("check " +c.dateValue + '?=' + dt);
58001 if(c.dateValue == dt){
58011 findCells : function(rec) {
58012 var s = rec.data.start_dt.clone().clearTime().getTime();
58014 var e= rec.data.end_dt.clone().clearTime().getTime();
58017 this.cells.each(function(c){
58018 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
58020 if(c.dateValue > e){
58023 if(c.dateValue < s){
58032 findBestRow: function(cells)
58036 for (var i =0 ; i < cells.length;i++) {
58037 ret = Math.max(cells[i].rows || 0,ret);
58044 addItem : function(rec)
58046 // look for vertical location slot in
58047 var cells = this.findCells(rec);
58049 rec.row = this.findBestRow(cells);
58051 // work out the location.
58055 for(var i =0; i < cells.length; i++) {
58063 if (crow.start.getY() == cells[i].getY()) {
58065 crow.end = cells[i];
58081 for (var i = 0; i < cells.length;i++) {
58082 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
58089 clearEvents: function() {
58091 if (!this.eventStore.getCount()) {
58094 // reset number of rows in cells.
58095 Roo.each(this.cells.elements, function(c){
58099 this.eventStore.each(function(e) {
58100 this.clearEvent(e);
58105 clearEvent : function(ev)
58108 Roo.each(ev.els, function(el) {
58109 el.un('mouseenter' ,this.onEventEnter, this);
58110 el.un('mouseleave' ,this.onEventLeave, this);
58118 renderEvent : function(ev,ctr) {
58120 ctr = this.view.el.select('.fc-event-container',true).first();
58124 this.clearEvent(ev);
58130 var cells = ev.cells;
58131 var rows = ev.rows;
58132 this.fireEvent('eventrender', this, ev);
58134 for(var i =0; i < rows.length; i++) {
58138 cls += ' fc-event-start';
58140 if ((i+1) == rows.length) {
58141 cls += ' fc-event-end';
58144 //Roo.log(ev.data);
58145 // how many rows should it span..
58146 var cg = this.eventTmpl.append(ctr,Roo.apply({
58149 }, ev.data) , true);
58152 cg.on('mouseenter' ,this.onEventEnter, this, ev);
58153 cg.on('mouseleave' ,this.onEventLeave, this, ev);
58154 cg.on('click', this.onEventClick, this, ev);
58158 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
58159 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
58162 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
58163 cg.setWidth(ebox.right - sbox.x -2);
58167 renderEvents: function()
58169 // first make sure there is enough space..
58171 if (!this.eventTmpl) {
58172 this.eventTmpl = new Roo.Template(
58173 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
58174 '<div class="fc-event-inner">' +
58175 '<span class="fc-event-time">{time}</span>' +
58176 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
58178 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
58186 this.cells.each(function(c) {
58187 //Roo.log(c.select('.fc-day-content div',true).first());
58188 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
58191 var ctr = this.view.el.select('.fc-event-container',true).first();
58194 this.eventStore.each(function(ev){
58196 this.renderEvent(ev);
58200 this.view.layout();
58204 onEventEnter: function (e, el,event,d) {
58205 this.fireEvent('evententer', this, el, event);
58208 onEventLeave: function (e, el,event,d) {
58209 this.fireEvent('eventleave', this, el, event);
58212 onEventClick: function (e, el,event,d) {
58213 this.fireEvent('eventclick', this, el, event);
58216 onMonthChange: function () {
58220 onLoad: function () {
58222 //Roo.log('calendar onload');
58224 if(this.eventStore.getCount() > 0){
58228 this.eventStore.each(function(d){
58233 if (typeof(add.end_dt) == 'undefined') {
58234 Roo.log("Missing End time in calendar data: ");
58238 if (typeof(add.start_dt) == 'undefined') {
58239 Roo.log("Missing Start time in calendar data: ");
58243 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
58244 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
58245 add.id = add.id || d.id;
58246 add.title = add.title || '??';
58254 this.renderEvents();
58264 render : function ()
58268 if (!this.view.el.hasClass('course-timesheet')) {
58269 this.view.el.addClass('course-timesheet');
58271 if (this.tsStyle) {
58276 Roo.log(_this.grid.view.el.getWidth());
58279 this.tsStyle = Roo.util.CSS.createStyleSheet({
58280 '.course-timesheet .x-grid-row' : {
58283 '.x-grid-row td' : {
58284 'vertical-align' : 0
58286 '.course-edit-link' : {
58288 'text-overflow' : 'ellipsis',
58289 'overflow' : 'hidden',
58290 'white-space' : 'nowrap',
58291 'cursor' : 'pointer'
58296 '.de-act-sup-link' : {
58297 'color' : 'purple',
58298 'text-decoration' : 'line-through'
58302 'text-decoration' : 'line-through'
58304 '.course-timesheet .course-highlight' : {
58305 'border-top-style': 'dashed !important',
58306 'border-bottom-bottom': 'dashed !important'
58308 '.course-timesheet .course-item' : {
58309 'font-family' : 'tahoma, arial, helvetica',
58310 'font-size' : '11px',
58311 'overflow' : 'hidden',
58312 'padding-left' : '10px',
58313 'padding-right' : '10px',
58314 'padding-top' : '10px'
58322 monitorWindowResize : false,
58323 cellrenderer : function(v,x,r)
58328 xtype: 'CellSelectionModel',
58335 beforeload : function (_self, options)
58337 options.params = options.params || {};
58338 options.params._month = _this.monthField.getValue();
58339 options.params.limit = 9999;
58340 options.params['sort'] = 'when_dt';
58341 options.params['dir'] = 'ASC';
58342 this.proxy.loadResponse = this.loadResponse;
58344 //this.addColumns();
58346 load : function (_self, records, options)
58348 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
58349 // if you click on the translation.. you can edit it...
58350 var el = Roo.get(this);
58351 var id = el.dom.getAttribute('data-id');
58352 var d = el.dom.getAttribute('data-date');
58353 var t = el.dom.getAttribute('data-time');
58354 //var id = this.child('span').dom.textContent;
58357 Pman.Dialog.CourseCalendar.show({
58361 productitem_active : id ? 1 : 0
58363 _this.grid.ds.load({});
58368 _this.panel.fireEvent('resize', [ '', '' ]);
58371 loadResponse : function(o, success, response){
58372 // this is overridden on before load..
58374 Roo.log("our code?");
58375 //Roo.log(success);
58376 //Roo.log(response)
58377 delete this.activeRequest;
58379 this.fireEvent("loadexception", this, o, response);
58380 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58385 result = o.reader.read(response);
58387 Roo.log("load exception?");
58388 this.fireEvent("loadexception", this, o, response, e);
58389 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58392 Roo.log("ready...");
58393 // loop through result.records;
58394 // and set this.tdate[date] = [] << array of records..
58396 Roo.each(result.records, function(r){
58398 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
58399 _this.tdata[r.data.when_dt.format('j')] = [];
58401 _this.tdata[r.data.when_dt.format('j')].push(r.data);
58404 //Roo.log(_this.tdata);
58406 result.records = [];
58407 result.totalRecords = 6;
58409 // let's generate some duumy records for the rows.
58410 //var st = _this.dateField.getValue();
58412 // work out monday..
58413 //st = st.add(Date.DAY, -1 * st.format('w'));
58415 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58417 var firstOfMonth = date.getFirstDayOfMonth();
58418 var days = date.getDaysInMonth();
58420 var firstAdded = false;
58421 for (var i = 0; i < result.totalRecords ; i++) {
58422 //var d= st.add(Date.DAY, i);
58425 for(var w = 0 ; w < 7 ; w++){
58426 if(!firstAdded && firstOfMonth != w){
58433 var dd = (d > 0 && d < 10) ? "0"+d : d;
58434 row['weekday'+w] = String.format(
58435 '<span style="font-size: 16px;"><b>{0}</b></span>'+
58436 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
58438 date.format('Y-m-')+dd
58441 if(typeof(_this.tdata[d]) != 'undefined'){
58442 Roo.each(_this.tdata[d], function(r){
58446 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
58447 if(r.parent_id*1>0){
58448 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
58451 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
58452 deactive = 'de-act-link';
58455 row['weekday'+w] += String.format(
58456 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
58458 r.product_id_name, //1
58459 r.when_dt.format('h:ia'), //2
58469 // only do this if something added..
58471 result.records.push(_this.grid.dataSource.reader.newRow(row));
58475 // push it twice. (second one with an hour..
58479 this.fireEvent("load", this, o, o.request.arg);
58480 o.request.callback.call(o.request.scope, result, o.request.arg, true);
58482 sortInfo : {field: 'when_dt', direction : 'ASC' },
58484 xtype: 'HttpProxy',
58487 url : baseURL + '/Roo/Shop_course.php'
58490 xtype: 'JsonReader',
58507 'name': 'parent_id',
58511 'name': 'product_id',
58515 'name': 'productitem_id',
58533 click : function (_self, e)
58535 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58536 sd.setMonth(sd.getMonth()-1);
58537 _this.monthField.setValue(sd.format('Y-m-d'));
58538 _this.grid.ds.load({});
58544 xtype: 'Separator',
58548 xtype: 'MonthField',
58551 render : function (_self)
58553 _this.monthField = _self;
58554 // _this.monthField.set today
58556 select : function (combo, date)
58558 _this.grid.ds.load({});
58561 value : (function() { return new Date(); })()
58564 xtype: 'Separator',
58570 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
58580 click : function (_self, e)
58582 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58583 sd.setMonth(sd.getMonth()+1);
58584 _this.monthField.setValue(sd.format('Y-m-d'));
58585 _this.grid.ds.load({});
58598 * Ext JS Library 1.1.1
58599 * Copyright(c) 2006-2007, Ext JS, LLC.
58601 * Originally Released Under LGPL - original licence link has changed is not relivant.
58604 * <script type="text/javascript">
58608 * @class Roo.LoadMask
58609 * A simple utility class for generically masking elements while loading data. If the element being masked has
58610 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
58611 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
58612 * element's UpdateManager load indicator and will be destroyed after the initial load.
58614 * Create a new LoadMask
58615 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
58616 * @param {Object} config The config object
58618 Roo.LoadMask = function(el, config){
58619 this.el = Roo.get(el);
58620 Roo.apply(this, config);
58622 this.store.on('beforeload', this.onBeforeLoad, this);
58623 this.store.on('load', this.onLoad, this);
58624 this.store.on('loadexception', this.onLoadException, this);
58625 this.removeMask = false;
58627 var um = this.el.getUpdateManager();
58628 um.showLoadIndicator = false; // disable the default indicator
58629 um.on('beforeupdate', this.onBeforeLoad, this);
58630 um.on('update', this.onLoad, this);
58631 um.on('failure', this.onLoad, this);
58632 this.removeMask = true;
58636 Roo.LoadMask.prototype = {
58638 * @cfg {Boolean} removeMask
58639 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
58640 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
58643 * @cfg {String} msg
58644 * The text to display in a centered loading message box (defaults to 'Loading...')
58646 msg : 'Loading...',
58648 * @cfg {String} msgCls
58649 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
58651 msgCls : 'x-mask-loading',
58654 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
58660 * Disables the mask to prevent it from being displayed
58662 disable : function(){
58663 this.disabled = true;
58667 * Enables the mask so that it can be displayed
58669 enable : function(){
58670 this.disabled = false;
58673 onLoadException : function()
58675 Roo.log(arguments);
58677 if (typeof(arguments[3]) != 'undefined') {
58678 Roo.MessageBox.alert("Error loading",arguments[3]);
58682 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
58683 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
58692 this.el.unmask(this.removeMask);
58695 onLoad : function()
58697 this.el.unmask(this.removeMask);
58701 onBeforeLoad : function(){
58702 if(!this.disabled){
58703 this.el.mask(this.msg, this.msgCls);
58708 destroy : function(){
58710 this.store.un('beforeload', this.onBeforeLoad, this);
58711 this.store.un('load', this.onLoad, this);
58712 this.store.un('loadexception', this.onLoadException, this);
58714 var um = this.el.getUpdateManager();
58715 um.un('beforeupdate', this.onBeforeLoad, this);
58716 um.un('update', this.onLoad, this);
58717 um.un('failure', this.onLoad, this);
58722 * Ext JS Library 1.1.1
58723 * Copyright(c) 2006-2007, Ext JS, LLC.
58725 * Originally Released Under LGPL - original licence link has changed is not relivant.
58728 * <script type="text/javascript">
58733 * @class Roo.XTemplate
58734 * @extends Roo.Template
58735 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
58737 var t = new Roo.XTemplate(
58738 '<select name="{name}">',
58739 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
58743 // then append, applying the master template values
58746 * Supported features:
58751 {a_variable} - output encoded.
58752 {a_variable.format:("Y-m-d")} - call a method on the variable
58753 {a_variable:raw} - unencoded output
58754 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
58755 {a_variable:this.method_on_template(...)} - call a method on the template object.
58760 <tpl for="a_variable or condition.."></tpl>
58761 <tpl if="a_variable or condition"></tpl>
58762 <tpl exec="some javascript"></tpl>
58763 <tpl name="named_template"></tpl> (experimental)
58765 <tpl for="."></tpl> - just iterate the property..
58766 <tpl for=".."></tpl> - iterates with the parent (probably the template)
58770 Roo.XTemplate = function()
58772 Roo.XTemplate.superclass.constructor.apply(this, arguments);
58779 Roo.extend(Roo.XTemplate, Roo.Template, {
58782 * The various sub templates
58787 * basic tag replacing syntax
58790 * // you can fake an object call by doing this
58794 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
58797 * compile the template
58799 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
58802 compile: function()
58806 s = ['<tpl>', s, '</tpl>'].join('');
58808 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
58809 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
58810 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
58811 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
58812 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
58817 while(true == !!(m = s.match(re))){
58818 var forMatch = m[0].match(nameRe),
58819 ifMatch = m[0].match(ifRe),
58820 execMatch = m[0].match(execRe),
58821 namedMatch = m[0].match(namedRe),
58826 name = forMatch && forMatch[1] ? forMatch[1] : '';
58829 // if - puts fn into test..
58830 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58832 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58837 // exec - calls a function... returns empty if true is returned.
58838 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58840 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58848 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58849 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58850 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58853 var uid = namedMatch ? namedMatch[1] : id;
58857 id: namedMatch ? namedMatch[1] : id,
58864 s = s.replace(m[0], '');
58866 s = s.replace(m[0], '{xtpl'+ id + '}');
58871 for(var i = tpls.length-1; i >= 0; --i){
58872 this.compileTpl(tpls[i]);
58873 this.tpls[tpls[i].id] = tpls[i];
58875 this.master = tpls[tpls.length-1];
58879 * same as applyTemplate, except it's done to one of the subTemplates
58880 * when using named templates, you can do:
58882 * var str = pl.applySubTemplate('your-name', values);
58885 * @param {Number} id of the template
58886 * @param {Object} values to apply to template
58887 * @param {Object} parent (normaly the instance of this object)
58889 applySubTemplate : function(id, values, parent)
58893 var t = this.tpls[id];
58897 if(t.test && !t.test.call(this, values, parent)){
58901 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58902 Roo.log(e.toString());
58908 if(t.exec && t.exec.call(this, values, parent)){
58912 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58913 Roo.log(e.toString());
58918 var vs = t.target ? t.target.call(this, values, parent) : values;
58919 parent = t.target ? values : parent;
58920 if(t.target && vs instanceof Array){
58922 for(var i = 0, len = vs.length; i < len; i++){
58923 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58925 return buf.join('');
58927 return t.compiled.call(this, vs, parent);
58929 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58930 Roo.log(e.toString());
58931 Roo.log(t.compiled);
58936 compileTpl : function(tpl)
58938 var fm = Roo.util.Format;
58939 var useF = this.disableFormats !== true;
58940 var sep = Roo.isGecko ? "+" : ",";
58941 var undef = function(str) {
58942 Roo.log("Property not found :" + str);
58946 var fn = function(m, name, format, args)
58948 //Roo.log(arguments);
58949 args = args ? args.replace(/\\'/g,"'") : args;
58950 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58951 if (typeof(format) == 'undefined') {
58952 format= 'htmlEncode';
58954 if (format == 'raw' ) {
58958 if(name.substr(0, 4) == 'xtpl'){
58959 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58962 // build an array of options to determine if value is undefined..
58964 // basically get 'xxxx.yyyy' then do
58965 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58966 // (function () { Roo.log("Property not found"); return ''; })() :
58971 Roo.each(name.split('.'), function(st) {
58972 lookfor += (lookfor.length ? '.': '') + st;
58973 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58976 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58979 if(format && useF){
58981 args = args ? ',' + args : "";
58983 if(format.substr(0, 5) != "this."){
58984 format = "fm." + format + '(';
58986 format = 'this.call("'+ format.substr(5) + '", ';
58990 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58994 // called with xxyx.yuu:(test,test)
58996 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58998 // raw.. - :raw modifier..
58999 return "'"+ sep + udef_st + name + ")"+sep+"'";
59003 // branched to use + in gecko and [].join() in others
59005 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
59006 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
59009 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
59010 body.push(tpl.body.replace(/(\r\n|\n)/g,
59011 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
59012 body.push("'].join('');};};");
59013 body = body.join('');
59016 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
59018 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
59024 applyTemplate : function(values){
59025 return this.master.compiled.call(this, values, {});
59026 //var s = this.subs;
59029 apply : function(){
59030 return this.applyTemplate.apply(this, arguments);
59035 Roo.XTemplate.from = function(el){
59036 el = Roo.getDom(el);
59037 return new Roo.XTemplate(el.value || el.innerHTML);